Defer NIP-07 encryption permissions

This commit is contained in:
thePR0M3TH3AN committed 2026-01-30 10:29:00 -05:00
1 parent 0e9f9204a1
commit abdfa4b68b
9 files changed
+117 -31

No files matched your search

+10 -4
View File
@@ -89,7 +89,7 @@ import {
onActiveSignerChanged,
} from "./nostrClientRegistry.js";
import { queueSignEvent } from "./nostr/signRequestQueue.js";
import { DEFAULT_NIP07_PERMISSION_METHODS } from "./nostr/nip07Permissions.js";
import { DEFAULT_NIP07_CORE_METHODS } from "./nostr/nip07Permissions.js";
import {
initViewCounter,
subscribeToVideoViewCount,
@@ -2027,7 +2027,9 @@ class Application {
case "nip04-missing":
return "Your Nostr extension must support NIP-04 to manage private block lists.";
case "extension-permission-denied":
return "Permission to update your block list was denied by your Nostr extension.";
return "Your Nostr extension denied the encryption permissions needed to update your block list.";
case "extension-encryption-permission-denied":
return "Your Nostr extension denied the encryption permissions needed to update your block list.";
case "sign-event-missing":
case "signer-missing":
return "Connect a Nostr signer that can encrypt and sign updates before managing block lists.";
@@ -2058,7 +2060,9 @@ class Application {
case "hashtag-preferences-missing-signer":
return "Connect a Nostr signer that supports encryption before managing hashtag preferences.";
case "hashtag-preferences-extension-denied":
return "Permission to manage hashtag preferences was denied by your signer.";
return "Your signer denied the encryption permissions needed to manage hashtag preferences.";
case "hashtag-preferences-permission-required":
return "Your Nostr extension must grant encryption permissions to read hashtag preferences.";
case "hashtag-preferences-no-decryptors":
return "Unable to decrypt hashtag preferences with the active signer.";
case "hashtag-preferences-decrypt-failed":
@@ -2694,7 +2698,9 @@ class Application {
}
if (signer.type === "extension" && nostrClient.ensureExtensionPermissions) {
const permissionResult = await nostrClient.ensureExtensionPermissions();
const permissionResult = await nostrClient.ensureExtensionPermissions(
DEFAULT_NIP07_CORE_METHODS,
);
if (!permissionResult?.ok) {
userLogger.warn(
"[Application] Signer permissions denied while publishing DM relays.",
+28 -11
View File
@@ -137,6 +137,7 @@ import {
resolveDmRelaySelection,
} from "../services/dmNostrService.js";
import {
DEFAULT_NIP07_CORE_METHODS,
DEFAULT_NIP07_ENCRYPTION_METHODS,
DEFAULT_NIP07_PERMISSION_METHODS,
NIP07_PRIORITY,
@@ -2003,7 +2004,7 @@ export class NostrClient {
}
const permissionResult = await this.ensureExtensionPermissions(
DEFAULT_NIP07_PERMISSION_METHODS,
DEFAULT_NIP07_CORE_METHODS,
);
if (!permissionResult.ok) {
const denialMessage =
@@ -4813,7 +4814,23 @@ export class NostrClient {
activeSigner = getActiveSigner();
}
if (activeSigner) {
let extensionPermissionResult = null;
if (
activeSigner?.type === "extension" &&
typeof this.ensureExtensionPermissions === "function"
) {
extensionPermissionResult = await this.ensureExtensionPermissions(
DEFAULT_NIP07_ENCRYPTION_METHODS,
);
if (!extensionPermissionResult?.ok) {
devLogger.warn(
"[nostr] Extension encryption permissions missing for DM decryption.",
extensionPermissionResult?.error,
);
}
}
if (activeSigner && extensionPermissionResult?.ok !== false) {
const capabilities = resolveSignerCapabilities(activeSigner);
if (
capabilities.nip44 &&
@@ -5260,16 +5277,16 @@ export class NostrClient {
if (shouldRequestExtensionPermissions(signer)) {
const permissionResult = await this.ensureExtensionPermissions(
DEFAULT_NIP07_PERMISSION_METHODS,
DEFAULT_NIP07_ENCRYPTION_METHODS,
);
if (!permissionResult.ok) {
userLogger.warn(
"[nostr] Cannot send direct message without extension permissions.",
"[nostr] Cannot send direct message without encryption permissions.",
permissionResult.error,
);
return {
ok: false,
error: "extension-permission-denied",
error: "extension-encryption-permission-denied",
details: permissionResult.error,
};
}
@@ -6539,7 +6556,7 @@ export class NostrClient {
if (shouldRequestExtensionPermissions(signer)) {
const permissionResult = await this.ensureExtensionPermissions(
DEFAULT_NIP07_PERMISSION_METHODS,
DEFAULT_NIP07_CORE_METHODS,
);
if (!permissionResult.ok) {
userLogger.warn(
@@ -6547,7 +6564,7 @@ export class NostrClient {
permissionResult.error,
);
const error = new Error(
"The active signer must grant decrypt and sign permissions before editing a video.",
"The active signer must allow signing before editing a video.",
);
error.code = "extension-permission-denied";
error.cause = permissionResult.error;
@@ -6718,7 +6735,7 @@ export class NostrClient {
if (shouldRequestExtensionPermissions(signer)) {
const permissionResult = await this.ensureExtensionPermissions(
DEFAULT_NIP07_PERMISSION_METHODS,
DEFAULT_NIP07_CORE_METHODS,
);
if (!permissionResult.ok) {
userLogger.warn(
@@ -6726,7 +6743,7 @@ export class NostrClient {
permissionResult.error,
);
const error = new Error(
"The active signer must grant decrypt and sign permissions before reverting a video.",
"The active signer must allow signing before reverting a video.",
);
error.code = "extension-permission-denied";
error.cause = permissionResult.error;
@@ -7026,7 +7043,7 @@ export class NostrClient {
if (shouldRequestExtensionPermissions(signer)) {
const permissionResult = await this.ensureExtensionPermissions(
DEFAULT_NIP07_PERMISSION_METHODS,
DEFAULT_NIP07_CORE_METHODS,
);
if (!permissionResult.ok) {
userLogger.warn(
@@ -7034,7 +7051,7 @@ export class NostrClient {
permissionResult.error,
);
const error = new Error(
"The active signer must grant decrypt and sign permissions before deleting a video.",
"The active signer must allow signing before deleting a video.",
);
error.code = "extension-permission-denied";
error.cause = permissionResult.error;
+2
View File
@@ -2,6 +2,7 @@
import { NostrClient } from "./client.js";
import {
DEFAULT_NIP07_CORE_METHODS,
DEFAULT_NIP07_ENCRYPTION_METHODS,
DEFAULT_NIP07_PERMISSION_METHODS,
} from "./nip07Permissions.js";
@@ -26,6 +27,7 @@ export function requestDefaultExtensionPermissions(
export {
NostrClient,
DEFAULT_NIP07_CORE_METHODS,
DEFAULT_NIP07_ENCRYPTION_METHODS,
DEFAULT_NIP07_PERMISSION_METHODS,
};
+5 -1
View File
@@ -21,12 +21,16 @@ export const DEFAULT_NIP07_ENCRYPTION_METHODS = Object.freeze([
"nip44.v2.decrypt",
]);
export const DEFAULT_NIP07_PERMISSION_METHODS = Object.freeze([
export const DEFAULT_NIP07_CORE_METHODS = Object.freeze([
// Core auth + relay metadata
"get_public_key",
"sign_event",
"read_relays",
"write_relays",
]);
export const DEFAULT_NIP07_PERMISSION_METHODS = Object.freeze([
...DEFAULT_NIP07_CORE_METHODS,
...DEFAULT_NIP07_ENCRYPTION_METHODS,
]);
+26 -4
View File
@@ -19,7 +19,11 @@ import { normalizeHashtag } from "../utils/hashtagNormalization.js";
import { profileCache } from "../state/profileCache.js";
import { DEFAULT_RELAY_URLS } from "../nostr/toolkit.js";
import { relayManager } from "../relayManager.js";
import { runNip07WithRetry, NIP07_PRIORITY } from "../nostr/nip07Permissions.js";
import {
DEFAULT_NIP07_ENCRYPTION_METHODS,
runNip07WithRetry,
NIP07_PRIORITY,
} from "../nostr/nip07Permissions.js";
import { relaySubscriptionService } from "./relaySubscriptionService.js";
const LOG_PREFIX = "[HashtagPreferences]";
@@ -901,12 +905,28 @@ class HashtagPreferencesService {
return { ok: false, error };
}
try {
await requestDefaultExtensionPermissions();
const permissionResult = await requestDefaultExtensionPermissions(
DEFAULT_NIP07_ENCRYPTION_METHODS,
);
if (!permissionResult?.ok) {
const error =
permissionResult?.error instanceof Error
? permissionResult.error
: new Error(
"Extension encryption permissions are required to read hashtag preferences.",
);
error.code = "hashtag-preferences-permission-required";
return { ok: false, error };
}
} catch (error) {
userLogger.warn(
`${LOG_PREFIX} Extension permissions request failed while loading preferences`,
error,
);
const wrapped =
error instanceof Error ? error : new Error(String(error));
wrapped.code = "hashtag-preferences-permission-required";
return { ok: false, error: wrapped };
}
}
@@ -1108,10 +1128,12 @@ class HashtagPreferencesService {
}
if (signer.type === "extension") {
const permissionResult = await requestDefaultExtensionPermissions();
const permissionResult = await requestDefaultExtensionPermissions(
DEFAULT_NIP07_ENCRYPTION_METHODS,
);
if (!permissionResult?.ok) {
const error = new Error(
"The active signer must allow encryption and signing before publishing preferences.",
"The active signer must allow encryption before publishing preferences.",
);
error.code = "hashtag-preferences-extension-denied";
error.cause = permissionResult?.error || null;
+11 -3
View File
@@ -31,7 +31,11 @@ import { devLogger, userLogger } from "./utils/logger.js";
import moderationService from "./services/moderationService.js";
import nostrService from "./services/nostrService.js";
import { profileCache } from "./state/profileCache.js";
import { runNip07WithRetry, NIP07_PRIORITY } from "./nostr/nip07Permissions.js";
import {
DEFAULT_NIP07_ENCRYPTION_METHODS,
runNip07WithRetry,
NIP07_PRIORITY,
} from "./nostr/nip07Permissions.js";
import { relaySubscriptionService } from "./services/relaySubscriptionService.js";
const SUBSCRIPTION_SET_KIND =
@@ -883,7 +887,9 @@ class SubscriptionsManager {
return { ok: false, error };
}
try {
const permissionResult = await requestDefaultExtensionPermissions();
const permissionResult = await requestDefaultExtensionPermissions(
DEFAULT_NIP07_ENCRYPTION_METHODS,
);
if (!permissionResult?.ok) {
const error =
permissionResult?.error instanceof Error
@@ -1112,7 +1118,9 @@ class SubscriptionsManager {
}
if (signer.type === "extension") {
const permissionResult = await requestDefaultExtensionPermissions();
const permissionResult = await requestDefaultExtensionPermissions(
DEFAULT_NIP07_ENCRYPTION_METHODS,
);
if (!permissionResult.ok) {
userLogger.warn(
"[SubscriptionsManager] Signer permissions denied while updating subscriptions.",
+2
View File
@@ -1520,6 +1520,8 @@ export default class MoreMenuController {
const message =
error?.code === "nip04-missing"
? "Your Nostr extension must support NIP-04 to manage private lists."
: error?.code === "extension-encryption-permission-denied"
? "Your Nostr extension must allow encryption to update your block list."
: "Failed to update your block list. Please try again.";
this.callbacks.showError(message);
}
+12
View File
@@ -3579,6 +3579,8 @@ export class ProfileModalController {
return "We couldn’t create secure wrapper keys for NIP-17 delivery.";
case "extension-permission-denied":
return "Please grant your Nostr extension permission to send messages.";
case "extension-encryption-permission-denied":
return "Please grant your Nostr extension encryption permission to send messages.";
case "missing-actor-pubkey":
return "We couldn’t determine your public key to send this message.";
case "nostr-uninitialized":
@@ -9213,6 +9215,9 @@ export class ProfileModalController {
const message =
mutationResult?.error?.code === "nip04-missing"
? "Your Nostr extension must support NIP-04 to manage private lists."
: mutationResult?.error?.code ===
"extension-encryption-permission-denied"
? "Your Nostr extension must allow encryption to update your block list."
: mutationResult?.error?.message ||
"Failed to update your block list. Please try again.";
context.error = mutationResult?.error || null;
@@ -9233,6 +9238,8 @@ export class ProfileModalController {
const message =
error?.code === "nip04-missing"
? "Your Nostr extension must support NIP-04 to manage private lists."
: error?.code === "extension-encryption-permission-denied"
? "Your Nostr extension must allow encryption to update your block list."
: "Failed to update your block list. Please try again.";
this.showError(message);
}
@@ -9283,6 +9290,9 @@ export class ProfileModalController {
const message =
mutationResult.error.code === "nip04-missing"
? "Your Nostr extension must support NIP-04 to manage private lists."
: mutationResult.error.code ===
"extension-encryption-permission-denied"
? "Your Nostr extension must allow encryption to update your block list."
: mutationResult.error.message ||
"Failed to update your block list. Please try again.";
if (message) {
@@ -9299,6 +9309,8 @@ export class ProfileModalController {
const message =
error?.code === "nip04-missing"
? "Your Nostr extension must support NIP-04 to manage private lists."
: error?.code === "extension-encryption-permission-denied"
? "Your Nostr extension must allow encryption to update your block list."
: "Failed to update your block list. Please try again.";
this.showError(message);
}
+21 -8
View File
@@ -20,7 +20,11 @@ import {
import { profileCache } from "./state/profileCache.js";
import { DEFAULT_RELAY_URLS } from "./nostr/toolkit.js";
import { relayManager } from "./relayManager.js";
import { runNip07WithRetry, NIP07_PRIORITY } from "./nostr/nip07Permissions.js";
import {
DEFAULT_NIP07_ENCRYPTION_METHODS,
runNip07WithRetry,
NIP07_PRIORITY,
} from "./nostr/nip07Permissions.js";
import { relaySubscriptionService } from "./services/relaySubscriptionService.js";
class TinyEventEmitter {
@@ -962,17 +966,24 @@ class UserBlockListManager {
let permissionError = null;
if ((!signerHasNip44 && requiresNip44) || (!signerHasNip04 && requiresNip04)) {
try {
const permissionResult = await requestDefaultExtensionPermissions();
const permissionResult = await requestDefaultExtensionPermissions(
DEFAULT_NIP07_ENCRYPTION_METHODS,
);
if (!permissionResult?.ok) {
permissionError =
const error =
permissionResult?.error instanceof Error
? permissionResult.error
: new Error(
"Extension permissions are required to use the browser decryptor.",
"Extension encryption permissions are required to use the browser decryptor.",
);
error.code = "user-blocklist-permission-required";
permissionError = error;
}
} catch (error) {
permissionError = error instanceof Error ? error : new Error(String(error));
const wrapped =
error instanceof Error ? error : new Error(String(error));
wrapped.code = "user-blocklist-permission-required";
permissionError = wrapped;
}
}
@@ -1981,16 +1992,18 @@ class UserBlockListManager {
}
if (signer.type === "extension") {
const permissionResult = await requestDefaultExtensionPermissions();
const permissionResult = await requestDefaultExtensionPermissions(
DEFAULT_NIP07_ENCRYPTION_METHODS,
);
if (!permissionResult.ok) {
userLogger.warn(
"[UserBlockList] Signer permissions denied while updating the block list.",
permissionResult.error,
);
const err = new Error(
"The active signer must allow encryption and signing before updating the block list.",
"The active signer must allow encryption before updating the block list.",
);
err.code = "extension-permission-denied";
err.code = "extension-encryption-permission-denied";
err.cause = permissionResult.error;
throw err;
}