From e26b540246342ecdd02940e7f9afb69eff4ab2df Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 30 Apr 2023 14:13:27 -0500 Subject: [PATCH] OAuth token endpoint: support formData --- src/api/oauth.ts | 44 +++++++++++++++++++++----------------------- src/deps.ts | 1 + src/utils.ts | 25 +++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/api/oauth.ts b/src/api/oauth.ts index cbad45b..fae3e88 100644 --- a/src/api/oauth.ts +++ b/src/api/oauth.ts @@ -1,5 +1,6 @@ -import { validator, z } from '@/deps.ts'; +import { z } from '@/deps.ts'; import { AppController } from '@/app.ts'; +import { parseBody } from '@/utils.ts'; const passwordGrantSchema = z.object({ grant_type: z.literal('password'), @@ -16,30 +17,27 @@ const createTokenSchema = z.discriminatedUnion('grant_type', [ codeGrantSchema, ]); -const createTokenController = validator('json', (value, c) => { - const result = createTokenSchema.safeParse(value); +const createTokenController: AppController = async (c) => { + const body = await parseBody(c.req.raw); + const data = createTokenSchema.parse(body); - if (result.success) { - 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), - }); - } + switch (data.grant_type) { + case 'password': + return c.json({ + access_token: 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: 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); -}); +}; /** Display the OAuth form. */ const oauthController: AppController = (c) => { diff --git a/src/deps.ts b/src/deps.ts index 08eab05..571303d 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -21,3 +21,4 @@ export { signEvent as getSignature, } from 'npm:nostr-tools@^1.10.1'; export { findReplyTag } from 'https://gitlab.com/soapbox-pub/mostr/-/raw/c67064aee5ade5e01597c6d23e22e53c628ef0e2/src/nostr/tags.ts'; +export { parseFormData } from 'npm:formdata-helper@^0.3.0'; diff --git a/src/utils.ts b/src/utils.ts index 5e6ce9e..e8acb84 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,4 @@ -import { Context, getPublicKey, nip19, nip21 } from '@/deps.ts'; +import { Context, getPublicKey, nip19, nip21, parseFormData } from '@/deps.ts'; import { type Event } from '@/event.ts'; /** Get the current time in Nostr format. */ @@ -75,4 +75,25 @@ function parseNip05(value: string): Nip05 { }; } -export { bech32ToPubkey, eventDateComparator, getKeys, isBech32, isNostrId, type Nip05, nostrNow, parseNip05 }; +/** Parse request body to JSON, depending on the content-type of the request. */ +async function parseBody(req: Request): Promise { + switch (req.headers.get('content-type')?.split(';')[0]) { + case 'multipart/form-data': + case 'application/x-www-form-urlencoded': + return parseFormData(await req.formData()); + case 'application/json': + return req.json(); + } +} + +export { + bech32ToPubkey, + eventDateComparator, + getKeys, + isBech32, + isNostrId, + type Nip05, + nostrNow, + parseBody, + parseNip05, +};