Merge branch 'emoji-unauth' into 'main'

Allow custom_emojis endpoint to be accessed without a user

See merge request soapbox-pub/ditto!722
This commit is contained in:
Alex Gleason 2025-03-15 18:24:52 +00:00
commit ed0a8dc36b
5 changed files with 34 additions and 10 deletions

View file

@ -10,6 +10,14 @@ Deno.test('customEmojisRoute', async (t) => {
await using test = new TestApp(route);
const { relay } = test.var;
await t.step('unauth', async () => {
const response = await test.api.get('/');
const body = await response.json();
assertEquals(response.status, 200);
assertEquals(body, []);
});
const sk = generateSecretKey();
const user = test.user({ relay, signer: new NSecSigner(sk) });
const pubkey = await user.signer.getPublicKey();

View file

@ -13,9 +13,13 @@ interface MastodonCustomEmoji {
category?: string;
}
route.get('/', userMiddleware(), async (c) => {
route.get('/', userMiddleware({ required: false }), async (c) => {
const { user } = c.var;
if (!user) {
return c.json([]);
}
const pubkey = await user.signer.getPublicKey();
const emojis = await getCustomEmojis(pubkey, c.var);

View file

@ -58,13 +58,11 @@ export async function getCustomEmojis(
const d = event.tags.find(([name]) => name === 'd')?.[1];
for (const [t, shortcode, url] of event.tags) {
if (t === 'emoji') {
if (!emojis.has(shortcode)) {
try {
emojis.set(shortcode, { url: new URL(url), category: d });
} catch {
// continue
}
if (t === 'emoji' && /^\w+$/.test(shortcode) && !emojis.has(shortcode)) {
try {
emojis.set(shortcode, { url: new URL(url), category: d });
} catch {
// continue
}
}
}

View file

@ -10,6 +10,18 @@ Deno.test('no user 401', async () => {
assertEquals(response.status, 401);
});
Deno.test('no user required false', async () => {
await using app = new TestApp();
app
.use(userMiddleware({ required: false }))
.get('/', (c) => c.text('ok'));
const response = await app.request('/');
assertEquals(response.status, 200);
});
Deno.test('unsupported signer 400', async () => {
await using app = new TestApp();

View file

@ -12,6 +12,7 @@ interface UserMiddlewareOpts {
enc?: 'nip04' | 'nip44';
role?: string;
verify?: boolean;
required?: boolean;
}
export function userMiddleware(): DittoMiddleware<{ user: User }>;
@ -19,13 +20,14 @@ export function userMiddleware(): DittoMiddleware<{ user: User }>;
export function userMiddleware(
opts: UserMiddlewareOpts & { enc: 'nip44' },
): DittoMiddleware<{ user: User<Nip44Signer> }>;
export function userMiddleware(opts: UserMiddlewareOpts & { required: false }): DittoMiddleware<{ user?: User }>;
export function userMiddleware(opts: UserMiddlewareOpts): DittoMiddleware<{ user: User }>;
export function userMiddleware(opts: UserMiddlewareOpts = {}): DittoMiddleware<{ user: User }> {
return async (c, next) => {
const { conf, user, relay } = c.var;
const { enc, role, verify } = opts;
const { enc, role, verify, required = true } = opts;
if (!user) {
if (!user && required) {
throw new HTTPException(401, { message: 'Authorization required' });
}