update swagger docs

This commit is contained in:
Izalia Mae 2024-07-04 22:58:50 -04:00
parent 773922e263
commit 9f5df5f95c
5 changed files with 220 additions and 56 deletions

View file

@ -352,7 +352,7 @@ async def handle_response_headers(
resp.headers['Server'] = 'ActivityRelay' resp.headers['Server'] = 'ActivityRelay'
# Still have to figure out how csp headers work # Still have to figure out how csp headers work
if resp.content_type == 'text/html': if resp.content_type == 'text/html' and not request.path.startswith("/api"):
resp.headers['Content-Security-Policy'] = get_csp(request) resp.headers['Content-Security-Policy'] = get_csp(request)
if not request.app['dev'] and request.path.endswith(('.css', '.js', '.woff2')): if not request.app['dev'] and request.path.endswith(('.css', '.js', '.woff2')):

View file

@ -51,7 +51,7 @@ WHERE username = :value or handle = :value;
-- name: get-user-by-token -- name: get-user-by-token
SELECT * FROM users SELECT * FROM users
WHERE username = ( WHERE username = (
SELECT user FROM app SELECT user FROM apps
WHERE token = :token WHERE token = :token
); );
@ -68,12 +68,12 @@ WHERE username = :value or handle = :value;
-- name: get-app -- name: get-app
SELECT * FROM app SELECT * FROM apps
WHERE client_id = :id and client_secret = :secret; WHERE client_id = :id and client_secret = :secret;
-- name: get-app-with-token -- name: get-app-with-token
SELECT * FROM app SELECT * FROM apps
WHERE client_id = :id and client_secret = :secret and token = :token; WHERE client_id = :id and client_secret = :secret and token = :token;

View file

@ -18,10 +18,12 @@ securityDefinitions:
in: cookie in: cookie
name: user-token name: user-token
Bearer: Bearer:
type: apiKey type: oauth2
name: Authorization name: Authorization
in: header in: header
description: "Enter the token with the `Bearer ` prefix" flow: accessCode
authorizationUrl: /oauth/authorize
tokenUrl: /oauth/token
paths: paths:
/: /:
@ -35,6 +37,161 @@ paths:
schema: schema:
$ref: "#/definitions/Error" $ref: "#/definitions/Error"
/oauth/authorize:
get:
tags:
- OAuth
description: Get an authorization code
parameters:
- in: query
name: response-type
required: true
type: string
- in: query
name: client_id
required: true
type: string
- in: query
name: redirect_uri
required: true
type: string
/oauth/token:
post:
tags:
- OAuth
description: Get a token for an authorized app
parameters:
- in: formData
name: grant_type
required: true
type: string
- in: formData
name: code
required: true
type: string
- in: formData
name: client_id
required: true
type: string
- in: formData
name: client_secret
required: true
type: string
- in: formData
name: redirect_uri
required: true
type: string
consumes:
- application/x-www-form-urlencoded
- application/json
- multipart/form-data
produces:
- application/json
responses:
"200":
description: Application
schema:
$ref: "#/definitions/Application"
/oauth/revoke:
post:
tags:
- OAuth
description: Get a token for an authorized app
parameters:
- in: formData
name: client_id
required: true
type: string
- in: formData
name: client_secret
required: true
type: string
- in: formData
name: token
required: true
type: string
consumes:
- application/json
- multipart/form-data
- application/x-www-form-urlencoded
produces:
- application/json
responses:
"200":
description: Message confirming application deletion
schema:
$ref: "#/definitions/Message"
/v1/app:
get:
tags:
- Applications
description: Verify the token is valid
produces:
- application/json
responses:
"200":
description: Application with the associated token
schema:
$ref: "#/definitions/Application"
post:
tags:
- Applications
description: Create a new application
parameters:
- in: query
name: name
required: true
type: string
- in: query
name: redirect_uri
required: true
type: string
- in: query
name: website
required: false
type: string
format: url
consumes:
- application/json
- multipart/form-data
- application/x-www-form-urlencoded
produces:
- application/json
responses:
"200":
description: Newly created application
schema:
$ref: "#/definitions/Application"
delete:
tags:
- Applications
description: Deletes an application
parameters:
- in: formData
name: client_id
required: true
type: string
- in: formData
name: client_secret
required: true
type: string
consumes:
- application/json
- multipart/form-data
- application/x-www-form-urlencoded
produces:
- application/json
responses:
"200":
description: Confirmation of application deletion
schema:
$ref: "#/definitions/Message"
/v1/relay: /v1/relay:
get: get:
tags: tags:
@ -48,23 +205,11 @@ paths:
schema: schema:
$ref: "#/definitions/Info" $ref: "#/definitions/Info"
/v1/token: /v1/login:
get:
tags:
- Token
description: Verify API token
produces:
- application/json
responses:
"200":
description: Valid token
schema:
$ref: "#/definitions/Message"
post: post:
tags: tags:
- Token - Login
description: Get a new token description: Login with a username and password
parameters: parameters:
- in: formData - in: formData
name: username name: username
@ -74,7 +219,6 @@ paths:
name: password name: password
required: true required: true
type: string type: string
format: password
consumes: consumes:
- application/json - application/json
- multipart/form-data - multipart/form-data
@ -83,22 +227,9 @@ paths:
- application/json - application/json
responses: responses:
"200": "200":
description: Created token description: A new Application
schema: schema:
$ref: "#/definitions/Token" $ref: "#/definitions/Application"
delete:
tags:
- Token
description: Revoke a token
produces:
- application/json
responses:
"200":
description: Revoked token
schema:
$ref: "#/definitions/Message"
/v1/config: /v1/config:
get: get:
@ -731,9 +862,43 @@ definitions:
description: Human-readable message text description: Human-readable message text
type: string type: string
Application:
type: object
properties:
client_id:
description: Identifier for the application
type: string
client_secret:
description: Secret string for the application
type: string
name:
description: Human-readable name of the application
type: string
website:
description: Website for the application
type: string
format: url
redirect_uri:
description: URL to redirect to when authorizing an app
type: string
token:
description: String to use in the Authorization header for client requests
type: string
created:
description: Date the application was created
type: string
format: date-time
accessed:
description: Date the application was last used
type: string
format: date-time
Config: Config:
type: object type: object
properties: properties:
approval-required:
description: Require instances to be approved when following
type: bool
log-level: log-level:
description: Maximum level of log messages to print to the console description: Maximum level of log messages to print to the console
type: string type: string
@ -743,6 +908,9 @@ definitions:
note: note:
description: Blurb to display on the home page description: Blurb to display on the home page
type: string type: string
theme:
description: Name of the color scheme to use for the frontend
type: string
whitelist-enabled: whitelist-enabled:
description: Only allow specific instances to join the relay when enabled description: Only allow specific instances to join the relay when enabled
type: boolean type: boolean
@ -843,13 +1011,6 @@ definitions:
type: string type: string
format: date-time format: date-time
Token:
type: object
properties:
token:
description: Character string used for authenticating with the api
type: string
User: User:
type: object type: object
properties: properties:

View file

@ -364,7 +364,7 @@ class Connection(SqlConnection):
'client_secret': app.client_secret 'client_secret': app.client_secret
} }
with self.update('app', data, **params) as cur: # type: ignore[arg-type] with self.update('apps', data, **params) as cur: # type: ignore[arg-type]
if (row := cur.one(schema.App)) is None: if (row := cur.one(schema.App)) is None:
raise RuntimeError('Failed to update row') raise RuntimeError('Failed to update row')

View file

@ -40,7 +40,7 @@ async def handle_api_path(
request: Request, request: Request,
handler: Callable[[Request], Awaitable[Response]]) -> Response: handler: Callable[[Request], Awaitable[Response]]) -> Response:
if not request.path.startswith('/api'): if not request.path.startswith('/api') or request.path == '/api/doc':
return await handler(request) return await handler(request)
if request.method != "OPTIONS" and check_api_path(request.method, request.path): if request.method != "OPTIONS" and check_api_path(request.method, request.path):
@ -58,6 +58,7 @@ async def handle_api_path(
@register_route('/oauth/authorize') @register_route('/oauth/authorize')
@register_route('/api/oauth/authorize')
class OauthAuthorize(View): class OauthAuthorize(View):
async def get(self, request: Request) -> Response: async def get(self, request: Request) -> Response:
data = await self.get_api_data(['response_type', 'client_id', 'redirect_uri'], []) data = await self.get_api_data(['response_type', 'client_id', 'redirect_uri'], [])
@ -66,11 +67,14 @@ class OauthAuthorize(View):
raise HttpError(400, 'Response type is not "code"') raise HttpError(400, 'Response type is not "code"')
with self.database.session(True) as conn: with self.database.session(True) as conn:
with conn.select('app', client_id = data['client_id']) as cur: with conn.select('apps', client_id = data['client_id']) as cur:
if (app := cur.one(schema.App)) is None: if (app := cur.one(schema.App)) is None:
raise HttpError(404, 'Could not find app') raise HttpError(404, 'Could not find app')
if app.token is not None or app.auth_code is not None: if app.token is not None:
raise HttpError(400, 'Application has already been authorized')
if app.auth_code is not None:
context = {'application': app} context = {'application': app}
html = self.template.render( html = self.template.render(
'page/authorize_show.haml', self.request, **context 'page/authorize_show.haml', self.request, **context
@ -96,6 +100,9 @@ class OauthAuthorize(View):
return Response.new_error(404, 'Could not find app', 'json') return Response.new_error(404, 'Could not find app', 'json')
if convert_to_boolean(data['response']): if convert_to_boolean(data['response']):
if app.token is not None:
raise HttpError(400, 'Application has already been authorized')
if app.auth_code is None: if app.auth_code is None:
app = conn.update_app(app, request['user'], True) app = conn.update_app(app, request['user'], True)
@ -116,6 +123,7 @@ class OauthAuthorize(View):
@register_route('/oauth/token') @register_route('/oauth/token')
@register_route('/api/oauth/token')
class OauthToken(View): class OauthToken(View):
async def post(self, request: Request) -> Response: async def post(self, request: Request) -> Response:
data = await self.get_api_data( data = await self.get_api_data(
@ -141,6 +149,7 @@ class OauthToken(View):
@register_route('/oauth/revoke') @register_route('/oauth/revoke')
@register_route('/api/oauth/revoke')
class OauthRevoke(View): class OauthRevoke(View):
async def post(self, request: Request) -> Response: async def post(self, request: Request) -> Response:
data = await self.get_api_data(['client_id', 'client_secret', 'token'], []) data = await self.get_api_data(['client_id', 'client_secret', 'token'], [])
@ -161,13 +170,7 @@ class OauthRevoke(View):
@register_route('/api/v1/app') @register_route('/api/v1/app')
class App(View): class App(View):
async def get(self, request: Request) -> Response: async def get(self, request: Request) -> Response:
data = await self.get_api_data(['client_id', 'client_secret'], []) return Response.new(request['token'].get_api_data(), ctype = 'json')
with self.database.session(False) as conn:
if (app := conn.get_app(data['client_id'], data['client_secret'])) is None:
raise HttpError(404, 'Application cannot be found')
return Response.new(app.get_api_data(), ctype = 'json')
async def post(self, request: Request) -> Response: async def post(self, request: Request) -> Response:
@ -210,7 +213,7 @@ class Login(View):
app = conn.put_app_login(user) app = conn.put_app_login(user)
resp = Response.new({'token': app.token}, ctype = 'json') resp = Response.new(app.get_api_data(), ctype = 'json')
resp.set_cookie( resp.set_cookie(
'user-token', 'user-token',
app.token, # type: ignore[arg-type] app.token, # type: ignore[arg-type]