Add requireVar middleware

This commit is contained in:
Alex Gleason 2025-02-17 21:11:10 -06:00
parent d1f8e3b92c
commit b360dfaf06
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
6 changed files with 34 additions and 7 deletions

View file

@ -1,7 +1,7 @@
import type { DittoConf } from '@ditto/conf';
import type { DittoDatabase } from '@ditto/db';
import type { Env } from '@hono/hono';
import type { NRelay } from '@nostrify/nostrify';
import type { NostrSigner, NRelay, NStore } from '@nostrify/nostrify';
export interface DittoEnv extends Env {
Variables: {
@ -13,5 +13,12 @@ export interface DittoEnv extends Env {
db: DittoDatabase;
/** Abort signal for the request. */
signal: AbortSignal;
/** The current user */
user?: {
/** The user's signer. */
signer: NostrSigner;
/** The user's store. */
store: NStore;
};
};
}

View file

@ -27,6 +27,7 @@ export class DittoRoute extends Hono<DittoEnv> {
if (!vars.signal) this.throwMissingVar('signal');
return {
...vars,
db: vars.db,
conf: vars.conf,
store: vars.store,

View file

@ -1 +1,2 @@
export { requireVar } from './requireVar.ts';
export { userMiddleware } from './userMiddleware.ts';

View file

@ -0,0 +1,17 @@
import { HTTPException } from '@hono/hono/http-exception';
import type { SetRequired } from 'type-fest';
import type { DittoEnv } from '../DittoEnv.ts';
import type { DittoMiddleware } from '../DittoMiddleware.ts';
type DittoVars = DittoEnv['Variables'];
export function requireVar<K extends keyof DittoVars>(key: K): DittoMiddleware<SetRequired<DittoVars, K>> {
return (c, next) => {
if (!c.var[key]) {
throw new HTTPException(500, { message: `Missing required variable: ${key}` });
}
return next();
};
}

View file

@ -18,14 +18,15 @@ interface UserMiddlewareOpts {
privileged: boolean;
}
// @ts-ignore The types are right.
export function userMiddleware(opts: { privileged: boolean; required: true }): DittoMiddleware<{ user: User }>;
export function userMiddleware(opts: { privileged: false; required: true }): DittoMiddleware<{ user: User }>;
export function userMiddleware(opts: { privileged: true; required?: boolean }): DittoMiddleware<{ user: User }>;
export function userMiddleware(opts: { privileged: false; required?: boolean }): DittoMiddleware<{ user?: User }>;
export function userMiddleware(opts: { privileged?: boolean; required?: boolean }): DittoMiddleware<{ user?: User }> {
export function userMiddleware(opts: { privileged: boolean; required?: boolean }): DittoMiddleware<{ user?: User }> {
/** We only accept "Bearer" type. */
const BEARER_REGEX = new RegExp(`^Bearer (${nip19.BECH32_REGEX.source})$`);
const { privileged, required = false } = opts;
return async (c, next) => {
const { conf, db, store } = c.var;
@ -83,7 +84,7 @@ export function userMiddleware(opts: { privileged?: boolean; required?: boolean
if (signer) {
const user: User = { signer, store };
c.set('user', user);
} else {
} else if (required) {
throw new HTTPException(401);
}

View file

@ -1,5 +1,5 @@
import { DittoRoute } from '@ditto/api';
import { userMiddleware } from '@ditto/api/middleware';
import { requireVar, userMiddleware } from '@ditto/api/middleware';
import { booleanParamSchema, languageSchema } from '@ditto/api/schema';
import { z } from 'zod';
@ -12,7 +12,7 @@ const homeQuerySchema = z.object({
only_media: booleanParamSchema.optional(),
});
route.get('/home', async (c) => {
route.get('/home', requireVar('user'), async (c) => {
const { user, pagination } = c.var;
const pubkey = await user.signer.getPublicKey()!;