mirror of
https://codeberg.org/keyoxide/keyoxide-web.git
synced 2025-01-10 07:19:27 -07:00
Integrate encrypt and verify into profiles
This commit is contained in:
parent
890efda4b1
commit
6616b7543c
9 changed files with 95 additions and 395 deletions
3
index.js
3
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'));
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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')
|
|
@ -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')
|
||||
|
|
|
@ -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')
|
Loading…
Reference in a new issue