updated nip-07 login

This commit is contained in:
thePR0M3TH3AN committed 2026-02-21 16:00:02 -05:00
1 parent 2946e50c0e
commit 576513ecdb
3 files changed
+77 -46

No files matched your search

+20 -4
View File
@@ -481,8 +481,6 @@ export class SignerManager {
extension = window.nostr;
}
const message = resolvePermissionStatusMessage(missing, context);
try {
const response = await requestEnablePermissions(extension, missing);
if (response?.ok) {
@@ -494,7 +492,10 @@ export class SignerManager {
}
return { ok: true };
}
return { ok: false, error: "permission-denied" };
return {
ok: false,
error: response?.error || "permission-denied",
};
} catch (error) {
devLogger.warn("[nostr] Extension permission request failed:", error);
return { ok: false, error: "request-failed" };
@@ -572,8 +573,23 @@ export class SignerManager {
{ context: "login", logMetrics: true, showStatus: false },
);
if (!permissionResult.ok) {
const permissionErrorDetail =
permissionResult && typeof permissionResult === "object"
? permissionResult.error
: null;
const permissionDetailMessage =
permissionErrorDetail instanceof Error &&
typeof permissionErrorDetail.message === "string" &&
permissionErrorDetail.message.trim()
? permissionErrorDetail.message.trim()
: typeof permissionErrorDetail === "string" &&
permissionErrorDetail.trim()
? permissionErrorDetail.trim()
: "";
const denialMessage =
'The NIP-07 extension reported "permission denied". Please approve the prompt and try again.';
permissionDetailMessage
? `The NIP-07 extension denied the permission request (${permissionDetailMessage}). Please approve the prompt and try again.`
: 'The NIP-07 extension reported "permission denied". Please approve the prompt and try again.';
const denialError = new Error(denialMessage);
if (permissionResult.error) {
denialError.cause = permissionResult.error;
+29 -42
View File
@@ -345,8 +345,10 @@ export async function requestEnablePermissions(
}
let lastError = null;
if (hasRequestPermissions) {
const runPermissionMethod = async (methodName, method) => {
for (const options of permissionVariants) {
// Specific permission payloads should fail fast; prompt-based no-arg calls
// get a longer timeout so users have time to confirm in extension UI.
const variantTimeoutOverrides = options
? {
timeoutMs: Math.min(3000, getEnableVariantTimeoutMs()),
@@ -364,64 +366,49 @@ export async function requestEnablePermissions(
await runNip07WithRetry(
() =>
options === null
? extension.requestPermissions()
: extension.requestPermissions(options),
? method()
: methodName === "enable"
? method(options)
: method(options),
{
label: "extension.requestPermissions",
label: `extension.${methodName}`,
...variantTimeoutOverrides,
},
);
return { ok: true };
return true;
} catch (error) {
lastError = error;
if (options && isDevMode) {
userLogger.warn(
"[nostr] extension.requestPermissions call failed:",
`[nostr] extension.${methodName} permission request failed:`,
error,
);
}
}
}
}
return false;
};
if (!hasEnable) {
return {
ok: false,
error: lastError || new Error("permission-denied"),
};
// Compatibility-first: prefer standard NIP-07 enable() where available.
if (hasEnable) {
const enableSucceeded = await runPermissionMethod(
"enable",
extension.enable.bind(extension),
);
if (enableSucceeded) {
return { ok: true };
}
}
for (const options of permissionVariants) {
// If specific permissions are requested (variants 1 & 2), fail fast (3s)
// to avoid hanging if the extension doesn't support the structured format.
// If we fall back to standard enable() (null), allow the full user interaction time.
const variantTimeoutOverrides = options
? {
timeoutMs: Math.min(3000, getEnableVariantTimeoutMs()),
retryMultiplier: 1,
}
: {
timeoutMs: Math.min(
NIP07_LOGIN_TIMEOUT_MS,
getEnableVariantTimeoutMs(),
),
retryMultiplier: 1,
};
try {
await runNip07WithRetry(
() => (options ? extension.enable(options) : extension.enable()),
{ label: "extension.enable", ...variantTimeoutOverrides },
);
// Fallback for extensions that implement requestPermissions() but not enable(),
// or where enable() payload handling is broken.
if (hasRequestPermissions) {
const requestPermissionsSucceeded = await runPermissionMethod(
"requestPermissions",
extension.requestPermissions.bind(extension),
);
if (requestPermissionsSucceeded) {
return { ok: true };
} catch (error) {
lastError = error;
if (options && isDevMode) {
userLogger.warn(
"[nostr] extension.enable request with explicit permissions failed:",
error,
);
}
}
}
+28
View File
@@ -89,6 +89,34 @@ test("requestEnablePermissions supports requestPermissions-only extensions", asy
assert.deepStrictEqual(calls, [{ permissions: [{ method: "sign_event" }] }]);
});
test("requestEnablePermissions prefers enable over requestPermissions when both exist", async () => {
clearStoredNip07Permissions();
const calls = {
enable: [],
requestPermissions: [],
};
const extension = {
enable: (options) => {
calls.enable.push(options);
return Promise.resolve();
},
requestPermissions: (options) => {
calls.requestPermissions.push(options);
return Promise.resolve({ granted: true });
},
};
const result = await requestEnablePermissions(
extension,
["sign_event"],
{ isDevMode: false },
);
assert.deepStrictEqual(result, { ok: true });
assert.deepStrictEqual(calls.enable, [{ permissions: [{ method: "sign_event" }] }]);
assert.deepStrictEqual(calls.requestPermissions, []);
});
test("requestEnablePermissions fails when requestPermissions exists but denies", async () => {
clearStoredNip07Permissions();
const extension = {