Integrate encrypt and verify into profiles

This commit is contained in:
Yarmo Mackenbach 2021-04-05 15:51:43 +02:00
parent 890efda4b1
commit 6616b7543c
No known key found for this signature in database
GPG key ID: 37367F4AF4087AD1
9 changed files with 95 additions and 395 deletions

View file

@ -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'));

View file

@ -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 <https://www.gnu.org/licenses/>.
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 <https://www.gnu.org/licenses/>.
*/
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;

View file

@ -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 <https://www.gnu.org/licenses/>.
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 <https://www.gnu.org/licenses/>.
*/
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;

View file

@ -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 <https://www.gnu.org/licenses/>.
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 <https://www.gnu.org/licenses/>.
*/
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;

View file

@ -215,8 +215,8 @@ async function displayProfile(opts) {
<a href="${data.key.url}">${data.fingerprint}</a>
</p>
<div class="buttons">
<a href="/encrypt/${data.key.mode}/${data.key.id}">Encrypt message</a>
<a href="/verify/${data.key.mode}/${data.key.id}">Verify signature</a>
<button onClick="document.querySelector('#dialog--encryptMessage').showModal();">Encrypt message</button>
<button onClick="document.querySelector('#dialog--verifySignature').showModal();">Verify signature</button>
</div>
</div>
`;
@ -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) {

View file

@ -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;

View file

@ -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')

View file

@ -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')

View file

@ -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')