mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 11:29:46 +00:00
67 lines
2.3 KiB
TypeScript
67 lines
2.3 KiB
TypeScript
import { HTTPException } from '@hono/hono/http-exception';
|
|
import { NSecSigner } from '@nostrify/nostrify';
|
|
import { nip19 } from 'nostr-tools';
|
|
|
|
import { AppMiddleware } from '@/app.ts';
|
|
import { Conf } from '@/config.ts';
|
|
import { ConnectSigner } from '@/signers/ConnectSigner.ts';
|
|
import { ReadOnlySigner } from '@/signers/ReadOnlySigner.ts';
|
|
import { Storages } from '@/storages.ts';
|
|
import { aesDecrypt } from '@/utils/aes.ts';
|
|
import { getTokenHash } from '@/utils/auth.ts';
|
|
|
|
/** Make a `signer` object available to all controllers, or unset if the user isn't logged in. */
|
|
export const signerMiddleware: AppMiddleware = async (c, next) => {
|
|
const accessToken = getAccessToken(c.req.raw);
|
|
|
|
if (accessToken?.startsWith('token1')) {
|
|
try {
|
|
const kysely = await Storages.kysely();
|
|
const tokenHash = await getTokenHash(accessToken as `token1${string}`);
|
|
|
|
const { pubkey, nip46_sk_enc, nip46_relays } = await kysely
|
|
.selectFrom('auth_tokens')
|
|
.select(['pubkey', 'nip46_sk_enc', 'nip46_relays'])
|
|
.where('token_hash', '=', tokenHash)
|
|
.executeTakeFirstOrThrow();
|
|
|
|
const nep46Seckey = await aesDecrypt(Conf.seckey, nip46_sk_enc);
|
|
|
|
c.set('signer', new ConnectSigner(pubkey, new NSecSigner(nep46Seckey), nip46_relays));
|
|
} catch {
|
|
throw new HTTPException(401);
|
|
}
|
|
} else if (accessToken) {
|
|
try {
|
|
const decoded = nip19.decode(accessToken!);
|
|
|
|
switch (decoded.type) {
|
|
case 'npub':
|
|
c.set('signer', new ReadOnlySigner(decoded.data));
|
|
break;
|
|
case 'nprofile':
|
|
c.set('signer', new ReadOnlySigner(decoded.data.pubkey));
|
|
break;
|
|
case 'nsec':
|
|
c.set('signer', new NSecSigner(decoded.data));
|
|
break;
|
|
}
|
|
} catch {
|
|
throw new HTTPException(401, { message: 'Invalid access token' });
|
|
}
|
|
}
|
|
|
|
await next();
|
|
};
|
|
|
|
/** Extract the access token from the request headers. */
|
|
function getAccessToken(req: Request): string | undefined {
|
|
const upgrade = req.headers.get('upgrade');
|
|
|
|
// WebSockets use the `sec-websocket-protocol` header instead of `authorization`.
|
|
if (upgrade === 'websocket') {
|
|
return req.headers.get('sec-websocket-protocol') ?? undefined;
|
|
}
|
|
|
|
return req.headers.get('authorization')?.match(/^Bearer (.+)$/)?.[1];
|
|
}
|