Add account lookup endpoint

This commit is contained in:
Alex Gleason 2023-04-29 16:23:23 -05:00
parent 5118aaf46c
commit 9e73a8e43c
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
3 changed files with 72 additions and 4 deletions

View File

@ -1,7 +1,9 @@
import { type AppController } from '@/app.ts';
import { nip19 } from '@/deps.ts';
import { getAuthor } from '../client.ts';
import { toAccount } from '../transmute.ts';
import { bech32ToPubkey, isNostrId } from '../utils.ts';
const credentialsController: AppController = async (c) => {
const pubkey = c.get('pubkey')!;
@ -14,4 +16,42 @@ const credentialsController: AppController = async (c) => {
return c.json({ error: 'Could not find user.' }, 404);
};
export { credentialsController };
const accountController: AppController = async (c) => {
const pubkey = c.req.param('id');
if (!isNostrId(pubkey)) {
return c.json({ error: 'Invalid account ID.' }, 422);
}
const event = await getAuthor(pubkey);
if (event) {
return c.json(toAccount(event));
}
return c.json({ error: 'Could not find user.' }, 404);
};
const accountLookupController: AppController = async (c) => {
const acct = c.req.query('acct');
if (!acct) {
return c.json({ error: 'Missing `acct` query parameter.' }, 422);
}
if (acct.includes('@')) {
// TODO: NIP-05 handling
return c.json({ error: 'NIP-05 lookups not yet implemented.' }, 422);
}
const pubkey = bech32ToPubkey(acct);
if (pubkey) {
const event = await getAuthor(pubkey);
if (event) {
return c.json(toAccount(event));
}
}
return c.json({ error: 'Could not find user.' }, 404);
};
export { accountController, accountLookupController, credentialsController };

View File

@ -1,6 +1,6 @@
import { type Context, cors, type Handler, Hono, type HonoEnv, type MiddlewareHandler } from '@/deps.ts';
import { credentialsController } from './api/accounts.ts';
import { accountController, accountLookupController, credentialsController } from './api/accounts.ts';
import { appCredentialsController, createAppController } from './api/apps.ts';
import { emptyArrayController, emptyObjectController } from './api/fallback.ts';
import homeController from './api/home.ts';
@ -33,6 +33,8 @@ app.post('/oauth/token', createTokenController);
app.post('/oauth/revoke', emptyObjectController);
app.get('/api/v1/accounts/verify_credentials', requireAuth, credentialsController);
app.get('/api/v1/accounts/lookup', accountLookupController);
app.get('/api/v1/accounts/:id', accountController);
app.post('/api/v1/statuses', requireAuth, createStatusController);

View File

@ -1,4 +1,4 @@
import { Context, getPublicKey } from '@/deps.ts';
import { Context, getPublicKey, nip19, nip21 } from '@/deps.ts';
import { type Event } from '@/event.ts';
/** Get the current time in Nostr format. */
@ -21,4 +21,30 @@ function getKeys(c: Context) {
}
}
export { eventDateComparator, getKeys, nostrNow };
/** Return true if the value is a bech32 string, eg for use with NIP-19. */
function isBech32(value: unknown): value is string {
return typeof value === 'string' && nip21.BECH32_REGEX.test(value);
}
/** Return true if the value is a Nostr pubkey, private key, or event ID. */
function isNostrId(value: unknown): value is string {
return typeof value === 'string' && /^[0-9a-f]{64}$/.test(value);
}
/** Get pubkey from bech32 string, if applicable. */
function bech32ToPubkey(bech32: string): string | undefined {
try {
const decoded = nip19.decode(bech32);
switch (decoded.type) {
case 'nprofile':
return decoded.data.pubkey;
case 'npub':
return decoded.data;
}
} catch (_) {
//
}
}
export { bech32ToPubkey, eventDateComparator, getKeys, isBech32, isNostrId, nostrNow };