From 8540fe9d9ddf1b623f03cbd7484992d2b296ab6f Mon Sep 17 00:00:00 2001 From: Yarmo Mackenbach Date: Fri, 26 Jun 2020 15:08:22 +0200 Subject: [PATCH] Add proof verification page --- encrypt.html | 1 + faq.html | 1 + index.html | 2 + proofs.html | 63 ++++++++++++++++ scripts.js | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++ verify.html | 1 + 6 files changed, 267 insertions(+) create mode 100644 proofs.html diff --git a/encrypt.html b/encrypt.html index 59239c0..a6b5e04 100644 --- a/encrypt.html +++ b/encrypt.html @@ -16,6 +16,7 @@ diff --git a/faq.html b/faq.html index 7208080..3e15fa5 100644 --- a/faq.html +++ b/faq.html @@ -16,6 +16,7 @@ diff --git a/index.html b/index.html index ec29dc3..23f4ce9 100644 --- a/index.html +++ b/index.html @@ -16,6 +16,7 @@ @@ -27,6 +28,7 @@

verify signature encrypt message + verify proofs

About

Keyoxide is a lightweight and FOSS solution to make basic cryptography operations accessible to regular humans.

diff --git a/proofs.html b/proofs.html new file mode 100644 index 0000000..05f869e --- /dev/null +++ b/proofs.html @@ -0,0 +1,63 @@ + + + + + + Profile - Keyoxide + + + + + +
+
+ Keyoxide +
+ +
+
+ +
+

Proofs

+
+
+

Public Key (1: plaintext)

+ +

Public Key (2: web key directory)

+ +

Public Key (3: HKP server)

+ + +

Result

+

Click on the button below.

+

+ +
+
+ + +
+ + + + + + diff --git a/scripts.js b/scripts.js index 8c87612..19ea2fd 100644 --- a/scripts.js +++ b/scripts.js @@ -132,6 +132,177 @@ async function encryptMessage(opts) { elEnc.value = encrypted.data; }; +async function verifyProofs(opts) { + // Init + const elRes = document.body.querySelector("#result"); + let keyData, feedback = "", message, encrypted; + + // Reset feedback + elRes.innerHTML = ""; + + try { + // Get key data + keyData = await fetchKeys(opts); + } catch (e) { + console.error(e); + elRes.innerHTML = e; + elRes.classList.remove('green'); + elRes.classList.add('red'); + return; + } + + let notation, isVerified, verifications = []; + for (var i = 0; i < keyData.notations.length; i++) { + notation = keyData.notations[i]; + if (!(notation[0] == "proof@keyoxide.org" || notation[0] == "proof@metacode.biz")) { continue; } + verifications.push(await verifyProof(notation[1], keyData.fingerprint)); + } + + // Generate feedback + for (var i = 0; i < verifications.length; i++) { + feedback += `${verifications[i].type}: ${verifications[i].display}: ${verifications[i].isVerified}
`; + } + + // Display feedback + elRes.innerHTML = feedback; +}; + +async function verifyProof(url, fingerprint) { + // Init + let reVerify, urlFetch, output = {url: url, type: null, isVerified: false, display: null}; + + // DNS + if (/^dns:/.test(url)) { + output.type = "dns"; + let domain = url.replace(/dns:/, '').replace(/\?type=TXT/, ''); + urlFetch = `https://dns.google.com/resolve?name=${domain}&type=TXT`; + output.display = domain; + + try { + response = await fetch(urlFetch, { + headers: { + Accept: 'application/json' + }, + credentials: 'omit' + }); + if (!response.ok) { + throw new Error('Response failed: ' + response.status); + } + json = await response.json(); + reVerify = new RegExp(`openpgp4fpr:${fingerprint}`); + json.Answer.forEach((item, i) => { + if (reVerify.test(item.data)) { + output.isVerified = true; + } + }); + } catch (e) { + } finally { + return output; + } + } + // HN + if (/^https:\/\/news.ycombinator.com/.test(url)) { + output.type = "hn"; + try { + response = await fetch(urlFetch, { + headers: { + Accept: 'application/json' + }, + credentials: 'omit' + }); + if (!response.ok) { + throw new Error('Response failed: ' + response.status); + } + json = await response.json(); + reVerify = new RegExp(`openpgp4fpr:${fingerprint}`); + json.Answer.forEach((item, i) => { + if (reVerify.test(item.data)) { + output.isVerified = true; + } + }); + } catch (e) { + } finally { + return output; + } + } + // Reddit + if (/^https:\/\/www.reddit.com\/user/.test(url)) { + output.type = "reddit"; + try { + response = await fetch(urlFetch, { + headers: { + Accept: 'application/json' + }, + credentials: 'omit' + }); + if (!response.ok) { + throw new Error('Response failed: ' + response.status); + } + json = await response.json(); + reVerify = new RegExp(`openpgp4fpr:${fingerprint}`); + json.Answer.forEach((item, i) => { + if (reVerify.test(item.data)) { + output.isVerified = true; + } + }); + } catch (e) { + } finally { + return output; + } + } + // Github + if (/^https:\/\/gist.github.com/.test(url)) { + output.type = "github"; + try { + response = await fetch(urlFetch, { + headers: { + Accept: 'application/json' + }, + credentials: 'omit' + }); + if (!response.ok) { + throw new Error('Response failed: ' + response.status); + } + json = await response.json(); + reVerify = new RegExp(`openpgp4fpr:${fingerprint}`); + json.Answer.forEach((item, i) => { + if (reVerify.test(item.data)) { + output.isVerified = true; + } + }); + } catch (e) { + } finally { + return output; + } + } + // Catchall + try { + response = await fetch(url, { + headers: { + Accept: 'application/json' + }, + credentials: 'omit' + }); + if (!response.ok) { + throw new Error('Response failed: ' + response.status); + } + json = await response.json(); + if ('attachment' in json) { + // Potentially Mastodon + json.attachment.forEach((item, i) => { + if (item.value === fingerprint) { + output.type = "mastodon"; + output.display = json.url; + output.isVerified = true; + } + }); + } + } catch (e) { + } finally { + return output; + } +} + async function fetchKeys(opts) { // Init let lookupOpts, wkd, hkd, sig, lastPrimarySig; @@ -215,6 +386,7 @@ async function fetchKeys(opts) { // General purpose let elFormVerify = document.body.querySelector("#form-verify"), elFormEncrypt = document.body.querySelector("#form-encrypt"); + elFormProofs = document.body.querySelector("#form-proofs"); if (elFormVerify) { elFormVerify.onsubmit = function (evt) { @@ -275,3 +447,30 @@ if (elFormEncrypt) { encryptMessage(opts); }; } + +if (elFormProofs) { + elFormProofs.onsubmit = function (evt) { + evt.preventDefault(); + + let opts = { + mode: null, + input: null, + server: null, + }; + + if (document.body.querySelector("#publicKey").value != "") { + opts.input = document.body.querySelector("#publicKey").value; + opts.mode = "plaintext"; + } else if (document.body.querySelector("#wkd").value != "") { + opts.input = document.body.querySelector("#wkd").value; + opts.mode = "wkd"; + } else if (document.body.querySelector("#hkp_input").value != "") { + opts.input = document.body.querySelector("#hkp_input").value; + opts.server = document.body.querySelector("#hkp_server").value; + opts.mode = "hkp"; + } else { + opts.mode = null; + } + verifyProofs(opts); + }; +} diff --git a/verify.html b/verify.html index 1f66378..aa308f0 100644 --- a/verify.html +++ b/verify.html @@ -16,6 +16,7 @@