mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-09-12 08:04:21 +08:00
Properly load keyrings of Mailvelope, OpenPGP.js and GnuPG
This commit is contained in:
parent
9f0b872839
commit
c2e162b01b
8 changed files with 98 additions and 46 deletions
|
@ -4,6 +4,7 @@
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
*/
|
*/
|
||||||
export const Capa = {
|
export const Capa = {
|
||||||
|
GnuPGP: 'GNUGP',
|
||||||
OpenPGP: 'OPEN_PGP',
|
OpenPGP: 'OPEN_PGP',
|
||||||
Prefetch: 'PREFETCH',
|
Prefetch: 'PREFETCH',
|
||||||
Contacts: 'CONTACTS',
|
Contacts: 'CONTACTS',
|
||||||
|
|
|
@ -57,7 +57,7 @@ export class SettingsUserScreen extends AbstractSettingsScreen {
|
||||||
settingsAddViewModel(ThemesUserSettings, 'SettingsThemes', 'SETTINGS_LABELS/LABEL_THEMES_NAME', 'themes');
|
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');
|
settingsAddViewModel(OpenPgpUserSettings, 'SettingsOpenPGP', 'OpenPGP', 'openpgp');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,7 @@ export const PgpUserStore = new class {
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
if (Settings.capa(Capa.OpenPGP)) {
|
if (Settings.capa(Capa.OpenPGP) && window.crypto && crypto.getRandomValues) {
|
||||||
if (window.crypto && crypto.getRandomValues) {
|
|
||||||
const script = createElement('script', {src:openPgpJs()});
|
const script = createElement('script', {src:openPgpJs()});
|
||||||
script.onload = () => {
|
script.onload = () => {
|
||||||
if (window.Worker) {
|
if (window.Worker) {
|
||||||
|
@ -53,18 +52,22 @@ export const PgpUserStore = new class {
|
||||||
}
|
}
|
||||||
this.loadKeyrings();
|
this.loadKeyrings();
|
||||||
};
|
};
|
||||||
script.onerror = () => console.error(script.src);
|
script.onerror = () => {
|
||||||
|
this.loadKeyrings();
|
||||||
|
console.error(script.src);
|
||||||
|
}
|
||||||
doc.head.append(script);
|
doc.head.append(script);
|
||||||
} else {
|
} else {
|
||||||
this.loadKeyrings();
|
this.loadKeyrings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
loadKeyrings(identifier) {
|
loadKeyrings(identifier) {
|
||||||
if (window.mailvelope) {
|
if (window.mailvelope) {
|
||||||
|
var fn = keyring => {
|
||||||
|
this.mailvelopeKeyring = keyring;
|
||||||
console.log('mailvelope ready');
|
console.log('mailvelope ready');
|
||||||
var fn = keyring => this.mailvelopeKeyring = keyring;
|
};
|
||||||
mailvelope.getKeyring().then(fn, err => {
|
mailvelope.getKeyring().then(fn, err => {
|
||||||
if (identifier) {
|
if (identifier) {
|
||||||
// attempt to create a new keyring for this app/user
|
// attempt to create a new keyring for this app/user
|
||||||
|
@ -79,19 +82,24 @@ export const PgpUserStore = new class {
|
||||||
} else {
|
} else {
|
||||||
addEventListener('mailvelope', () => this.loadKeyrings(identifier));
|
addEventListener('mailvelope', () => this.loadKeyrings(identifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openpgp) {
|
if (openpgp) {
|
||||||
console.log('openpgp.js ready');
|
|
||||||
this.openpgpKeyring = new openpgp.Keyring();
|
this.openpgpKeyring = new openpgp.Keyring();
|
||||||
this.reloadOpenPgpKeys();
|
this.reloadOpenPgpKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Settings.capa(Capa.GnuPGP)) {
|
||||||
this.gnupgkeys = [];
|
this.gnupgkeys = [];
|
||||||
Remote.request('PgpGetKeysEmails',
|
Remote.request('GnupgGetKeysEmails',
|
||||||
(iError, oData) => {
|
(iError, oData) => {
|
||||||
console.dir(oData);
|
if (oData.Result) {
|
||||||
|
this.gnupgkeys = oData.Result;
|
||||||
|
console.log('gnupg ready');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reloadOpenPgpKeys() {
|
reloadOpenPgpKeys() {
|
||||||
if (this.openpgpKeyring) {
|
if (this.openpgpKeyring) {
|
||||||
|
@ -148,6 +156,7 @@ export const PgpUserStore = new class {
|
||||||
|
|
||||||
delegateRunOnDestroy(this.openpgpkeys());
|
delegateRunOnDestroy(this.openpgpkeys());
|
||||||
this.openpgpkeys(keys);
|
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))
|
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)) {
|
if (openpgp && openpgp.length && (!all || openpgp.length === count)) {
|
||||||
return 'openpgp';
|
return 'openpgp';
|
||||||
}
|
}
|
||||||
|
@ -234,6 +250,10 @@ export const PgpUserStore = new class {
|
||||||
* Returns the first library that can.
|
* Returns the first library that can.
|
||||||
*/
|
*/
|
||||||
async hasPrivateKeyForEmail(email) {
|
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))) {
|
if (this.openpgpkeys && this.openpgpkeys.find(item => item && item.isPrivate && item.emails.includes(email))) {
|
||||||
return 'openpgp';
|
return 'openpgp';
|
||||||
}
|
}
|
||||||
|
|
|
@ -1191,6 +1191,9 @@ class Actions
|
||||||
if ($oConfig->Get('security', 'openpgp', false)) {
|
if ($oConfig->Get('security', 'openpgp', false)) {
|
||||||
$aResult[] = Enumerations\Capa::OPEN_PGP;
|
$aResult[] = Enumerations\Capa::OPEN_PGP;
|
||||||
}
|
}
|
||||||
|
if (\SnappyMail\PGP\GnuPG::isSupported()) {
|
||||||
|
$aResult[] = Enumerations\Capa::GNUGP;
|
||||||
|
}
|
||||||
|
|
||||||
if ($bAdmin || ($oAccount && $oAccount->Domain()->UseSieve())) {
|
if ($bAdmin || ($oAccount && $oAccount->Domain()->UseSieve())) {
|
||||||
$aResult[] = Enumerations\Capa::SIEVE;
|
$aResult[] = Enumerations\Capa::SIEVE;
|
||||||
|
|
|
@ -9,39 +9,60 @@ trait Pgp
|
||||||
*/
|
*/
|
||||||
public function GnuPG() : ?\SnappyMail\PGP\GnuPG
|
public function GnuPG() : ?\SnappyMail\PGP\GnuPG
|
||||||
{
|
{
|
||||||
$pgp_dir = $this->StorageProvider()->GenerateFilePath(
|
$pgp_dir = \dirname($this->StorageProvider()->GenerateFilePath(
|
||||||
$this->getAccountFromToken(),
|
$this->getAccountFromToken(),
|
||||||
\RainLoop\Providers\Storage\Enumerations\StorageType::PGP
|
\RainLoop\Providers\Storage\Enumerations\StorageType::PGP
|
||||||
);
|
));
|
||||||
return \SnappyMail\PGP\GnuPG::getInstance($pgp_dir);
|
return \SnappyMail\PGP\GnuPG::getInstance($pgp_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function DoPgpGetKeysEmails() : array
|
public function DoGnupgGetKeysEmails() : array
|
||||||
{
|
{
|
||||||
$GPG = $this->GnuPG();
|
$GPG = $this->GnuPG();
|
||||||
if ($GPG) {
|
if ($GPG) {
|
||||||
$sign = $encrypt = $keys = [];
|
$keys = [];
|
||||||
foreach ($GPG->keyInfo('') as $info) {
|
foreach ($GPG->keyInfo('') as $info) {
|
||||||
if (!$info['disabled'] && !$info['expired'] && !$info['revoked']) {
|
if (!$info['disabled'] && !$info['expired'] && !$info['revoked']) {
|
||||||
if ($info['can_sign']) {
|
|
||||||
foreach ($info['uids'] as $uid) {
|
foreach ($info['uids'] as $uid) {
|
||||||
$private[] = $info['email'];
|
$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) {
|
foreach ($info['subkeys'] as $key) {
|
||||||
$public[] = $info['email'];
|
$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
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return $this->DefaultResponse(__FUNCTION__, $keys);
|
||||||
$keys[] = $info;
|
|
||||||
}
|
|
||||||
return $this->DefaultResponse(__FUNCTION__, [
|
|
||||||
'sign' => $sign,
|
|
||||||
'encrypt' => $encrypt,
|
|
||||||
'keys' => $keys,
|
|
||||||
'info' => $GPG->getEngineInfo()
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
return $this->FalseResponse(__FUNCTION__);
|
return $this->FalseResponse(__FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,7 +254,7 @@ trait Response
|
||||||
|
|
||||||
$mResult['Plain'] = $mResponse->Plain();
|
$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['isPgpEncrypted'] = $mResponse->isPgpEncrypted();
|
||||||
$mResult['PgpSigned'] = $mResponse->PgpSigned();
|
$mResult['PgpSigned'] = $mResponse->PgpSigned();
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace RainLoop\Enumerations;
|
||||||
|
|
||||||
class Capa
|
class Capa
|
||||||
{
|
{
|
||||||
|
const GNUGP = 'GNUGP';
|
||||||
const OPEN_PGP = 'OPEN_PGP';
|
const OPEN_PGP = 'OPEN_PGP';
|
||||||
const PREFETCH = 'PREFETCH';
|
const PREFETCH = 'PREFETCH';
|
||||||
const THEMES = 'THEMES';
|
const THEMES = 'THEMES';
|
||||||
|
|
|
@ -11,10 +11,16 @@ class GnuPG
|
||||||
// Instance of PEAR Crypt_GPG
|
// Instance of PEAR Crypt_GPG
|
||||||
$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;
|
$self = null;
|
||||||
$home .= '/.gnupg';
|
$home = $base_dir . '/.gnupg';
|
||||||
if (\class_exists('gnupg')) {
|
if (\class_exists('gnupg')) {
|
||||||
$self = new self;
|
$self = new self;
|
||||||
$self->GnuPG = new \gnupg([
|
$self->GnuPG = new \gnupg([
|
||||||
|
|
Loading…
Add table
Reference in a new issue