Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ This feature can be enable / disabled in Options.
- nip44.encrypt()
- nip44.decrypt()

[NIP-60](https://github.com/nostr-protocol/nips/blob/master/60.md)

- nip60.[signSecret()](https://github.com/nostr-protocol/nips/pull/1890)



These javascript functions are made available to web apps through injection of `window.nostr` script element defined in `nostr-provider.js` into the DOM.
Expand Down
38 changes: 38 additions & 0 deletions src/background/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,16 @@ async function handleContentScriptMessage({ type, params, host, protocol }) {

return nip44.v2.decrypt(ciphertext, key);
}
case 'nip60.signSecret': {
if (!validateNut10Secret(params.secret)) {
return { error: { message: "invalid Cashu secret" } };
}
const utf8Encoder = new TextEncoder();
const hash = bytesToHex(sha256(utf8Encoder.encode(params.secret)));
const sig = bytesToHex(schnorr.sign(hash, sk));
const pubkey = bytesToHex(schnorr.getPublicKey(sk));
return {hash: hash, sig: sig, pubkey: pubkey};
}
}
} catch (error) {
return {
Expand All @@ -350,6 +360,34 @@ async function handleContentScriptMessage({ type, params, host, protocol }) {
}
}

function validateNut10Secret(proof_secret) {
try {
if (typeof proof_secret !== 'string') return false;
const secret = JSON.parse(proof_secret);
if (!Array.isArray(secret) || secret.length !== 2) return false;
const [kind, payload] = secret;
if (typeof kind !== 'string' || !kind.trim()) return false;
if (!payload || !payload.nonce?.trim() || !payload.data?.trim()) return false;
if (payload.tags) {
if (!Array.isArray(payload.tags)) return false;
const year = new Date().getUTCFullYear(); // for deprecation check
for (const tag of payload.tags) {
if (!Array.isArray(tag) || tag.length < 2) return false;
// Some older secret tags may include integers (now deprecated)
// Enforce strings only from 2026 onwards
for (const e of tag) {
if (typeof e !== 'string' && (year > 2025 || typeof e !== 'number' || !Number.isInteger(e))) {
return false;
}
}
}
}
return true;
} catch {
return false;
}
}

async function handlePromptMessage(result, sender) {
// console.log("handlePromptMessage received " + JSON.stringify(result));
const { host, type, accept, conditions, pubkey } = result;
Expand Down
1 change: 1 addition & 0 deletions src/common/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const PERMISSION_NAMES = {
"nip04.decrypt": "decrypt messages from peers",
"nip44.encrypt": "encrypt messages to peers",
"nip44.decrypt": "decrypt messages from peers",
"nip60.signSecret": "sign cashu secrets using your private key",
};

function matchConditions(conditions, event) {
Expand Down
3 changes: 3 additions & 0 deletions src/popup/components/PermissionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export function PermissionItem(props: {
case "nip04.decrypt":
strMesg = "decrypt received messages";
break;
case "nip60.signSecret":
strMesg = "decrypt received messages";
break;
case "signEvent":
if (strEvents != "") {
strMesg = `sign ${strEvents} events`;
Expand Down
2 changes: 1 addition & 1 deletion src/static/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "AKA Profiles",
"description": "Nostr Signer Extension supporting multiple public / private key pairs.",
"version": "1.0.9",
"version": "1.0.10",
"manifest_version": 3,
"action": {
"default_popup": "app.html",
Expand Down
6 changes: 6 additions & 0 deletions src/static/nostr-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ window.nostr = {
},
},

nip60: {
async signSecret(secret) {
return window.nostr._call('nip60.signSecret', {secret});
},
},

// send request to contentScript.js
_call(type, params) {
// console.log("[np] sending mesg to [cs]: " + type + " " + JSON.stringify(params));
Expand Down