mirror of
https://git.pleroma.social/pleroma/relay.git
synced 2024-11-22 22:48:00 +00:00
add user management api endpoints and allow cookie for api auth
This commit is contained in:
parent
08f4f0e72d
commit
1ffc609058
|
@ -13,6 +13,10 @@ schemes:
|
||||||
- https
|
- https
|
||||||
|
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
|
Cookie:
|
||||||
|
type: apiKey
|
||||||
|
in: cookie
|
||||||
|
name: user-token
|
||||||
Bearer:
|
Bearer:
|
||||||
type: apiKey
|
type: apiKey
|
||||||
name: Authorization
|
name: Authorization
|
||||||
|
@ -549,6 +553,104 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/Error"
|
$ref: "#/definitions/Error"
|
||||||
|
|
||||||
|
/v1/user:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
description: Get a list of all local users
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: List of users
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/definitions/User"
|
||||||
|
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
description: Create a new user
|
||||||
|
parameters:
|
||||||
|
- in: formData
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- in: formData
|
||||||
|
name: password
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
format: password
|
||||||
|
- in: formData
|
||||||
|
name: handle
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Newly created user
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/User"
|
||||||
|
"404":
|
||||||
|
description: User already exists
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/Error"
|
||||||
|
|
||||||
|
patch:
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
description: Update a user's password or handle
|
||||||
|
parameters:
|
||||||
|
- in: formData
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- in: formData
|
||||||
|
name: password
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
format: password
|
||||||
|
- in: formData
|
||||||
|
name: handle
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Updated user data
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/User"
|
||||||
|
"404":
|
||||||
|
description: User does not exist
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/Error"
|
||||||
|
|
||||||
|
delete:
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
description: Delete a user
|
||||||
|
parameters:
|
||||||
|
- in: formData
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"202":
|
||||||
|
description: Successfully deleted user
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/Message"
|
||||||
|
"404":
|
||||||
|
description: User not found
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/Error"
|
||||||
|
|
||||||
/v1/whitelist:
|
/v1/whitelist:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
@ -748,6 +850,21 @@ definitions:
|
||||||
description: Character string used for authenticating with the api
|
description: Character string used for authenticating with the api
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
|
User:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
description: Username of the account
|
||||||
|
type: string
|
||||||
|
handle:
|
||||||
|
description: Fediverse handle associated with the account
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
created:
|
||||||
|
description: Date the account was created
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
|
||||||
Whitelist:
|
Whitelist:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -190,13 +190,28 @@ class Connection(SqlConnection):
|
||||||
return cur.one() # type: ignore
|
return cur.one() # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def put_user(self, username: str, password: str, handle: str | None = None) -> Row:
|
def put_user(self, username: str, password: str | None, handle: str | None = None) -> Row:
|
||||||
data = {
|
if self.get_user(username):
|
||||||
'username': username,
|
data = {
|
||||||
'hash': self.hasher.hash(password),
|
'username': username
|
||||||
'handle': handle,
|
}
|
||||||
'created': datetime.now(tz = timezone.utc)
|
|
||||||
}
|
if password:
|
||||||
|
data['password'] = password
|
||||||
|
|
||||||
|
if handle:
|
||||||
|
data['handler'] = handle
|
||||||
|
|
||||||
|
else:
|
||||||
|
if password is None:
|
||||||
|
raise ValueError('Password cannot be empty')
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'username': username,
|
||||||
|
'hash': self.hasher.hash(password),
|
||||||
|
'handle': handle,
|
||||||
|
'created': datetime.now(tz = timezone.utc)
|
||||||
|
}
|
||||||
|
|
||||||
with self.run('put-user', data) as cur:
|
with self.run('put-user', data) as cur:
|
||||||
return cur.one() # type: ignore
|
return cur.one() # type: ignore
|
||||||
|
|
|
@ -34,7 +34,11 @@ def check_api_path(method: str, path: str) -> bool:
|
||||||
@web.middleware
|
@web.middleware
|
||||||
async def handle_api_path(request: Request, handler: Callable) -> Response:
|
async def handle_api_path(request: Request, handler: Callable) -> Response:
|
||||||
try:
|
try:
|
||||||
request['token'] = request.headers['Authorization'].replace('Bearer', '').strip()
|
if (token := request.cookies.get('user-token')):
|
||||||
|
request['token'] = token
|
||||||
|
|
||||||
|
else:
|
||||||
|
request['token'] = request.headers['Authorization'].replace('Bearer', '').strip()
|
||||||
|
|
||||||
with get_app().database.session() as conn:
|
with get_app().database.session() as conn:
|
||||||
request['user'] = conn.get_user_by_token(request['token'])
|
request['user'] = conn.get_user_by_token(request['token'])
|
||||||
|
@ -384,6 +388,63 @@ class SoftwareBan(View):
|
||||||
return Response.new({'message': 'Unbanned software'}, ctype = 'json')
|
return Response.new({'message': 'Unbanned software'}, ctype = 'json')
|
||||||
|
|
||||||
|
|
||||||
|
@register_route('/api/v1/user')
|
||||||
|
class User(View):
|
||||||
|
async def get(self, request: Request) -> Response:
|
||||||
|
with self.database.session() as conn:
|
||||||
|
items = []
|
||||||
|
|
||||||
|
for row in conn.execute('SELECT * FROM users'):
|
||||||
|
del row['hash']
|
||||||
|
items.append(row)
|
||||||
|
|
||||||
|
return Response.new(items, ctype = 'json')
|
||||||
|
|
||||||
|
|
||||||
|
async def post(self, request: Request) -> Response:
|
||||||
|
data = await self.get_api_data(['username', 'password'], ['handle'])
|
||||||
|
|
||||||
|
if isinstance(data, Response):
|
||||||
|
return data
|
||||||
|
|
||||||
|
with self.database.session() as conn:
|
||||||
|
if conn.get_user(data['username']):
|
||||||
|
return Response.new_error(404, 'User already exists', 'json')
|
||||||
|
|
||||||
|
user = conn.put_user(**data)
|
||||||
|
del user['hash']
|
||||||
|
|
||||||
|
return Response.new(user, ctype = 'json')
|
||||||
|
|
||||||
|
|
||||||
|
async def patch(self, request: Request) -> Response:
|
||||||
|
data = await self.get_api_data(['username'], ['password', ['handle']])
|
||||||
|
|
||||||
|
if isinstance(data, Response):
|
||||||
|
return data
|
||||||
|
|
||||||
|
with self.database.session(True) as conn:
|
||||||
|
user = conn.put_user(**data)
|
||||||
|
del user['hash']
|
||||||
|
|
||||||
|
return Response.new(user, ctype = 'json')
|
||||||
|
|
||||||
|
|
||||||
|
async def delete(self, request: Request) -> Response:
|
||||||
|
data = await self.get_api_data(['username'], [])
|
||||||
|
|
||||||
|
if isinstance(data, Response):
|
||||||
|
return data
|
||||||
|
|
||||||
|
with self.database.session(True) as conn:
|
||||||
|
if not conn.get_user(data['username']):
|
||||||
|
return Response.new_error(404, 'User does not exist', 'json')
|
||||||
|
|
||||||
|
conn.del_user(data['username'])
|
||||||
|
|
||||||
|
return Response.new({'message': 'Deleted user'}, ctype = 'json')
|
||||||
|
|
||||||
|
|
||||||
@register_route('/api/v1/whitelist')
|
@register_route('/api/v1/whitelist')
|
||||||
class Whitelist(View):
|
class Whitelist(View):
|
||||||
async def get(self, request: Request) -> Response:
|
async def get(self, request: Request) -> Response:
|
||||||
|
|
|
@ -126,7 +126,7 @@ class View(AbstractView):
|
||||||
return Response.new_error(400, 'Invalid JSON data', 'json')
|
return Response.new_error(400, 'Invalid JSON data', 'json')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
post_data = convert_data(await self.request.query) # type: ignore
|
post_data = convert_data(self.request.query) # type: ignore
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue