Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implemented nip04 #1777

Merged
merged 9 commits into from
Dec 2, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
33 changes: 33 additions & 0 deletions src/extension/background-script/actions/nostr/decryptOrPrompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import state from "~/extension/background-script/state";
import { MessageDecryptGet } from "~/types";

const decryptOrPrompt = async (message: MessageDecryptGet) => {
if (!("host" in message.origin)) {
console.error("error", message.origin);
return;
}

const result = await prompt(message);

return result;
};

const prompt = async (message: MessageDecryptGet) => {
try {

// TODO: Add prompt & permissions

const response = {
data: state.getState().getNostr().decrypt(message.args.peer, message.args.ciphertext)
}

return response;
} catch (e) {
console.error("decrypt cancelled", e);
reneaaron marked this conversation as resolved.
Show resolved Hide resolved
if (e instanceof Error) {
return { error: e.message };
}
}
};

export default decryptOrPrompt;
33 changes: 33 additions & 0 deletions src/extension/background-script/actions/nostr/encryptOrPrompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import state from "~/extension/background-script/state";
import { MessageEncryptGet } from "~/types";

const encryptOrPrompt = async (message: MessageEncryptGet) => {
if (!("host" in message.origin)) {
console.error("error", message.origin);
return;
}

const result = await prompt(message);

return result;
};

const prompt = async (message: MessageEncryptGet) => {
try {

// TODO: Add prompt & permissions

const response = {
data: state.getState().getNostr().encrypt(message.args.peer, message.args.plaintext),
};

return response;
} catch (e) {
console.error("encrypt cancelled", e);
reneaaron marked this conversation as resolved.
Show resolved Hide resolved
if (e instanceof Error) {
return { error: e.message };
}
}
};

export default encryptOrPrompt;
4 changes: 4 additions & 0 deletions src/extension/background-script/actions/nostr/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import decryptOrPrompt from "./decryptOrPrompt";
import encryptOrPrompt from "./encryptOrPrompt";
import generatePrivateKey from "./generatePrivateKey";
import getPrivateKey from "./getPrivateKey";
import getPublicKeyOrPrompt from "./getPublicKeyOrPrompt";
Expand All @@ -12,4 +14,6 @@ export {
getPublicKeyOrPrompt,
getRelays,
signEventOrPrompt,
encryptOrPrompt,
decryptOrPrompt,
};
36 changes: 35 additions & 1 deletion src/extension/background-script/nostr/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as secp256k1 from "@noble/secp256k1";
import { decryptData, encryptData } from "~/common/lib/crypto";
import { Event } from "~/extension/ln/nostr/types";

import { signEvent } from "../actions/nostr/helpers";
import state from "../state";
import aes from 'browserify-cipher';
reneaaron marked this conversation as resolved.
Show resolved Hide resolved
import {Buffer} from 'buffer'

class Nostr {
getPrivateKey() {
Expand Down Expand Up @@ -36,6 +37,39 @@ class Nostr {
event.sig = signature;
return event;
}

encrypt(pubkey: string, text: string) {
const key = secp256k1.getSharedSecret(this.getPrivateKey(), '02' + pubkey);
//const normalizedKey = secp256k1.utils.bytesToHex(key).substring(2, 64);
const normalizedKey = Buffer.from(key.slice(1, 33));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this doing?
should this be a compressed key?
https://www.npmjs.com/package/@noble/secp256k1#getsharedsecretprivatekeya-publickeyb

isCompressed = false determines whether to return compact (33-byte), or full (65-byte) key


let iv = Uint8Array.from(secp256k1.utils.randomBytes(16));
var cipher = aes.createCipheriv(
'aes-256-cbc',
Buffer.from(normalizedKey, 'hex'),
iv
);
let encryptedMessage = cipher.update(text, 'utf8', 'base64');
encryptedMessage += cipher.final('base64');

return `${encryptedMessage}?iv=${Buffer.from(iv.buffer).toString('base64')}`;
}

decrypt(pubkey: string, ciphertext: string) {
let [cip, iv] = ciphertext.split('?iv=')
let key = secp256k1.getSharedSecret(this.getPrivateKey(), '02' + pubkey);
const normalizedKey = Buffer.from(key.slice(1, 33));

var decipher = aes.createDecipheriv(
'aes-256-cbc',
Buffer.from(normalizedKey, 'hex'),
Buffer.from(iv, 'base64')
)
let decryptedMessage = decipher.update(cip, 'base64', 'utf8')
decryptedMessage += decipher.final('utf8')

return decryptedMessage;
}
}

export default Nostr;
2 changes: 2 additions & 0 deletions src/extension/background-script/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ const routes = {
getPublicKeyOrPrompt: nostr.getPublicKeyOrPrompt,
signEventOrPrompt: nostr.signEventOrPrompt,
getRelays: nostr.getRelays,
encryptOrPrompt: nostr.encryptOrPrompt,
decryptOrPrompt: nostr.decryptOrPrompt,
},
},
};
Expand Down
2 changes: 2 additions & 0 deletions src/extension/content-script/onendnostr.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const nostrCalls = [
"nostr/getPublicKeyOrPrompt",
"nostr/signEventOrPrompt",
"nostr/getRelays",
"nostr/encryptOrPrompt",
"nostr/decryptOrPrompt",
];
let callActive = false;

Expand Down
4 changes: 2 additions & 2 deletions src/extension/ln/nostr/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ class Nip04 {
}

async encrypt(peer: string, plaintext: string): Promise<string> {
throw new Error("Nip04 is not yet implemented.");
return this.provider.execute("encryptOrPrompt", { peer, plaintext });
}

async decrypt(peer: string, ciphertext: string): Promise<string> {
throw new Error("Nip04 is not yet implemented.");
return this.provider.execute("decryptOrPrompt", { peer, ciphertext });
}
}
16 changes: 16 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,22 @@ export interface MessageSignEvent extends MessageDefault {
action: "signEvent";
}

export interface MessageEncryptGet extends MessageDefault {
args: {
peer: string;
plaintext: string;
};
action: "encrypt";
}

export interface MessageDecryptGet extends MessageDefault {
args: {
peer: string;
ciphertext: string;
};
action: "decrypt";
}

export interface LNURLChannelServiceResponse {
uri: string; // Remote node address of form node_key@ip_address:port_number
callback: string; // a second-level URL which would initiate an OpenChannel message from target LN node
Expand Down