diff --git a/src/api/oauth.ts b/src/api/oauth.ts index fa3dbac..cbad45b 100644 --- a/src/api/oauth.ts +++ b/src/api/oauth.ts @@ -1,22 +1,98 @@ import { validator, z } from '@/deps.ts'; +import { AppController } from '@/app.ts'; -const createTokenSchema = z.object({ +const passwordGrantSchema = z.object({ + grant_type: z.literal('password'), password: z.string(), }); +const codeGrantSchema = z.object({ + grant_type: z.literal('authorization_code'), + code: z.string(), +}); + +const createTokenSchema = z.discriminatedUnion('grant_type', [ + passwordGrantSchema, + codeGrantSchema, +]); + const createTokenController = validator('json', (value, c) => { const result = createTokenSchema.safeParse(value); if (result.success) { - return c.json({ - access_token: result.data.password, - token_type: 'Bearer', - scope: 'read write follow push', - created_at: Math.floor(new Date().getTime() / 1000), - }); - } else { - return c.json({ error: 'Invalid request' }, 400); + switch (result.data.grant_type) { + case 'password': + return c.json({ + access_token: result.data.password, + token_type: 'Bearer', + scope: 'read write follow push', + created_at: Math.floor(new Date().getTime() / 1000), + }); + case 'authorization_code': + return c.json({ + access_token: result.data.code, + token_type: 'Bearer', + scope: 'read write follow push', + created_at: Math.floor(new Date().getTime() / 1000), + }); + } } + + return c.json({ error: 'Invalid request' }, 400); }); -export { createTokenController }; +/** Display the OAuth form. */ +const oauthController: AppController = (c) => { + const encodedUri = c.req.query('redirect_uri'); + if (!encodedUri) { + return c.text('Missing `redirect_uri` query param.', 422); + } + + const redirectUri = decodeURIComponent(encodedUri); + + // Poor man's XSS check. + // TODO: Render form with JSX. + try { + new URL(redirectUri); + } catch (_e) { + return c.text('Invalid `redirect_uri`.', 422); + } + + c.res.headers.set('content-security-policy', 'default-src \'self\''); + + // TODO: Login with `window.nostr` (NIP-07). + return c.html(` + +
+