From c5ddd2ebb7bda8fd5c53696048b6418468c867ce Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 11 Oct 2024 16:25:29 -0500 Subject: [PATCH] Make verify_credentials and update_credentials return a consistent CredentialAccount object --- src/controllers/api/accounts.ts | 41 ++++++++++++++++++--------------- src/entities/MastodonAccount.ts | 2 +- src/views/mastodon/accounts.ts | 19 ++++++++------- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/controllers/api/accounts.ts b/src/controllers/api/accounts.ts index c4a2bc40..50c7d140 100644 --- a/src/controllers/api/accounts.ts +++ b/src/controllers/api/accounts.ts @@ -51,7 +51,7 @@ const verifyCredentialsController: AppController = async (c) => { const store = await Storages.db(); - const [author, [settingsStore], [captcha]] = await Promise.all([ + const [author, [settingsEvent], [captcha]] = await Promise.all([ getAuthor(pubkey, { signal: AbortSignal.timeout(5000) }), store.query([{ @@ -71,21 +71,16 @@ const verifyCredentialsController: AppController = async (c) => { }]), ]); + let settingsStore: Record | undefined; + try { + settingsStore = n.json().pipe(z.record(z.string(), z.unknown())).parse(settingsEvent?.content); + } catch { + // Do nothing + } + const account = author - ? await renderAccount(author, { withSource: true }) - : await accountFromPubkey(pubkey, { withSource: true }); - - if (settingsStore) { - try { - account.pleroma.settings_store = JSON.parse(settingsStore.content); - } catch { - // Ignore - } - } - - if (captcha && account.source) { - account.source.ditto.captcha_solved = true; - } + ? await renderAccount(author, { withSource: true, settingsStore, captcha }) + : await accountFromPubkey(pubkey, { withSource: true, settingsStore, captcha }); return c.json(account); }; @@ -280,7 +275,7 @@ const updateCredentialsSchema = z.object({ bot: z.boolean().optional(), discoverable: z.boolean().optional(), nip05: z.string().email().or(z.literal('')).optional(), - pleroma_settings_store: z.unknown().optional(), + pleroma_settings_store: z.record(z.string(), z.unknown()).optional(), lud16: z.string().email().or(z.literal('')).optional(), website: z.string().url().or(z.literal('')).optional(), }); @@ -290,6 +285,7 @@ const updateCredentialsController: AppController = async (c) => { const pubkey = await signer.getPublicKey(); const body = await parseBody(c.req.raw); const result = updateCredentialsSchema.safeParse(body); + const store = await Storages.db(); if (!result.success) { return c.json(result.error, 422); @@ -339,8 +335,17 @@ const updateCredentialsController: AppController = async (c) => { c, ); - const account = await renderAccount(event, { withSource: true }); + const [captcha] = await store.query([{ + kinds: [1985], + authors: [Conf.pubkey], + '#L': ['pub.ditto.captcha'], + '#l': ['solved'], + '#p': [pubkey], + limit: 1, + }]); + const settingsStore = result.data.pleroma_settings_store; + const account = await renderAccount(event, { withSource: true, settingsStore, captcha }); if (settingsStore) { await createEvent({ @@ -350,8 +355,6 @@ const updateCredentialsController: AppController = async (c) => { }, c); } - account.pleroma.settings_store = settingsStore; - return c.json(account); }; diff --git a/src/entities/MastodonAccount.ts b/src/entities/MastodonAccount.ts index b713d70c..99409c6a 100644 --- a/src/entities/MastodonAccount.ts +++ b/src/entities/MastodonAccount.ts @@ -54,7 +54,7 @@ export interface MastodonAccount { is_moderator: boolean; is_suggested: boolean; is_local: boolean; - settings_store: unknown; + settings_store?: Record; tags: string[]; }; nostr: { diff --git a/src/views/mastodon/accounts.ts b/src/views/mastodon/accounts.ts index 1e10c4ff..83bd705d 100644 --- a/src/views/mastodon/accounts.ts +++ b/src/views/mastodon/accounts.ts @@ -1,4 +1,4 @@ -import { NSchema as n } from '@nostrify/nostrify'; +import { type NostrEvent, NSchema as n } from '@nostrify/nostrify'; import { escape } from 'entities'; import { nip19, UnsignedEvent } from 'nostr-tools'; @@ -12,16 +12,19 @@ import { faviconCache } from '@/utils/favicon.ts'; import { nostrDate, nostrNow } from '@/utils.ts'; import { renderEmojis } from '@/views/mastodon/emojis.ts'; -interface ToAccountOpts { - withSource?: boolean; -} +type ToAccountOpts = { + withSource: true; + settingsStore: Record | undefined; + captcha: NostrEvent | undefined; +} | { + withSource?: false; +}; async function renderAccount( event: Omit, opts: ToAccountOpts = {}, signal = AbortSignal.timeout(3000), ): Promise { - const { withSource = false } = opts; const { pubkey } = event; const names = getTagSet(event.user?.tags ?? [], 'n'); @@ -76,7 +79,7 @@ async function renderAccount( locked: false, note: about ? escape(about) : '', roles: [], - source: withSource + source: opts.withSource ? { fields: [], language: '', @@ -88,7 +91,7 @@ async function renderAccount( nip05, }, ditto: { - captcha_solved: false, + captcha_solved: Boolean(opts.captcha), }, } : undefined, @@ -107,7 +110,7 @@ async function renderAccount( is_moderator: names.has('admin') || names.has('moderator'), is_suggested: names.has('suggested'), is_local: parsed05?.domain === Conf.url.host, - settings_store: undefined as unknown, + settings_store: opts.withSource ? opts.settingsStore : undefined, tags: [...getTagSet(event.user?.tags ?? [], 't')], favicon: favicon?.toString(), },