diff --git a/dev/Common/Enums.js b/dev/Common/Enums.js index f3bb7f5b5..34840ec27 100644 --- a/dev/Common/Enums.js +++ b/dev/Common/Enums.js @@ -4,6 +4,7 @@ * @enum {string} */ export const Capa = { + GnuPGP: 'GNUGP', OpenPGP: 'OPEN_PGP', Prefetch: 'PREFETCH', Contacts: 'CONTACTS', diff --git a/dev/Screen/User/Settings.js b/dev/Screen/User/Settings.js index 26a2d2ed2..b0f17f4b6 100644 --- a/dev/Screen/User/Settings.js +++ b/dev/Screen/User/Settings.js @@ -57,7 +57,7 @@ export class SettingsUserScreen extends AbstractSettingsScreen { settingsAddViewModel(ThemesUserSettings, 'SettingsThemes', 'SETTINGS_LABELS/LABEL_THEMES_NAME', 'themes'); } - if (Settings.capa(Capa.OpenPGP)) { + if (Settings.capa(Capa.OpenPGP) || Settings.capa(Capa.GnuPGP)) { settingsAddViewModel(OpenPgpUserSettings, 'SettingsOpenPGP', 'OpenPGP', 'openpgp'); } diff --git a/dev/Stores/User/Pgp.js b/dev/Stores/User/Pgp.js index 1b7967d58..6395eae4d 100644 --- a/dev/Stores/User/Pgp.js +++ b/dev/Stores/User/Pgp.js @@ -40,31 +40,34 @@ export const PgpUserStore = new class { } init() { - if (Settings.capa(Capa.OpenPGP)) { - if (window.crypto && crypto.getRandomValues) { - const script = createElement('script', {src:openPgpJs()}); - script.onload = () => { - if (window.Worker) { - try { - openpgp.initWorker({ path: openPgpWorkerJs() }); - } catch (e) { - console.error(e); - } + if (Settings.capa(Capa.OpenPGP) && window.crypto && crypto.getRandomValues) { + const script = createElement('script', {src:openPgpJs()}); + script.onload = () => { + if (window.Worker) { + try { + openpgp.initWorker({ path: openPgpWorkerJs() }); + } catch (e) { + console.error(e); } - this.loadKeyrings(); - }; - script.onerror = () => console.error(script.src); - doc.head.append(script); - } else { + } this.loadKeyrings(); + }; + script.onerror = () => { + this.loadKeyrings(); + console.error(script.src); } + doc.head.append(script); + } else { + this.loadKeyrings(); } } loadKeyrings(identifier) { if (window.mailvelope) { - console.log('mailvelope ready'); - var fn = keyring => this.mailvelopeKeyring = keyring; + var fn = keyring => { + this.mailvelopeKeyring = keyring; + console.log('mailvelope ready'); + }; mailvelope.getKeyring().then(fn, err => { if (identifier) { // attempt to create a new keyring for this app/user @@ -79,18 +82,23 @@ export const PgpUserStore = new class { } else { addEventListener('mailvelope', () => this.loadKeyrings(identifier)); } + if (openpgp) { - console.log('openpgp.js ready'); this.openpgpKeyring = new openpgp.Keyring(); this.reloadOpenPgpKeys(); } - this.gnupgkeys = []; - Remote.request('PgpGetKeysEmails', - (iError, oData) => { - console.dir(oData); - } - ); + if (Settings.capa(Capa.GnuPGP)) { + this.gnupgkeys = []; + Remote.request('GnupgGetKeysEmails', + (iError, oData) => { + if (oData.Result) { + this.gnupgkeys = oData.Result; + console.log('gnupg ready'); + } + } + ); + } } reloadOpenPgpKeys() { @@ -148,6 +156,7 @@ export const PgpUserStore = new class { delegateRunOnDestroy(this.openpgpkeys()); this.openpgpkeys(keys); + console.log('openpgp.js ready'); } } @@ -213,6 +222,13 @@ export const PgpUserStore = new class { this.openpgpkeys.find(item => item && !item.isPrivate && item.emails.includes(email)) ); + if (this.gnupgkeys) { + let length = recipients.filter(email => this.gnupgkeys[email] && this.gnupgkeys[email].can_encrypt).length; + if (length && (!all || length === count)) { + return 'gnupg'; + } + } + if (openpgp && openpgp.length && (!all || openpgp.length === count)) { return 'openpgp'; } @@ -234,6 +250,10 @@ export const PgpUserStore = new class { * Returns the first library that can. */ async hasPrivateKeyForEmail(email) { + if (this.gnupgkeys && this.gnupgkeys[email] && this.gnupgkeys[email].can_sign) { + return 'gnupg'; + } + if (this.openpgpkeys && this.openpgpkeys.find(item => item && item.isPrivate && item.emails.includes(email))) { return 'openpgp'; } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php index e2de5be99..24365499b 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -1191,6 +1191,9 @@ class Actions if ($oConfig->Get('security', 'openpgp', false)) { $aResult[] = Enumerations\Capa::OPEN_PGP; } + if (\SnappyMail\PGP\GnuPG::isSupported()) { + $aResult[] = Enumerations\Capa::GNUGP; + } if ($bAdmin || ($oAccount && $oAccount->Domain()->UseSieve())) { $aResult[] = Enumerations\Capa::SIEVE; diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Pgp.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Pgp.php index 7402e9e5a..fba5bc918 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Pgp.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Pgp.php @@ -9,39 +9,60 @@ trait Pgp */ public function GnuPG() : ?\SnappyMail\PGP\GnuPG { - $pgp_dir = $this->StorageProvider()->GenerateFilePath( + $pgp_dir = \dirname($this->StorageProvider()->GenerateFilePath( $this->getAccountFromToken(), \RainLoop\Providers\Storage\Enumerations\StorageType::PGP - ); + )); return \SnappyMail\PGP\GnuPG::getInstance($pgp_dir); } - public function DoPgpGetKeysEmails() : array + public function DoGnupgGetKeysEmails() : array { $GPG = $this->GnuPG(); if ($GPG) { - $sign = $encrypt = $keys = []; + $keys = []; foreach ($GPG->keyInfo('') as $info) { if (!$info['disabled'] && !$info['expired'] && !$info['revoked']) { - if ($info['can_sign']) { - foreach ($info['uids'] as $uid) { - $private[] = $info['email']; + foreach ($info['uids'] as $uid) { + $id = $uid['email']; + if (isset($keys[$id])) { + $keys[$id]['can_sign'] = $keys[$id]['can_sign'] || $info['can_sign']; + $keys[$id]['can_encrypt'] = $keys[$id]['can_encrypt'] || $info['can_encrypt']; + } else { + $keys[$id] = [ + 'name' => $uid['name'], + 'email' => $uid['email'], + 'can_sign' => $info['can_sign'], + 'can_encrypt' => $info['can_encrypt'] + ]; } } - if ($info['can_encrypt']) { - foreach ($info['uids'] as $uid) { - $public[] = $info['email']; - } + /* + foreach ($info['subkeys'] as $key) { + $key['can_authenticate'] = true + ​​​​​​$key['can_certify'] = true + ​​​​​​$key['can_encrypt'] = true + ​​​​​​$key['can_sign'] = true + ​​​​​​$key['disabled'] = false + ​​​​​​$key['expired'] = false + ​​​​​​$key['expires'] = 0 + ​​​​​​$key['fingerprint'] = "99BBB6F2FDDE9E20CD78B98DC85B364A5A6CCF52" + ​​​​​​$key['invalid'] = false + ​​​​​​$key['is_cardkey'] = false + ​​​​​​$key['is_de_vs'] = true + ​​​​​​$key['is_qualified'] = false + ​​​​​​$key['is_secret'] = false + ​​​​​​$key['keygrip'] = "CBCCF45D4F6D300417F044A08E08F8F14522BABE" + ​​​​​​$key['keyid'] = "C85B364A5A6CCF52" + ​​​​​​$key['length'] = 4096 + ​​​​​​$key['pubkey_algo'] = 1 + ​​​​​​$key['revoked'] = false + ​​​​​​$key['timestamp'] = 1428449321 } + */ } - $keys[] = $info; } - return $this->DefaultResponse(__FUNCTION__, [ - 'sign' => $sign, - 'encrypt' => $encrypt, - 'keys' => $keys, - 'info' => $GPG->getEngineInfo() - ]); + return $this->DefaultResponse(__FUNCTION__, $keys); } return $this->FalseResponse(__FUNCTION__); } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php index fc8bf4a70..4ae45530b 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php @@ -254,7 +254,7 @@ trait Response $mResult['Plain'] = $mResponse->Plain(); -// $this->GetCapa(false, Capa::OPEN_PGP) +// $this->GetCapa(false, Capa::OPEN_PGP) || $this->GetCapa(false, Capa::GNUGP) $mResult['isPgpEncrypted'] = $mResponse->isPgpEncrypted(); $mResult['PgpSigned'] = $mResponse->PgpSigned(); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Enumerations/Capa.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Enumerations/Capa.php index d9cf4ae2b..f11ab8269 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Enumerations/Capa.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Enumerations/Capa.php @@ -4,6 +4,7 @@ namespace RainLoop\Enumerations; class Capa { + const GNUGP = 'GNUGP'; const OPEN_PGP = 'OPEN_PGP'; const PREFETCH = 'PREFETCH'; const THEMES = 'THEMES'; diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php b/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php index c0a7dcd70..af7f8ea4b 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php @@ -11,10 +11,16 @@ class GnuPG // Instance of PEAR Crypt_GPG $Crypt_GPG; - public static function getInstance(string $home) : ?self + public static function isSupported() : bool + { + return \class_exists('gnupg') + || \stream_resolve_include_path('Crypt/GPG.php'); + } + + public static function getInstance(string $base_dir) : ?self { $self = null; - $home .= '/.gnupg'; + $home = $base_dir . '/.gnupg'; if (\class_exists('gnupg')) { $self = new self; $self->GnuPG = new \gnupg([