diff --git a/index.js b/index.js
index bb8bbfe..c41fce7 100644
--- a/index.js
+++ b/index.js
@@ -27,37 +27,35 @@ You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary. For
more information on this, and how to apply and follow the GNU AGPL, see
"+sigContent+"";
- }
-
- // Provide different feedback depending on key input mode
- if (opts.mode == "signature" && keyData.sigUserId) {
- if (valid) {
- feedback += "The message was signed by the userId extracted from the signature.
";
- feedback += 'UserId: '+keyData.sigUserId+'
';
- feedback += "Fingerprint: "+keyData.fingerprint+"
";
- elRes.classList.remove('red');
- elRes.classList.add('green');
- } else {
- feedback += "The message's signature COULD NOT BE verified using the userId extracted from the signature.
";
- feedback += 'UserId: '+keyData.sigUserId+'
';
- elRes.classList.remove('green');
- elRes.classList.add('red');
- }
- } else if (opts.mode == "signature" && keyData.sigKeyId) {
- if (valid) {
- feedback += "The message was signed by the keyId extracted from the signature.
";
- feedback += 'KeyID: '+keyData.sigKeyId+'
';
- feedback += "Fingerprint: "+keyData.fingerprint+"
";
- feedback += "!!! You should manually verify the fingerprint to confirm the signer's identity !!!";
- elRes.classList.remove('red');
- elRes.classList.add('green');
- } else {
- feedback += "The message's signature COULD NOT BE verified using the keyId extracted from the signature.
";
- feedback += 'KeyID: '+keyData.sigKeyId+'
';
- elRes.classList.remove('green');
- elRes.classList.add('red');
- }
- } else {
- if (valid) {
- feedback += "The message was signed by the provided key ("+opts.mode+").
";
- feedback += "Fingerprint: "+keyData.fingerprint+"
";
- elRes.classList.remove('red');
- elRes.classList.add('green');
- } else {
- feedback += "The message's signature COULD NOT BE verified using the provided key ("+opts.mode+").
";
- elRes.classList.remove('green');
- elRes.classList.add('red');
- }
- }
-
- // Display feedback
- elRes.innerHTML = feedback;
-};
-
-async function encryptMessage(opts) {
- // Init
- const elEnc = document.body.querySelector("#message");
- const elRes = document.body.querySelector("#result");
- const elBtn = document.body.querySelector("[name='submit']");
- let keyData, feedback, message, encrypted;
-
- // Reset feedback
- elRes.innerHTML = "";
- elRes.classList.remove('green');
- elRes.classList.remove('red');
-
- try {
- // Get key data
- keyData = await fetchKeys(opts);
-
- // Handle missing message
- if (opts.message == null) {
- throw("No message was provided.");
- }
-
- // Encrypt the message
- encrypted = await openpgp.encrypt({
- message: openpgp.message.fromText(opts.message),
- publicKeys: keyData.publicKey
- });
- } catch (e) {
- console.error(e);
- elRes.innerHTML = e;
- elRes.classList.remove('green');
- elRes.classList.add('red');
- return;
- }
-
- // Display encrypted data
- elEnc.value = encrypted.data;
- elEnc.toggleAttribute("readonly");
- elBtn.setAttribute("disabled", "true");
-};
-
-async function displayProfile(opts) {
- /// UTILITY FUNCTIONS
- // Sort claims by name and filter for errors
- const sortClaims = (claims) => {
- claims = claims.filter((a) => (a && a.errors.length == 0 && a.serviceproviderData));
- claims = claims.sort((a,b) => (a.serviceproviderData.serviceprovider.name > b.serviceproviderData.serviceprovider.name) ? 1 : ((b.serviceproviderData.serviceprovider.name > a.serviceproviderData.serviceprovider.name) ? -1 : 0));
- return claims;
- }
- // Find the primary claims
- const getPrimaryClaims = (primaryUserId, userIds, verifications) => {
- let primaryClaims = null;
- userIds.forEach((userId, i) => {
- if (!primaryClaims && userId.userId && userId.userId.email === primaryUserId.email) {
- primaryClaims = sortClaims(verifications[i]);
- }
- });
- return primaryClaims;
- }
- // Generate a HTML string for the profile header
- const generateProfileHeaderHTML = (data) => {
- if (!data) {
- data = {
- profileHide: true,
- name: '',
- fingerprint: '',
- key: {
- url: '',
- mode: '',
- server: '',
- id: '',
- },
- avatarURL: '/static/img/avatar_placeholder.png',
- }
- }
-
- // TODO Add support for custom HKP server
- return `
-
${data.name}
- - -Identical to primary claims
-No claims associated
-${claimData.profile.display}
-- ${capitalizeLetteredServices(claimData.serviceprovider.name)} - View account - View proof - `; - if (claimData.profile.qr) { - output += ` - View QR - `; - } - output += ` - -
-There was a problem reading the signature.
`; - if ('errors' in e) { - feedback += `${e.errors.join(', ')}
`;
- } else {
- feedback += `${e}
`;
- }
- document.body.querySelector('#profileData').innerHTML = feedback;
- document.body.querySelector('#profileName').innerHTML = "Could not load profile";
+// Register modals
+document.querySelectorAll('dialog').forEach(function(d) {
+ dialogPolyfill.registerDialog(d);
+ d.addEventListener('click', function(ev) {
+ if (ev && ev.target != d) {
return;
}
- } else {
- try {
- let keyURI;
- if (opts.mode === 'hkp' && opts.server) {
- keyURI = `${opts.mode}:${opts.server}:${opts.input}`
- } else {
- keyURI = `${opts.mode}:${opts.input}`
- }
- keyData = await doip.keys.fetch.uri(keyURI);
- fingerprint = keyData.keyPacket.getFingerprint();
- } catch (e) {
- feedback += `There was a problem fetching the keys.
`; - feedback += `${e}
`;
- document.body.querySelector('#profileData').innerHTML = feedback;
- document.body.querySelector('#profileName').innerHTML = "Could not load profile";
- return;
- }
- }
-
- // Get data of primary userId
- const userPrimary = await keyData.getPrimaryUser();
- const userData = userPrimary.user.userId;
- const userName = userData.name ? userData.name : userData.email;
- const userMail = userData.email ? userData.email : null;
-
- // TODO Get image from user attribute
- let imgUri = null;
-
- // Determine WKD or HKP link
- let keyUriMode = opts.mode;
- let keyUriServer = null;
- let keyUriId = opts.input;
- if (opts.mode === 'sig') {
- const keyUriMatch = sigVerification.publicKey.uri.match(/([^:]*)(?:\:(.*))?:(.*)/);
- keyUriMode = keyUriMatch[1];
- keyUriServer = keyUriMatch[2];
- keyUriId = keyUriMatch[3];
- }
-
- switch (keyUriMode) {
- case "wkd":
- const [, localPart, domain] = /(.*)@(.*)/.exec(keyUriId);
- const localEncoded = await computeWKDLocalPart(localPart.toLowerCase());
- const urlAdvanced = `https://openpgpkey.${domain}/.well-known/openpgpkey/${domain}/hu/${localEncoded}`;
- const urlDirect = `https://${domain}/.well-known/openpgpkey/hu/${localEncoded}`;
-
- try {
- keyLink = await fetch(urlAdvanced).then(function(response) {
- if (response.status === 200) {
- return urlAdvanced;
- }
- });
- } catch (e) {
- console.warn(e);
- }
- if (!keyLink) {
- try {
- keyLink = await fetch(urlDirect).then(function(response) {
- if (response.status === 200) {
- return urlDirect;
- }
- });
- } catch (e) {
- console.warn(e);
- }
- }
- if (!keyLink) {
- keyLink = `https://${keyUriServer ? keyUriServer : 'keys.openpgp.org'}/pks/lookup?op=get&options=mr&search=0x${fingerprint}`;
- }
- break;
-
- case "hkp":
- keyLink = `https://${keyUriServer ? keyUriServer : 'keys.openpgp.org'}/pks/lookup?op=get&options=mr&search=0x${fingerprint}`;
- break;
-
- case "keybase":
- keyLink = opts.keyLink;
- break;
- }
-
- // Generate profile header
- const profileHash = openpgp.util.str_to_hex(openpgp.util.Uint8Array_to_str(await openpgp.crypto.hash.md5(openpgp.util.str_to_Uint8Array(userData.email))));
- document.body.querySelector('#profileHeader').innerHTML = generateProfileHeaderHTML({
- profileHide: false,
- name: userName,
- fingerprint: fingerprint,
- key: {
- url: keyLink,
- mode: keyUriMode,
- server: keyUriServer,
- id: keyUriId,
- },
- avatarURL: imgUri ? imgUri : `https://www.gravatar.com/avatar/${profileHash}?s=128&d=mm`
- })
- document.title = `${userName} - Keyoxide`;
-
- try {
- if (sigVerification) {
- verifications = sigVerification.claims
- } else {
- verifications = await doip.claims.verify(keyData, fingerprint, doipOpts)
- }
- } catch (e) {
- feedback += `There was a problem verifying the claims.
`; - feedback += `${e}
`;
- document.body.querySelector('#profileData').innerHTML = feedback;
- document.body.querySelector('#profileName').innerHTML = "Could not load profile";
- return;
- }
-
- // Exit if no notations are available
- if (verifications.length == 0) {
- return;
- }
-
- let feedbackDialog = "";
- let dialogIds = null;
- feedback = "";
-
- if (opts.mode === 'sig') {
- const claims = sortClaims(verifications);
-
- dialogIds = new Uint32Array(claims.length);
- window.crypto.getRandomValues(dialogIds);
-
- feedback += generateProfileUserIdHTML(userData, claims, dialogIds, {isPrimary: false});
- feedbackDialog += generateClaimDialogHTML(claims, dialogIds);
- } else {
- const primaryClaims = getPrimaryClaims(userData, keyData.users, verifications);
-
- dialogIds = new Uint32Array(primaryClaims.length);
- window.crypto.getRandomValues(dialogIds);
-
- feedback += generateProfileUserIdHTML(userData, primaryClaims, dialogIds, {isPrimary: true});
- feedbackDialog += generateClaimDialogHTML(primaryClaims, dialogIds);
-
- keyData.users.forEach((user, i) => {
- if (!user.userId || userData.email && user.userId && user.userId.email === userData.email) {
- return;
- }
-
- const claims = sortClaims(verifications[i])
- const opts = {
- isPrimary: false,
- isIdenticaltoPrimary: primaryClaims && primaryClaims.toString() === claims.toString()
- }
-
- dialogIds = new Uint32Array(claims.length);
- window.crypto.getRandomValues(dialogIds);
-
- feedback += generateProfileUserIdHTML(user.userId, claims, dialogIds, opts);
- feedbackDialog += generateClaimDialogHTML(claims, dialogIds);
- })
- }
-
- feedback += `
-
-
- - - -
`; - - // Display feedback - document.body.querySelector('#profileProofs').innerHTML = feedback; - if (feedbackDialog) { - document.body.querySelector('#profileDialogs').innerHTML = feedbackDialog; - } - - // Register modals - document.querySelectorAll('dialog').forEach(function(d) { - dialogPolyfill.registerDialog(d); - d.addEventListener('click', function(ev) { - if (ev && ev.target != d) { - return; - } - d.close(); - }); + d.close(); }); +}); - // Register form listeners - const elFormEncrypt = document.body.querySelector("#dialog--encryptMessage form"); - elFormEncrypt.onsubmit = async function (evt) { - evt.preventDefault(); +// let elFormSignatureProfile = document.body.querySelector("#formGenerateSignatureProfile"), +// elProfileUid = document.body.querySelector("#profileUid"), +// elProfileMode = document.body.querySelector("#profileMode"), +// elProfileServer = document.body.querySelector("#profileServer"), +// elModeSelect = document.body.querySelector("#modeSelect"), +// elUtilWKD = document.body.querySelector("#form-util-wkd"), +// elUtilQRFP = document.body.querySelector("#form-util-qrfp"), +// elUtilQR = document.body.querySelector("#form-util-qr"), +// elUtilProfileURL = document.body.querySelector("#form-util-profile-url"); - try { - // Encrypt the message - encrypted = await openpgp.encrypt({ - message: openpgp.message.fromText(elFormEncrypt.querySelector('.input').value), - publicKeys: keyData - }); - elFormEncrypt.querySelector('.output').value = encrypted.data; - } catch (e) { - console.error(e); - elFormEncrypt.querySelector('.output').value = `Could not encrypt message!\n==========================\n${e.message ? e.message : e}`; - } - }; - const elFormVerify = document.body.querySelector("#dialog--verifySignature form"); - elFormVerify.onsubmit = async function (evt) { - evt.preventDefault(); +// if (elModeSelect) { +// elModeSelect.onchange = function (evt) { +// let elAllModes = document.body.querySelectorAll('.modes'); +// elAllModes.forEach(function(el) { +// el.classList.remove('modes--visible'); +// }); +// document.body.querySelector(`.modes--${elModeSelect.value}`).classList.add('modes--visible'); +// } +// elModeSelect.dispatchEvent(new Event("change")); +// } - try { - // Try two different methods of signature reading - let signature = null, verified = null, readError = null; - try { - signature = await openpgp.message.readArmored(elFormVerify.querySelector('.input').value); - } catch(e) { - readError = e; - } - try { - signature = await openpgp.cleartext.readArmored(elFormVerify.querySelector('.input').value); - } catch(e) { - readError = e; - } - if (signature == null) { throw(readError) }; +// if (elProfileUid) { +// let opts, profileUid = elProfileUid.innerHTML; +// switch (elProfileMode.innerHTML) { +// default: +// case "sig": +// elFormSignatureProfile.onsubmit = function (evt) { +// evt.preventDefault(); - // Verify the signature - verified = await openpgp.verify({ - message: signature, - publicKeys: keyData - }); +// opts = { +// input: document.body.querySelector("#plaintext_input").value, +// mode: elProfileMode.innerHTML +// } - if (verified.signatures[0].valid) { - elFormVerify.querySelector('.output').value = `The message was signed by the profile's key.`; - } else { - elFormVerify.querySelector('.output').value = `The message was NOT signed by the profile's key.`; - } - } catch (e) { - console.error(e); - elFormVerify.querySelector('.output').value = `Could not verify signature!\n===========================\n${e.message ? e.message : e}`; - } - }; -} +// displayProfile(opts) +// } +// break; -async function fetchKeys(opts) { - // Init - let lookupOpts, wkd, hkd, sig, lastPrimarySig; - let output = { - publicKey: null, - user: null, - notations: null, - sigKeyId: null, - sigUserId: null, - sigContent: null - }; +// case "auto": +// if (/.*@.*/.test(profileUid)) { +// // Match email for wkd +// opts = { +// input: profileUid, +// mode: "wkd" +// } +// } else { +// // Match fingerprint for hkp +// opts = { +// input: profileUid, +// mode: "hkp" +// } +// } +// break; - // Autodetect mode - if (opts.mode == "auto") { - if (/.*@.*\..*/.test(opts.input)) { - opts.mode = "wkd"; - } else { - opts.mode = "hkp"; - } - } +// case "hkp": +// opts = { +// input: profileUid, +// server: elProfileServer.innerHTML, +// mode: elProfileMode.innerHTML +// } +// break; - // Fetch keys depending on the input mode - switch (opts.mode) { - case "plaintext": - output.publicKey = (await openpgp.key.readArmored(opts.input)).keys[0]; +// case "wkd": +// opts = { +// input: profileUid, +// mode: elProfileMode.innerHTML +// } +// break; - if (!output.publicKey) { - throw("Error: No public keys could be fetched from the plaintext input."); - } - break; +// case "keybase": +// let match = profileUid.match(/(.*)\/(.*)/); +// opts = { +// username: match[1], +// fingerprint: match[2], +// mode: elProfileMode.innerHTML +// } +// break; +// } - case "wkd": - wkd = new openpgp.WKD(); - lookupOpts = { - email: opts.input - }; - output.publicKey = (await wkd.lookup(lookupOpts)).keys[0]; +// if (elProfileMode.innerHTML !== 'sig') { +// keyoxide.displayProfile(opts); +// } +// } - if (!output.publicKey) { - throw("Error: No public keys could be fetched using WKD."); - } - break; +// if (elUtilWKD) { +// elUtilWKD.onsubmit = function (evt) { +// evt.preventDefault(); +// } - case "hkp": - if (!opts.server) {opts.server = "https://keys.openpgp.org/"}; - hkp = new openpgp.HKP(opts.server); - lookupOpts = { - query: opts.input - }; - output.publicKey = await hkp.lookup(lookupOpts); - output.publicKey = (await openpgp.key.readArmored(output.publicKey)).keys[0]; +// const elInput = document.body.querySelector("#input"); +// const elOutput = document.body.querySelector("#output"); +// const elOutputDirect = document.body.querySelector("#output_url_direct"); +// const elOutputAdvanced = document.body.querySelector("#output_url_advanced"); +// let match; - if (!output.publicKey) { - throw("Error: No public keys could be fetched from the HKP server."); - } - break; +// elInput.addEventListener("input", async function(evt) { +// if (evt.target.value) { +// if (/(.*)@(.{1,}\..{1,})/.test(evt.target.value)) { +// match = evt.target.value.match(/(.*)@(.*)/); +// elOutput.innerText = await computeWKDLocalPart(match[1]); +// elOutputDirect.innerText = `https://${match[2]}/.well-known/openpgpkey/hu/${elOutput.innerText}?l=${match[1]}`; +// elOutputAdvanced.innerText = `https://openpgpkey.${match[2]}/.well-known/openpgpkey/${match[2]}/hu/${elOutput.innerText}?l=${match[1]}`; +// } else { +// elOutput.innerText = await computeWKDLocalPart(evt.target.value); +// elOutputDirect.innerText = "Waiting for input"; +// elOutputAdvanced.innerText = "Waiting for input"; +// } +// } else { +// elOutput.innerText = "Waiting for input"; +// elOutputDirect.innerText = "Waiting for input"; +// elOutputAdvanced.innerText = "Waiting for input"; +// } +// }); - case "keybase": - opts.keyLink = `https://keybase.io/${opts.username}/pgp_keys.asc?fingerprint=${opts.fingerprint}`; - opts.input = `${opts.username}/${opts.fingerprint}`; - try { - opts.plaintext = await fetch(opts.keyLink).then(function(response) { - if (response.status === 200) { - return response; - } - }) - .then(response => response.text()); - } catch (e) { - throw(`Error: No public keys could be fetched from the Keybase account (${e}).`); - } - output.publicKey = (await openpgp.key.readArmored(opts.plaintext)).keys[0]; +// elInput.dispatchEvent(new Event("input")); +// } - if (!output.publicKey) { - throw("Error: No public keys could be read from the Keybase account."); - } - break; +// if (elUtilQRFP) { +// elUtilQRFP.onsubmit = function (evt) { +// evt.preventDefault(); +// } - case "signature": - sig = (await openpgp.signature.readArmored(opts.signature)); - if ('compressed' in sig.packets[0]) { - sig = sig.packets[0]; - output.sigContent = (await openpgp.stream.readToEnd(await sig.packets[1].getText())); - }; - output.sigUserId = sig.packets[0].signersUserId; - output.sigKeyId = (await sig.packets[0].issuerKeyId.toHex()); +// const qrTarget = document.getElementById('qrcode'); +// const qrContext = qrTarget.getContext('2d'); +// const qrOpts = { +// errorCorrectionLevel: 'H', +// margin: 1, +// width: 256, +// height: 256 +// }; - if (!opts.server) {opts.server = "https://keys.openpgp.org/"}; - hkp = new openpgp.HKP(opts.server); - lookupOpts = { - query: output.sigUserId ? output.sigUserId : output.sigKeyId - }; - output.publicKey = await hkp.lookup(lookupOpts); - output.publicKey = (await openpgp.key.readArmored(output.publicKey)).keys[0]; +// const elInput = document.body.querySelector("#input"); - if (!output.publicKey) { - throw("Error: No public keys could be extracted from the signature."); - } - break; - } +// elInput.addEventListener("input", async function(evt) { +// if (evt.target.value) { +// QRCode.toCanvas(qrTarget, evt.target.value, qrOpts, function (error) { +// if (error) { +// qrContext.clearRect(0, 0, qrTarget.width, qrTarget.height); +// console.error(error); +// } +// }); +// } else { +// qrContext.clearRect(0, 0, qrTarget.width, qrTarget.height); +// } +// }); - // Gather more data about the primary key and user - output.fingerprint = await output.publicKey.primaryKey.getFingerprint(); - output.user = await output.publicKey.getPrimaryUser(); - lastPrimarySig = output.user.selfCertification; - output.notations = lastPrimarySig.notations || []; +// elInput.dispatchEvent(new Event("input")); +// } - return output; -} +// if (elUtilQR) { +// elUtilQR.onsubmit = function (evt) { +// evt.preventDefault(); +// } -async function computeWKDLocalPart(message) { - const data = openpgp.util.str_to_Uint8Array(message); - const hash = await openpgp.crypto.hash.sha1(data); - return openpgp.util.encodeZBase32(hash); -} +// const qrTarget = document.getElementById('qrcode'); +// const qrContext = qrTarget.getContext('2d'); +// const qrOpts = { +// errorCorrectionLevel: 'L', +// margin: 1, +// width: 256, +// height: 256 +// }; -async function generateProfileURL(data) { - let hostname = window.location.hostname; +// const elInput = document.body.querySelector("#input"); - if (data.input == "") { - return "Waiting for input..."; - } - switch (data.source) { - case "wkd": - return `https://${hostname}/${data.input}`; - break; - case "hkp": - if (/.*@.*\..*/.test(data.input)) { - return `https://${hostname}/hkp/${data.input}`; - } else { - return `https://${hostname}/${data.input}`; - } - break; - case "keybase": - const re = /https\:\/\/keybase.io\/(.*)\/pgp_keys\.asc\?fingerprint\=(.*)/; - if (!re.test(data.input)) { - return "Incorrect Keybase public key URL."; - } - const match = data.input.match(re); - return `https://${hostname}/keybase/${match[1]}/${match[2]}`; - break; - } -} +// if (elInput.innerText) { +// elInput.innerText = decodeURIComponent(elInput.innerText); -async function fetchWithTimeout(url, timeout = 3000) { - return Promise.race([ - fetch(url), - new Promise((_, reject) => - setTimeout(() => reject(new Error('timeout')), timeout) - ) - ]); -} +// QRCode.toCanvas(qrTarget, elInput.innerText, qrOpts, function (error) { +// if (error) { +// document.body.querySelector("#qrcode--altLink").href = "#"; +// qrContext.clearRect(0, 0, qrTarget.width, qrTarget.height); +// console.error(error); +// } else { +// document.body.querySelector("#qrcode--altLink").href = elInput.innerText; +// } +// }); +// } else { +// qrContext.clearRect(0, 0, qrTarget.width, qrTarget.height); +// } +// } -// General purpose -let elFormSignatureProfile = document.body.querySelector("#formGenerateSignatureProfile"), - elProfileUid = document.body.querySelector("#profileUid"), - elProfileMode = document.body.querySelector("#profileMode"), - elProfileServer = document.body.querySelector("#profileServer"), - elModeSelect = document.body.querySelector("#modeSelect"), - elUtilWKD = document.body.querySelector("#form-util-wkd"), - elUtilQRFP = document.body.querySelector("#form-util-qrfp"), - elUtilQR = document.body.querySelector("#form-util-qr"), - elUtilProfileURL = document.body.querySelector("#form-util-profile-url"); +// if (elUtilProfileURL) { +// elUtilProfileURL.onsubmit = function (evt) { +// evt.preventDefault(); +// } -if (elModeSelect) { - elModeSelect.onchange = function (evt) { - let elAllModes = document.body.querySelectorAll('.modes'); - elAllModes.forEach(function(el) { - el.classList.remove('modes--visible'); - }); - document.body.querySelector(`.modes--${elModeSelect.value}`).classList.add('modes--visible'); - } - elModeSelect.dispatchEvent(new Event("change")); -} +// const elInput = document.body.querySelector("#input"), +// elSource = document.body.querySelector("#source"), +// elOutput = document.body.querySelector("#output"); -if (elProfileUid) { - let opts, profileUid = elProfileUid.innerHTML; - switch (elProfileMode.innerHTML) { - default: - case "sig": - elFormSignatureProfile.onsubmit = function (evt) { - evt.preventDefault(); +// let data = { +// input: elInput.value, +// source: elSource.value +// }; - opts = { - input: document.body.querySelector("#plaintext_input").value, - mode: elProfileMode.innerHTML - } +// elInput.addEventListener("input", async function(evt) { +// data = { +// input: elInput.value, +// source: elSource.value +// }; +// elOutput.innerText = await generateProfileURL(data); +// }); - displayProfile(opts) - } - break; +// elSource.addEventListener("input", async function(evt) { +// data = { +// input: elInput.value, +// source: elSource.value +// }; +// elOutput.innerText = await generateProfileURL(data); +// }); - case "auto": - if (/.*@.*/.test(profileUid)) { - // Match email for wkd - opts = { - input: profileUid, - mode: "wkd" - } - } else { - // Match fingerprint for hkp - opts = { - input: profileUid, - mode: "hkp" - } - } - break; - - case "hkp": - opts = { - input: profileUid, - server: elProfileServer.innerHTML, - mode: elProfileMode.innerHTML - } - break; - - case "wkd": - opts = { - input: profileUid, - mode: elProfileMode.innerHTML - } - break; - - case "keybase": - let match = profileUid.match(/(.*)\/(.*)/); - opts = { - username: match[1], - fingerprint: match[2], - mode: elProfileMode.innerHTML - } - break; - } - - if (elProfileMode.innerHTML !== 'sig') { - displayProfile(opts); - } -} - -if (elUtilWKD) { - elUtilWKD.onsubmit = function (evt) { - evt.preventDefault(); - } - - const elInput = document.body.querySelector("#input"); - const elOutput = document.body.querySelector("#output"); - const elOutputDirect = document.body.querySelector("#output_url_direct"); - const elOutputAdvanced = document.body.querySelector("#output_url_advanced"); - let match; - - elInput.addEventListener("input", async function(evt) { - if (evt.target.value) { - if (/(.*)@(.{1,}\..{1,})/.test(evt.target.value)) { - match = evt.target.value.match(/(.*)@(.*)/); - elOutput.innerText = await computeWKDLocalPart(match[1]); - elOutputDirect.innerText = `https://${match[2]}/.well-known/openpgpkey/hu/${elOutput.innerText}?l=${match[1]}`; - elOutputAdvanced.innerText = `https://openpgpkey.${match[2]}/.well-known/openpgpkey/${match[2]}/hu/${elOutput.innerText}?l=${match[1]}`; - } else { - elOutput.innerText = await computeWKDLocalPart(evt.target.value); - elOutputDirect.innerText = "Waiting for input"; - elOutputAdvanced.innerText = "Waiting for input"; - } - } else { - elOutput.innerText = "Waiting for input"; - elOutputDirect.innerText = "Waiting for input"; - elOutputAdvanced.innerText = "Waiting for input"; - } - }); - - elInput.dispatchEvent(new Event("input")); -} - -if (elUtilQRFP) { - elUtilQRFP.onsubmit = function (evt) { - evt.preventDefault(); - } - - const qrTarget = document.getElementById('qrcode'); - const qrContext = qrTarget.getContext('2d'); - const qrOpts = { - errorCorrectionLevel: 'H', - margin: 1, - width: 256, - height: 256 - }; - - const elInput = document.body.querySelector("#input"); - - elInput.addEventListener("input", async function(evt) { - if (evt.target.value) { - QRCode.toCanvas(qrTarget, evt.target.value, qrOpts, function (error) { - if (error) { - qrContext.clearRect(0, 0, qrTarget.width, qrTarget.height); - console.error(error); - } - }); - } else { - qrContext.clearRect(0, 0, qrTarget.width, qrTarget.height); - } - }); - - elInput.dispatchEvent(new Event("input")); -} - -if (elUtilQR) { - elUtilQR.onsubmit = function (evt) { - evt.preventDefault(); - } - - const qrTarget = document.getElementById('qrcode'); - const qrContext = qrTarget.getContext('2d'); - const qrOpts = { - errorCorrectionLevel: 'L', - margin: 1, - width: 256, - height: 256 - }; - - const elInput = document.body.querySelector("#input"); - - if (elInput.innerText) { - elInput.innerText = decodeURIComponent(elInput.innerText); - - QRCode.toCanvas(qrTarget, elInput.innerText, qrOpts, function (error) { - if (error) { - document.body.querySelector("#qrcode--altLink").href = "#"; - qrContext.clearRect(0, 0, qrTarget.width, qrTarget.height); - console.error(error); - } else { - document.body.querySelector("#qrcode--altLink").href = elInput.innerText; - } - }); - } else { - qrContext.clearRect(0, 0, qrTarget.width, qrTarget.height); - } -} - -if (elUtilProfileURL) { - elUtilProfileURL.onsubmit = function (evt) { - evt.preventDefault(); - } - - const elInput = document.body.querySelector("#input"), - elSource = document.body.querySelector("#source"), - elOutput = document.body.querySelector("#output"); - - let data = { - input: elInput.value, - source: elSource.value - }; - - elInput.addEventListener("input", async function(evt) { - data = { - input: elInput.value, - source: elSource.value - }; - elOutput.innerText = await generateProfileURL(data); - }); - - elSource.addEventListener("input", async function(evt) { - data = { - input: elInput.value, - source: elSource.value - }; - elOutput.innerText = await generateProfileURL(data); - }); - - elInput.dispatchEvent(new Event("input")); -} - -function capitalizeLetteredServices(serviceName) { - const servName = serviceName.toLowerCase(); - if (servName === 'dns' || servName === 'xmpp' || servName === 'irc') { - return servName.toUpperCase(); - } - return serviceName; -} +// elInput.dispatchEvent(new Event("input")); +// } diff --git a/static/styles.css b/static/styles.css index 2d2932a..7d56310 100644 --- a/static/styles.css +++ b/static/styles.css @@ -126,12 +126,14 @@ section.profile p, .demo p { } .card--profileHeader { display: flex; + flex-direction: column; flex-wrap: wrap; - gap: 2rem; + align-items: center; + gap: 24px; /* text-align: center; */ } .card--profileHeader p, .card--profileHeader small { - margin: 0 0 1.2rem; + margin: 0; } .card--small-profile { display: flex; @@ -172,7 +174,7 @@ section.profile p, .demo p { color: #fff; } #profileName { - font-size: 2rem; + font-size: 1.6rem; color: var(--grey-700); } #profileURLFingerprint { @@ -248,96 +250,21 @@ section.profile p, .demo p { margin-bottom: 0; } -.claim { - display: flex; - align-items: center; - width: 100%; - margin: 0.8rem 0; - padding: 0.8rem 1.2rem; - background-color: var(--purple-100); - border-radius: 8px; +kx-claim { + display: block; + margin: 12px 0; } -.claim p { - margin: 0; -} -.claim .claim__main { - flex: 1; -} -.claim .claim__description p { - font-size: 1.4rem; - line-height: 2rem; -} -.claim .claim__links p, p.subtle-links { - display: flex; - align-items: center; - flex-wrap: wrap; - font-size: 1rem; - color: var(--grey-700); -} -.claim .claim__links a, .claim .claim__links span, p.subtle-links a { - font-size: 1rem; - margin: 0 10px 0 0; - color: var(--grey-700); -} -/* p.subtle-links a:first-of-type { - margin: 0; -} */ -.claim .serviceProvider { - color: var(--grey-500); -} -.claim .claim__verification { - display: flex; - align-items: center; - justify-content: center; - min-width: 48px; - height: 48px; - border-radius: 100%; - background-color: var(--red-600); - color: #fff; - font-size: 2rem; - user-select: none; -} -.claim .claim__verification--true { - background-color: var(--green-600); -} -@media screen and (max-width: 640px) { - .claim .claim__description p { - font-size: 1.2rem; - } - .claim .claim__links a, p.subtle-links a { - font-size: 0.9rem; - } -} -@media screen and (max-width: 480px) { - .claim .claim__description p { - font-size: 1rem; - } - .claim .claim__verification { - min-width: 36px; - height: 36px; - font-size: 1.6rem; - } -} - -/* .demo { - text-align: center; - margin: 9.6rem 0; - font-size: 1.6rem; -} -.demo .claim { - margin: 1.6rem 0; -} */ .avatar { display: inline-block; min-width: 96px; max-width: 128px; - /* margin-top: 1.6rem; */ + line-height: 0; text-align: center; } .avatar img { width: 100%; - border-radius: 24px; + border-radius: 50%; } /* .buttons { diff --git a/views/profile-failed.pug b/views/profile-failed.pug new file mode 100644 index 0000000..268d181 --- /dev/null +++ b/views/profile-failed.pug @@ -0,0 +1,9 @@ +extends templates/base.pug + +block content + section.profile.narrow + h2 Something went wrong when generating the profile + + ul + each error in data.errors + li= error diff --git a/views/profile.pug b/views/profile.pug index e183ad6..a6d8980 100644 --- a/views/profile.pug +++ b/views/profile.pug @@ -1,9 +1,19 @@ extends templates/base.pug +mixin generateUser(user, isPrimary) + h2 + | #{user.userData.email} + if isPrimary + small.primary primary + each claim in user.claims + kx-claim(data-claim=claim) + block js + script(type='application/javascript' src='/static/dialog-polyfill.js' charset='utf-8') script(type='application/javascript' src='/static/openpgp.min.js' charset='utf-8') script(type='application/javascript' src='/static/doip.js' charset='utf-8') - script(type='application/javascript' src='/static/dialog-polyfill.js' charset='utf-8') + script(type='application/javascript' src='/static/kx-claim.js' charset='utf-8') + script(type='application/javascript' src='/static/kx-key.js' charset='utf-8') script(type='application/javascript' src='/static/scripts.js' charset='utf-8') block css @@ -13,9 +23,6 @@ block content section.profile.narrow noscript p Keyoxide requires JavaScript to function. - span#profileUid(style='display: none;') #{uid} - span#profileServer(style='display: none;') #{server} - span#profileMode(style='display: none;') #{mode} dialog#dialog--encryptMessage div @@ -35,19 +42,23 @@ block content form(method="dialog") input(type="submit" value="Close") - #profileDialogs - - if (mode == 'sig') - #profileSigInput.card.card--form - form#formGenerateSignatureProfile(method='post') - label(for="plaintext_input") Please enter the raw profile signature below and press "Generate profile". - textarea#plaintext_input(name='plaintext_input') - input(type='submit', name='submit', value='Generate profile') - #profileHeader.card.card--profileHeader + a.avatar(href="#") + img#profileAvatar(src=data.extra.avatarURL alt="avatar") + + p#profileName= data.keyData.users[data.keyData.primaryUserIndex].userData.name + //- p#profileURLFingerprint + //- a(href=data.key.fetchURL)=data.keyData.fingerprint + .buttons + button(onClick="document.querySelector('#dialog--encryptMessage').showModal();") Encrypt message + button(onClick="document.querySelector('#dialog--verifySignature').showModal();") Verify signature #profileProofs.card - if (mode == 'sig') - //- p Waiting for input… - else - p Loading keys & verifying proofs… + h2 Key + kx-key(data-keydata=data.keyData) + + +generateUser(data.keyData.users[data.keyData.primaryUserIndex], true) + each user, index in data.keyData.users + unless index == data.keyData.primaryUserIndex + +generateUser(user, false) +