diff --git a/backend/src/mastodon/client.ts b/backend/src/mastodon/client.ts index 2c2df3d..db8472b 100644 --- a/backend/src/mastodon/client.ts +++ b/backend/src/mastodon/client.ts @@ -6,16 +6,16 @@ export interface Client { secret: string name: string redirect_uris: string - website: string scopes: string + website?: string } export async function createClient( db: Database, name: string, redirect_uris: string, - website: string, - scopes: string + scopes: string, + website?: string ): Promise { const id = crypto.randomUUID() diff --git a/backend/test/mastodon/apps.spec.ts b/backend/test/mastodon/apps.spec.ts index 998a2fa..17896f5 100644 --- a/backend/test/mastodon/apps.spec.ts +++ b/backend/test/mastodon/apps.spec.ts @@ -36,6 +36,33 @@ describe('Mastodon APIs', () => { assert.deepEqual(rest, {}) }) + test('POST /apps registers client without website', async () => { + const db = await makeDB() + const vapidKeys = await generateVAPIDKeys() + const request = new Request('https://example.com', { + method: 'POST', + body: '{"redirect_uris":"mastodon://example.com/oauth","client_name":"Example mastodon client","scopes":"read write follow push"}', + headers: { + 'content-type': 'application/json', + }, + }) + + const res = await apps.handleRequest(db, request, vapidKeys) + assert.equal(res.status, 200) + assertCORS(res) + assertJSON(res) + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { name, redirect_uri, client_id, client_secret, vapid_key, id, ...rest } = await res.json< + Record + >() + + assert.equal(name, 'Example mastodon client') + assert.equal(redirect_uri, 'mastodon://example.com/oauth') + assert.equal(id, '20') + assert.deepEqual(rest, {}) + }) + test('POST /apps returns 422 for malformed requests', async () => { // client_name and redirect_uris are required according to https://docs.joinmastodon.org/methods/apps/#form-data-parameters const db = await makeDB() diff --git a/backend/test/utils.ts b/backend/test/utils.ts index 7220ca7..418607e 100644 --- a/backend/test/utils.ts +++ b/backend/test/utils.ts @@ -73,7 +73,7 @@ export async function createTestClient( redirectUri: string = 'https://localhost', scopes: string = 'read follow' ): Promise { - return createClient(db, 'test client', redirectUri, 'https://cloudflare.com', scopes) + return createClient(db, 'test client', redirectUri, scopes, 'https://cloudflare.com') } type TestQueue = Queue & { messages: Array } diff --git a/functions/api/v1/apps.ts b/functions/api/v1/apps.ts index 32d9f17..ef19120 100644 --- a/functions/api/v1/apps.ts +++ b/functions/api/v1/apps.ts @@ -11,7 +11,7 @@ import { type Database, getDatabase } from 'wildebeest/backend/src/database' type AppsPost = { redirect_uris: string - website: string + website?: string client_name: string scopes: string } @@ -42,9 +42,18 @@ export async function handleRequest(db: Database, request: Request, vapidKeys: J } catch { return errors.unprocessableEntity('redirect_uris must be a valid URI') } + } else if (body.website) { + if (body.website.length > 2000) { + return errors.unprocessableEntity('website cannot exceed 2000 characters') + } + try { + new URL('', body.website) + } catch { + return errors.unprocessableEntity('website is invalid URI') + } } - const client = await createClient(db, body.client_name, body.redirect_uris, body.website, body.scopes) + const client = await createClient(db, body.client_name, body.redirect_uris, body.scopes, body.website) const vapidKey = VAPIDPublicKey(vapidKeys) const res = {