Merge pull request 'Add support for keys hosted on keybase' (#9) from keybase-integration into dev

Reviewed-on: https://codeberg.org/yarmo/keyoxide/pulls/9
This commit is contained in:
yarmo 2020-07-05 15:10:33 +02:00
commit e7f3dccfcf
4 changed files with 107 additions and 31 deletions

View file

@ -205,37 +205,45 @@ async function displayProfile(opts) {
let userData = keyData.user.user.userId; let userData = keyData.user.user.userId;
// Determine WKD or HKP link // Determine WKD or HKP link
if (opts.mode == "wkd") { switch (opts.mode) {
const [, localPart, domain] = /(.*)@(.*)/.exec(opts.input); case "wkd":
const localEncoded = await computeWKDLocalPart(localPart.toLowerCase()); const [, localPart, domain] = /(.*)@(.*)/.exec(opts.input);
const urlAdvanced = `https://openpgpkey.${domain}/.well-known/openpgpkey/${domain}/hu/${localEncoded}`; const localEncoded = await computeWKDLocalPart(localPart.toLowerCase());
const urlDirect = `https://${domain}/.well-known/openpgpkey/hu/${localEncoded}`; const urlAdvanced = `https://openpgpkey.${domain}/.well-known/openpgpkey/${domain}/hu/${localEncoded}`;
const urlDirect = `https://${domain}/.well-known/openpgpkey/hu/${localEncoded}`;
try {
keyLink = await fetch(urlAdvanced).then(function(response) {
if (response.status === 200) {
return urlAdvanced;
}
});
} catch (e) {
console.warn(e);
}
if (!keyLink) {
try { try {
keyLink = await fetch(urlDirect).then(function(response) { keyLink = await fetch(urlAdvanced).then(function(response) {
if (response.status === 200) { if (response.status === 200) {
return urlDirect; return urlAdvanced;
} }
}); });
} catch (e) { } catch (e) {
console.warn(e); console.warn(e);
} }
} if (!keyLink) {
if (!keyLink) { try {
keyLink = await fetch(urlDirect).then(function(response) {
if (response.status === 200) {
return urlDirect;
}
});
} catch (e) {
console.warn(e);
}
}
if (!keyLink) {
keyLink = `https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=0x${keyData.fingerprint}`;
}
break;
case "hkp":
keyLink = `https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=0x${keyData.fingerprint}`; keyLink = `https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=0x${keyData.fingerprint}`;
} break;
} else {
keyLink = `https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=0x${keyData.fingerprint}`; case "keybase":
keyLink = opts.keyLink;
break;
} }
// Fill in various data // Fill in various data
@ -261,10 +269,13 @@ async function displayProfile(opts) {
feedback += `<div class="profileDataItem__label">fingerprint</div>`; feedback += `<div class="profileDataItem__label">fingerprint</div>`;
feedback += `<div class="profileDataItem__value"><a href="${keyLink}">${keyData.fingerprint}</a></div>`; feedback += `<div class="profileDataItem__value"><a href="${keyLink}">${keyData.fingerprint}</a></div>`;
feedback += `</div>`; feedback += `</div>`;
feedback += `<div class="profileDataItem">`;
feedback += `<div class="profileDataItem__label">qrcode</div>`; if (opts.mode == "hkp") {
feedback += `<div class="profileDataItem__value"><a href="/util/qr/${keyData.fingerprint}">fingerprint</a></div>`; feedback += `<div class="profileDataItem">`;
feedback += `</div>`; feedback += `<div class="profileDataItem__label">qrcode</div>`;
feedback += `<div class="profileDataItem__value"><a href="/util/qr/${keyData.fingerprint}">fingerprint</a></div>`;
feedback += `</div>`;
}
if (keyData.notations.length > 0) { if (keyData.notations.length > 0) {
feedback += `<div class="profileDataItem profileDataItem--separator profileDataItem--noLabel">`; feedback += `<div class="profileDataItem profileDataItem--separator profileDataItem--noLabel">`;
@ -589,6 +600,27 @@ async function fetchKeys(opts) {
} }
break; break;
case "keybase":
opts.keyLink = `https://keybase.io/${opts.username}/pgp_keys.asc?fingerprint=${opts.fingerprint}`;
opts.input = `${opts.username}/${opts.fingerprint}`;
try {
opts.plaintext = await fetch(opts.keyLink).then(function(response) {
if (response.status === 200) {
return response;
}
})
.then(response => response.blob())
.then(response => response.text());
} catch (e) {
throw("Error: No public keys could be fetched from the Keybase account.");
}
output.publicKey = (await openpgp.key.readArmored(opts.plaintext)).keys[0];
if (!output.publicKey) {
throw("Error: No public keys could be read from the Keybase account.");
}
break;
case "signature": case "signature":
sig = (await openpgp.signature.readArmored(opts.signature)); sig = (await openpgp.signature.readArmored(opts.signature));
if ('compressed' in sig.packets[0]) { if ('compressed' in sig.packets[0]) {
@ -738,10 +770,15 @@ if (elFormVerify) {
case "plaintext": case "plaintext":
opts.input = document.body.querySelector("#plaintext_input").value; opts.input = document.body.querySelector("#plaintext_input").value;
break; 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 no input was detect
if (!opts.input) { if (!opts.input && !opts.username) {
opts.mode = "signature"; opts.mode = "signature";
} }
@ -781,6 +818,11 @@ if (elFormEncrypt) {
case "plaintext": case "plaintext":
opts.input = document.body.querySelector("#plaintext_input").value; opts.input = document.body.querySelector("#plaintext_input").value;
break; break;
case "keybase":
opts.username = document.body.querySelector("#keybase_username").value;
opts.fingerprint = document.body.querySelector("#keybase_fingerprint").value;
break;
} }
encryptMessage(opts); encryptMessage(opts);
@ -850,6 +892,15 @@ if (elProfileUid) {
mode: elProfileMode.innerHTML mode: elProfileMode.innerHTML
} }
break; break;
case "keybase":
let match = profileUid.match(/(.*)\/(.*)/);
opts = {
username: match[1],
fingerprint: match[2],
mode: elProfileMode.innerHTML
}
break;
} }
displayProfile(opts); displayProfile(opts);
} }

View file

@ -21,16 +21,19 @@ $router->map('GET', '/verify', function() {}, 'verify');
$router->map('GET', '/encrypt', function() {}, 'encrypt'); $router->map('GET', '/encrypt', function() {}, 'encrypt');
$router->map('GET', '/proofs', function() {}, 'proofs'); $router->map('GET', '/proofs', function() {}, 'proofs');
$router->map('GET', '/verify/hkp/[**:uid]', function() {}, 'verifyHKP'); $router->map('GET', '/verify/hkp/[**:uid]', function() {}, 'verifyHKP');
$router->map('GET', '/encrypt/hkp/[**:uid]', function() {}, 'encryptHKP');
$router->map('GET', '/proofs/hkp/[**:uid]', function() {}, 'proofsHKP');
$router->map('GET', '/verify/wkd/[**:uid]', function() {}, 'verifyWKD'); $router->map('GET', '/verify/wkd/[**:uid]', function() {}, 'verifyWKD');
$router->map('GET', '/encrypt/wkd/[**:uid]', function() {}, 'encryptWKD'); $router->map('GET', '/verify/keybase/[:uid]/[:fp]', function() {}, 'verifyKeybase');
$router->map('GET', '/proofs/wkd/[**:uid]', function() {}, 'proofsWKD');
$router->map('GET', '/verify/[**:uid]', function() {}, 'verifyAUTO'); $router->map('GET', '/verify/[**:uid]', function() {}, 'verifyAUTO');
$router->map('GET', '/encrypt/hkp/[**:uid]', function() {}, 'encryptHKP');
$router->map('GET', '/encrypt/wkd/[**:uid]', function() {}, 'encryptWKD');
$router->map('GET', '/encrypt/keybase/[:uid]/[:fp]', function() {}, 'encryptKeybase');
$router->map('GET', '/encrypt/[**:uid]', function() {}, 'encryptAUTO'); $router->map('GET', '/encrypt/[**:uid]', function() {}, 'encryptAUTO');
$router->map('GET', '/proofs/hkp/[**:uid]', function() {}, 'proofsHKP');
$router->map('GET', '/proofs/wkd/[**:uid]', function() {}, 'proofsWKD');
$router->map('GET', '/proofs/[**:uid]', function() {}, 'proofsAUTO'); $router->map('GET', '/proofs/[**:uid]', function() {}, 'proofsAUTO');
$router->map('GET', '/hkp/[**:uid]', function() {}, 'profileHKP'); $router->map('GET', '/hkp/[**:uid]', function() {}, 'profileHKP');
$router->map('GET', '/wkd/[**:uid]', function() {}, 'profileWKD'); $router->map('GET', '/wkd/[**:uid]', function() {}, 'profileWKD');
$router->map('GET', '/keybase/[:uid]/[:fp]', function() {}, 'profileKeybase');
$router->map('GET', '/[**:uid]', function() {}, 'profile'); $router->map('GET', '/[**:uid]', function() {}, 'profile');
// Router matching // Router matching
@ -59,6 +62,10 @@ if(is_array($match) && is_callable($match['target'])) {
echo $templates->render('verify', ['title' => 'Verify — ', 'mode' => 'wkd', 'wkd_input' => $match['params']['uid']]); echo $templates->render('verify', ['title' => 'Verify — ', 'mode' => 'wkd', 'wkd_input' => $match['params']['uid']]);
break; break;
case 'verifyKeybase':
echo $templates->render('verify', ['title' => 'Verify — ', 'mode' => 'keybase', 'keybase_username' => htmlspecialchars($match['params']['uid']), 'keybase_fingerprint' => htmlspecialchars($match['params']['fp'])]);
break;
case 'encrypt': case 'encrypt':
echo $templates->render('encrypt', ['title' => 'Encrypt — ', 'mode' => 'auto']); echo $templates->render('encrypt', ['title' => 'Encrypt — ', 'mode' => 'auto']);
break; break;
@ -75,6 +82,10 @@ if(is_array($match) && is_callable($match['target'])) {
echo $templates->render('encrypt', ['title' => 'Encrypt — ', 'mode' => 'wkd', 'wkd_input' => $match['params']['uid']]); echo $templates->render('encrypt', ['title' => 'Encrypt — ', 'mode' => 'wkd', 'wkd_input' => $match['params']['uid']]);
break; break;
case 'encryptKeybase':
echo $templates->render('encrypt', ['title' => 'Encrypt — ', 'mode' => 'keybase', 'keybase_username' => htmlspecialchars($match['params']['uid']), 'keybase_fingerprint' => htmlspecialchars($match['params']['fp'])]);
break;
case 'proofs': case 'proofs':
echo $templates->render('proofs', ['title' => 'Proofs — ', 'mode' => 'auto']); echo $templates->render('proofs', ['title' => 'Proofs — ', 'mode' => 'auto']);
break; break;
@ -103,6 +114,10 @@ if(is_array($match) && is_callable($match['target'])) {
echo $templates->render('profile', ['mode' => 'wkd', 'uid' => htmlspecialchars($match['params']['uid'])]); echo $templates->render('profile', ['mode' => 'wkd', 'uid' => htmlspecialchars($match['params']['uid'])]);
break; break;
case 'profileKeybase':
echo $templates->render('profile', ['mode' => 'keybase', 'uid' => htmlspecialchars($match['params']['uid']).'/'.htmlspecialchars($match['params']['fp'])]);
break;
case 'guides': case 'guides':
echo $templates->render('guides'); echo $templates->render('guides');
break; break;

View file

@ -10,6 +10,7 @@
<option value="wkd" <?php if ($mode=="wkd"): ?>selected<?php endif ?>>Web Key Directory</option> <option value="wkd" <?php if ($mode=="wkd"): ?>selected<?php endif ?>>Web Key Directory</option>
<option value="hkp" <?php if ($mode=="hkp"): ?>selected<?php endif ?>>Keyserver</option> <option value="hkp" <?php if ($mode=="hkp"): ?>selected<?php endif ?>>Keyserver</option>
<option value="plaintext" <?php if ($mode=="plaintext"): ?>selected<?php endif ?>>Plaintext</option> <option value="plaintext" <?php if ($mode=="plaintext"): ?>selected<?php endif ?>>Plaintext</option>
<option value="keybase" <?php if ($mode=="keybase"): ?>selected<?php endif ?>>Keybase</option>
</select> </select>
<div class="modesContainer"> <div class="modesContainer">
<div class='modes modes--auto <?php if ($mode=="auto"): ?>modes--visible<?php endif ?>'> <div class='modes modes--auto <?php if ($mode=="auto"): ?>modes--visible<?php endif ?>'>
@ -25,6 +26,10 @@
<div class='modes modes--plaintext <?php if ($mode=="plaintext"): ?>modes--visible<?php endif ?>'> <div class='modes modes--plaintext <?php if ($mode=="plaintext"): ?>modes--visible<?php endif ?>'>
<textarea name="plaintext_input" id="plaintext_input"></textarea> <textarea name="plaintext_input" id="plaintext_input"></textarea>
</div> </div>
<div class='modes modes--keybase <?php if ($mode=="keybase"): ?>modes--visible<?php endif ?>'>
<input type="text" name="keybase_username" id="keybase_username" placeholder="username" value="<?=$this->escape($keybase_username)?>">
<input type="text" name="keybase_fingerprint" id="keybase_fingerprint" placeholder="fingerprint" value="<?=$this->escape($keybase_fingerprint)?>">
</div>
</div> </div>
<h3>Message</h3> <h3>Message</h3>
<textarea name="message" id="message"></textarea> <textarea name="message" id="message"></textarea>

View file

@ -10,6 +10,7 @@
<option value="wkd" <?php if ($mode=="wkd"): ?>selected<?php endif ?>>Web Key Directory</option> <option value="wkd" <?php if ($mode=="wkd"): ?>selected<?php endif ?>>Web Key Directory</option>
<option value="hkp" <?php if ($mode=="hkp"): ?>selected<?php endif ?>>Keyserver</option> <option value="hkp" <?php if ($mode=="hkp"): ?>selected<?php endif ?>>Keyserver</option>
<option value="plaintext" <?php if ($mode=="plaintext"): ?>selected<?php endif ?>>Plaintext</option> <option value="plaintext" <?php if ($mode=="plaintext"): ?>selected<?php endif ?>>Plaintext</option>
<option value="keybase" <?php if ($mode=="keybase"): ?>selected<?php endif ?>>Keybase</option>
</select> </select>
<div class="modesContainer"> <div class="modesContainer">
<div class='modes modes--auto <?php if ($mode=="auto"): ?>modes--visible<?php endif ?>'> <div class='modes modes--auto <?php if ($mode=="auto"): ?>modes--visible<?php endif ?>'>
@ -25,6 +26,10 @@
<div class='modes modes--plaintext <?php if ($mode=="plaintext"): ?>modes--visible<?php endif ?>'> <div class='modes modes--plaintext <?php if ($mode=="plaintext"): ?>modes--visible<?php endif ?>'>
<textarea name="plaintext_input" id="plaintext_input"></textarea> <textarea name="plaintext_input" id="plaintext_input"></textarea>
</div> </div>
<div class='modes modes--keybase <?php if ($mode=="keybase"): ?>modes--visible<?php endif ?>'>
<input type="text" name="keybase_username" id="keybase_username" placeholder="username" value="<?=$this->escape($keybase_username)?>">
<input type="text" name="keybase_fingerprint" id="keybase_fingerprint" placeholder="fingerprint" value="<?=$this->escape($keybase_fingerprint)?>">
</div>
</div> </div>
<h3>Signature</h3> <h3>Signature</h3>
<textarea name="signature" id="signature"></textarea> <textarea name="signature" id="signature"></textarea>