mirror of
https://codeberg.org/keyoxide/keyoxide-web.git
synced 2024-12-22 14:59:29 -07:00
Add proof verification page
This commit is contained in:
parent
7155e603f1
commit
8540fe9d9d
6 changed files with 267 additions and 0 deletions
|
@ -16,6 +16,7 @@
|
||||||
<nav>
|
<nav>
|
||||||
<a href="/verify">verify</a>
|
<a href="/verify">verify</a>
|
||||||
<a href="/encrypt">encrypt</a>
|
<a href="/encrypt">encrypt</a>
|
||||||
|
<a href="/proofs">proofs</a>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
1
faq.html
1
faq.html
|
@ -16,6 +16,7 @@
|
||||||
<nav>
|
<nav>
|
||||||
<a href="/verify">verify</a>
|
<a href="/verify">verify</a>
|
||||||
<a href="/encrypt">encrypt</a>
|
<a href="/encrypt">encrypt</a>
|
||||||
|
<a href="/proofs">proofs</a>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
<nav>
|
<nav>
|
||||||
<a href="/verify">verify</a>
|
<a href="/verify">verify</a>
|
||||||
<a href="/encrypt">encrypt</a>
|
<a href="/encrypt">encrypt</a>
|
||||||
|
<a href="/proofs">proofs</a>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
<p>
|
<p>
|
||||||
<a class="bigBtn" href="/verify">verify signature</a>
|
<a class="bigBtn" href="/verify">verify signature</a>
|
||||||
<a class="bigBtn" href="/encrypt">encrypt message</a>
|
<a class="bigBtn" href="/encrypt">encrypt message</a>
|
||||||
|
<a class="bigBtn" href="/proofs">verify proofs</a>
|
||||||
</p>
|
</p>
|
||||||
<h2>About</h2>
|
<h2>About</h2>
|
||||||
<p><a href="/">Keyoxide</a> is a lightweight and FOSS solution to make basic cryptography operations accessible to regular humans.</p>
|
<p><a href="/">Keyoxide</a> is a lightweight and FOSS solution to make basic cryptography operations accessible to regular humans.</p>
|
||||||
|
|
63
proofs.html
Normal file
63
proofs.html
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Profile - Keyoxide</title>
|
||||||
|
<script async defer data-domain="keyoxide.org" src="https://plausible.io/js/plausible.js"></script>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.css">
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="container">
|
||||||
|
<a href="/">Keyoxide</a>
|
||||||
|
<div class="spacer"></div>
|
||||||
|
<nav>
|
||||||
|
<a href="/verify">verify</a>
|
||||||
|
<a href="/encrypt">encrypt</a>
|
||||||
|
<a href="/proofs">proofs</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h1>Proofs</h1>
|
||||||
|
<div class="content">
|
||||||
|
<form id="form-proofs" method="post">
|
||||||
|
<h3>Public Key (1: plaintext)</h3>
|
||||||
|
<textarea name="publicKey" id="publicKey"></textarea>
|
||||||
|
<h3>Public Key (2: web key directory)</h3>
|
||||||
|
<input type="text" name="wkd" id="wkd" placeholder="name@domain.com">
|
||||||
|
<h3>Public Key (3: HKP server)</h3>
|
||||||
|
<input type="text" name="hkp_server" id="hkp_server" placeholder="https://keys.openpgp.org/">
|
||||||
|
<input type="text" name="hkp_input" id="hkp_input" placeholder="Email / key id / fingerprint">
|
||||||
|
<h3>Result</h3>
|
||||||
|
<p id="result">Click on the button below.</p>
|
||||||
|
<p id="resultContent"></p>
|
||||||
|
<input type="submit" class="bigBtn" name="submit" value="VERIFY PROOFS" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>
|
||||||
|
<a href="/">Keyoxide</a> makes basic cryptography operations accessible to regular humans.
|
||||||
|
<br>
|
||||||
|
Made by <a href="https://yarmo.eu">Yarmo Mackenbach</a>.
|
||||||
|
<br>
|
||||||
|
Code hosted on <a href="https://codeberg.org/yarmo/keyoxide">Codeberg</a> (<a href="https://drone.private.foss.best/yarmo/keyoxide/">drone CI/CD</a>).
|
||||||
|
<br>
|
||||||
|
Uses <a href="https://github.com/openpgpjs/openpgpjs">openpgp.js</a> (version <a href="https://github.com/openpgpjs/openpgpjs/releases/tag/v4.10.4">4.10.4</a>).
|
||||||
|
<br>
|
||||||
|
Privacy-friendly public usage stats by <a href="https://plausible.io/keyoxide.org">Plausible.io</a>.
|
||||||
|
<br>
|
||||||
|
Because SO2 + 2NaOH → Na2SO3 + H2O
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
<script src="openpgp.min.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts.js" charset="utf-8"></script>
|
||||||
|
</html>
|
199
scripts.js
199
scripts.js
|
@ -132,6 +132,177 @@ async function encryptMessage(opts) {
|
||||||
elEnc.value = encrypted.data;
|
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}: <a href="${verifications[i].url}">${verifications[i].display}</a>: ${verifications[i].isVerified}<br>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
async function fetchKeys(opts) {
|
||||||
// Init
|
// Init
|
||||||
let lookupOpts, wkd, hkd, sig, lastPrimarySig;
|
let lookupOpts, wkd, hkd, sig, lastPrimarySig;
|
||||||
|
@ -215,6 +386,7 @@ async function fetchKeys(opts) {
|
||||||
// General purpose
|
// General purpose
|
||||||
let elFormVerify = document.body.querySelector("#form-verify"),
|
let elFormVerify = document.body.querySelector("#form-verify"),
|
||||||
elFormEncrypt = document.body.querySelector("#form-encrypt");
|
elFormEncrypt = document.body.querySelector("#form-encrypt");
|
||||||
|
elFormProofs = document.body.querySelector("#form-proofs");
|
||||||
|
|
||||||
if (elFormVerify) {
|
if (elFormVerify) {
|
||||||
elFormVerify.onsubmit = function (evt) {
|
elFormVerify.onsubmit = function (evt) {
|
||||||
|
@ -275,3 +447,30 @@ if (elFormEncrypt) {
|
||||||
encryptMessage(opts);
|
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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
<nav>
|
<nav>
|
||||||
<a href="/verify">verify</a>
|
<a href="/verify">verify</a>
|
||||||
<a href="/encrypt">encrypt</a>
|
<a href="/encrypt">encrypt</a>
|
||||||
|
<a href="/proofs">proofs</a>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
Loading…
Reference in a new issue