mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
fix(dm): can't open conversations + "helpers unavailable" on a working signer
After switching to a responsive signer (nos2x), two DM-specific bugs surfaced. 1. Clicking a conversation in the list threw "this.controller.handleDmConversationSelect is not a function" (ProfileDirectMessageRenderer onSelectConversation). The method exists on ProfileDirectMessageActions and the controller delegates ~15 sibling Actions methods — but the handleDmConversationSelect delegation was missing. Add it. 2. Loading a conversation's messages threw "DM decryption helpers are unavailable" even though the signer decrypts blocks/subscriptions/hashtags fine. buildDmDecryptContext gated decryptor registration on (a) the dynamic `capabilities` getter (which probes window.nostr and false-negatives on lazy injection / nos2x's module shape) and (b) the permission-probe result. The list services already learned to register by METHOD EXISTENCE and validate at call time; align the DM path to do the same so a present, working signer never yields zero decryptors. The permission probe still runs. Tests: tests/dm-decrypt-context.test.mjs (cheat-resistant — a signer whose capabilities getter reports false and whose permission probe returns ok:false must still register nip04+nip44 decryptors). Full unit + dm:unit + dm:integration suites green. KNOWN_BUGS #0. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
8f39b2c479
commit
7951fd0f09
3 files changed
+78
-10
No files matched your search
+12
-10
@@ -1264,12 +1264,17 @@ export class NostrClient {
|
||||
}
|
||||
}
|
||||
|
||||
if (activeSigner && extensionPermissionResult?.ok !== false) {
|
||||
const capabilities = resolveSignerCapabilities(activeSigner);
|
||||
if (
|
||||
capabilities.nip44 &&
|
||||
typeof activeSigner.nip44Decrypt === "function"
|
||||
) {
|
||||
// Register the active signer's decryptors by METHOD EXISTENCE, not by the
|
||||
// dynamic capabilities getter or the permission-request result. The getter
|
||||
// probes window.nostr for injected nip04/nip44 modules and gives false
|
||||
// negatives (lazy injection, or providers like nos2x that expose decrypt
|
||||
// methods which validate at call time) — the list services already learned
|
||||
// this. Hard-gating here returned ZERO decryptors and made the DM load throw
|
||||
// "DM decryption helpers are unavailable" even though the signer decrypts
|
||||
// everything else fine (KNOWN_BUGS #0). The permission request above still
|
||||
// runs (it can grant), it just no longer blocks decryptor registration.
|
||||
if (activeSigner) {
|
||||
if (typeof activeSigner.nip44Decrypt === "function") {
|
||||
addCandidate(
|
||||
"nip44",
|
||||
(pubkey, ciphertext, options) =>
|
||||
@@ -1289,10 +1294,7 @@ export class NostrClient {
|
||||
},
|
||||
);
|
||||
}
|
||||
if (
|
||||
capabilities.nip04 &&
|
||||
typeof activeSigner.nip04Decrypt === "function"
|
||||
) {
|
||||
if (typeof activeSigner.nip04Decrypt === "function") {
|
||||
addCandidate(
|
||||
"nip04",
|
||||
(pubkey, ciphertext, options) =>
|
||||
|
||||
@@ -599,6 +599,10 @@ export class ProfileDirectMessageController {
|
||||
return this.actions.pauseProfileMessages(...args);
|
||||
}
|
||||
|
||||
handleDmConversationSelect(...args) {
|
||||
return this.actions.handleDmConversationSelect(...args);
|
||||
}
|
||||
|
||||
handleSendDmRequest(...args) {
|
||||
return this.actions.handleSendDmRequest(...args);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Scenario (SCN-dm-context-method-existence):
|
||||
// Given an active NIP-07 signer that EXPOSES nip04Decrypt/nip44Decrypt methods
|
||||
// but whose dynamic `capabilities` getter reports them false (the real-env
|
||||
// nos2x case — lazy/odd module shape) AND whose extension permission probe
|
||||
// returns ok:false,
|
||||
// When buildDmDecryptContext runs for a DM load,
|
||||
// Then it must still register the signer's decryptors (by method existence,
|
||||
// like the list services do) — otherwise listDirectMessages throws
|
||||
// "DM decryption helpers are unavailable" even though the signer decrypts
|
||||
// everything else fine (KNOWN_BUGS #0).
|
||||
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
if (!globalThis.WebSocket) {
|
||||
globalThis.WebSocket = class MockWebSocket {};
|
||||
}
|
||||
|
||||
const { NostrClient } = await import("../js/nostr/client.js");
|
||||
|
||||
test("buildDmDecryptContext registers decryptors by method existence, not capabilities/permission gate", async () => {
|
||||
const client = new NostrClient();
|
||||
const actor = "a".repeat(64);
|
||||
client.pubkey = actor;
|
||||
|
||||
const fakeSigner = {
|
||||
type: "nip07",
|
||||
pubkey: actor,
|
||||
nip04Decrypt: async () => "plaintext",
|
||||
nip44Decrypt: async () => "plaintext",
|
||||
// The dynamic capabilities getter that returned false negatives and made
|
||||
// the DM path register zero decryptors.
|
||||
get capabilities() {
|
||||
return { sign: true, nip04: false, nip44: false };
|
||||
},
|
||||
};
|
||||
|
||||
// Active signer resolves to our fake regardless of how it's looked up.
|
||||
client.signerManager.resolveActiveSigner = () => fakeSigner;
|
||||
client.signerManager.getActiveSigner = () => fakeSigner;
|
||||
// Permission probe reports NOT ok — must NOT block decryptor registration.
|
||||
client.ensureExtensionPermissions = async () => ({
|
||||
ok: false,
|
||||
error: new Error("permission-not-granted"),
|
||||
});
|
||||
|
||||
const context = await client.buildDmDecryptContext(actor);
|
||||
|
||||
const schemes = context.decryptors.map((d) => d.scheme);
|
||||
assert.ok(
|
||||
schemes.includes("nip44"),
|
||||
"nip44 decryptor must be registered from the signer method",
|
||||
);
|
||||
assert.ok(
|
||||
schemes.includes("nip04"),
|
||||
"nip04 decryptor must be registered from the signer method",
|
||||
);
|
||||
assert.ok(
|
||||
context.decryptors.length >= 2,
|
||||
`expected at least the two signer decryptors, got ${context.decryptors.length}`,
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user