From b4b7381b490ab637af8f0c64e9a3aef839887c96 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 17 Oct 2024 14:15:25 -0500 Subject: [PATCH] Implement OAuth revoke endpoint --- src/app.ts | 11 ++++++++--- src/controllers/api/fallback.ts | 3 +-- src/controllers/api/oauth.ts | 35 +++++++++++++++++++++++++++++++-- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/app.ts b/src/app.ts index b2a34765..fdcacf29 100644 --- a/src/app.ts +++ b/src/app.ts @@ -51,7 +51,7 @@ import { statusZapSplitsController, updateZapSplitsController, } from '@/controllers/api/ditto.ts'; -import { emptyArrayController, emptyObjectController, notImplementedController } from '@/controllers/api/fallback.ts'; +import { emptyArrayController, notImplementedController } from '@/controllers/api/fallback.ts'; import { instanceDescriptionController, instanceV1Controller, @@ -61,7 +61,12 @@ import { markersController, updateMarkersController } from '@/controllers/api/ma import { mediaController, updateMediaController } from '@/controllers/api/media.ts'; import { mutesController } from '@/controllers/api/mutes.ts'; import { notificationController, notificationsController } from '@/controllers/api/notifications.ts'; -import { createTokenController, oauthAuthorizeController, oauthController } from '@/controllers/api/oauth.ts'; +import { + createTokenController, + oauthAuthorizeController, + oauthController, + revokeTokenController, +} from '@/controllers/api/oauth.ts'; import { configController, frontendConfigController, @@ -201,7 +206,7 @@ app.get('/api/v1/apps/verify_credentials', appCredentialsController); app.post('/api/v1/apps', createAppController); app.post('/oauth/token', createTokenController); -app.post('/oauth/revoke', emptyObjectController); +app.post('/oauth/revoke', revokeTokenController); app.post('/oauth/authorize', oauthAuthorizeController); app.get('/oauth/authorize', oauthController); diff --git a/src/controllers/api/fallback.ts b/src/controllers/api/fallback.ts index 0fdf14a7..9e170093 100644 --- a/src/controllers/api/fallback.ts +++ b/src/controllers/api/fallback.ts @@ -1,7 +1,6 @@ import { Context } from '@hono/hono'; const emptyArrayController = (c: Context) => c.json([]); -const emptyObjectController = (c: Context) => c.json({}); const notImplementedController = (c: Context) => Promise.resolve(c.json({ error: 'Not implemented' }, 404)); -export { emptyArrayController, emptyObjectController, notImplementedController }; +export { emptyArrayController, notImplementedController }; diff --git a/src/controllers/api/oauth.ts b/src/controllers/api/oauth.ts index 61f8e1cd..eb5aee2d 100644 --- a/src/controllers/api/oauth.ts +++ b/src/controllers/api/oauth.ts @@ -9,7 +9,7 @@ import { Storages } from '@/storages.ts'; import { nostrNow } from '@/utils.ts'; import { parseBody } from '@/utils/api.ts'; import { aesEncrypt } from '@/utils/aes.ts'; -import { generateToken } from '@/utils/auth.ts'; +import { generateToken, getTokenHash } from '@/utils/auth.ts'; const passwordGrantSchema = z.object({ grant_type: z.literal('password'), @@ -79,6 +79,37 @@ const createTokenController: AppController = async (c) => { } }; +// This endpoint only requires the token. +// I don't think having the app credentials solves anything. +const revokeTokenSchema = z.object({ + token: z.string(), +}); + +/** + * Mastodon OAuth token revocation. + * https://docs.joinmastodon.org/methods/oauth/#revoke + */ +const revokeTokenController: AppController = async (c) => { + const body = await parseBody(c.req.raw); + const result = revokeTokenSchema.safeParse(body); + + if (!result.success) { + return c.json({ error: 'Bad request', schema: result.error }, 400); + } + + const { token } = result.data; + + const kysely = await Storages.kysely(); + const tokenHash = await getTokenHash(token as `token1${string}`); + + await kysely + .deleteFrom('auth_tokens') + .where('token_hash', '=', tokenHash) + .execute(); + + return c.json({}); +}; + async function getToken( { pubkey, secret, relays = [] }: { pubkey: string; secret?: string; relays?: string[] }, ): Promise<`token1${string}`> { @@ -229,4 +260,4 @@ function addCodeToRedirectUri(redirectUri: string, code: string, state?: string) return url.toString(); } -export { createTokenController, oauthAuthorizeController, oauthController }; +export { createTokenController, oauthAuthorizeController, oauthController, revokeTokenController };