From 88a2dd806d71f405b630fe2edf58a952746551dc Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Mon, 10 Jan 2022 14:11:49 -0300 Subject: [PATCH] basic functionality, untested. --- .gitignore | 1 + README.md | 2 +- build.js | 26 +++++++++++++++++++++ extension/background.js | 39 ++++++++++++++++++++++++++------ extension/content-script.js | 13 ++++++----- extension/manifest.json | 7 +----- extension/nostr-provider.js | 45 +++++++++++++++++++++++++++++++++++-- extension/options.html | 11 +++++++++ extension/options.js | 15 +++++++++++++ package.json | 5 ++++- yarn.lock | 15 +++++++++++++ 11 files changed, 156 insertions(+), 23 deletions(-) create mode 100755 build.js create mode 100644 extension/options.js diff --git a/.gitignore b/.gitignore index 3c3629e..a6bb1fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +*.build.js diff --git a/README.md b/README.md index 25ef631..931766d 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ It provides a `window.nostr` object which has the following methods: ``` async window.nostr.getPublicKey(): string // returns your public key as hex -async window.nostr.signEvent(event) // signs the given event in place +async window.nostr.signEvent(event): string // returns the signature as hex ``` --- diff --git a/build.js b/build.js new file mode 100755 index 0000000..8cd917d --- /dev/null +++ b/build.js @@ -0,0 +1,26 @@ +#!/usr/bin/env node + +const esbuild = require('esbuild') +const alias = require('esbuild-plugin-alias') + +esbuild.build({ + bundle: true, + entryPoints: ['./extension/options.js'], + outfile: './extension/options.build.js', + plugins: [ + alias({ + stream: require.resolve('readable-stream') + }) + ] +}) + +esbuild.build({ + bundle: true, + entryPoints: ['./extension/background.js'], + outfile: './extension/background.build.js', + plugins: [ + alias({ + stream: require.resolve('readable-stream') + }) + ] +}) diff --git a/extension/background.js b/extension/background.js index bd88a24..6e25461 100644 --- a/extension/background.js +++ b/extension/background.js @@ -1,9 +1,34 @@ -browser.runtime.onMessage.addListener((req, sender, reply) => { - switch (req.type) { - case 'getPublicKey': - reply({}) - break - case 'signEvent': - break +import browser from 'webextension-polyfill' +import {validateEvent, signEvent, getPublicKey} from 'nostr-tools' + +browser.runtime.onMessage.addListener(async (req, sender, reply) => { + let {type, params, host} = req + + try { + switch (type) { + case 'getPublicKey': { + let results = browser.storage.local.get('private_key') + if (results && results.private_key) { + reply(getPublicKey(results.private_key)) + } else { + reply({error: 'no private key found'}) + } + break + } + case 'signEvent': { + let {event} = params + if (!validateEvent(event)) return reply({error: 'invalid event'}) + + let results = browser.storage.local.get('private_key') + if (results && results.private_key) { + reply(signEvent(event, results.private_key)) + } else { + reply({error: 'no private key found'}) + } + break + } + } + } catch (error) { + reply({error}) } }) diff --git a/extension/content-script.js b/extension/content-script.js index 7a65ad2..aa9164d 100644 --- a/extension/content-script.js +++ b/extension/content-script.js @@ -6,19 +6,20 @@ document.head.appendChild(script) // listen for messages from that script window.addEventListener('message', async ev => { if (ev.source !== window) return - if (!ev.data || ev.data.ext !== 'nostr') { + if (!ev.data || ev.data.ext !== 'nos2x') { // pass on to background - var reply + var response try { - reply = browser.runtime.sendMessage({ - ...ev.data, + response = browser.runtime.sendMessage({ + type: ev.data.type, + params: ev.data.params, host: window.location.host }) } catch (error) { - reply = {error} + response = {error} } // return response - window.postMessage({id: ev.data.id, reply}) + window.postMessage({id: ev.data.id, ext: 'nos2x', response}) } }) diff --git a/extension/manifest.json b/extension/manifest.json index 82b6a70..8caeb2a 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -3,15 +3,10 @@ "description": "Nostr Signer Extension", "version": "0.0.1", "manifest_version": 2, - "icons": { - "16": "icons/icon-16x16.png", - "48": "icons/icon-48x48.png", - "128": "icons/icon-128x128.png" - }, "options_page": "options.html", "background": { "scripts": [ - "background.js" + "background.build.js" ], "persistent": false }, diff --git a/extension/nostr-provider.js b/extension/nostr-provider.js index b39c549..92e07f7 100644 --- a/extension/nostr-provider.js +++ b/extension/nostr-provider.js @@ -1,4 +1,45 @@ window.nostr = { - getPublicKey() {}, - signEvent(event) {} + _requests: {}, + _pubkey: null, + + async getPublicKey() { + if (this._pubkey) return this._pubkey + this._pubkey = await this._call('getPublicKey') + return this._pubkey + }, + + async signEvent(event) { + return this._call('signEvent', {event}) + }, + + _call(type, params) { + return new Promise((resolve, reject) => { + let id = Math.random().toString().slice(4) + this._requests[id] = {resolve, reject} + window.postMessage( + { + id, + ext: 'nos2x', + type, + params + }, + '*' + ) + }) + } } + +window.addEventListener('message', message => { + if ( + !message.data || + message.data.ext !== 'nos2x' || + !window.nostr._requests[message.data.id] + ) + return + + if (message.data.response.error) { + window.nostr._requests[message.data.id].reject(message.data.response.error) + } else { + window.nostr._requests[message.data.id].resolve(message.data.response) + } +}) diff --git a/extension/options.html b/extension/options.html index e69de29..1b5a02c 100644 --- a/extension/options.html +++ b/extension/options.html @@ -0,0 +1,11 @@ + + + +nos2x + + + + diff --git a/extension/options.js b/extension/options.js new file mode 100644 index 0000000..9444abd --- /dev/null +++ b/extension/options.js @@ -0,0 +1,15 @@ +/* global document */ + +import browser from 'webextension-polyfill' + +document.getElementById('privateKeyInput').addEventListener('input', ev => { + browser.storage.local + .set({private_key: document.getElementById('privateKeyInput').value}) + .then(() => { + console.log('success') + }) +}) + +browser.storage.local.get('private_key').then(results => { + document.getElementById('privateKeyInput').value = results.private_key +}) diff --git a/package.json b/package.json index 49389d6..f519473 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,11 @@ { "dependencies": { "esbuild": "^0.14.11", + "esbuild-plugin-alias": "^0.2.1", "eslint": "^8.6.0", + "events": "^3.3.0", "nostr-tools": "^0.17.0", - "prettier": "^2.5.1" + "prettier": "^2.5.1", + "webextension-polyfill": "^0.8.0" } } diff --git a/yarn.lock b/yarn.lock index ca65ea0..ef89663 100644 --- a/yarn.lock +++ b/yarn.lock @@ -367,6 +367,11 @@ esbuild-openbsd-64@0.14.11: resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.11.tgz#caeff5f946f79a60ce7bcf88871ca4c71d3476e8" integrity sha512-l18TZDjmvwW6cDeR4fmizNoxndyDHamGOOAenwI4SOJbzlJmwfr0jUgjbaXCUuYVOA964siw+Ix+A+bhALWg8Q== +esbuild-plugin-alias@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/esbuild-plugin-alias/-/esbuild-plugin-alias-0.2.1.tgz#45a86cb941e20e7c2bc68a2bea53562172494fcb" + integrity sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ== + esbuild-sunos-64@0.14.11: version "0.14.11" resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.11.tgz#90ce7e1749c2958a53509b4bae7b8f7d98f276d6" @@ -518,6 +523,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +events@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" @@ -1007,6 +1017,11 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +webextension-polyfill@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.8.0.tgz#f80e9f4b7f81820c420abd6ffbebfa838c60e041" + integrity sha512-a19+DzlT6Kp9/UI+mF9XQopeZ+n2ussjhxHJ4/pmIGge9ijCDz7Gn93mNnjpZAk95T4Tae8iHZ6sSf869txqiQ== + websocket-polyfill@^0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/websocket-polyfill/-/websocket-polyfill-0.0.3.tgz#7321ada0f5f17516290ba1cb587ac111b74ce6a5"