Added support to lookup public keys online #89

This commit is contained in:
the-djmaze 2024-02-07 01:55:52 +01:00
parent bac6c2d332
commit 6c01db395d
4 changed files with 47 additions and 9 deletions

View file

@ -4,11 +4,16 @@ import { OpenPGPUserStore } from 'Stores/User/OpenPGP';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
import Remote from 'Remote/User/Fetch';
import { i18n } from 'Common/Translator';
export class OpenPgpImportPopupView extends AbstractViewPopup {
constructor() {
super('OpenPgpImport');
addObservablesTo(this, {
search: '',
key: '',
keyError: false,
keyErrorMessage: '',
@ -25,6 +30,21 @@ export class OpenPgpImportPopupView extends AbstractViewPopup {
});
}
searchPGP() {
this.key(i18n('SUGGESTIONS/SEARCHING_DESC'));
Remote.request('SearchPGPKey',
(iError, oData) => {
if (iError) {
this.key(oData.ErrorMessage);
} else {
this.key(oData.Result);
}
}, {
query: this.search()
}
);
}
submitForm() {
let keyTrimmed = this.key().trim();

View file

@ -10,6 +10,14 @@ trait Pgp
* Also see trait Messages::DoMessagePgpVerify
*/
public function DoSearchPGPKey() : array
{
$result = \SnappyMail\PGP\Keyservers::get(
$this->GetActionParam('query', '')
);
return $this->DefaultResponse($result ?: false);
}
/**
* @throws \MailSo\RuntimeException
*/

View file

@ -8,6 +8,10 @@
* https://datatracker.ietf.org/doc/html/rfc4387
* https://datatracker.ietf.org/doc/html/rfc7929
* https://datatracker.ietf.org/doc/html/draft-koch-openpgp-webkey-service-13
*
* GET https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=security@snappymail.eu
* GET https://keys.openpgp.org/vks/v1/by-fingerprint/445D265124E6072671E64D0733F868A7E35E8277
* GET https://openpgpkey.example.org/.well-known/openpgpkey/example.org/hu/ihyath4noz8dsckzjbuyqnh4kbup6h4i?l=john.doe
*/
namespace SnappyMail\PGP;
@ -15,18 +19,16 @@ namespace SnappyMail\PGP;
abstract class Keyservers
{
public static $hosts = [
'https://keys.openpgp.org'
/*
'https://keys.openpgp.org',
'https://pgp.mit.edu',
'https://keyring.debian.org',
'https://attester.flowcrypt.com',
'https://zimmermann.mayfirst.org',
'https://pool.sks-keyservers.net',
'https://keys.mailvelope.com',
*/
'https://keyserver.ubuntu.com',
'https://keys.fedoraproject.org',
'https://keys.openpgp.org'
*/
];
private static function fetch(string $host, string $op, string $search, bool $fingerprint = false, bool $exact = false) : ?\SnappyMail\HTTP\Response
@ -36,7 +38,9 @@ abstract class Keyservers
$search = \urlencode($search);
$fingerprint = $fingerprint ? '&fingerprint=on' : '';
$exact = $exact ? '&exact=on' : '';
return static::HTTP()->doRequest('GET', "{$host}/pks/lookup?op={$op}&options=mr{$fingerprint}&search={$search}");
$url = "{$host}/pks/lookup?op={$op}&options=mr{$fingerprint}&search={$search}";
\SnappyMail\Log::debug('PGP', $url);
return static::HTTP()->doRequest('GET', $url);
}
private static $HTTP;
@ -56,11 +60,12 @@ abstract class Keyservers
*/
public static function get(string $keyId) : string
{
/*
// add the 0x prefix if absent
if ('0x' !== \substr($keyId, 0, 2)) {
$keyId = '0x' . $keyId;
}
*/
foreach (static::$hosts as $host) {
$oResponse = static::fetch($host, 'get', $keyId);
if (!$oResponse) {
@ -68,14 +73,14 @@ abstract class Keyservers
continue;
}
if (200 !== $oResponse->status) {
\SnappyMail\Log::info('PGP', "{$oResponse->status} for key {$keyId} on {$host}");
\SnappyMail\Log::debug('PGP', "{$oResponse->status} for key {$keyId} on {$host}");
continue;
}
return $oResponse->body;
}
throw new \Exception('Could not obtain public key from the keyserver.');
throw new \Exception('Could not obtain public key from the keyservers.');
}
/**
@ -97,7 +102,7 @@ abstract class Keyservers
continue;
}
if (200 !== $oResponse->status) {
\SnappyMail\Log::info('PGP', "{$oResponse->status} for search `{$search}` on {$host}");
\SnappyMail\Log::debug('PGP', "{$oResponse->status} for search `{$search}` on {$host}");
continue;
}

View file

@ -4,6 +4,11 @@
</header>
<form id="openpgp-import" class="modal-body" autocomplete="off" data-bind="submit: submitForm">
<div class="alert" data-bind="visible: keyError() && keyErrorMessage(), text: keyErrorMessage"></div>
<div class="control-group">
<!-- could be email or fingerprint -->
<input type="text" data-bind="textInput: search"/>
<button class="btn" type="button" data-bind="enable: search, click: searchPGP" data-i18n="GLOBAL/SEARCH"></button>
</div>
<div class="control-group" data-bind="css: {'error': keyError}">
<textarea class="input-xxlarge" rows="14" autofocus="" autocomplete="off" data-bind="value: key" required=""></textarea>
</div>