Fix NIP-07 decryption fallback and storage unlock issues

- Updated `StorageService` to check `signer.capabilities` before calling encryption methods, ensuring graceful fallback from NIP-44 to NIP-04.
- Updated `UserBlockList` to check `signer.capabilities` before registering decryptors, preventing "Decryption timed out" errors caused by queueing unsupported method calls.
- Fixed flakiness in `tests/user-blocks.test.mjs` by adding delays to allow background promises to settle between tests.
- Verified changes with reproduction test case and existing test suite.

Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-02-02 19:59:24 +00:00
1 parent b478cbaf01
commit 1954739624
3 files changed
+18 -8

No files matched your search

+9 -6
View File
@@ -276,7 +276,9 @@ export class StorageService {
// 2. Encrypt hex key with signer (encrypt to self)
// We prefer NIP-44 if available, else NIP-04
if (typeof signer.nip44Encrypt === "function") {
const caps = signer.capabilities || { nip04: true, nip44: true };
if (caps.nip44 && typeof signer.nip44Encrypt === "function") {
try {
const ciphertext = await signer.nip44Encrypt(pubkey, hexKey);
return { method: "nip44", ciphertext };
@@ -285,10 +287,10 @@ export class StorageService {
}
}
if (typeof signer.nip04Encrypt === "function") {
if (caps.nip04 && typeof signer.nip04Encrypt === "function") {
const ciphertext = await signer.nip04Encrypt(pubkey, hexKey);
return { method: "nip04", ciphertext };
} else if (typeof signer.encrypt === "function") {
} else if (caps.nip04 && typeof signer.encrypt === "function") {
// Legacy NIP-04 direct method on some signer objects
const ciphertext = await signer.encrypt(pubkey, hexKey);
return { method: "nip04", ciphertext };
@@ -306,15 +308,16 @@ export class StorageService {
*/
async _decryptMasterKey(encryptedData, signer, pubkey) {
const { method, ciphertext } = encryptedData;
const caps = signer.capabilities || { nip04: true, nip44: true };
let hexKey = null;
if (method === "nip44" && typeof signer.nip44Decrypt === "function") {
if (method === "nip44" && caps.nip44 && typeof signer.nip44Decrypt === "function") {
hexKey = await signer.nip44Decrypt(pubkey, ciphertext);
} else if (method === "nip04" || !method) {
// Default to NIP-04 if method not specified (legacy)
if (typeof signer.nip04Decrypt === "function") {
if (caps.nip04 && typeof signer.nip04Decrypt === "function") {
hexKey = await signer.nip04Decrypt(pubkey, ciphertext);
} else if (typeof signer.decrypt === "function") {
} else if (caps.nip04 && typeof signer.decrypt === "function") {
hexKey = await signer.decrypt(pubkey, ciphertext);
}
}
+5 -2
View File
@@ -983,8 +983,11 @@ class UserBlockListManager {
signer = await nostrClient.ensureActiveSignerForPubkey(normalized);
}
const signerHasNip04 = typeof signer?.nip04Decrypt === "function";
const signerHasNip44 = typeof signer?.nip44Decrypt === "function";
const caps = signer?.capabilities || {};
const signerHasNip04 =
caps.nip04 !== false && typeof signer?.nip04Decrypt === "function";
const signerHasNip44 =
caps.nip44 !== false && typeof signer?.nip44Decrypt === "function";
const signerAvailable = Boolean(signer);
const signerHasDecryptors = signerHasNip04 || signerHasNip44;
const signerStatus = signerAvailable
+4
View File
@@ -166,6 +166,8 @@ await (async () => {
}
})();
await new Promise((resolve) => setTimeout(resolve, 100));
await (async () => {
const actor = "a".repeat(64);
const initialBlocked = "b".repeat(64);
@@ -328,6 +330,8 @@ await (async () => {
}
})();
await new Promise((resolve) => setTimeout(resolve, 100));
await (async () => {
const actor = "1".repeat(64);
const seedOneHex = "2".repeat(64);