diff --git a/src/app.ts b/src/app.ts index 2a36a83..24fdc98 100644 --- a/src/app.ts +++ b/src/app.ts @@ -29,6 +29,7 @@ import { import { appCredentialsController, createAppController } from './controllers/api/apps.ts'; import { emptyArrayController, emptyObjectController } from './controllers/api/fallback.ts'; import { instanceController } from './controllers/api/instance.ts'; +import { mediaController } from './controllers/api/media.ts'; import { notificationsController } from './controllers/api/notifications.ts'; import { createTokenController, oauthAuthorizeController, oauthController } from './controllers/api/oauth.ts'; import { frontendConfigController, updateConfigController } from './controllers/api/pleroma.ts'; @@ -56,7 +57,7 @@ import { nodeInfoController, nodeInfoSchemaController } from './controllers/well import { nostrController } from './controllers/well-known/nostr.ts'; import { webfingerController } from './controllers/well-known/webfinger.ts'; import { auth19, requirePubkey } from './middleware/auth19.ts'; -import { auth98, requireAdmin } from './middleware/auth98.ts'; +import { auth98, requireRole } from './middleware/auth98.ts'; interface AppEnv extends HonoEnv { Variables: { @@ -121,6 +122,9 @@ app.get('/api/v1/statuses/:id{[0-9a-f]{64}}', statusController); app.post('/api/v1/statuses/:id{[0-9a-f]{64}}/favourite', favouriteController); app.post('/api/v1/statuses', requirePubkey, createStatusController); +app.post('/api/v1/media', requireRole('user'), mediaController); +app.post('/api/v2/media', requireRole('user'), mediaController); + app.get('/api/v1/timelines/home', requirePubkey, homeTimelineController); app.get('/api/v1/timelines/public', publicTimelineController); app.get('/api/v1/timelines/tag/:hashtag', hashtagTimelineController); @@ -137,7 +141,7 @@ app.get('/api/v1/trends', trendingTagsController); app.get('/api/v1/notifications', requirePubkey, notificationsController); app.get('/api/v1/favourites', requirePubkey, favouritesController); -app.post('/api/v1/pleroma/admin/config', requireAdmin, updateConfigController); +app.post('/api/v1/pleroma/admin/config', requireRole('admin'), updateConfigController); // Not (yet) implemented. app.get('/api/v1/bookmarks', emptyArrayController); diff --git a/src/middleware/auth98.ts b/src/middleware/auth98.ts index dad0d0a..a64370a 100644 --- a/src/middleware/auth98.ts +++ b/src/middleware/auth98.ts @@ -3,7 +3,7 @@ import { HTTPException } from '@/deps.ts'; import { buildAuthEventTemplate, parseAuthRequest, type ParseAuthRequestOpts } from '@/utils/nip98.ts'; import { localRequest } from '@/utils/web.ts'; import { signNostrConnect } from '@/sign.ts'; -import { findUser } from '@/db/users.ts'; +import { findUser, User } from '@/db/users.ts'; /** * NIP-98 auth. @@ -23,20 +23,36 @@ function auth98(opts: ParseAuthRequestOpts = {}): AppMiddleware { }; } -/** Require the user to prove they're an admin before invoking the controller. */ -const requireAdmin: AppMiddleware = async (c, next) => { - const header = c.req.headers.get('x-nostr-sign'); - const proof = c.get('proof') || header ? await obtainProof(c) : undefined; - const user = proof ? await findUser({ pubkey: proof.pubkey }) : undefined; +type UserRole = 'user' | 'admin'; - if (proof && user?.admin) { - c.set('pubkey', proof.pubkey); - c.set('proof', proof); - await next(); - } else { - throw new HTTPException(401); +/** Require the user to prove their role before invoking the controller. */ +function requireRole(role: UserRole): AppMiddleware { + return async (c, next) => { + const header = c.req.headers.get('x-nostr-sign'); + const proof = c.get('proof') || header ? await obtainProof(c) : undefined; + const user = proof ? await findUser({ pubkey: proof.pubkey }) : undefined; + + if (proof && user && matchesRole(user, role)) { + c.set('pubkey', proof.pubkey); + c.set('proof', proof); + await next(); + } else { + throw new HTTPException(401); + } + }; +} + +/** Check whether the user fulfills the role. */ +function matchesRole(user: User, role: UserRole): boolean { + switch (role) { + case 'user': + return true; + case 'admin': + return user.admin; + default: + return false; } -}; +} /** Get the proof over Nostr Connect. */ async function obtainProof(c: AppContext) { @@ -45,4 +61,4 @@ async function obtainProof(c: AppContext) { return signNostrConnect(event, c); } -export { auth98, requireAdmin }; +export { auth98, requireRole };