From 72ea81af403d09dea10f79ed1c46aba8f831e21f Mon Sep 17 00:00:00 2001 From: Yarmo Mackenbach Date: Mon, 3 May 2021 11:48:48 +0200 Subject: [PATCH] Fix support for QR codes --- static/img/qrcode.png | Bin 0 -> 401 bytes static/kx-claim.js | 91 ++++++++++++++++++++++++------------------ static/kx-styles.css | 14 +++++++ static/scripts.js | 31 ++++++++++++++ static/styles.css | 5 ++- views/profile.pug | 9 ++++- 6 files changed, 110 insertions(+), 40 deletions(-) create mode 100644 static/img/qrcode.png diff --git a/static/img/qrcode.png b/static/img/qrcode.png new file mode 100644 index 0000000000000000000000000000000000000000..f3e044ff08808d8f2abe12c36c3528c1df900a92 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmUKs7M+SzC{oH>NS%G|oWRD45dJguM!v-tY$DUh!@P+6=(yLU`z6LcLCBs@Y8vBJ&@uo z@Q5r1(g|SvA=~LZkTKcQ#W5t~-rF0VLJbN$E*GzT`WJr9mOJ^hK=R-1u9~+Ql!O>k zZspxN*I4WOx?cXTTbQ!Lw!=HN$u?hD{C62K6eV9vYvr) z(^?zxBz>TR9bPkqiHJD4r~TXybe?L7YeY#(Vo9o1a#1RfVlXl=GSoFN)ip2&^9ozGB5~O67UX1LvDUbW?Cg~4T?WsfC8Pt)78&qol`;+0JBSji~s-t literal 0 HcmV?d00001 diff --git a/static/kx-claim.js b/static/kx-claim.js index 8fa1ff2..378242a 100644 --- a/static/kx-claim.js +++ b/static/kx-claim.js @@ -102,51 +102,66 @@ class Claim extends HTMLElement { if (claim.status === 'verified' && !claim.verification.result && claim.isAmbiguous()) { shadow.querySelector('.info .subtitle').innerText = '---'; - const subsection0 = elContent.appendChild(document.createElement('div')); - subsection0.setAttribute('class', 'subsection'); - const subsection0_icon = subsection0.appendChild(document.createElement('img')); - subsection0_icon.setAttribute('src', '/static/img/alert-decagram.png'); - const subsection0_text = subsection0.appendChild(document.createElement('div')); + const subsection_alert = elContent.appendChild(document.createElement('div')); + subsection_alert.setAttribute('class', 'subsection'); + const subsection_alert_icon = subsection_alert.appendChild(document.createElement('img')); + subsection_alert_icon.setAttribute('src', '/static/img/alert-decagram.png'); + const subsection_alert_text = subsection_alert.appendChild(document.createElement('div')); - const message = subsection0_text.appendChild(document.createElement('p')); + const message = subsection_alert_text.appendChild(document.createElement('p')); message.innerHTML = `None of the matched service providers could be verified. Keyoxide was not able to determine which was the correct service provider or why the verification process failed.`; return; } // Links to profile and proof - const subsection1 = elContent.appendChild(document.createElement('div')); - subsection1.setAttribute('class', 'subsection'); - const subsection1_icon = subsection1.appendChild(document.createElement('img')); - subsection1_icon.setAttribute('src', '/static/img/link.png'); - const subsection1_text = subsection1.appendChild(document.createElement('div')); + const subsection_links = elContent.appendChild(document.createElement('div')); + subsection_links.setAttribute('class', 'subsection'); + const subsection_links_icon = subsection_links.appendChild(document.createElement('img')); + subsection_links_icon.setAttribute('src', '/static/img/link.png'); + const subsection_links_text = subsection_links.appendChild(document.createElement('div')); - const profile_link = subsection1_text.appendChild(document.createElement('p')); + const profile_link = subsection_links_text.appendChild(document.createElement('p')); if (claim.matches[0].profile.uri) { profile_link.innerHTML = `Profile link: ${claim.matches[0].profile.uri}`; } else { profile_link.innerHTML = `Profile link: not accessible from browser`; } - const proof_link = subsection1_text.appendChild(document.createElement('p')); + const proof_link = subsection_links_text.appendChild(document.createElement('p')); if (claim.matches[0].proof.uri) { proof_link.innerHTML = `Proof link: ${claim.matches[0].proof.uri}`; } else { proof_link.innerHTML = `Proof link: not accessible from browser`; } + // QR Code + if (claim.matches[0].profile.qr) { + elContent.appendChild(document.createElement('hr')); + + const subsection_qr = elContent.appendChild(document.createElement('div')); + subsection_qr.setAttribute('class', 'subsection'); + const subsection_qr_icon = subsection_qr.appendChild(document.createElement('img')); + subsection_qr_icon.setAttribute('src', '/static/img/qrcode.png'); + const subsection_qr_text = subsection_qr.appendChild(document.createElement('div')); + + const button_profileQR = subsection_qr_text.appendChild(document.createElement('button')); + button_profileQR.innerText = `Show profile QR`; + button_profileQR.setAttribute('onClick', `showQR('${claim.matches[0].profile.qr}')`); + } + elContent.appendChild(document.createElement('hr')); // Claim verification status - const subsection2 = elContent.appendChild(document.createElement('div')); - subsection2.setAttribute('class', 'subsection'); - const subsection2_icon = subsection2.appendChild(document.createElement('img')); - subsection2_icon.setAttribute('src', '/static/img/decagram.png'); - const subsection2_text = subsection2.appendChild(document.createElement('div')); + const subsection_status = elContent.appendChild(document.createElement('div')); + subsection_status.setAttribute('class', 'subsection'); + const subsection_status_icon = subsection_status.appendChild(document.createElement('img')); + subsection_status_icon.setAttribute('src', '/static/img/decagram.png'); + const subsection_status_text = subsection_status.appendChild(document.createElement('div')); - const verification = subsection2_text.appendChild(document.createElement('p')); + const verification = subsection_status_text.appendChild(document.createElement('p')); if (claim.status === 'verified') { verification.innerHTML = `Claim verification has completed.`; - subsection2_icon.setAttribute('src', '/static/img/check-decagram.png'); + subsection_status_icon.setAttribute('src', '/static/img/check-decagram.png'); } else { verification.innerHTML = `Claim verification is in progress…`; return; @@ -155,26 +170,26 @@ class Claim extends HTMLElement { elContent.appendChild(document.createElement('hr')); // Result of claim verification - const subsection3 = elContent.appendChild(document.createElement('div')); - subsection3.setAttribute('class', 'subsection'); - const subsection3_icon = subsection3.appendChild(document.createElement('img')); - subsection3_icon.setAttribute('src', '/static/img/shield-search.png'); - const subsection3_text = subsection3.appendChild(document.createElement('div')); + const subsection_result = elContent.appendChild(document.createElement('div')); + subsection_result.setAttribute('class', 'subsection'); + const subsection_result_icon = subsection_result.appendChild(document.createElement('img')); + subsection_result_icon.setAttribute('src', '/static/img/shield-search.png'); + const subsection_result_text = subsection_result.appendChild(document.createElement('div')); - const result = subsection3_text.appendChild(document.createElement('p')); + const result = subsection_result_text.appendChild(document.createElement('p')); result.innerHTML = `The claim ${claim.verification.result ? 'HAS BEEN' : 'COULD NOT BE'} verified by the proof.`; // Additional info if (claim.verification.proof.viaProxy) { elContent.appendChild(document.createElement('hr')); - const subsection4 = elContent.appendChild(document.createElement('div')); - subsection4.setAttribute('class', 'subsection'); - const subsection4_icon = subsection4.appendChild(document.createElement('img')); - subsection4_icon.setAttribute('src', '/static/img/information.png'); - const subsection4_text = subsection4.appendChild(document.createElement('div')); + const subsection_info = elContent.appendChild(document.createElement('div')); + subsection_info.setAttribute('class', 'subsection'); + const subsection_info_icon = subsection_info.appendChild(document.createElement('img')); + subsection_info_icon.setAttribute('src', '/static/img/information.png'); + const subsection_info_text = subsection_info.appendChild(document.createElement('div')); - const result_proxyUsed = subsection4_text.appendChild(document.createElement('p')); + const result_proxyUsed = subsection_info_text.appendChild(document.createElement('p')); result_proxyUsed.innerHTML = `A proxy was used to fetch the proof: PLACEHOLDER__PROXY_HOSTNAME`; } @@ -183,14 +198,14 @@ class Claim extends HTMLElement { // console.log(claim.verification); // elContent.appendChild(document.createElement('hr')); - // const subsection5 = elContent.appendChild(document.createElement('div')); - // subsection5.setAttribute('class', 'subsection'); - // const subsection5_icon = subsection5.appendChild(document.createElement('img')); - // subsection5_icon.setAttribute('src', '/static/img/alert-circle.png'); - // const subsection5_text = subsection5.appendChild(document.createElement('div')); + // const subsection_errors = elContent.appendChild(document.createElement('div')); + // subsection_errors.setAttribute('class', 'subsection'); + // const subsection_errors_icon = subsection_errors.appendChild(document.createElement('img')); + // subsection_errors_icon.setAttribute('src', '/static/img/alert-circle.png'); + // const subsection_errors_text = subsection_errors.appendChild(document.createElement('div')); // claim.verification.errors.forEach(message => { - // const error = subsection5_text.appendChild(document.createElement('p')); + // const error = subsection_errors_text.appendChild(document.createElement('p')); // if (message instanceof Error) { // error.innerText = message.message; diff --git a/static/kx-styles.css b/static/kx-styles.css index 77c6ef1..4f1bd97 100644 --- a/static/kx-styles.css +++ b/static/kx-styles.css @@ -164,6 +164,20 @@ details.kx-item .inProgress:after { bottom: 0; right: 0; } +details.kx-item button { + padding: 0.4rem 0.8rem; + margin-right: 8px; + text-decoration: none; + text-transform: uppercase; + background-color: var(--purple-50); + border: solid 2px var(--purple-400); + border-radius: 4px; + cursor: pointer; +} +details.kx-item button:hover { + background-color: var(--purple-400); + color: #fff; +} @media screen and (max-width: 640px) { details.kx-item summary .claim__description p { diff --git a/static/scripts.js b/static/scripts.js index ef5a3e5..14af431 100644 --- a/static/scripts.js +++ b/static/scripts.js @@ -131,6 +131,37 @@ const fetchProfileKey = async function() { } } +// Enable QR modal +const showQR = function(input) { + const qrTarget = document.getElementById('qr'); + const qrContext = qrTarget.getContext('2d'); + const qrOpts = { + errorCorrectionLevel: 'L', + margin: 1, + width: 256, + height: 256 + }; + + if (input) { + input = decodeURIComponent(input); + + QRCode.toCanvas(qrTarget, input, qrOpts, function(error) { + if (error) { + document.querySelector("#qr--altLink").innerText = ""; + document.querySelector("#qr--altLink").href = "#"; + qrContext.clearRect(0, 0, qrTarget.width, qrTarget.height); + console.error(error); + } else { + document.querySelector("#qr--altLink").innerText = input; + document.querySelector("#qr--altLink").href = input; + document.querySelector('#dialog--qr').showModal(); + } + }); + } else { + qrContext.clearRect(0, 0, qrTarget.width, qrTarget.height); + } +} + // let elFormSignatureProfile = document.body.querySelector("#formGenerateSignatureProfile"), // elProfileUid = document.body.querySelector("#profileUid"), // elProfileMode = document.body.querySelector("#profileMode"), diff --git a/static/styles.css b/static/styles.css index 9fbd8df..1766240 100644 --- a/static/styles.css +++ b/static/styles.css @@ -475,7 +475,10 @@ dialog p:first-of-type { margin-top: 0; } -#qrcode { +#qr { display: block; + width: 100% !important; + max-width: 256px !important; + height: auto !important; margin: 0 auto 16px; } diff --git a/views/profile.pug b/views/profile.pug index eb46897..df9685e 100644 --- a/views/profile.pug +++ b/views/profile.pug @@ -9,9 +9,10 @@ mixin generateUser(user, isPrimary) kx-claim(data-claim=claim) block js + script(type='application/javascript' src='/static/qrcode.min.js' charset='utf-8') 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/doip.min.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') @@ -50,6 +51,12 @@ block content form(method="dialog") input(type="submit" value="Close") + dialog#dialog--qr + div + canvas#qr + p + a#qr--altLink + #profileHeader.card.card--profileHeader a.avatar(href="#") img#profileAvatar(src=data.extra.avatarURL alt="avatar")