Clean up the webfingerController a bit

This commit is contained in:
Alex Gleason 2023-07-09 17:38:39 -05:00
parent da9bea7560
commit 9d6216aff7
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
2 changed files with 35 additions and 29 deletions

View File

@ -1,13 +1,13 @@
import { Conf } from '@/config.ts'; import { Conf } from '@/config.ts';
import { db } from '@/db.ts'; import { db } from '@/db.ts';
import { nip19, z } from '@/deps.ts'; import { nip19, z } from '@/deps.ts';
import { urlTransformSchema } from '@/schema.ts'; import { npubSchema } from '@/schema.ts';
import type { AppController } from '@/app.ts'; import type { AppController } from '@/app.ts';
import type { Webfinger } from '@/schemas/webfinger.ts'; import type { Webfinger } from '@/schemas/webfinger.ts';
/** Transforms the resource URI into a `[username, domain]` tuple. */ /** Transforms the resource URI into a `[username, domain]` tuple. */
const acctSchema = urlTransformSchema const acctSchema = z.custom<URL>((value) => value instanceof URL)
.transform((uri) => uri.pathname) .transform((uri) => uri.pathname)
.pipe(z.string().email('Invalid acct')) .pipe(z.string().email('Invalid acct'))
.transform((acct) => acct.split('@') as [username: string, host: string]) .transform((acct) => acct.split('@') as [username: string, host: string])
@ -30,30 +30,31 @@ const webfingerController: AppController = (c) => {
const handleAcct = async (): Promise<Response> => { const handleAcct = async (): Promise<Response> => {
try { try {
const [username] = acctSchema.parse(query.data.resource); const [username] = acctSchema.parse(resource);
const user = await db.users.findFirst({ where: { username } }); const user = await db.users.findFirst({ where: { username } });
c.header('content-type', 'application/jrd+json'); c.header('content-type', 'application/jrd+json');
return c.body(JSON.stringify(renderWebfinger({ ...user, resource: query.data.resource }))); return c.body(JSON.stringify(renderWebfinger({ ...user, resource })));
} catch (_e) { } catch (e) {
if (e instanceof z.ZodError) {
return c.json({ error: 'Invalid acct URI', schema: e }, 400);
} else {
return c.json({ error: 'Not found' }, 404); return c.json({ error: 'Not found' }, 404);
} }
}
}; };
const handleNostr = async (): Promise<Response> => { const handleNostr = async (): Promise<Response> => {
try { try {
const decoded = nip19.decode(resource.pathname); const pubkey = npubSchema.parse(resource.pathname);
if (decoded.type === 'npub') { const user = await db.users.findFirst({ where: { pubkey } });
const user = await db.users.findFirst({ where: { pubkey: decoded.data } }); c.header('content-type', 'application/jrd+json');
if (!user) { return c.body(JSON.stringify(renderWebfinger({ ...user, resource })));
} catch (e) {
if (e instanceof z.ZodError) {
return c.json({ error: 'Invalid Nostr URI', schema: e }, 400);
} else {
return c.json({ error: 'Not found' }, 404); return c.json({ error: 'Not found' }, 404);
} }
c.header('content-type', 'application/jrd+json');
return c.body(JSON.stringify(renderWebfinger({ ...user, resource: query.data.resource })));
} else {
return c.json({ error: 'Unsupported Nostr URI' }, 400);
}
} catch (_e) {
return c.json({ error: 'Invalid Nostr URI' }, 404);
} }
}; };
@ -81,7 +82,7 @@ const hostMetaController: AppController = (c) => {
interface RenderWebfingerOpts { interface RenderWebfingerOpts {
pubkey: string; pubkey: string;
username: string; username: string;
resource: string; resource: URL;
} }
/** Present Nostr user on Webfinger. */ /** Present Nostr user on Webfinger. */
@ -89,7 +90,7 @@ function renderWebfinger({ pubkey, username, resource }: RenderWebfingerOpts): W
const apId = Conf.url(`/users/${username}`); const apId = Conf.url(`/users/${username}`);
return { return {
subject: resource, subject: resource.toString(),
aliases: [apId], aliases: [apId],
links: [ links: [
{ {

View File

@ -1,4 +1,4 @@
import { verifySignature, z } from '@/deps.ts'; import { nip19, verifySignature, z } from '@/deps.ts';
import type { Event } from './event.ts'; import type { Event } from './event.ts';
@ -95,16 +95,20 @@ const decode64Schema = z.string().transform((value, ctx) => {
} }
}); });
/** Transforms a string into a `URL` object. */ const nip19Schema = z.string().transform((val, ctx) => {
const urlTransformSchema = z.string().transform((val, ctx) => {
try { try {
return new URL(val); return nip19.decode(val);
} catch (_e) { } catch (_e) {
ctx.addIssue({ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Invalid NIP-19 identifier', fatal: true });
code: z.ZodIssueCode.custom, return z.NEVER;
message: 'Invalid URI', }
fatal: true,
}); });
const npubSchema = nip19Schema.transform((decoded, ctx) => {
if (decoded.type === 'npub') {
return decoded.data;
} else {
ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Unsupported NIP-19 identifier', fatal: true });
return z.NEVER; return z.NEVER;
} }
}); });
@ -116,9 +120,10 @@ export {
jsonSchema, jsonSchema,
type MetaContent, type MetaContent,
metaContentSchema, metaContentSchema,
nip19Schema,
npubSchema,
parseMetaContent, parseMetaContent,
parseRelay, parseRelay,
relaySchema, relaySchema,
signedEventSchema, signedEventSchema,
urlTransformSchema,
}; };