Webfinger: reorganize more

This commit is contained in:
Alex Gleason 2023-07-09 18:10:12 -05:00
parent 9d6216aff7
commit 60cd92384d
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
1 changed files with 53 additions and 53 deletions

View File

@ -3,19 +3,9 @@ import { db } from '@/db.ts';
import { nip19, z } from '@/deps.ts';
import { npubSchema } from '@/schema.ts';
import type { AppController } from '@/app.ts';
import type { AppContext, AppController } from '@/app.ts';
import type { Webfinger } from '@/schemas/webfinger.ts';
/** Transforms the resource URI into a `[username, domain]` tuple. */
const acctSchema = z.custom<URL>((value) => value instanceof URL)
.transform((uri) => uri.pathname)
.pipe(z.string().email('Invalid acct'))
.transform((acct) => acct.split('@') as [username: string, host: string])
.refine(([_username, host]) => host === new URL(Conf.localDomain).hostname, {
message: 'Host must be local',
path: ['resource', 'acct'],
});
const webfingerQuerySchema = z.object({
resource: z.string().url(),
});
@ -28,12 +18,34 @@ const webfingerController: AppController = (c) => {
const resource = new URL(query.data.resource);
const handleAcct = async (): Promise<Response> => {
switch (resource.protocol) {
case 'acct:': {
return handleAcct(c, resource);
}
case 'nostr:': {
return handleNostr(c, resource);
}
default:
return c.json({ error: 'Unsupported URI scheme' }, 400);
}
};
/** Transforms the resource URI into a `[username, domain]` tuple. */
const acctSchema = z.custom<URL>((value) => value instanceof URL)
.transform((uri) => uri.pathname)
.pipe(z.string().email('Invalid acct'))
.transform((acct) => acct.split('@') as [username: string, host: string])
.refine(([_username, host]) => host === new URL(Conf.localDomain).hostname, {
message: 'Host must be local',
path: ['resource', 'acct'],
});
async function handleAcct(c: AppContext, resource: URL): Promise<Response> {
try {
const [username] = acctSchema.parse(resource);
const user = await db.users.findFirst({ where: { username } });
c.header('content-type', 'application/jrd+json');
return c.body(JSON.stringify(renderWebfinger({ ...user, resource })));
return c.body(JSON.stringify(renderWebfinger({ ...user, subject: `acct:${resource.pathname}` })));
} catch (e) {
if (e instanceof z.ZodError) {
return c.json({ error: 'Invalid acct URI', schema: e }, 400);
@ -41,14 +53,14 @@ const webfingerController: AppController = (c) => {
return c.json({ error: 'Not found' }, 404);
}
}
};
}
const handleNostr = async (): Promise<Response> => {
async function handleNostr(c: AppContext, resource: URL): Promise<Response> {
try {
const pubkey = npubSchema.parse(resource.pathname);
const user = await db.users.findFirst({ where: { pubkey } });
c.header('content-type', 'application/jrd+json');
return c.body(JSON.stringify(renderWebfinger({ ...user, resource })));
return c.body(JSON.stringify(renderWebfinger({ ...user, subject: `nostr:${resource.pathname}` })));
} catch (e) {
if (e instanceof z.ZodError) {
return c.json({ error: 'Invalid Nostr URI', schema: e }, 400);
@ -56,41 +68,20 @@ const webfingerController: AppController = (c) => {
return c.json({ error: 'Not found' }, 404);
}
}
};
switch (resource.protocol) {
case 'acct:': {
return handleAcct();
}
case 'nostr:': {
return handleNostr();
}
default:
return c.json({ error: 'Unsupported URI scheme' }, 400);
}
};
const hostMetaController: AppController = (c) => {
const template = Conf.url('/.well-known/webfinger?resource={uri}');
c.header('content-type', 'application/xrd+xml');
return c.body(
`<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" template="${template}" type="application/xrd+xml" /></XRD>`,
);
};
}
interface RenderWebfingerOpts {
pubkey: string;
username: string;
resource: URL;
subject: string;
}
/** Present Nostr user on Webfinger. */
function renderWebfinger({ pubkey, username, resource }: RenderWebfingerOpts): Webfinger {
function renderWebfinger({ pubkey, username, subject }: RenderWebfingerOpts): Webfinger {
const apId = Conf.url(`/users/${username}`);
return {
subject: resource.toString(),
subject,
aliases: [apId],
links: [
{
@ -112,4 +103,13 @@ function renderWebfinger({ pubkey, username, resource }: RenderWebfingerOpts): W
};
}
const hostMetaController: AppController = (c) => {
const template = Conf.url('/.well-known/webfinger?resource={uri}');
c.header('content-type', 'application/xrd+xml');
return c.body(
`<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" template="${template}" type="application/xrd+xml" /></XRD>`,
);
};
export { hostMetaController, webfingerController };