mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 11:29:46 +00:00
Add controller test, refactor some middlewares
This commit is contained in:
parent
1368304d25
commit
425edf2174
6 changed files with 58 additions and 15 deletions
26
src/controllers/api/cashu.test.ts
Normal file
26
src/controllers/api/cashu.test.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
// deno-lint-ignore-file require-await
|
||||||
|
import { NSecSigner } from '@nostrify/nostrify';
|
||||||
|
import { assertEquals } from '@std/assert';
|
||||||
|
import { generateSecretKey } from 'nostr-tools';
|
||||||
|
|
||||||
|
import { createTestDB } from '@/test.ts';
|
||||||
|
|
||||||
|
import cashuApp from './cashu.ts';
|
||||||
|
|
||||||
|
Deno.test('PUT /wallet', async () => {
|
||||||
|
await using db = await createTestDB();
|
||||||
|
const store = db.store;
|
||||||
|
|
||||||
|
const sk = generateSecretKey();
|
||||||
|
const signer = new NSecSigner(sk);
|
||||||
|
|
||||||
|
const app = cashuApp.use(
|
||||||
|
'*',
|
||||||
|
async (c) => c.set('store', store),
|
||||||
|
async (c) => c.set('signer', signer),
|
||||||
|
);
|
||||||
|
|
||||||
|
const response = await app.request('/wallet', { method: 'PUT' });
|
||||||
|
|
||||||
|
assertEquals(response.status, 200);
|
||||||
|
});
|
||||||
|
|
@ -11,10 +11,10 @@ import { isNostrId } from '@/utils.ts';
|
||||||
import { createEvent, parseBody } from '@/utils/api.ts';
|
import { createEvent, parseBody } from '@/utils/api.ts';
|
||||||
import { errorJson } from '@/utils/log.ts';
|
import { errorJson } from '@/utils/log.ts';
|
||||||
import { signerMiddleware } from '@/middleware/signerMiddleware.ts';
|
import { signerMiddleware } from '@/middleware/signerMiddleware.ts';
|
||||||
import { requireSigner } from '@/middleware/requireSigner.ts';
|
import { requireNip44Signer } from '@/middleware/requireSigner.ts';
|
||||||
import { storeMiddleware } from '@/middleware/storeMiddleware.ts';
|
import { storeMiddleware } from '@/middleware/storeMiddleware.ts';
|
||||||
|
|
||||||
const app = new Hono();
|
const app = new Hono().use('*', storeMiddleware, signerMiddleware);
|
||||||
|
|
||||||
// CASHU_MINTS = ['https://mint.cashu.io/1', 'https://mint.cashu.io/2', 'https://mint.cashu.io/3']
|
// CASHU_MINTS = ['https://mint.cashu.io/1', 'https://mint.cashu.io/2', 'https://mint.cashu.io/3']
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ const createCashuWalletSchema = z.object({
|
||||||
* Creates a replaceable Cashu wallet.
|
* Creates a replaceable Cashu wallet.
|
||||||
* https://github.com/nostr-protocol/nips/blob/master/60.md
|
* https://github.com/nostr-protocol/nips/blob/master/60.md
|
||||||
*/
|
*/
|
||||||
app.post('/wallet', storeMiddleware, signerMiddleware, requireSigner, async (c) => {
|
app.post('/wallet', requireNip44Signer, async (c) => {
|
||||||
const signer = c.get('signer');
|
const signer = c.get('signer');
|
||||||
const store = c.get('store');
|
const store = c.get('store');
|
||||||
const pubkey = await signer.getPublicKey();
|
const pubkey = await signer.getPublicKey();
|
||||||
|
|
@ -67,11 +67,6 @@ app.post('/wallet', storeMiddleware, signerMiddleware, requireSigner, async (c)
|
||||||
return c.json({ error: 'Bad schema', schema: result.error }, 400);
|
return c.json({ error: 'Bad schema', schema: result.error }, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
const nip44 = signer.nip44;
|
|
||||||
if (!nip44) {
|
|
||||||
return c.json({ error: 'Signer does not have nip 44' }, 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
const [event] = await store.query([{ authors: [pubkey], kinds: [17375] }], { signal });
|
const [event] = await store.query([{ authors: [pubkey], kinds: [17375] }], { signal });
|
||||||
if (event) {
|
if (event) {
|
||||||
return c.json({ error: 'You already have a wallet 😏' }, 400);
|
return c.json({ error: 'You already have a wallet 😏' }, 400);
|
||||||
|
|
@ -90,7 +85,7 @@ app.post('/wallet', storeMiddleware, signerMiddleware, requireSigner, async (c)
|
||||||
contentTags.push(['mint', mint]);
|
contentTags.push(['mint', mint]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptedContentTags = await nip44.encrypt(pubkey, JSON.stringify(contentTags));
|
const encryptedContentTags = await signer.nip44.encrypt(pubkey, JSON.stringify(contentTags));
|
||||||
|
|
||||||
// Wallet
|
// Wallet
|
||||||
await createEvent({
|
await createEvent({
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { MiddlewareHandler } from '@hono/hono';
|
import { MiddlewareHandler } from '@hono/hono';
|
||||||
import { HTTPException } from '@hono/hono/http-exception';
|
import { HTTPException } from '@hono/hono/http-exception';
|
||||||
import { NostrSigner } from '@nostrify/nostrify';
|
import { NostrSigner } from '@nostrify/nostrify';
|
||||||
|
import { SetRequired } from 'type-fest';
|
||||||
|
|
||||||
/** Throw a 401 if a signer isn't set. */
|
/** Throw a 401 if a signer isn't set. */
|
||||||
export const requireSigner: MiddlewareHandler<{ Variables: { signer: NostrSigner } }> = async (c, next) => {
|
export const requireSigner: MiddlewareHandler<{ Variables: { signer: NostrSigner } }> = async (c, next) => {
|
||||||
|
|
@ -10,3 +11,19 @@ export const requireSigner: MiddlewareHandler<{ Variables: { signer: NostrSigner
|
||||||
|
|
||||||
await next();
|
await next();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Throw a 401 if a NIP-44 signer isn't set. */
|
||||||
|
export const requireNip44Signer: MiddlewareHandler<{ Variables: { signer: SetRequired<NostrSigner, 'nip44'> } }> =
|
||||||
|
async (c, next) => {
|
||||||
|
const signer = c.get('signer');
|
||||||
|
|
||||||
|
if (!signer) {
|
||||||
|
throw new HTTPException(401, { message: 'No pubkey provided' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!signer.nip44) {
|
||||||
|
throw new HTTPException(401, { message: 'No NIP-44 signer provided' });
|
||||||
|
}
|
||||||
|
|
||||||
|
await next();
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
import { MiddlewareHandler } from '@hono/hono';
|
||||||
import { HTTPException } from '@hono/hono/http-exception';
|
import { HTTPException } from '@hono/hono/http-exception';
|
||||||
import { NSecSigner } from '@nostrify/nostrify';
|
import { NostrSigner, NSecSigner } from '@nostrify/nostrify';
|
||||||
import { nip19 } from 'nostr-tools';
|
import { nip19 } from 'nostr-tools';
|
||||||
|
|
||||||
import { AppMiddleware } from '@/app.ts';
|
|
||||||
import { Conf } from '@/config.ts';
|
import { Conf } from '@/config.ts';
|
||||||
import { ConnectSigner } from '@/signers/ConnectSigner.ts';
|
import { ConnectSigner } from '@/signers/ConnectSigner.ts';
|
||||||
import { ReadOnlySigner } from '@/signers/ReadOnlySigner.ts';
|
import { ReadOnlySigner } from '@/signers/ReadOnlySigner.ts';
|
||||||
|
|
@ -14,7 +14,7 @@ import { getTokenHash } from '@/utils/auth.ts';
|
||||||
const BEARER_REGEX = new RegExp(`^Bearer (${nip19.BECH32_REGEX.source})$`);
|
const BEARER_REGEX = new RegExp(`^Bearer (${nip19.BECH32_REGEX.source})$`);
|
||||||
|
|
||||||
/** Make a `signer` object available to all controllers, or unset if the user isn't logged in. */
|
/** Make a `signer` object available to all controllers, or unset if the user isn't logged in. */
|
||||||
export const signerMiddleware: AppMiddleware = async (c, next) => {
|
export const signerMiddleware: MiddlewareHandler<{ Variables: { signer: NostrSigner } }> = async (c, next) => {
|
||||||
const header = c.req.header('authorization');
|
const header = c.req.header('authorization');
|
||||||
const match = header?.match(BEARER_REGEX);
|
const match = header?.match(BEARER_REGEX);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
import { AppMiddleware } from '@/app.ts';
|
import { MiddlewareHandler } from '@hono/hono';
|
||||||
|
import { NostrSigner, NStore } from '@nostrify/nostrify';
|
||||||
|
|
||||||
import { UserStore } from '@/storages/UserStore.ts';
|
import { UserStore } from '@/storages/UserStore.ts';
|
||||||
import { Storages } from '@/storages.ts';
|
import { Storages } from '@/storages.ts';
|
||||||
|
|
||||||
/** Store middleware. */
|
/** Store middleware. */
|
||||||
export const storeMiddleware: AppMiddleware = async (c, next) => {
|
export const storeMiddleware: MiddlewareHandler<{ Variables: { signer?: NostrSigner; store: NStore } }> = async (
|
||||||
|
c,
|
||||||
|
next,
|
||||||
|
) => {
|
||||||
const pubkey = await c.get('signer')?.getPublicKey();
|
const pubkey = await c.get('signer')?.getPublicKey();
|
||||||
|
|
||||||
if (pubkey) {
|
if (pubkey) {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import { purifyEvent } from '@/utils/purify.ts';
|
||||||
type EventStub = TypeFest.SetOptional<EventTemplate, 'content' | 'created_at' | 'tags'>;
|
type EventStub = TypeFest.SetOptional<EventTemplate, 'content' | 'created_at' | 'tags'>;
|
||||||
|
|
||||||
/** Publish an event through the pipeline. */
|
/** Publish an event through the pipeline. */
|
||||||
async function createEvent(t: EventStub, c: AppContext): Promise<NostrEvent> {
|
async function createEvent(t: EventStub, c: Context): Promise<NostrEvent> {
|
||||||
const signer = c.get('signer');
|
const signer = c.get('signer');
|
||||||
|
|
||||||
if (!signer) {
|
if (!signer) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue