From 6616b7543c1063d617668a6dac817199ff7e9230 Mon Sep 17 00:00:00 2001
From: Yarmo Mackenbach
Date: Mon, 5 Apr 2021 15:51:43 +0200
Subject: [PATCH] Integrate encrypt and verify into profiles
---
index.js | 3 -
routes/encrypt.js | 68 -----------------
routes/proofs.js | 68 -----------------
routes/verify.js | 68 -----------------
static/scripts.js | 190 ++++++++++++++--------------------------------
static/styles.css | 24 ++++--
views/encrypt.pug | 22 ------
views/profile.pug | 22 +++++-
views/verify.pug | 25 ------
9 files changed, 95 insertions(+), 395 deletions(-)
delete mode 100644 routes/encrypt.js
delete mode 100644 routes/proofs.js
delete mode 100644 routes/verify.js
delete mode 100644 views/encrypt.pug
delete mode 100644 views/verify.pug
diff --git a/index.js b/index.js
index fab1499..bb8bbfe 100644
--- a/index.js
+++ b/index.js
@@ -55,9 +55,6 @@ app.use(stringReplace({
app.use('/', require('./routes/main'));
app.use('/static', require('./routes/static'));
app.use('/server', require('./routes/server'));
-app.use('/encrypt', require('./routes/encrypt'));
-app.use('/verify', require('./routes/verify'));
-app.use('/proofs', require('./routes/proofs'));
app.use('/util', require('./routes/util'));
app.use('/', require('./routes/profile'));
diff --git a/routes/encrypt.js b/routes/encrypt.js
deleted file mode 100644
index 873f32f..0000000
--- a/routes/encrypt.js
+++ /dev/null
@@ -1,68 +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 .
-*/
-const router = require('express').Router();
-
-router.get('/', function(req, res) {
- res.render('encrypt', { mode: "auto" })
-});
-
-router.get('/wkd', function(req, res) {
- res.render('encrypt', { mode: "wkd" })
-});
-router.get('/wkd/:input', function(req, res) {
- res.render('encrypt', { mode: "wkd", input: req.params.input })
-});
-
-router.get('/hkp', function(req, res) {
- res.render('encrypt', { mode: "hkp" })
-});
-router.get('/hkp/:input', function(req, res) {
- res.render('encrypt', { mode: "hkp", input: req.params.input })
-});
-
-router.get('/plaintext', function(req, res) {
- res.render('encrypt', { mode: "plaintext" })
-});
-
-router.get('/keybase', function(req, res) {
- res.render('encrypt', { mode: "keybase" })
-});
-router.get('/keybase/:username', function(req, res) {
- res.render('encrypt', { mode: "keybase", username: req.params.username })
-});
-router.get('/keybase/:username/:fingerprint', function(req, res) {
- res.render('encrypt', { mode: "keybase", username: req.params.username, fingerprint: req.params.fingerprint })
-});
-
-router.get('/:input', function(req, res) {
- res.render('encrypt', { mode: "auto", input: req.params.input })
-});
-
-module.exports = router;
diff --git a/routes/proofs.js b/routes/proofs.js
deleted file mode 100644
index 2130617..0000000
--- a/routes/proofs.js
+++ /dev/null
@@ -1,68 +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 .
-*/
-const router = require('express').Router();
-
-router.get('/', function(req, res) {
- res.render('proofs', { mode: "auto" })
-});
-
-router.get('/wkd', function(req, res) {
- res.render('proofs', { mode: "wkd" })
-});
-router.get('/wkd/:input', function(req, res) {
- res.render('proofs', { mode: "wkd", input: req.params.input })
-});
-
-router.get('/hkp', function(req, res) {
- res.render('proofs', { mode: "hkp" })
-});
-router.get('/hkp/:input', function(req, res) {
- res.render('proofs', { mode: "hkp", input: req.params.input })
-});
-
-router.get('/plaintext', function(req, res) {
- res.render('proofs', { mode: "plaintext" })
-});
-
-router.get('/keybase', function(req, res) {
- res.render('proofs', { mode: "keybase" })
-});
-router.get('/keybase/:username', function(req, res) {
- res.render('proofs', { mode: "keybase", username: req.params.username })
-});
-router.get('/keybase/:username/:fingerprint', function(req, res) {
- res.render('proofs', { mode: "keybase", username: req.params.username, fingerprint: req.params.fingerprint })
-});
-
-router.get('/:input', function(req, res) {
- res.render('proofs', { mode: "auto", input: req.params.input })
-});
-
-module.exports = router;
diff --git a/routes/verify.js b/routes/verify.js
deleted file mode 100644
index 25361e3..0000000
--- a/routes/verify.js
+++ /dev/null
@@ -1,68 +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 .
-*/
-const router = require('express').Router();
-
-router.get('/', function(req, res) {
- res.render('verify', { mode: "auto" })
-});
-
-router.get('/wkd', function(req, res) {
- res.render('verify', { mode: "wkd" })
-});
-router.get('/wkd/:input', function(req, res) {
- res.render('verify', { mode: "wkd", input: req.params.input })
-});
-
-router.get('/hkp', function(req, res) {
- res.render('verify', { mode: "hkp" })
-});
-router.get('/hkp/:input', function(req, res) {
- res.render('verify', { mode: "hkp", input: req.params.input })
-});
-
-router.get('/plaintext', function(req, res) {
- res.render('verify', { mode: "plaintext" })
-});
-
-router.get('/keybase', function(req, res) {
- res.render('verify', { mode: "keybase" })
-});
-router.get('/keybase/:username', function(req, res) {
- res.render('verify', { mode: "keybase", username: req.params.username })
-});
-router.get('/keybase/:username/:fingerprint', function(req, res) {
- res.render('verify', { mode: "keybase", username: req.params.username, fingerprint: req.params.fingerprint })
-});
-
-router.get('/:input', function(req, res) {
- res.render('verify', { mode: "auto", input: req.params.input })
-});
-
-module.exports = router;
diff --git a/static/scripts.js b/static/scripts.js
index ad99df0..aab38a9 100644
--- a/static/scripts.js
+++ b/static/scripts.js
@@ -215,8 +215,8 @@ async function displayProfile(opts) {
${data.fingerprint}
`;
@@ -262,7 +262,6 @@ async function displayProfile(opts) {
// Generate output for each claim
claims.forEach((claim, i) => {
- console.log(claim);
const claimData = claim.serviceproviderData;
if (!claimData.serviceprovider.name) {
return;
@@ -592,6 +591,59 @@ async function displayProfile(opts) {
d.close();
});
});
+
+ // Register form listeners
+ const elFormEncrypt = document.body.querySelector("#dialog--encryptMessage form");
+ elFormEncrypt.onsubmit = async function (evt) {
+ evt.preventDefault();
+
+ 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();
+
+ 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) };
+
+ // Verify the signature
+ verified = await openpgp.verify({
+ message: signature,
+ publicKeys: keyData
+ });
+
+ 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}`;
+ }
+ };
}
async function fetchKeys(opts) {
@@ -747,10 +799,7 @@ async function fetchWithTimeout(url, timeout = 3000) {
}
// General purpose
-let elFormVerify = document.body.querySelector("#form-verify"),
- elFormEncrypt = document.body.querySelector("#form-encrypt"),
- elFormProofs = document.body.querySelector("#form-proofs"),
- elFormSignatureProfile = document.body.querySelector("#form-generate-signature-profile"),
+let elFormSignatureProfile = document.body.querySelector("#formGenerateSignatureProfile"),
elProfileUid = document.body.querySelector("#profileUid"),
elProfileMode = document.body.querySelector("#profileMode"),
elProfileServer = document.body.querySelector("#profileServer"),
@@ -771,133 +820,6 @@ if (elModeSelect) {
elModeSelect.dispatchEvent(new Event("change"));
}
-if (elFormVerify) {
- elFormVerify.onsubmit = function (evt) {
- evt.preventDefault();
-
- let opts = {
- signature: null,
- mode: null,
- input: null,
- server: null,
- };
-
- opts.signature = document.body.querySelector("#signature").value;
- opts.mode = document.body.querySelector("#modeSelect").value;
-
- switch (opts.mode) {
- default:
- case "auto":
- opts.input = document.body.querySelector("#auto_input").value;
- break;
-
- case "wkd":
- opts.input = document.body.querySelector("#wkd_input").value;
- break;
-
- case "hkp":
- opts.input = document.body.querySelector("#hkp_input").value;
- opts.server = document.body.querySelector("#hkp_server").value;
- break;
-
- case "plaintext":
- opts.input = document.body.querySelector("#plaintext_input").value;
- break;
-
- case "keybase":
- opts.username = document.body.querySelector("#keybase_username").value;
- opts.fingerprint = document.body.querySelector("#keybase_fingerprint").value;
- break;
- }
-
- // If no input was detect
- if (!opts.input && !opts.username) {
- opts.mode = "signature";
- }
-
- verifySignature(opts);
- };
-}
-
-if (elFormEncrypt) {
- elFormEncrypt.onsubmit = function (evt) {
- evt.preventDefault();
-
- let opts = {
- message: null,
- mode: null,
- input: null,
- server: null,
- };
-
- opts.message = document.body.querySelector("#message").value;
- opts.mode = document.body.querySelector("#modeSelect").value;
-
- switch (opts.mode) {
- default:
- case "auto":
- opts.input = document.body.querySelector("#auto_input").value;
- break;
-
- case "wkd":
- opts.input = document.body.querySelector("#wkd_input").value;
- break;
-
- case "hkp":
- opts.input = document.body.querySelector("#hkp_input").value;
- opts.server = document.body.querySelector("#hkp_server").value;
- break;
-
- case "plaintext":
- opts.input = document.body.querySelector("#plaintext_input").value;
- break;
-
- case "keybase":
- opts.username = document.body.querySelector("#keybase_username").value;
- opts.fingerprint = document.body.querySelector("#keybase_fingerprint").value;
- break;
- }
-
- encryptMessage(opts);
- };
-}
-
-if (elFormProofs) {
- elFormProofs.onsubmit = function (evt) {
- evt.preventDefault();
-
- let opts = {
- mode: null,
- input: null,
- server: null,
- };
-
- opts.mode = document.body.querySelector("#modeSelect").value;
-
- switch (opts.mode) {
- default:
- case "auto":
- opts.input = document.body.querySelector("#auto_input").value;
- break;
-
- case "wkd":
- opts.input = document.body.querySelector("#wkd_input").value;
- break;
-
- case "hkp":
- opts.input = document.body.querySelector("#hkp_input").value;
- opts.server = document.body.querySelector("#hkp_server").value;
- break;
-
- case "plaintext":
- opts.input = document.body.querySelector("#plaintext_input").value;
- break;
- }
-
- verifyProofs(opts);
- };
-}
-
if (elProfileUid) {
let opts, profileUid = elProfileUid.innerHTML;
switch (elProfileMode.innerHTML) {
diff --git a/static/styles.css b/static/styles.css
index 924dfc2..addf920 100644
--- a/static/styles.css
+++ b/static/styles.css
@@ -337,8 +337,7 @@ section.profile p, .demo p {
border-radius: 24px;
}
-.buttons {
- /* margin: 2.4rem 0; */
+/* .buttons {
margin: 1.2rem 0;
}
.buttons a {
@@ -353,7 +352,7 @@ section.profile p, .demo p {
}
.buttons a:hover {
background-color: #ccc;
-}
+} */
.modes {
display: none;
}
@@ -495,8 +494,9 @@ form .modesContainer input {
}
form input[type="submit"] {
display: block;
- width: 100%;
+ /* width: 100%; */
padding: 0.4rem 0.8rem;
+ margin: 8px 8px 12px 0;
text-decoration: none;
text-transform: uppercase;
background-color: #fff;
@@ -504,10 +504,24 @@ form input[type="submit"] {
border-radius: 4px;
cursor: pointer;
}
-form input[type="submit"]:hover {
+button {
+ padding: 0.4rem 0.8rem;
+ margin-right: 8px;
+ text-decoration: none;
+ text-transform: uppercase;
+ background-color: #fff;
+ border: solid 1px var(--blue-700);
+ border-radius: 4px;
+ cursor: pointer;
+}
+form input[type="submit"]:hover, button:hover {
background-color: var(--blue-700);
color: #fff;
}
+.card--form form {
+ background-color: var(--purple-100) !important;
+ padding: 1rem;
+}
dialog {
width: 100% !important;
diff --git a/views/encrypt.pug b/views/encrypt.pug
deleted file mode 100644
index 61d3d5e..0000000
--- a/views/encrypt.pug
+++ /dev/null
@@ -1,22 +0,0 @@
-extends templates/base.pug
-
-block js
- 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/scripts.js' charset='utf-8')
-
-block content
- section.narrow
- noscript
- p Keyoxide requires JavaScript to function.
-
- h1 Encrypt
- form#form-encrypt(method='post')
- h3 Recipient
- label(for='modeSelect') Mode:
- include partials/key_selector
-
- h3 Message
- textarea#message(name='message')
- p#result
- input.bigBtn(type='submit' name='submit' value='ENCRYPT MESSAGE')
diff --git a/views/profile.pug b/views/profile.pug
index d5b1560..e183ad6 100644
--- a/views/profile.pug
+++ b/views/profile.pug
@@ -17,11 +17,29 @@ block content
span#profileServer(style='display: none;') #{server}
span#profileMode(style='display: none;') #{mode}
+ dialog#dialog--encryptMessage
+ div
+ form(method='post')
+ textarea.input(name='message' placeholder='Message')
+ input(type='submit' name='submit' value='ENCRYPT MESSAGE')
+ textarea.output(name='message' placeholder='Waiting for input' readonly)
+ form(method="dialog")
+ input(type="submit" value="Close")
+
+ dialog#dialog--verifySignature
+ div
+ form(method='post')
+ textarea.input(name='signature' placeholder='Signature')
+ input(type='submit' name='submit' value='VERIFY SIGNATURE')
+ textarea.output(name='message' placeholder='Waiting for input' readonly)
+ form(method="dialog")
+ input(type="submit" value="Close")
+
#profileDialogs
if (mode == 'sig')
- #profileSigInput.card
- form#form-generate-signature-profile(method='post')
+ #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')
diff --git a/views/verify.pug b/views/verify.pug
deleted file mode 100644
index d50f8a9..0000000
--- a/views/verify.pug
+++ /dev/null
@@ -1,25 +0,0 @@
-extends templates/base.pug
-
-block js
- 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/scripts.js' charset='utf-8')
-
-block content
- section.narrow
- noscript
- p Keyoxide requires JavaScript to function.
-
- h1 Verify
- form#form-verify(method='post')
- h3 Signer
- label(for='modeSelect') Mode:
- include partials/key_selector
-
- h3 Signature
- textarea#signature(name='signature')
-
- h3 Result
- p#result
- p#resultContent
- input.bigBtn(type='submit' name='submit' value='VERIFY SIGNATURE')