refactor(acl): align IMethod with NIP-46 wire-name vocabulary (#14)
NDK 3.x's `NDKNip46Backend` passes the wire method name verbatim to `pubkeyAllowed` — `nip04_encrypt`, `nip04_decrypt`, `nip44_encrypt`, `nip44_decrypt`, etc. NDK 2.8.1 normalized these to `encrypt`/`decrypt` before calling the permit callback; that normalization was the root of why our encrypt/decrypt path had never worked end-to-end against lnbits's bunker-backed signer (lnbits stores `PolicyRule.method` using wire names, our auth lookup looked for the normalized name → no match → request fell through to the never-resolved admin prompt and timed out at 15s). Source `IMethod` directly from NDK's exported `NIP46Method` union so it can't drift across future bumps. If NDK adds a new method (e.g. `nip60_*`) we pick it up for free. Drop the `method as IMethod` cast at the `signingAuthorizationCallback` call site — both sides now share the same vocabulary by construction. This is the substantive win that aiolabs/nsecbunkerd#14 is filed for. With this commit: - `sign_event` policy rules with kinds continue to match exactly as before (kind stringification path unchanged). - `nip04_encrypt` / `nip04_decrypt` / `nip44_encrypt` / `nip44_decrypt` policy rules — kind-less — now match the live-policy join (step 4 of `checkIfPubkeyAllowed`) by their method-name alone. lnbits's bunker-mediated `signer.nip44_decrypt` and `signer.nip44_encrypt` calls (per `aiolabs/lnbits` PR #38 phase 2.4) start succeeding end-to-end against any operator account whose Policy carries those rules — which `_ensure_policy`'s self-heal already ensures for every newly-bound operator (per coord log 2026-05-30T22:00Z). - `switch_relays` (new in NDK 3) flows through the auth check the same way as any other method. `requestToSigningConditionQuery` needs no further change — the existing `sign_event` switch case covers the only method that discriminates on kind; all other methods use the default `{ method }` query against the override layer, which is correct for the kind-less wire names too. Refs aiolabs/nsecbunkerd#14, aiolabs/nsecbunkerd#11 (whose live-policy join this finally puts to use).
This commit is contained in:
parent
94b5d55376
commit
db1a834587
2 changed files with 23 additions and 7 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { NDKEvent, NostrEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent, NostrEvent, NIP46Method } from '@nostr-dev-kit/ndk';
|
||||||
import prisma from '../../../db.js';
|
import prisma from '../../../db.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -114,7 +114,26 @@ export async function checkIfPubkeyAllowed(
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IMethod = "connect" | "sign_event" | "encrypt" | "decrypt" | "ping";
|
/**
|
||||||
|
* Sign-time auth method names follow the NIP-46 wire convention as
|
||||||
|
* NDK 3.x's `NDKNip46Backend` passes them through to `pubkeyAllowed`
|
||||||
|
* verbatim (it stopped normalizing `nip04_encrypt`/`nip04_decrypt`
|
||||||
|
* to `encrypt`/`decrypt` somewhere between 2.8.1 and current
|
||||||
|
* upstream).
|
||||||
|
*
|
||||||
|
* lnbits's `_ensure_policy` writes `PolicyRule.method` using the same
|
||||||
|
* wire-name vocabulary (`nip04_encrypt`, `nip04_decrypt`,
|
||||||
|
* `nip44_encrypt`, `nip44_decrypt`, `sign_event`, `get_public_key`,
|
||||||
|
* `connect`, `ping`). With the wire-name vocabulary on both sides,
|
||||||
|
* the post-#11 live-policy join (step 4 of `checkIfPubkeyAllowed`)
|
||||||
|
* naturally matches lnbits's stored rules — no `encrypt → nip04_encrypt`
|
||||||
|
* adapter layer needed.
|
||||||
|
*
|
||||||
|
* Source the type from NDK itself so it can't drift across future
|
||||||
|
* NDK bumps; if NDK adds a new method (e.g. `nip60_*`) we pick it up
|
||||||
|
* for free.
|
||||||
|
*/
|
||||||
|
export type IMethod = NIP46Method;
|
||||||
|
|
||||||
export type IAllowScope = {
|
export type IAllowScope = {
|
||||||
kind?: number | 'all';
|
kind?: number | 'all';
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
import NDK, { NDKPrivateKeySigner, Nip46PermitCallback, Nip46PermitCallbackParams } from '@nostr-dev-kit/ndk';
|
import NDK, { NDKPrivateKeySigner, Nip46PermitCallback, Nip46PermitCallbackParams } from '@nostr-dev-kit/ndk';
|
||||||
import { nip19, utils as nostrUtils } from 'nostr-tools';
|
import { nip19, utils as nostrUtils } from 'nostr-tools';
|
||||||
import { Backend } from './backend/index.js';
|
import { Backend } from './backend/index.js';
|
||||||
import {
|
import { checkIfPubkeyAllowed } from './lib/acl/index.js';
|
||||||
IMethod,
|
|
||||||
checkIfPubkeyAllowed,
|
|
||||||
} from './lib/acl/index.js';
|
|
||||||
import AdminInterface from './admin/index.js';
|
import AdminInterface from './admin/index.js';
|
||||||
import { IConfig } from '../config/index.js';
|
import { IConfig } from '../config/index.js';
|
||||||
import { NDKRpcRequest } from '@nostr-dev-kit/ndk';
|
import { NDKRpcRequest } from '@nostr-dev-kit/ndk';
|
||||||
|
|
@ -107,7 +104,7 @@ function signingAuthorizationCallback(keyName: string, adminInterface: AdminInte
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const keyAllowed = await checkIfPubkeyAllowed(keyName, remotePubkey, method as IMethod, payload);
|
const keyAllowed = await checkIfPubkeyAllowed(keyName, remotePubkey, method, payload);
|
||||||
|
|
||||||
if (keyAllowed === true || keyAllowed === false) {
|
if (keyAllowed === true || keyAllowed === false) {
|
||||||
console.log(`🔎 ${nip19.npubEncode(remotePubkey)} is ${keyAllowed ? 'allowed' : 'denied'} to ${method} with key ${keyName}`);
|
console.log(`🔎 ${nip19.npubEncode(remotePubkey)} is ${keyAllowed ? 'allowed' : 'denied'} to ${method} with key ${keyName}`);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue