Merge branch 'no-unauthenticated' into 'main'

Support Bluesky's !no-unauthenticated self-label

See merge request soapbox-pub/ditto!596
This commit is contained in:
Alex Gleason 2024-11-26 06:52:12 +00:00
commit 45cb9757b4
3 changed files with 36 additions and 7 deletions

View file

@ -9,7 +9,7 @@ import { booleanParamSchema, fileSchema } from '@/schema.ts';
import { Storages } from '@/storages.ts'; import { Storages } from '@/storages.ts';
import { uploadFile } from '@/utils/upload.ts'; import { uploadFile } from '@/utils/upload.ts';
import { nostrNow } from '@/utils.ts'; import { nostrNow } from '@/utils.ts';
import { createEvent, paginated, parseBody, updateEvent, updateListEvent } from '@/utils/api.ts'; import { assertAuthenticated, createEvent, paginated, parseBody, updateEvent, updateListEvent } from '@/utils/api.ts';
import { extractIdentifier, lookupAccount, lookupPubkey } from '@/utils/lookup.ts'; import { extractIdentifier, lookupAccount, lookupPubkey } from '@/utils/lookup.ts';
import { renderAccounts, renderEventAccounts, renderStatuses } from '@/views.ts'; import { renderAccounts, renderEventAccounts, renderStatuses } from '@/views.ts';
import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts'; import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts';
@ -82,6 +82,7 @@ const accountController: AppController = async (c) => {
const event = await getAuthor(pubkey); const event = await getAuthor(pubkey);
if (event) { if (event) {
assertAuthenticated(c, event);
return c.json(await renderAccount(event)); return c.json(await renderAccount(event));
} else { } else {
return c.json(await accountFromPubkey(pubkey)); return c.json(await accountFromPubkey(pubkey));
@ -97,6 +98,7 @@ const accountLookupController: AppController = async (c) => {
const event = await lookupAccount(decodeURIComponent(acct)); const event = await lookupAccount(decodeURIComponent(acct));
if (event) { if (event) {
assertAuthenticated(c, event);
return c.json(await renderAccount(event)); return c.json(await renderAccount(event));
} }
try { try {
@ -204,7 +206,15 @@ const accountStatusesController: AppController = async (c) => {
const store = await Storages.db(); const store = await Storages.db();
const [user] = await store.query([{ kinds: [30382], authors: [Conf.pubkey], '#d': [pubkey], limit: 1 }], { signal }); const [[author], [user]] = await Promise.all([
store.query([{ kinds: [0], authors: [pubkey], limit: 1 }], { signal }),
store.query([{ kinds: [30382], authors: [Conf.pubkey], '#d': [pubkey], limit: 1 }], { signal }),
]);
if (author) {
assertAuthenticated(c, author);
}
const names = getTagSet(user?.tags ?? [], 'n'); const names = getTagSet(user?.tags ?? [], 'n');
if (names.has('disabled')) { if (names.has('disabled')) {

View file

@ -16,7 +16,7 @@ import { lookupPubkey } from '@/utils/lookup.ts';
import { languageSchema } from '@/schema.ts'; import { languageSchema } from '@/schema.ts';
import { Storages } from '@/storages.ts'; import { Storages } from '@/storages.ts';
import { hydrateEvents } from '@/storages/hydrate.ts'; import { hydrateEvents } from '@/storages/hydrate.ts';
import { createEvent, paginated, paginatedList, parseBody, updateListEvent } from '@/utils/api.ts'; import { assertAuthenticated, createEvent, paginated, paginatedList, parseBody, updateListEvent } from '@/utils/api.ts';
import { getInvoice, getLnurl } from '@/utils/lnurl.ts'; import { getInvoice, getLnurl } from '@/utils/lnurl.ts';
import { purifyEvent } from '@/utils/purify.ts'; import { purifyEvent } from '@/utils/purify.ts';
import { getZapSplits } from '@/utils/zap-split.ts'; import { getZapSplits } from '@/utils/zap-split.ts';
@ -48,13 +48,18 @@ const createStatusSchema = z.object({
const statusController: AppController = async (c) => { const statusController: AppController = async (c) => {
const id = c.req.param('id'); const id = c.req.param('id');
const signal = AbortSignal.any([c.req.raw.signal, AbortSignal.timeout(1500)]);
const event = await getEvent(id, { const event = await getEvent(id, { signal });
signal: AbortSignal.timeout(1500),
}); if (event?.author) {
assertAuthenticated(c, event.author);
}
if (event) { if (event) {
return c.json(await renderStatus(event, { viewerPubkey: await c.get('signer')?.getPublicKey() })); const viewerPubkey = await c.get('signer')?.getPublicKey();
const status = await renderStatus(event, { viewerPubkey });
return c.json(status);
} }
return c.json({ error: 'Event not found.' }, 404); return c.json({ error: 'Event not found.' }, 404);

View file

@ -286,8 +286,22 @@ function localRequest(c: Context): Request {
}); });
} }
/** Actors with Bluesky's `!no-unauthenticated` self-label should require authorization to view. */
function assertAuthenticated(c: AppContext, author: NostrEvent): void {
if (
!c.get('signer') && author.tags.some(([name, value, ns]) =>
name === 'l' &&
value === '!no-unauthenticated' &&
ns === 'com.atproto.label.defs#selfLabels'
)
) {
throw new HTTPException(401, { message: 'Sign-in required.' });
}
}
export { export {
activityJson, activityJson,
assertAuthenticated,
createAdminEvent, createAdminEvent,
createEvent, createEvent,
type EventStub, type EventStub,