allow signing manually with an external key.

This commit is contained in:
fiatjaf 2022-01-12 22:35:12 -03:00
parent 46ab2566b0
commit 161941a9c5
10 changed files with 89 additions and 53 deletions

View File

@ -15,7 +15,7 @@
"core-js": "^3.6.5",
"identicon.js": "^2.3.3",
"markdown-it": "^12.3.0",
"nostr-tools": "^0.18.0",
"nostr-tools": "^0.19.0",
"pouchdb-adapter-idb": "6",
"pouchdb-core": "6",
"pouchdb-mapreduce": "6",

View File

@ -28,7 +28,6 @@
unelevated
type="submit"
color="primary"
:disable="!$store.state.keys.priv"
/>
</div>
</q-form>
@ -48,9 +47,9 @@ export default {
}
},
methods: {
sendPost() {
this.$store.dispatch('sendPost', {message: this.text})
this.text = ''
async sendPost() {
let ok = await this.$store.dispatch('sendPost', {message: this.text})
if (ok) this.text = ''
}
}
}

View File

@ -10,14 +10,7 @@
</q-input>
<div class="flex justify-end mt-2">
<q-btn
:disable="!$store.state.keys.priv"
label="Reply"
rounded
unelevated
type="submit"
color="primary"
/>
<q-btn label="Reply" rounded unelevated type="submit" color="primary" />
</div>
</q-form>
</template>
@ -39,7 +32,7 @@ export default {
},
methods: {
sendReply() {
async sendReply() {
// build tags
let tags = []
@ -69,11 +62,12 @@ export default {
// remove ourselves
tags = tags.filter(([_, v]) => v !== this.$store.state.keys.pub)
this.$store.dispatch('sendPost', {
let ok = await this.$store.dispatch('sendPost', {
message: this.text,
tags
})
this.text = ''
if (ok) this.text = ''
}
}
}

View File

@ -221,22 +221,21 @@
<div class="text-lg text-bold tracking-wide leading-relaxed py-2">
Initial Key Setup
</div>
<p>
Type your mnemonic seed from a previous Nostr account or generate a
<div class="mb-2">
Type your private key from a previous Nostr account or generate a
new one.
</p>
<p>
You can also type a raw private key or just a public key for a
watch-only setup.
</p>
</q-card-section>
<q-card-section>
</div>
<div>
You can also type just a public key and later sign events manually
or using a Nostr-capable browser extension.
</div>
<q-form @submit="proceed">
<q-input
v-model="key"
autogrow
autofocus
label="BIP39 Seed Words, private key or public key"
label="Private key or public key"
class="text-lg"
/>
<q-toggle

View File

@ -103,23 +103,17 @@
<div class="text-lg text-bold tracking-wide leading-relaxed py-2">
Your keys <q-icon name="vpn_key" />
</div>
<p>
Make sure you back up your private key! <br />
<small
>Posts are published using your private key. Others can see your
posts or follow you using only your public key.</small
>
<p v-if="$store.state.keys.priv">
Make sure you back up your private key!
</p>
<p v-else>Your private key is not here!</p>
<div class="mt-1 text-xs">
Posts are published using your private key. Others can see your
posts or follow you using only your public key.
</div>
</q-card-section>
<q-card-section>
<p>Seed Words:</p>
<q-input
v-model="$store.state.keys.mnemonic"
class="mb-2"
readonly
filled
/>
<p>Private Key:</p>
<q-input
v-model="$store.state.keys.priv"

View File

@ -1,5 +1,36 @@
import {relayPool} from 'nostr-tools'
import {Dialog} from 'quasar'
export const pool = relayPool()
pool.setPolicy('randomChoice', 3)
// this will try to sign either with window.nostr or using a manual prompt
export async function signAsynchronously(event) {
if (window.nostr) {
return window.nostr.signEvent(event)
} else {
return new Promise((resolve, reject) => {
Dialog.create({
class: 'px-6 py-1 overflow-hidden',
title: 'Sign this event manually',
message: `<pre class="font-mono">${JSON.stringify(
event,
null,
2
)}</pre>`,
html: true,
prompt: {
model: '',
type: 'text',
isValid: val => !!val.toLowerCase().match(/^[a-z0-9]{128}$/),
attrs: {autocomplete: 'off'},
label: 'Paste the signature here (as hex)'
}
})
.onOk(resolve)
.onCancel(() => reject('Canceled.'))
.onDismiss(() => reject('Canceled.'))
})
}
}

View File

@ -1,7 +1,7 @@
import {encrypt} from 'nostr-tools/nip04'
import {Notify, LocalStorage} from 'quasar'
import {pool} from '../pool'
import {pool, signAsynchronously} from '../pool'
import {dbSave, dbGetProfile, dbGetContactList} from '../db'
export function initKeys(store, keys) {
@ -19,9 +19,11 @@ export async function launch(store) {
store.commit('haveReadNotifications')
}
// now we already have a key
// if we have already have a private key
if (store.state.keys.priv) {
pool.setPrivateKey(store.state.keys.priv)
} else {
pool.registerSigningFunction(signAsynchronously)
}
// translate localStorage into a kind3 event -- or load relays and following from event
@ -138,15 +140,31 @@ export function restartMainSubscription(store) {
export async function sendPost(store, {message, tags = [], kind = 1}) {
if (message.length === 0) return
let event = await pool.publish({
pubkey: store.state.keys.pub,
created_at: Math.floor(Date.now() / 1000),
kind,
tags,
content: message
})
let event
try {
event = await pool.publish({
pubkey: store.state.keys.pub,
created_at: Math.floor(Date.now() / 1000),
kind,
tags,
content: message
})
} catch (err) {
Notify.create({
message: `Did not publish: ${err}`,
color: 'red'
})
return
}
if (!event) {
// aborted
return
}
store.dispatch('addEvent', {event})
return true
}
export async function setMetadata(store, metadata) {

View File

@ -20,7 +20,7 @@ export function setKeys(state, {mnemonic, priv, pub} = {}) {
pub = getPublicKey(priv)
}
state.keys = {mnemonic, priv, pub}
state.keys = {priv, pub}
}
export function setRelays(state, relays) {

View File

@ -3,6 +3,7 @@ import {LocalStorage} from 'quasar'
export default function () {
return {
keys: LocalStorage.getItem('keys') || {pub: '00'}, // { mnemonic, priv, pub }
relays: {
// 'wss://nostr.rocks': {read: true, write: true},
'wss://relayer.fiatjaf.com': {read: true, write: true},

View File

@ -4769,10 +4769,10 @@ normalize-url@^6.0.1:
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
nostr-tools@^0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-0.18.0.tgz#d5c76ecd2ea6728a772de5daa5ab5d8110f3425c"
integrity sha512-NOAC7JhNrAtFnEsr4vEG3PzSzhAcChzXr0SCcfrlFbXcwIFKHcrBGZ4K6qmhJPGpVvhuXwquixG3KlfMIoqc5g==
nostr-tools@^0.19.0:
version "0.19.0"
resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-0.19.0.tgz#3e086f4a1715607d8917912f56a16866a115efec"
integrity sha512-kn7+gy+Ncrf7WkIN/OTuNu/EZtfK2hVLQZw9CQOVcngeF5nlqMRVrgMQBo2CkrkFFV5G5tS71lH4imtiklh13g==
dependencies:
"@noble/hashes" "^0.5.7"
"@noble/secp256k1" "^1.3.0"