forro

Forro is a end-to-end encrypted contract form based on PGP.
git clone git://git.defalsify.org/forro.git
Log | Files | Refs | LICENSE

commit b4fa0f3f17f499cc66de0f175aa07cdd944c5f91
parent bcd3d942da966ca5648f0b68c5d6ca39d5f5b3a1
Author: lash <dev@holbrook.no>
Date:   Mon, 19 Sep 2022 20:33:21 +0000

Add settable passphrase for key

Diffstat:
MCHANGELOG | 2++
Mindex.html | 164+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mkey.js | 23++++++++++-------------
Mpackage.json | 2+-
4 files changed, 127 insertions(+), 64 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -1,3 +1,5 @@ +- 0.0.4 + * settable passphrase for key encryption - 0.0.3 * add (optional) userid info for sender * use funny names for default userid diff --git a/index.html b/index.html @@ -2,7 +2,9 @@ <head> <script> const PUBKEY_PFX = 'pgp.publickey'; - +let g_passphrase = undefined; +let g_passphrase_use = true; +let g_passphrase_time = new Date(0); let g_remote_key = undefined; let g_local_key = undefined; let g_remote_key_id = '(none)'; @@ -49,39 +51,26 @@ let g_counter = undefined; if (klf.length > 1) { g_local_key_identified = true; } + console.log('klf', klf[0]); return klf[klf.length-1].name; } - - async function setUp() { - let k = undefined; + + async function unlockLocalKey(pwd) { try { - stateChange('attempt load local signing key'); - k = await getKey('deadbeef'); - } catch { - stateChange('generate initial bogus name'); - let name = generateName(); - let uid = { - 'name': name, - 'email': 'test@devnull.holbrook.no', - }; - console.debug('you will initially be called', uid.name); - - stateChange('generate new local signing key'); - k = await generatePGPKey('deadbeef', uid); - }; - - g_local_key = k; - g_local_key_id = k.getKeyID().toHex(); - g_local_key_name = getEffectiveName(k); - - - stateChange('load settings'); - let settings = await loadSettings(); - if (settings.data_endpoint !== undefined) { - stateChange('update data endpoint to ' + settings.data_endpoint); - g_data_endpoint = settings.data_endpoint; + stateChange('check existing key'); + g_local_key = await getKey(pwd); + } catch(e) { + return false; } + const decrypted = g_local_key.isDecrypted() + stateChange('found key ' + g_local_key.getKeyID().toHex() + ' (decrypted: ' + decrypted + ')'); + return decrypted; + } + async function applyLocalKey() { + g_local_key_id = g_local_key.getKeyID().toHex(); + g_local_key_name = getEffectiveName(g_local_key); + stateChange('load counter'); let c = localStorage.getItem('msg_count'); if (c == null) { @@ -89,8 +78,18 @@ let g_counter = undefined; } else { g_counter = parseInt(c); } + stateChange('ready to send'); + + } + + async function setUp() { + stateChange('load settings'); + let settings = await loadSettings(); + if (settings.data_endpoint !== undefined) { + stateChange('update data endpoint to ' + settings.data_endpoint); + g_data_endpoint = settings.data_endpoint; + } - stateChange('load remote encryption key'); let r = await fetch(settings.remote_pubkey_url); let remote_key_src = await r.text(); let remote_key = await openpgp.readKey({ @@ -100,26 +99,36 @@ let g_counter = undefined; g_remote_key_id = g_remote_key.getKeyID().toHex(); g_remote_key.getPrimaryUser().then((v) => { g_remote_key_name = v.user.userID.name; - stateChange('ready to send'); + stateChange('loaded remote encryption key'); }); } async function stateChange(s) { + let k_remote_str = ''; + let k_local_str = ''; + if (g_remote_key !== undefined) { + k_remote_str = g_remote_key_id + ' (' + g_remote_key_name + ')'; + } + if (g_local_key !== undefined) { + k_local_str = g_local_key_id + ' (' + g_local_key_name + ')'; + } + const ev = new CustomEvent('messagestatechange', { bubbles: true, cancelable: false, composed: true, + detail: { s: s, c: g_counter, - kr: g_remote_key_id + ' (' + g_remote_key_name + ')', - kl: g_local_key_id + ' (' + g_local_key_name + ')', + kr: k_remote_str, + kl: k_local_str, }, }); window.dispatchEvent(ev); } - async function try_dispatch(s, name, email) { + async function tryDispatch(s, name, email) { try { return await dispatch(s, name, email) } catch(e) { @@ -243,35 +252,90 @@ let g_counter = undefined; stateChange('ready to send next message'); return rcpt; }; + + async function createLocalKey(pwd) { + stateChange('generate new local signing key'); + const uid = { + name: generateName(), + email: 'foo@devnull.holbrook.no', + }; + g_local_key = await generatePGPKey(pwd, uid); + console.debug('you will initially be called', uid.name); + } + + async function setPwd(pwd) { + if (pwd === undefined) { + if (g_local_key === undefined) { + g_passphrase_use = false; + await createLocalKey(); + } + } else if (pwd.length == 0) { + return false; + } else if (g_local_key === undefined) { + await createLocalKey(pwd); + } + const r = await unlockLocalKey(pwd); + if (r) { + applyLocalKey(); + } + return r; + } window.addEventListener('messagestatechange', (v) => { console.debug('message state change:', v.detail.s); }); + + </script> </head> - <body> - <div x-init="await setUp();" x-data="{ - key: '(none)', - rkey: '(none)', - message_status: '(none)', - message_count: g_counter, + <body x-data="{ + have_passphrase: false, + key: '', + rkey: '', + key_armor: undefined, + rkey_armor: undefined, + defaultname: true, + identify: false, + realname: '', + realemail: '', + message_status: '', + message_count: g_counter, + + }" +> + <h1><a href="https://git.defalsify.org/cgit/forro">forro v0.0.4 (GPLv3)</a></h1> + + <div x-data="{ + passphrase_cache: '', + passphrase_status: 'please create key', + }" + + x-init=" + have_passphrase = await unlockLocalKey(); + if (key.length > 0) { + if (have_passphrase) { + applyLocalKey(); + } else { + passphrase_status = 'please unlock key'; + } + }" + + x-show='!have_passphrase'> + <input name="pwd" type="password" x-model='passphrase_cache' x-bind:placeholder='passphrase_status' /> + <button @click='have_passphrase = true; await setPwd(passphrase_cache);' >go</button> + <button x-show='!key' @click='have_passphrase = true; await setPwd();' >without passphrase</button> + </div> + <div x-show='have_passphrase' x-init="await setUp();" x-data="{ rcpt: '', content: '', - key_armor: undefined, - rkey_armor: undefined, - defaultname: true, - identify: false, - realname: '', - realemail: '', - + }"> <dl> - <dt>Application:</dt> - <dd><a href="https://git.defalsify.org/cgit/forro">forro v0.0.3 (GPLv3)</a></dt> <dt>Status:</dt> <dd x-text="message_status" x-on:messagestatechange.window="message_status = $event.detail.s; message_count = $event.detail.c; key = $event.detail.kl; rkey = $event.detail.kr; if (key_armor === undefined && g_local_key !== undefined) { key_armor = g_local_key.armor(); }; if (rkey_armor === undefined && g_remote_key !== undefined) { rkey_armor = g_remote_key.armor(); }; defaultname = !g_local_key_identified;"></dd> + <dt>Your identity:</dt> <dd><a x-text="key" x-bind:href="'data:text/plain;charset=utf-8,' + key_armor" download="privatekey.asc"></a></dd> <dt>Their identity:</dt> @@ -294,7 +358,7 @@ let g_counter = undefined; </div> </div> <div> - <button @click="r = await try_dispatch(content, realname, realemail); rcpt = r;">sign, encrypt and send</button> + <button @click="r = await tryDispatch(content, realname, realemail); rcpt = r;">sign, encrypt and send</button> </div> </div> </body> diff --git a/key.js b/key.js @@ -16,19 +16,13 @@ async function generatePGPKey(pwd, uid) { format: 'armored', //config: { rejectCurves: new Set() }, }); - //console.debug('pk ' + v.privateKey ); - console.debug('our public key', v.publicKey ); + console.info('our public key', v.publicKey ); let pk = await openpgp.readKey({ armoredKey: v.privateKey, }); localStorage.setItem('pgp-key', pk.armor()); - - let k = await openpgp.decryptKey({ - privateKey: pk, - passphrase: pwd, - }); - whohoo(k); + whohoo(pk); }); } @@ -48,12 +42,15 @@ async function getKey(pwd) { // }); //console.debug('pk ' + k.armor()); console.debug('our public key', pk.toPublic().armor()); - let k = await openpgp.decryptKey({ - privateKey: pk, - passphrase: pwd, - }); - whohoo(k); + if (pwd !== undefined) { + pk = await openpgp.decryptKey({ + privateKey: pk, + passphrase: pwd, + }); + } + + whohoo(pk); }); } diff --git a/package.json b/package.json @@ -1,6 +1,6 @@ { "name": "forro", - "version": "0.0.3", + "version": "0.0.4", "license": "GPLv3", "author": "Louis Holbrook <dev@holbrook.no> (https://holbrook.no)", "dependencies": {