Improve profile page

This commit is contained in:
Yarmo Mackenbach 2020-06-27 00:50:21 +02:00
parent d763ea1f27
commit 6847d2a285
3 changed files with 141 additions and 51 deletions

View file

@ -172,8 +172,7 @@ async function displayProfile(opts) {
let userData = keyData.user.user.userId; let userData = keyData.user.user.userId;
let feedback = "", notation, isVerified, verifications = []; let feedback = "", notation, isVerified, verifications = [];
document.body.querySelector('#profile--name').innerHTML = userData.name; document.body.querySelector('#profileName').innerHTML = userData.name;
document.body.querySelector('#profile--email').innerHTML = userData.email;
for (var i = 0; i < keyData.notations.length; i++) { for (var i = 0; i < keyData.notations.length; i++) {
notation = keyData.notations[i]; notation = keyData.notations[i];
@ -182,27 +181,55 @@ async function displayProfile(opts) {
} }
// Generate feedback // Generate feedback
feedback += `<div class="profileDataItem profileDataItem--separator">`;
feedback += `<div class="profileDataItem__label"></div>`;
feedback += `<div class="profileDataItem__value">general information</div>`;
feedback += `</div>`;
feedback += `<div class="profileDataItem">`;
feedback += `<div class="profileDataItem__label">email</div>`;
feedback += `<div class="profileDataItem__value"><a href="mailto:${userData.email}">${userData.email}</a></div>`;
feedback += `</div>`;
feedback += `<div class="profileDataItem">`;
feedback += `<div class="profileDataItem__label">fingerprint</div>`;
feedback += `<div class="profileDataItem__value"><a href="https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=0x${keyData.fingerprint}">${keyData.fingerprint}</a></div>`;
feedback += `</div>`;
feedback += `<div class="profileDataItem profileDataItem--separator">`;
feedback += `<div class="profileDataItem__label"></div>`;
feedback += `<div class="profileDataItem__value">proofs</div>`;
feedback += `</div>`;
for (var i = 0; i < verifications.length; i++) { 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>`; // feedback += `${verifications[i].type}: <a href="${verifications[i].url}">${verifications[i].display}</a>: ${verifications[i].isVerified}<br>`;
feedback += `<div class="profileDataItem">`;
feedback += `<div class="profileDataItem__label">${verifications[i].type}</div>`;
feedback += `<div class="profileDataItem__value">`;
feedback += `<a class="proofDisplay" href="${verifications[i].url}">${verifications[i].display}</a>`;
if (verifications[i].isVerified) {
feedback += `<a class="proofUrl proofUrl--verified" href="${verifications[i].proofUrl}">verified &#10004;</a>`;
} else {
feedback += `<a class="proofUrl" href="${verifications[i].proofUrl}">proof</a>`;
}
feedback += `</div>`;
feedback += `</div>`;
} }
// Display feedback // Display feedback
document.body.querySelector('#profile--proofs').innerHTML = feedback; document.body.querySelector('#profileData').innerHTML = feedback;
} }
async function verifyProof(url, fingerprint) { async function verifyProof(url, fingerprint) {
// Init // Init
let reVerify, urlFetch, output = {url: url, type: null, isVerified: false, display: null}; let reVerify, output = {url: url, type: null, proofUrl: url, proofUrlFetch: null, isVerified: false, display: null};
// DNS // DNS
if (/^dns:/.test(url)) { if (/^dns:/.test(url)) {
output.type = "dns"; output.type = "website";
let domain = url.replace(/dns:/, '').replace(/\?type=TXT/, ''); output.display = url.replace(/dns:/, '').replace(/\?type=TXT/, '');
urlFetch = `https://dns.google.com/resolve?name=${domain}&type=TXT`; output.proofUrlFetch = `https://dns.google.com/resolve?name=${output.display}&type=TXT`;
output.display = domain; output.url = `https://${output.display}`;
try { try {
response = await fetch(urlFetch, { response = await fetch(output.proofUrlFetch, {
headers: { headers: {
Accept: 'application/json' Accept: 'application/json'
}, },
@ -226,8 +253,10 @@ async function verifyProof(url, fingerprint) {
// HN // HN
if (/^https:\/\/news.ycombinator.com/.test(url)) { if (/^https:\/\/news.ycombinator.com/.test(url)) {
output.type = "hn"; output.type = "hn";
output.display = url.replace(/https:\/\/news.ycombinator.com\/user\?id=/, "");
output.proofUrlFetch = `https://hacker-news.firebaseio.com/v0/user/${output.display}.json`;
try { try {
response = await fetch(urlFetch, { response = await fetch(output.proofUrlFetch, {
headers: { headers: {
Accept: 'application/json' Accept: 'application/json'
}, },
@ -238,11 +267,9 @@ async function verifyProof(url, fingerprint) {
} }
json = await response.json(); json = await response.json();
reVerify = new RegExp(`openpgp4fpr:${fingerprint}`); reVerify = new RegExp(`openpgp4fpr:${fingerprint}`);
json.Answer.forEach((item, i) => { if (reVerify.test(json.about)) {
if (reVerify.test(item.data)) { output.isVerified = true;
output.isVerified = true; }
}
});
} catch (e) { } catch (e) {
} finally { } finally {
return output; return output;
@ -251,8 +278,11 @@ async function verifyProof(url, fingerprint) {
// Reddit // Reddit
if (/^https:\/\/www.reddit.com\/user/.test(url)) { if (/^https:\/\/www.reddit.com\/user/.test(url)) {
output.type = "reddit"; output.type = "reddit";
output.display = url.replace(/^https:\/\/www.reddit.com\/user\//, "").replace(/\/comments\/.*/, "");
output.url = `https://www.reddit.com/user/${output.display}`;
output.proofUrlFetch = url.replace(/\/[a-zA-Z0-9_]*\/$/, ".json");
try { try {
response = await fetch(urlFetch, { response = await fetch(output.proofUrlFetch, {
headers: { headers: {
Accept: 'application/json' Accept: 'application/json'
}, },
@ -262,7 +292,8 @@ async function verifyProof(url, fingerprint) {
throw new Error('Response failed: ' + response.status); throw new Error('Response failed: ' + response.status);
} }
json = await response.json(); json = await response.json();
reVerify = new RegExp(`openpgp4fpr:${fingerprint}`); console.log(json);
reVerify = new RegExp(`Verifying my OpenPGP key: openpgp4fpr:${fingerprint}`);
json.Answer.forEach((item, i) => { json.Answer.forEach((item, i) => {
if (reVerify.test(item.data)) { if (reVerify.test(item.data)) {
output.isVerified = true; output.isVerified = true;
@ -276,8 +307,12 @@ async function verifyProof(url, fingerprint) {
// Github // Github
if (/^https:\/\/gist.github.com/.test(url)) { if (/^https:\/\/gist.github.com/.test(url)) {
output.type = "github"; output.type = "github";
output.display = url.replace(/^https:\/\/gist.github.com\//, "").replace(/\/[a-zA-Z0-9]*$/, "");
output.url = `https://github.com/${output.display}`;
let gistId = url.replace(/^https:\/\/gist.github.com\/[a-zA-Z0-9_-]*\//, "");
output.proofUrlFetch = `https://api.github.com/gists/${gistId}`;
try { try {
response = await fetch(urlFetch, { response = await fetch(output.proofUrlFetch, {
headers: { headers: {
Accept: 'application/json' Accept: 'application/json'
}, },
@ -287,12 +322,10 @@ async function verifyProof(url, fingerprint) {
throw new Error('Response failed: ' + response.status); throw new Error('Response failed: ' + response.status);
} }
json = await response.json(); json = await response.json();
reVerify = new RegExp(`openpgp4fpr:${fingerprint}`); reVerify = new RegExp(`[Verifying my OpenPGP key: openpgp4fpr:${fingerprint}]`);
json.Answer.forEach((item, i) => { if (reVerify.test(json.files["openpgp.md"].content)) {
if (reVerify.test(item.data)) { output.isVerified = true;
output.isVerified = true; }
}
});
} catch (e) { } catch (e) {
} finally { } finally {
return output; return output;
@ -316,6 +349,7 @@ async function verifyProof(url, fingerprint) {
if (item.value === fingerprint) { if (item.value === fingerprint) {
output.type = "mastodon"; output.type = "mastodon";
output.display = json.url; output.display = json.url;
output.proofUrlFetch = json.url;
output.isVerified = true; output.isVerified = true;
} }
}); });

View file

@ -20,7 +20,7 @@ nav a {
footer { footer {
color: #777; color: #777;
margin: 64px 0; margin: 64px 0;
padding: 32px; padding: 0 32px;
} }
.container { .container {
max-width: 720px; max-width: 720px;
@ -91,3 +91,78 @@ input[type="submit"] {
display: inline-block; display: inline-block;
margin: 0 0 8px; margin: 0 0 8px;
} }
.container--profile {
margin-top: 64px;
}
.container--profile .content {
padding-top: 32px;
font-size: 1.2em;
}
.container--profile footer {
text-align: center;
}
.profileDataItem {
position: relative;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.profileDataItem--separator {
margin-top: 1em;
font-weight: bold;
}
.profileDataItem__label {
display: inline-block;
position: relative;
flex: 1;
min-height: 32px;
padding: 0 8px;
max-width: 20%;
color: #777;
text-align: right;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.profileDataItem__value {
display: inline-block;
flex: 1;
min-height: 32px;
max-width: 100%;
padding: 0 8px;
}
.profileDataItem__value a {
display: inline-block;
max-width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.profileDataItem__value a.proofDisplay {
margin-right: 16px;
}
.profileDataItem__value a.proofUrl {
color: #777;
/* text-decoration: none; */
}
.profileDataItem__value a.proofUrl.proofUrl--verified {
color: #499539;
}
.profileDataItem__value a.proofUrl:hover {
text-decoration: underline;
}
@media (max-width: 680px) {
.profileDataItem {
flex-direction: column;
}
.profileDataItem__label {
max-width: 100%;
min-height: 28px;
text-align: left;
}
.profileDataItem__value {
min-height: 28px;
}
}

View file

@ -3,41 +3,22 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Encrypt - Keyoxide</title> <title>Keyoxide</title>
<script async defer data-domain="keyoxide.org" src="https://plausible.io/js/plausible.js"></script> <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="https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.css">
<link rel="stylesheet" href="/assets/styles.css"> <link rel="stylesheet" href="/assets/styles.css">
</head> </head>
<body> <body>
<header> <div class="container container--profile">
<div class="container"> <h1 id="profileName"></h1>
<a href="/">Keyoxide</a>
</div>
</header>
<div class="container">
<h1>Profile</h1>
<div class="content"> <div class="content">
<h3></h3> <span id="profileUid" style="display: none;">%UID%</span>
<p>Input: <span id="profileUid">%UID%</span></p> <div id="profileData"></div>
<p>Name: <span id="profile--name"></span></p>
<p>Email address: <span id="profile--email">/span></p>
<p>Proofs: <span id="profile--proofs">/span></p>
</div> </div>
<footer> <footer>
<p> <p>
<a href="/">Keyoxide</a> makes basic cryptography operations accessible to regular humans. Page generated by <a href="/">Keyoxide</a>.
<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> </p>
</footer> </footer>
</div> </div>