diff --git a/static/kx-claim.js b/static/kx-claim.js
deleted file mode 100644
index e08e941..0000000
--- a/static/kx-claim.js
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
-Copyright (C) 2021 Yarmo Mackenbach
-
-This program is free software: you can redistribute it and/or modify it under
-the terms of the GNU Affero General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option)
-any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-details.
-
-You should have received a copy of the GNU Affero General Public License along
-with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
-If your software can interact with users remotely through a computer network,
-you should also make sure that it provides a way for users to get its source.
-For example, if your program is a web application, its interface could display
-a "Source" link that leads users to an archive of the code. There are many
-ways you could offer source, and different solutions will be better for different
-programs; see section 13 for the specific requirements.
-
-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 .
-*/
-class Claim extends HTMLElement {
- // Specify the attributes to observe
- static get observedAttributes() {
- return ['data-claim'];
- }
-
- constructor() {
- // Call super
- super();
- }
-
- attributeChangedCallback(name, oldValue, newValue) {
- this.updateContent(newValue);
- }
-
- async verify() {
- const claim = new doip.Claim(JSON.parse(this.getAttribute('data-claim')));
- await claim.verify({
- proxy: {
- policy: 'adaptive',
- hostname: 'PLACEHOLDER__PROXY_HOSTNAME'
- }
- });
- this.setAttribute('data-claim', JSON.stringify(claim));
- }
-
- updateContent(value) {
- const root = this;
- const claim = new doip.Claim(JSON.parse(value));
-
- switch (claim.matches[0].serviceprovider.name) {
- case 'dns':
- case 'xmpp':
- case 'irc':
- root.querySelector('.info .subtitle').innerText = claim.matches[0].serviceprovider.name.toUpperCase();
- break;
-
- default:
- root.querySelector('.info .subtitle').innerText = claim.matches[0].serviceprovider.name;
- break;
- }
- root.querySelector('.info .title').innerText = claim.matches[0].profile.display;
-
- try {
- if (claim.status === 'verified') {
- root.querySelector('.icons .verificationStatus').setAttribute('data-value', claim.verification.result ? 'success' : 'failed');
- } else {
- root.querySelector('.icons .verificationStatus').setAttribute('data-value', 'running');
- }
- } catch (error) {
- root.querySelector('.icons .verificationStatus').setAttribute('data-value', 'failed');
- }
-
- const elContent = root.querySelector('.content');
- elContent.innerHTML = ``;
-
- // Handle failed ambiguous claim
- if (claim.status === 'verified' && !claim.verification.result && claim.isAmbiguous()) {
- root.querySelector('.info .subtitle').innerText = '---';
-
- 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');
- subsection_alert_icon.setAttribute('alt', '');
- subsection_alert_icon.setAttribute('aria-hidden', 'true');
- const subsection_alert_text = subsection_alert.appendChild(document.createElement('div'));
-
- 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 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');
- subsection_links_icon.setAttribute('alt', '');
- subsection_links_icon.setAttribute('aria-hidden', 'true');
- const subsection_links_text = subsection_links.appendChild(document.createElement('div'));
-
- 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 = 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');
- subsection_qr_icon.setAttribute('alt', '');
- subsection_qr_icon.setAttribute('aria-hidden', 'true');
- 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}', 'url')`);
- button_profileQR.setAttribute('aria-label', `Show QR code linking to profile`);
- }
-
- elContent.appendChild(document.createElement('hr'));
-
- // Claim verification status
- 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');
- subsection_status_icon.setAttribute('alt', '');
- subsection_status_icon.setAttribute('aria-hidden', 'true');
- const subsection_status_text = subsection_status.appendChild(document.createElement('div'));
-
- const verification = subsection_status_text.appendChild(document.createElement('p'));
- if (claim.status === 'verified') {
- verification.innerHTML = `Claim verification has completed.`;
- subsection_status_icon.setAttribute('src', '/static/img/check-decagram.png');
- subsection_status_icon.setAttribute('alt', '');
- subsection_status_icon.setAttribute('aria-hidden', 'true');
- } else {
- verification.innerHTML = `Claim verification is in progress…`;
- return;
- }
-
- elContent.appendChild(document.createElement('hr'));
-
- // Result of claim verification
- 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');
- subsection_result_icon.setAttribute('alt', '');
- subsection_result_icon.setAttribute('aria-hidden', 'true');
- const subsection_result_text = subsection_result.appendChild(document.createElement('div'));
-
- 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 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');
- subsection_info_icon.setAttribute('alt', '');
- subsection_info_icon.setAttribute('aria-hidden', 'true');
- const subsection_info_text = subsection_info.appendChild(document.createElement('div'));
-
- const result_proxyUsed = subsection_info_text.appendChild(document.createElement('p'));
- result_proxyUsed.innerHTML = `A proxy was used to fetch the proof: PLACEHOLDER__PROXY_HOSTNAME`;
- }
-
- // TODO Display errors
- // if (claim.verification.errors.length > 0) {
- // console.log(claim.verification);
- // elContent.appendChild(document.createElement('hr'));
-
- // 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 = subsection_errors_text.appendChild(document.createElement('p'));
-
- // if (message instanceof Error) {
- // error.innerText = message.message;
- // } else {
- // error.innerText = message;
- // }
- // });
- // }
- }
-}
-
-customElements.define('kx-claim', Claim);
diff --git a/static/kx-key.js b/static/kx-key.js
deleted file mode 100644
index 6290dac..0000000
--- a/static/kx-key.js
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
-Copyright (C) 2021 Yarmo Mackenbach
-
-This program is free software: you can redistribute it and/or modify it under
-the terms of the GNU Affero General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option)
-any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-details.
-
-You should have received a copy of the GNU Affero General Public License along
-with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
-If your software can interact with users remotely through a computer network,
-you should also make sure that it provides a way for users to get its source.
-For example, if your program is a web application, its interface could display
-a "Source" link that leads users to an archive of the code. There are many
-ways you could offer source, and different solutions will be better for different
-programs; see section 13 for the specific requirements.
-
-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 .
-*/
-class Key extends HTMLElement {
- // Specify the attributes to observe
- static get observedAttributes() {
- return ['data-keydata'];
- }
-
- constructor() {
- // Call super
- super();
- }
-
- attributeChangedCallback(name, oldValue, newValue) {
- this.updateContent(newValue);
- }
-
- updateContent(value) {
- const root = this;
- const data = JSON.parse(value);
-
- root.querySelector('.info .subtitle').innerText = data.key.fetchMethod;
- root.querySelector('.info .title').innerText = data.fingerprint;
-
- const elContent = root.querySelector('.content');
- elContent.innerHTML = ``;
-
- // Link to key
- 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');
- subsection_links_icon.setAttribute('alt', '');
- subsection_links_icon.setAttribute('aria-hidden', 'true');
- const subsection_links_text = subsection_links.appendChild(document.createElement('div'));
-
- const profile_link = subsection_links_text.appendChild(document.createElement('p'));
- profile_link.innerHTML = `Key link: ${data.key.uri}`;
-
- elContent.appendChild(document.createElement('hr'));
-
- // QR Code
- 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');
- subsection_qr_icon.setAttribute('alt', '');
- subsection_qr_icon.setAttribute('aria-hidden', 'true');
- const subsection_qr_text = subsection_qr.appendChild(document.createElement('div'));
-
- const button_fingerprintQR = subsection_qr_text.appendChild(document.createElement('button'));
- button_fingerprintQR.innerText = `Show OpenPGP fingerprint QR`;
- button_fingerprintQR.setAttribute('onClick', `showQR('${data.fingerprint}', 'fingerprint')`);
- button_fingerprintQR.setAttribute('aria-label', `Show QR code for cryptographic fingerprint`);
- }
-}
-
-customElements.define('kx-key', Key);
diff --git a/static/kx-styles.css b/static/kx-styles.css
deleted file mode 100644
index 0210c52..0000000
--- a/static/kx-styles.css
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
-Copyright (C) 2021 Yarmo Mackenbach
-
-This program is free software: you can redistribute it and/or modify it under
-the terms of the GNU Affero General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option)
-any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-details.
-
-You should have received a copy of the GNU Affero General Public License along
-with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
-If your software can interact with users remotely through a computer network,
-you should also make sure that it provides a way for users to get its source.
-For example, if your program is a web application, its interface could display
-a "Source" link that leads users to an archive of the code. There are many
-ways you could offer source, and different solutions will be better for different
-programs; see section 13 for the specific requirements.
-
-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 .
-*/
-* {
- box-sizing: border-box;
-}
-details.kx-item {
- width: 100%;
- border-radius: 8px;
-}
-details.kx-item p {
- margin: 0;
- word-break: break-word;
-}
-details.kx-item a {
- color: var(--blue-700);
-}
-details.kx-item hr {
- border: none;
- border-top: 2px solid var(--purple-100);
-}
-details.kx-item .content {
- padding: 12px;
- border: solid 3px var(--purple-100);
- border-top: 0px;
- border-radius: 0px 0px 8px 8px;
-}
-details.kx-item summary {
- display: flex;
- align-items: center;
- padding: 8px 12px;
- background-color: var(--purple-100);
- border: solid 3px var(--purple-100);
- border-radius: 8px;
- list-style: none;
- cursor: pointer;
-}
-details.kx-item summary::-webkit-details-marker {
- display: none;
-}
-details.kx-item summary:hover, summary:focus {
- border-color: var(--purple-400);
-}
-details[open] summary {
- border-radius: 8px 8px 0px 0px;
-}
-details.kx-item summary .info {
- flex: 1;
-}
-details.kx-item summary .info .title {
- font-size: 1.1em;
-}
-details.kx-item summary .claim__description p {
- font-size: 1.4rem;
- line-height: 2rem;
-}
-details.kx-item summary .claim__links p, p.subtle-links {
- display: flex;
- align-items: center;
- flex-wrap: wrap;
- font-size: 1rem;
- color: var(--grey-700);
-}
-details.kx-item summary .claim__links a, summary .claim__links span, p.subtle-links a {
- font-size: 1rem;
- margin: 0 10px 0 0;
- color: var(--grey-700);
-}
-details.kx-item summary .subtitle {
- color: var(--purple-700);
-}
-details.kx-item summary .verificationStatus {
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
- width: 48px;
- height: 48px;
- border-radius: 100%;
- color: #fff;
- font-size: 2rem;
- user-select: none;
-}
-details.kx-item summary .verificationStatus::after {
- position: absolute;
- display: flex;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- align-items: center;
- justify-content: center;
-}
-details.kx-item summary .verificationStatus .inProgress {
- opacity: 0;
- transition: opacity 0.4s ease;
- pointer-events: none;
-}
-details.kx-item summary .verificationStatus[data-value="success"] {
- content: "v";
- background-color: var(--green-600);
-}
-details.kx-item summary .verificationStatus[data-value="success"]::after {
- content: "✔";
-}
-details.kx-item summary .verificationStatus[data-value="failed"] {
- background-color: var(--red-400);
-}
-details.kx-item summary .verificationStatus[data-value="failed"]::after {
- content: "✕";
-}
-details.kx-item summary .verificationStatus[data-value="running"] .inProgress {
- opacity: 1;
-}
-
-details.kx-item .subsection {
- display: flex;
- align-items: center;
- gap: 16px;
-}
-details.kx-item .subsection > img {
- width: 24px;
- height: 24px;
- opacity: 0.4;
-}
-
-details.kx-item .inProgress {
- font-size: 10px;
- margin: 50px auto;
- text-indent: -9999em;
- width: 48px;
- height: 48px;
- border-radius: 50%;
- background: var(--purple-400);
- background: -moz-linear-gradient(left, var(--purple-400) 10%, rgba(255, 255, 255, 0) 42%);
- background: -webkit-linear-gradient(left, var(--purple-400) 10%, rgba(255, 255, 255, 0) 42%);
- background: -o-linear-gradient(left, var(--purple-400) 10%, rgba(255, 255, 255, 0) 42%);
- background: -ms-linear-gradient(left, var(--purple-400) 10%, rgba(255, 255, 255, 0) 42%);
- background: linear-gradient(to right, var(--purple-400) 10%, rgba(255, 255, 255, 0) 42%);
- position: relative;
- -webkit-animation: load3 1.4s infinite linear;
- animation: load3 1.4s infinite linear;
- -webkit-transform: translateZ(0);
- -ms-transform: translateZ(0);
- transform: translateZ(0);
-}
-details.kx-item .inProgress:before {
- width: 50%;
- height: 50%;
- background: var(--purple-400);
- border-radius: 100% 0 0 0;
- position: absolute;
- top: 0;
- left: 0;
- content: '';
-}
-details.kx-item .inProgress:after {
- background: var(--purple-100);
- width: 65%;
- height: 65%;
- border-radius: 50%;
- content: '';
- margin: auto;
- position: absolute;
- top: 0;
- left: 0;
- bottom: 0;
- right: 0;
-}
-details.kx-item button {
- padding: 0.4rem 0.8rem;
- margin-right: 8px;
- text-decoration: none;
- text-transform: uppercase;
- background-color: #fff;
- border: solid 2px var(--purple-400);
- border-radius: 4px;
- cursor: pointer;
-}
-details.kx-item button:hover {
- background-color: var(--purple-500);
- border-color: var(--purple-500);
- color: #fff;
-}
-
-@media screen and (max-width: 640px) {
- details.kx-item summary .claim__description p {
- font-size: 1.2rem;
- }
- details.kx-item summary .claim__links a, p.subtle-links a {
- font-size: 0.9rem;
- }
-}
-@media screen and (max-width: 480px) {
- summary .claim__description p {
- font-size: 1rem;
- }
- details.kx-item summary .verificationStatus {
- width: 36px;
- height: 36px;
- font-size: 1.6rem;
- }
- details.kx-item .inProgress {
- width: 36px;
- height: 36px;
- }
-}
-
-@-webkit-keyframes load3 {
- 0% {
- -webkit-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(360deg);
- transform: rotate(360deg);
- }
-}
-@keyframes load3 {
- 0% {
- -webkit-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(360deg);
- transform: rotate(360deg);
- }
-}
diff --git a/static/scripts.js b/static/scripts.js
deleted file mode 100644
index 9c5a418..0000000
--- a/static/scripts.js
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
-Copyright (C) 2021 Yarmo Mackenbach
-
-This program is free software: you can redistribute it and/or modify it under
-the terms of the GNU Affero General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option)
-any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-details.
-
-You should have received a copy of the GNU Affero General Public License along
-with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
-If your software can interact with users remotely through a computer network,
-you should also make sure that it provides a way for users to get its source.
-For example, if your program is a web application, its interface could display
-a "Source" link that leads users to an archive of the code. There are many
-ways you could offer source, and different solutions will be better for different
-programs; see section 13 for the specific requirements.
-
-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 .
-*/
-// Verify all claims
-const claims = document.querySelectorAll('kx-claim');
-claims.forEach(function(claim) {
- if (claim.hasAttribute('data-skip') && claim.getAttribute('data-skip')) {
- return;
- }
- claim.verify();
-});
-
-// Register modals
-document.querySelectorAll('dialog').forEach(function(d) {
- dialogPolyfill.registerDialog(d);
- d.addEventListener('click', function(ev) {
- if (ev && ev.target != d) {
- return;
- }
- d.close();
- });
-});
-
-// Register form listeners
-const elFormEncrypt = document.body.querySelector("#dialog--encryptMessage form");
-if (elFormEncrypt) {
- elFormEncrypt.onsubmit = async function (evt) {
- evt.preventDefault();
-
- try {
- // Fetch a key if needed
- await fetchProfileKey();
-
- // Encrypt the message
- let config = openpgp.config;
- config.show_comment = false;
- config.show_version = false;
-
- encrypted = await openpgp.encrypt({
- message: openpgp.message.fromText(elFormEncrypt.querySelector('.input').value),
- publicKeys: window.kx.key.object,
- config: config
- });
- 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");
-if (elFormVerify) {
- elFormVerify.onsubmit = async function (evt) {
- evt.preventDefault();
-
- try {
- // Fetch a key if needed
- await fetchProfileKey();
-
- // 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) };
-
- // Verify the signature
- verified = await openpgp.verify({
- message: signature,
- publicKeys: window.kx.key.object
- });
-
- 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}`;
- }
- }
-}
-
-const elFormSearch = document.body.querySelector("#search");
-if (elFormSearch) {
- elFormSearch.onsubmit = function (evt) {
- evt.preventDefault();
-
- const protocol = elFormSearch.querySelector("input[type='radio']:checked").value;
- const identifier = elFormSearch.querySelector("input[type='search']").value;
-
- if (protocol == 'sig') {
- window.location.href = `/${protocol}`;
- } else {
- window.location.href = `/${protocol}/${encodeURIComponent(identifier)}`;
- }
- }
-
- const elSearchRadio = elFormSearch.querySelectorAll("input[type='radio']");
- elSearchRadio.forEach(function (el) {
- el.oninput = function (evt) {
- evt.preventDefault();
-
- if (evt.target.getAttribute('id') === 'protocol-sig') {
- elFormSearch.querySelector("input[type='search']").setAttribute('disabled', true);
- } else {
- elFormSearch.querySelector("input[type='search']").removeAttribute('disabled');
- }
- }
- });
- elFormSearch.querySelector("input[type='radio']:checked").dispatchEvent(new Event('input'));
-}
-
-// Functions
-const fetchProfileKey = async function() {
- if (window.kx.key.object && window.kx.key.object instanceof openpgp.key.Key) {
- return;
- }
-
- const rawKeyData = await fetch(window.kx.key.url)
- let key, errorMsg
-
- try {
- key = (await openpgp.key.read(new Uint8Array(await rawKeyData.clone().arrayBuffer()))).keys[0]
- } catch(error) {
- errorMsg = error.message
- }
-
- if (!key) {
- try {
- key = (await openpgp.key.readArmored(await rawKeyData.clone().text())).keys[0]
- } catch (error) {
- errorMsg = error.message
- }
- }
-
- if (key) {
- window.kx.key.object = key
- return
- } else {
- throw new Error(`Public key could not be fetched (${errorMsg})`)
- }
-}
-
-// Enable QR modal
-const showQR = function(input, type) {
- const qrTarget = document.getElementById('qr');
- const qrContext = qrTarget.getContext('2d');
- const qrOpts = {
- errorCorrectionLevel: 'L',
- margin: 1,
- width: 256,
- height: 256
- };
-
- if (input) {
- if (type === 'url') {
- input = decodeURIComponent(input);
- }
- if (type === 'fingerprint') {
- input = `OPENPGP4FPR:${input.toUpperCase()}`
- }
-
- 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);
- }
-}
diff --git a/static/scripts.util.js b/static/scripts.util.js
deleted file mode 100644
index 8a1ed48..0000000
--- a/static/scripts.util.js
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
-Copyright (C) 2021 Yarmo Mackenbach
-
-This program is free software: you can redistribute it and/or modify it under
-the terms of the GNU Affero General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option)
-any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-details.
-
-You should have received a copy of the GNU Affero General Public License along
-with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
-If your software can interact with users remotely through a computer network,
-you should also make sure that it provides a way for users to get its source.
-For example, if your program is a web application, its interface could display
-a "Source" link that leads users to an archive of the code. There are many
-ways you could offer source, and different solutions will be better for different
-programs; see section 13 for the specific requirements.
-
-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 .
-*/
-async function computeWKDLocalPart(message) {
- const data = openpgp.util.str_to_Uint8Array(message.toLowerCase());
- const hash = await openpgp.crypto.hash.sha1(data);
- return openpgp.util.encodeZBase32(hash);
-}
-async function generateProfileURL(data) {
- let hostname = window.location.hostname;
-
- 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;
- }
-}
-
-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 (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"));
-}
-
-if (elProfileUid) {
- let opts, profileUid = elProfileUid.innerHTML;
- switch (elProfileMode.innerHTML) {
- default:
- case "sig":
- elFormSignatureProfile.onsubmit = function (evt) {
- evt.preventDefault();
-
- opts = {
- input: document.body.querySelector("#plaintext_input").value,
- mode: elProfileMode.innerHTML
- }
-
- displayProfile(opts)
- }
- break;
-
- 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') {
- keyoxide.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"));
-}
diff --git a/static/styles.css b/static/styles.css
deleted file mode 100644
index 279c7e1..0000000
--- a/static/styles.css
+++ /dev/null
@@ -1,741 +0,0 @@
-/*
-Copyright (C) 2021 Yarmo Mackenbach
-
-This program is free software: you can redistribute it and/or modify it under
-the terms of the GNU Affero General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option)
-any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-details.
-
-You should have received a copy of the GNU Affero General Public License along
-with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
-If your software can interact with users remotely through a computer network,
-you should also make sure that it provides a way for users to get its source.
-For example, if your program is a web application, its interface could display
-a "Source" link that leads users to an archive of the code. There are many
-ways you could offer source, and different solutions will be better for different
-programs; see section 13 for the specific requirements.
-
-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 .
-*/
-:root {
- --grey-500: hsl(0, 0%, 50%);
- --grey-600: hsl(0, 0%, 40%);
- --grey-700: hsl(0, 0%, 30%);
- --grey-900: hsl(0, 0%, 10%);
- --green-300: hsl(110, 45%, 70%);
- --green-400: hsl(110, 45%, 60%);
- --green-600: hsl(110, 45%, 40%);
- --red-400: hsl(10, 60%, 60%);
- --blue-500: hsl(201, 80%, 59%);
- --blue-700: hsl(201, 90%, 30%);
- --purple-50: hsl(250, 30%, 98%);
- --purple-100: hsl(250, 48%, 95%);
- --purple-200: hsl(250, 48%, 90%);
- --purple-300: hsl(250, 48%, 85%);
- --purple-400: hsl(250, 48%, 70%);
- --purple-500: hsl(250, 48%, 65%);
- --purple-600: hsl(250, 48%, 60%);
- --purple-700: hsl(250, 48%, 55%);
- --purple-900: hsl(250, 38%, 45%);
- --yellow-100: hsl(56, 100%, 95%);
- --yellow-200: hsl(56, 100%, 90%);
- --yellow-500: hsl(56, 100%, 65%);
-}
-
-* {
- box-sizing: border-box;
-}
-:focus {
- outline: none;
- box-shadow: 0 0 0 3px lightskyblue;
-}
-input:focus, textarea:focus {
- background: azure;
-}
-input[type="radio"]:focus + label {
- box-shadow: 0 0 0 3px lightskyblue;
- background: azure !important;
- color: var(--grey-900) !important;
-}
-body {
- display: flex;
- flex-direction: column;
- min-height: 100vh;
- margin: 0;
- padding: 1.6rem 0 0;
- line-height: 1.4rem;
- font-family: sans-serif;
- color: var(--grey-900);
-}
-
-/* HELPERS */
-.spacer {
- flex: 1;
-}
-.no-margin {
- margin: 0 !important;
-}
-.full-width {
- display: block;
- width: 100% !important;
-}
-
-/* LAYOUT */
-header {
- margin: 0 1.6rem 1.6rem;
-}
-header nav {
- flex: 1;
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- justify-content: center;
- gap: 8px;
-}
-header nav a.logo {
- width: 64px;
- height: 64px;
- font-size: 1.6rem;
- text-transform: uppercase;
- text-decoration: none;
- color: var(--purple-700);
-}
-header nav a.logo img {
- width: 100%;
-}
-nav a.text {
- /* font-size: 0.9em; */
- margin: 0;
- padding: 0.5em 1em;
- text-transform: uppercase;
- text-decoration: none;
- color: var(--purple-700);
- border-radius: 4px;
-}
-nav a.text:hover, nav a.text:active {
- color: #fff;
- background-color: var(--purple-500);
-}
-main {
- flex: 1;
- margin: 0 1.6rem;
-}
-footer {
- margin: 4.8rem 0 0;
- padding: 0 1.6rem 1.6rem;
- background-color: var(--purple-900);
- color: var(--purple-200);
-}
-
-.container {
- width: 100%;
- max-width: 720px;
- margin: 0 auto;
-}
-section.profile p, .demo p {
- font-size: 1.2rem;
-}
-.demo {
- margin: 4.8rem auto;
-}
-
-.card {
- margin: 0 0 1.6rem;
- padding: 0 1.2rem;
- background-color: #fff;
- background-color: var(--purple-50);
- border: 2px solid var(--purple-200);
- border-radius: 4px;
-}
-.card.card--transparent {
- padding-left: 0;
- padding-right: 0;
- background-color: transparent;
- border: 0;
-}
-.card--profileHeader {
- display: flex;
- flex-direction: column;
- flex-wrap: wrap;
- align-items: center;
- gap: 24px;
-}
-.card--profileHeader p, .card--profileHeader small {
- margin: 0;
-}
-.card--small-profile {
- display: flex;
- flex-direction: column;
- text-align: center;
-}
-.card--small-profile-dummy {
- opacity: 0.5;
- border: 0;
-}
-.card--small-profile .name {
- font-size: 1.4em;
-}
-.card--small-profile p {
- margin-top: 0;
-}
-.card--small-profile p span.fingerprint {
- display: inline-block;
- width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- font-size: 0.8rem;
-}
-#profileName {
- font-size: 1.6rem;
- color: var(--grey-700);
-}
-#profileURLFingerprint {
- font-size: 1rem;
- margin: 0 0 1.2rem;
-}
-
-.hcards {
- display: grid;
- grid-gap: 1.2rem;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- margin-bottom: 1.6rem;
-}
-.hcards .card {
- margin: 0;
-}
-.hcards--col-1-2, .hcards--col-2-1 {
- grid-template-columns: repeat(auto-fit, minmax(256px, 1fr));
-}
-.hcards--col-1-2 .card, .hcards--col-2-1 .card {
- grid-column: 1 / 2;
-}
-@media screen and (min-width: 1024px) {
- .hcards--max-3 {
- grid-template-columns: 1fr 1fr 1fr;
- }
- .hcards--col-1-2, .hcards--col-2-1 {
- grid-template-columns: repeat(3, 1fr);
- }
-}
-@media screen and (min-width: 720px) {
- .hcards--col-2-1 .card:nth-of-type(1) {
- grid-column: 1 / -2;
- }
- .hcards--col-2-1 .card:nth-of-type(2) {
- grid-column: -2 / -1;
- }
- .hcards--col-1-2 .card:nth-of-type(1) {
- grid-column: 1 / 2;
- }
- .hcards--col-1-2 .card:nth-of-type(2) {
- grid-column: 2 / -1;
- }
-}
-
-.warning {
- padding: calc(0.8rem - 2px) 0.8rem;
- background-color: var(--yellow-200);
- border: solid 2px var(--yellow-500);
-}
-.warning p:first-of-type {
- margin-top: 0;
-}
-.warning p:last-of-type {
- margin-bottom: 0;
-}
-
-kx-claim {
- display: block;
- margin: 12px 0;
-}
-
-#profileAvatar {
- display: inline-block;
- min-width: 96px;
- max-width: 128px;
- line-height: 0;
- text-align: center;
- border-radius: 50%;
-}
-
-/* TYPOGRAPHY */
-h1 {
- font-size: 1.6em;
- margin: 3.2rem 0 1.6rem;
- font-weight: normal;
- color: var(--purple-700);
- cursor: default;
-}
-h2 {
- font-size: 1.4em;
- margin: 3.2rem 0 1.6rem;
- font-weight: normal;
- color: var(--purple-700);
- cursor: default;
-}
-h2 small {
- margin-left: 0.8rem;
- padding: 3px 6px;
- background-color: var(--purple-600);
- color: #fff;
- border-radius: 4px;
-}
-h3 {
- margin: 1.6rem 0;
- font-size: 1.3em;
- line-height: 1.6rem;
- color: var(--grey-700);
- font-weight: normal;
- /* text-align: center; */
- cursor: default;
-}
-h3 small {
- margin-left: 0.8rem;
- padding: 3px 6px;
- background-color: var(--purple-400);
- color: #fff;
- border-radius: 4px;
-}
-h4 {
- margin: 1.6rem 0;
- font-size: 1em;
- line-height: 1.6rem;
- color: var(--grey-600);
- /* color: var(--purple-700); */
- font-weight: bold;
- cursor: default;
-}
-h4 small {
- margin-left: 0.8rem;
- padding: 3px 6px;
- background-color: var(--purple-400);
- color: #fff;
- border-radius: 4px;
-}
-p {
- margin: 1.6rem 0;
-}
-p.warning {
- padding: 8px;
- background-color: #fffadc;
- border: solid 1px #ffeea8;
-}
-a {
- color: var(--blue-700);
-}
-ul {
- padding-left: 1em;
- list-style: '- ';
-}
-main h1:first-of-type {
- margin-top: 1.6rem;
-}
-footer h1 {
- margin-bottom: 0.8rem;
- color: var(--purple-200);
- font-size: 1.2rem;
- font-weight: bold;
-}
-footer a {
- display: inline-block;
- color: var(--purple-100);
- height: 32px;
-}
-
-code {
- padding: 2px 4px;
- background-color: var(--purple-100);
- border: 1px solid var(--purple-500);
-}
-pre {
- padding: 8px 12px;
- background-color: var(--purple-100);
- border: 1px solid var(--purple-500);
- overflow-x: auto;
- line-height: 1.2rem;
- font-size: 1rem;
-}
-pre code {
- padding: 0;
- background-color: 0px;
- border: 0px;
-}
-
-#qr {
- display: block;
- width: 100% !important;
- max-width: 256px !important;
- height: auto !important;
- margin: 0 auto 16px;
-}
-
-/* FORM ELEMENTS */
-.form-wrapper {
- align-items: center;
- padding-top: 1.4rem;
- padding-bottom: 1.6rem;
- margin-bottom: 48px;
-}
-.form-wrapper form {
- display: flex;
- flex-direction: column;
- margin: 0;
-}
-.form-wrapper h2 {
- margin-top: 0;
-}
-form input[type="text"], form input[type="search"] {
- margin: 8px 0;
- padding: 4px;
- border: 1px solid #444;
- font-size: 0.9rem;
-}
-form textarea {
- width: 100%;
- height: 128px;
- margin: 8px 0;
- resize: vertical;
- font-size: 0.9rem;
- border: 1px solid #444;
-}
-.button-wrapper {
- display: flex;
- flex-wrap: wrap;
- gap: 8px;
- margin: 8px 0;
-}
-.radio-wrapper {
- display: flex;
- flex-wrap: wrap;
- margin: 8px 0;
-}
-.radio-wrapper input[type="radio"] {
- position: absolute;
- opacity: 0;
- z-index: -1;
-}
-.radio-wrapper input[type="radio"] + label {
- margin: 0;
- padding: 2px 8px;
- background-color: #fff;
- border: solid var(--purple-400);
- border-width: 2px 1px;
- cursor: pointer;
-}
-.radio-wrapper input[type="radio"]:first-of-type + label {
- border-radius: 4px 0 0 4px;
- border-left-width: 2px;
-}
-.radio-wrapper input[type="radio"]:last-of-type + label {
- border-radius: 0 4px 4px 0;
- border-right-width: 2px;
-}
-.radio-wrapper input[type="radio"]:focus + label {
- z-index: 1;
-}
-.radio-wrapper input[type="radio"] + label:hover {
- background-color: var(--purple-100);
- border-color: var(--purple-500);
-}
-.radio-wrapper input[type="radio"]:checked + label {
- color: #fff;
- background-color: var(--purple-600);
- border-color: var(--purple-600);
-}
-
-input[type="button"], input[type="submit"], button, a.button {
- display: inline-block;
- min-height: 36px;
- margin: 8px 0;
- padding: 4px 8px;
- font-family: sans-serif;
- font-size: 0.9rem;
- text-decoration: none;
- text-transform: uppercase;
- color: #333;
- background-color: #fff;
- border: solid 2px var(--purple-400);
- border-radius: 4px;
- cursor: pointer;
-}
-input[type="button"]:focus, input[type="submit"]:focus, button:focus, a.button:focus {
- background-color: azure;
-}
-input[type="button"]:hover, input[type="submit"]:hover, button:hover, a.button:hover {
- background-color: var(--purple-500);
- border-color: var(--purple-500);
- color: #fff;
-}
-a.button i {
- font-size: 1.4em;
-}
-a.button.button--liberapay {
- padding: 8px 16px;
- font-size: 0.95rem;
- color: #333;
- background-color: #ffee16;
- border: 0;
-}
-a.button.button--liberapay:hover {
- background-color: #fff463;
-}
-
-/* DIALOGS */
-dialog {
- width: 100% !important;
- max-width: 800px !important;
- padding: 0 !important;
- word-wrap: anywhere;
-}
-dialog > div {
- padding: 1em;
-}
-dialog form[method="Dialog"] {
- margin: 1em 0 0 !important;
-}
-dialog form[method="Dialog"] input {
- width: auto;
-}
-dialog p {
- font-size: 1rem !important;
- margin: 1rem 0;
-}
-dialog p:first-of-type {
- margin-top: 0;
-}
-
-/* KX-ITEM */
-.kx-item details {
- width: 100%;
- border-radius: 8px;
-}
-.kx-item details p {
- margin: 0;
- word-break: break-word;
- font-size: 1rem;
-}
-.kx-item details a {
- color: var(--blue-700);
-}
-.kx-item details hr {
- border: none;
- border-top: 2px solid var(--purple-100);
-}
-.kx-item details .content {
- padding: 12px;
- border: solid 3px var(--purple-100);
- border-top: 0px;
- border-radius: 0px 0px 8px 8px;
-}
-.kx-item details summary {
- display: flex;
- align-items: center;
- padding: 8px 12px;
- background-color: var(--purple-100);
- border: solid 3px var(--purple-100);
- border-radius: 8px;
- list-style: none;
- cursor: pointer;
-}
-.kx-item details summary::-webkit-details-marker {
- display: none;
-}
-.kx-item details summary:hover, summary:focus {
- border-color: var(--purple-400);
-}
-details[open] summary {
- border-radius: 8px 8px 0px 0px;
-}
-.kx-item details summary .info {
- flex: 1;
-}
-.kx-item details summary .info .title {
- font-size: 1.1em;
-}
-.kx-item details summary .claim__description p {
- font-size: 1.4rem;
- line-height: 2rem;
-}
-.kx-item details summary .claim__links p, p.subtle-links {
- display: flex;
- align-items: center;
- flex-wrap: wrap;
- font-size: 1rem;
- color: var(--grey-700);
-}
-.kx-item details summary .claim__links a, summary .claim__links span, p.subtle-links a {
- font-size: 1rem;
- margin: 0 10px 0 0;
- color: var(--grey-700);
-}
-.kx-item details summary .subtitle {
- color: var(--purple-700);
-}
-.kx-item details summary .verificationStatus {
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
- width: 48px;
- height: 48px;
- border-radius: 100%;
- color: #fff;
- font-size: 2rem;
- user-select: none;
-}
-.kx-item details summary .verificationStatus::after {
- position: absolute;
- display: flex;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- align-items: center;
- justify-content: center;
-}
-.kx-item details summary .verificationStatus .inProgress {
- opacity: 0;
- transition: opacity 0.4s ease;
- pointer-events: none;
-}
-.kx-item details summary .verificationStatus[data-value="success"] {
- content: "v";
- background-color: var(--green-600);
-}
-.kx-item details summary .verificationStatus[data-value="success"]::after {
- content: "✔";
-}
-.kx-item details summary .verificationStatus[data-value="failed"] {
- background-color: var(--red-400);
-}
-.kx-item details summary .verificationStatus[data-value="failed"]::after {
- content: "✕";
-}
-.kx-item details summary .verificationStatus[data-value="running"] .inProgress {
- opacity: 1;
-}
-
-.kx-item details .subsection {
- display: flex;
- align-items: center;
- gap: 16px;
-}
-.kx-item details .subsection > img {
- width: 24px;
- height: 24px;
- opacity: 0.4;
-}
-
-.kx-item details .inProgress {
- font-size: 10px;
- margin: 50px auto;
- text-indent: -9999em;
- width: 48px;
- height: 48px;
- border-radius: 50%;
- background: var(--purple-400);
- background: -moz-linear-gradient(left, var(--purple-400) 10%, rgba(255, 255, 255, 0) 42%);
- background: -webkit-linear-gradient(left, var(--purple-400) 10%, rgba(255, 255, 255, 0) 42%);
- background: -o-linear-gradient(left, var(--purple-400) 10%, rgba(255, 255, 255, 0) 42%);
- background: -ms-linear-gradient(left, var(--purple-400) 10%, rgba(255, 255, 255, 0) 42%);
- background: linear-gradient(to right, var(--purple-400) 10%, rgba(255, 255, 255, 0) 42%);
- position: relative;
- -webkit-animation: load3 1.4s infinite linear;
- animation: load3 1.4s infinite linear;
- -webkit-transform: translateZ(0);
- -ms-transform: translateZ(0);
- transform: translateZ(0);
-}
-.kx-item details .inProgress:before {
- width: 50%;
- height: 50%;
- background: var(--purple-400);
- border-radius: 100% 0 0 0;
- position: absolute;
- top: 0;
- left: 0;
- content: '';
-}
-.kx-item details .inProgress:after {
- background: var(--purple-100);
- width: 65%;
- height: 65%;
- border-radius: 50%;
- content: '';
- margin: auto;
- position: absolute;
- top: 0;
- left: 0;
- bottom: 0;
- right: 0;
-}
-.kx-item details button {
- padding: 0.4rem 0.8rem;
- margin-right: 8px;
- text-decoration: none;
- text-transform: uppercase;
- background-color: #fff;
- border: solid 2px var(--purple-400);
- border-radius: 4px;
- cursor: pointer;
-}
-.kx-item details button:hover {
- background-color: var(--purple-500);
- border-color: var(--purple-500);
- color: #fff;
-}
-
-@media screen and (max-width: 640px) {
- .kx-item details summary .claim__description p {
- font-size: 1.2rem;
- }
- .kx-item details summary .claim__links a, p.subtle-links a {
- font-size: 0.9rem;
- }
-}
-@media screen and (max-width: 480px) {
- summary .claim__description p {
- font-size: 1rem;
- }
- .kx-item details summary .verificationStatus {
- width: 36px;
- height: 36px;
- font-size: 1.6rem;
- }
- .kx-item details .inProgress {
- width: 36px;
- height: 36px;
- }
-}
-
-@-webkit-keyframes load3 {
- 0% {
- -webkit-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(360deg);
- transform: rotate(360deg);
- }
-}
-@keyframes load3 {
- 0% {
- -webkit-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(360deg);
- transform: rotate(360deg);
- }
-}