c.get('pubkey') -> await c.get('signer')?.getPublicKey()

This commit is contained in:
Alex Gleason 2024-05-14 11:57:03 -05:00
parent c5fbe69b80
commit c715827c81
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
14 changed files with 81 additions and 46 deletions

View File

@ -29,7 +29,7 @@ const createAccountSchema = z.object({
});
const createAccountController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const result = createAccountSchema.safeParse(await c.req.json());
if (!result.success) {
@ -45,7 +45,7 @@ const createAccountController: AppController = async (c) => {
};
const verifyCredentialsController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const event = await getAuthor(pubkey, { relations: ['author_stats'] });
if (event) {
@ -122,7 +122,7 @@ const accountSearchController: AppController = async (c) => {
};
const relationshipsController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const ids = z.array(z.string()).safeParse(c.req.queries('id[]'));
if (!ids.success) {
@ -178,7 +178,11 @@ const accountStatusesController: AppController = async (c) => {
return events;
});
const statuses = await Promise.all(events.map((event) => renderStatus(event, { viewerPubkey: c.get('pubkey') })));
const viewerPubkey = await c.get('signer')?.getPublicKey();
const statuses = await Promise.all(
events.map((event) => renderStatus(event, { viewerPubkey })),
);
return paginated(c, events, statuses);
};
@ -194,7 +198,7 @@ const updateCredentialsSchema = z.object({
});
const updateCredentialsController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const body = await parseBody(c.req.raw);
const result = updateCredentialsSchema.safeParse(body);
@ -236,7 +240,7 @@ const updateCredentialsController: AppController = async (c) => {
/** https://docs.joinmastodon.org/methods/accounts/#follow */
const followController: AppController = async (c) => {
const sourcePubkey = c.get('pubkey')!;
const sourcePubkey = await c.get('signer')?.getPublicKey()!;
const targetPubkey = c.req.param('pubkey');
await updateListEvent(
@ -253,7 +257,7 @@ const followController: AppController = async (c) => {
/** https://docs.joinmastodon.org/methods/accounts/#unfollow */
const unfollowController: AppController = async (c) => {
const sourcePubkey = c.get('pubkey')!;
const sourcePubkey = await c.get('signer')?.getPublicKey()!;
const targetPubkey = c.req.param('pubkey');
await updateListEvent(
@ -290,7 +294,7 @@ const unblockController: AppController = (c) => {
/** https://docs.joinmastodon.org/methods/accounts/#mute */
const muteController: AppController = async (c) => {
const sourcePubkey = c.get('pubkey')!;
const sourcePubkey = await c.get('signer')?.getPublicKey()!;
const targetPubkey = c.req.param('pubkey');
await updateListEvent(
@ -305,7 +309,7 @@ const muteController: AppController = async (c) => {
/** https://docs.joinmastodon.org/methods/accounts/#unmute */
const unmuteController: AppController = async (c) => {
const sourcePubkey = c.get('pubkey')!;
const sourcePubkey = await c.get('signer')?.getPublicKey()!;
const targetPubkey = c.req.param('pubkey');
await updateListEvent(
@ -319,7 +323,7 @@ const unmuteController: AppController = async (c) => {
};
const favouritesController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const params = paginationSchema.parse(c.req.query());
const { signal } = c.req.raw;
@ -335,7 +339,11 @@ const favouritesController: AppController = async (c) => {
const events1 = await Storages.db.query([{ kinds: [1], ids }], { signal })
.then((events) => hydrateEvents({ events, storage: Storages.db, signal }));
const statuses = await Promise.all(events1.map((event) => renderStatus(event, { viewerPubkey: c.get('pubkey') })));
const viewerPubkey = await c.get('signer')?.getPublicKey();
const statuses = await Promise.all(
events1.map((event) => renderStatus(event, { viewerPubkey })),
);
return paginated(c, events1, statuses);
};

View File

@ -5,7 +5,7 @@ import { renderStatuses } from '@/views.ts';
/** https://docs.joinmastodon.org/methods/bookmarks/#get */
const bookmarksController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const { signal } = c.req.raw;
const [event10003] = await Storages.db.query(

View File

@ -14,7 +14,7 @@ interface Marker {
}
export const markersController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const timelines = c.req.queries('timeline[]') ?? [];
const results = await kv.getMany<Marker[]>(
@ -37,7 +37,7 @@ const markerDataSchema = z.object({
});
export const updateMarkersController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const record = z.record(z.enum(['home', 'notifications']), markerDataSchema).parse(await parseBody(c.req.raw));
const timelines = Object.keys(record) as Timeline[];

View File

@ -14,7 +14,7 @@ const mediaBodySchema = z.object({
});
const mediaController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const result = mediaBodySchema.safeParse(await parseBody(c.req.raw));
const { signal } = c.req.raw;

View File

@ -5,7 +5,7 @@ import { renderAccounts } from '@/views.ts';
/** https://docs.joinmastodon.org/methods/mutes/#get */
const mutesController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const { signal } = c.req.raw;
const [event10000] = await Storages.db.query(

View File

@ -5,8 +5,8 @@ import { hydrateEvents } from '@/storages/hydrate.ts';
import { paginated, paginationSchema } from '@/utils/api.ts';
import { renderNotification } from '@/views/mastodon/notifications.ts';
const notificationsController: AppController = (c) => {
const pubkey = c.get('pubkey')!;
const notificationsController: AppController = async (c) => {
const pubkey = await c.get('signer')?.getPublicKey()!;
const { since, until } = paginationSchema.parse(c.req.query());
return renderNotifications(c, [{ kinds: [1, 6, 7], '#p': [pubkey], since, until }]);
@ -14,7 +14,7 @@ const notificationsController: AppController = (c) => {
async function renderNotifications(c: AppContext, filters: NostrFilter[]) {
const store = c.get('store');
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const { signal } = c.req.raw;
const events = await store

View File

@ -55,9 +55,15 @@ const reportController: AppController = async (c) => {
/** https://docs.joinmastodon.org/methods/admin/reports/#get */
const adminReportsController: AppController = async (c) => {
const store = c.get('store');
const viewerPubkey = await c.get('signer')?.getPublicKey();
const reports = await store.query([{ kinds: [1984], '#P': [Conf.pubkey] }])
.then((events) => hydrateEvents({ storage: store, events: events, signal: c.req.raw.signal }))
.then((events) => Promise.all(events.map((event) => renderAdminReport(event, { viewerPubkey: c.get('pubkey') }))));
.then((events) =>
Promise.all(
events.map((event) => renderAdminReport(event, { viewerPubkey })),
)
);
return c.json(reports);
};
@ -67,7 +73,7 @@ const adminReportController: AppController = async (c) => {
const eventId = c.req.param('id');
const { signal } = c.req.raw;
const store = c.get('store');
const pubkey = c.get('pubkey');
const pubkey = await c.get('signer')?.getPublicKey();
const [event] = await store.query([{
kinds: [1984],
@ -89,7 +95,7 @@ const adminReportResolveController: AppController = async (c) => {
const eventId = c.req.param('id');
const { signal } = c.req.raw;
const store = c.get('store');
const pubkey = c.get('pubkey');
const pubkey = await c.get('signer')?.getPublicKey();
const [event] = await store.query([{
kinds: [1984],

View File

@ -43,6 +43,7 @@ const searchController: AppController = async (c) => {
}
const results = dedupeEvents(events);
const viewerPubkey = await c.get('signer')?.getPublicKey();
const [accounts, statuses] = await Promise.all([
Promise.all(
@ -54,7 +55,7 @@ const searchController: AppController = async (c) => {
Promise.all(
results
.filter((event) => event.kind === 1)
.map((event) => renderStatus(event, { viewerPubkey: c.get('pubkey') }))
.map((event) => renderStatus(event, { viewerPubkey }))
.filter(Boolean),
),
]);

View File

@ -47,7 +47,7 @@ const statusController: AppController = async (c) => {
});
if (event) {
return c.json(await renderStatus(event, { viewerPubkey: c.get('pubkey') }));
return c.json(await renderStatus(event, { viewerPubkey: await c.get('signer')?.getPublicKey() }));
}
return c.json({ error: 'Event not found.' }, 404);
@ -89,9 +89,11 @@ const createStatusController: AppController = async (c) => {
tags.push(['subject', data.spoiler_text]);
}
const viewerPubkey = await c.get('signer')?.getPublicKey();
if (data.media_ids?.length) {
const media = await getUnattachedMediaByIds(data.media_ids)
.then((media) => media.filter(({ pubkey }) => pubkey === c.get('pubkey')))
.then((media) => media.filter(({ pubkey }) => pubkey === viewerPubkey))
.then((media) => media.map(({ url, data }) => ['media', url, data]));
tags.push(...media);
@ -143,12 +145,12 @@ const createStatusController: AppController = async (c) => {
});
}
return c.json(await renderStatus({ ...event, author }, { viewerPubkey: c.get('pubkey') }));
return c.json(await renderStatus({ ...event, author }, { viewerPubkey: await c.get('signer')?.getPublicKey() }));
};
const deleteStatusController: AppController = async (c) => {
const id = c.req.param('id');
const pubkey = c.get('pubkey');
const pubkey = await c.get('signer')?.getPublicKey();
const event = await getEvent(id, { signal: c.req.raw.signal });
@ -172,9 +174,12 @@ const deleteStatusController: AppController = async (c) => {
const contextController: AppController = async (c) => {
const id = c.req.param('id');
const event = await getEvent(id, { kind: 1, relations: ['author', 'event_stats', 'author_stats'] });
const viewerPubkey = await c.get('signer')?.getPublicKey();
async function renderStatuses(events: NostrEvent[]) {
const statuses = await Promise.all(events.map((event) => renderStatus(event, { viewerPubkey: c.get('pubkey') })));
const statuses = await Promise.all(
events.map((event) => renderStatus(event, { viewerPubkey })),
);
return statuses.filter(Boolean);
}
@ -204,7 +209,7 @@ const favouriteController: AppController = async (c) => {
],
}, c);
const status = await renderStatus(target, { viewerPubkey: c.get('pubkey') });
const status = await renderStatus(target, { viewerPubkey: await c.get('signer')?.getPublicKey() });
if (status) {
status.favourited = true;
@ -247,7 +252,7 @@ const reblogStatusController: AppController = async (c) => {
signal: signal,
});
const status = await renderReblog(reblogEvent, { viewerPubkey: c.get('pubkey') });
const status = await renderReblog(reblogEvent, { viewerPubkey: await c.get('signer')?.getPublicKey() });
return c.json(status);
};
@ -255,7 +260,7 @@ const reblogStatusController: AppController = async (c) => {
/** https://docs.joinmastodon.org/methods/statuses/#unreblog */
const unreblogStatusController: AppController = async (c) => {
const eventId = c.req.param('id');
const pubkey = c.get('pubkey') as string;
const pubkey = await c.get('signer')?.getPublicKey() as string;
const event = await getEvent(eventId, {
kind: 1,
@ -282,7 +287,7 @@ const rebloggedByController: AppController = (c) => {
/** https://docs.joinmastodon.org/methods/statuses/#bookmark */
const bookmarkController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const eventId = c.req.param('id');
const event = await getEvent(eventId, {
@ -309,7 +314,7 @@ const bookmarkController: AppController = async (c) => {
/** https://docs.joinmastodon.org/methods/statuses/#unbookmark */
const unbookmarkController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const eventId = c.req.param('id');
const event = await getEvent(eventId, {
@ -336,7 +341,7 @@ const unbookmarkController: AppController = async (c) => {
/** https://docs.joinmastodon.org/methods/statuses/#pin */
const pinController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const eventId = c.req.param('id');
const event = await getEvent(eventId, {
@ -363,7 +368,7 @@ const pinController: AppController = async (c) => {
/** https://docs.joinmastodon.org/methods/statuses/#unpin */
const unpinController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const eventId = c.req.param('id');
const { signal } = c.req.raw;
@ -423,7 +428,7 @@ const zapController: AppController = async (c) => {
],
}, c);
const status = await renderStatus(target, { viewerPubkey: c.get('pubkey') });
const status = await renderStatus(target, { viewerPubkey: await c.get('signer')?.getPublicKey() });
status.zapped = true;
return c.json(status);

View File

@ -11,7 +11,7 @@ import { renderReblog, renderStatus } from '@/views/mastodon/statuses.ts';
const homeTimelineController: AppController = async (c) => {
const params = paginationSchema.parse(c.req.query());
const pubkey = c.get('pubkey')!;
const pubkey = await c.get('signer')?.getPublicKey()!;
const authors = await getFeedPubkeys(pubkey);
return renderStatuses(c, [{ authors, kinds: [1, 6], ...params }]);
};
@ -61,11 +61,13 @@ async function renderStatuses(c: AppContext, filters: NostrFilter[]) {
return c.json([]);
}
const viewerPubkey = await c.get('signer')?.getPublicKey();
const statuses = (await Promise.all(events.map((event) => {
if (event.kind === 6) {
return renderReblog(event, { viewerPubkey: c.get('pubkey') });
return renderReblog(event, { viewerPubkey });
}
return renderStatus(event, { viewerPubkey: c.get('pubkey') });
return renderStatus(event, { viewerPubkey });
}))).filter((boolean) => boolean);
if (!statuses.length) {

View File

@ -8,7 +8,6 @@ import {
validateAuthEvent,
} from '@/utils/nip98.ts';
import { localRequest } from '@/utils/api.ts';
import { APISigner } from '@/signers/APISigner.ts';
import { findUser, User } from '@/db/users.ts';
/**
@ -70,7 +69,7 @@ function withProof(
opts?: ParseAuthRequestOpts,
): AppMiddleware {
return async (c, next) => {
const pubkey = c.get('pubkey');
const pubkey = await c.get('signer')?.getPublicKey();
const proof = c.get('proof') || await obtainProof(c, opts);
// Prevent people from accidentally using the wrong account. This has no other security implications.
@ -90,9 +89,16 @@ function withProof(
/** Get the proof over Nostr Connect. */
async function obtainProof(c: AppContext, opts?: ParseAuthRequestOpts) {
const signer = c.get('signer');
if (!signer) {
throw new HTTPException(401, {
res: c.json({ error: 'No way to sign Nostr event' }, 401),
});
}
const req = localRequest(c);
const reqEvent = await buildAuthEventTemplate(req, opts);
const resEvent = await new APISigner(c).signEvent(reqEvent);
const resEvent = await signer.signEvent(reqEvent);
const result = await validateAuthEvent(req, resEvent, opts);
if (result.success) {

View File

@ -4,7 +4,7 @@ import { Storages } from '@/storages.ts';
/** Store middleware. */
const storeMiddleware: AppMiddleware = async (c, next) => {
const pubkey = c.get('pubkey');
const pubkey = await c.get('signer')?.getPublicKey();
if (pubkey) {
const store = new UserStore(pubkey, Storages.admin);

View File

@ -10,7 +10,6 @@ import { type AppContext } from '@/app.ts';
import { Conf } from '@/config.ts';
import * as pipeline from '@/pipeline.ts';
import { AdminSigner } from '@/signers/AdminSigner.ts';
import { APISigner } from '@/signers/APISigner.ts';
import { Storages } from '@/storages.ts';
import { nostrNow } from '@/utils.ts';
@ -21,7 +20,13 @@ type EventStub = TypeFest.SetOptional<EventTemplate, 'content' | 'created_at' |
/** Publish an event through the pipeline. */
async function createEvent(t: EventStub, c: AppContext): Promise<NostrEvent> {
const signer = new APISigner(c);
const signer = c.get('signer');
if (!signer) {
throw new HTTPException(401, {
res: c.json({ error: 'No way to sign Nostr event' }, 401),
});
}
const event = await signer.signEvent({
content: '',

View File

@ -59,8 +59,10 @@ async function renderStatuses(c: AppContext, ids: string[], signal = AbortSignal
const sortedEvents = [...events].sort((a, b) => ids.indexOf(a.id) - ids.indexOf(b.id));
const viewerPubkey = await c.get('signer')?.getPublicKey();
const statuses = await Promise.all(
sortedEvents.map((event) => renderStatus(event, { viewerPubkey: c.get('pubkey') })),
sortedEvents.map((event) => renderStatus(event, { viewerPubkey })),
);
// TODO: pagination with min_id and max_id based on the order of `ids`.