Changes for #973

This commit is contained in:
the-djmaze 2023-02-17 13:35:21 +01:00
parent 6e6ed0eab3
commit ab77949e64
3 changed files with 96 additions and 60 deletions

View file

@ -15,6 +15,8 @@ import { showScreenPopup } from 'Knoin/Knoin';
import { OpenPgpImportPopupView } from 'View/Popup/OpenPgpImport';
import { OpenPgpGeneratePopupView } from 'View/Popup/OpenPgpGenerate';
import Remote from 'Remote/User/Fetch';
export class UserSettingsSecurity extends AbstractViewSettings {
constructor() {
super();
@ -60,5 +62,11 @@ export class UserSettingsSecurity extends AbstractViewSettings {
* The iframe will be injected into the container identified by selector.
*/
window.mailvelope && mailvelope.createSettingsContainer('#mailvelope-settings'/*[, keyring], options*/);
/**
* https://github.com/the-djmaze/snappymail/issues/973
Remote.request('GetStoredPGPKeys', (iError, data) => {
console.dir([iError, data]);
});
*/
}
}

View file

@ -2,6 +2,8 @@
namespace RainLoop\Actions;
use SnappyMail\PGP\Backup;
trait Pgp
{
/**
@ -191,35 +193,7 @@ trait Pgp
*/
public function DoGetStoredPGPKeys() : array
{
$oAccount = $this->getMainAccountFromToken();
if (!$oAccount) {
return null;
}
$dir = $this->StorageProvider()->GenerateFilePath(
$oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::PGP
);
$keys = [];
foreach (\glob("{$dir}/*") as $file) {
if (\is_file($file)) {
if ('.asc' === \substr($file, -4)) {
$keys[] = \file_get_contents($file);
} else if ('.key' === \substr($file, -4)) {
$key = \json_decode(\file_get_contents($file), true);
$mac = \array_pop($key);
$hash = $oAccount->CryptKey();
if ($mac === \hash_hmac('sha1', $key[2], $hash)) {
$key[1] = \base64_decode($key[1]);
$key[2] = \base64_decode($key[2]);
$keys[] = \SnappyMail\Crypt::Decrypt($key, $hash);
}
}
}
}
return $this->DefaultResponse($keys);
return $this->DefaultResponse(\SnappyMail\PGP\Backup::getKeys());
}
/**
@ -232,16 +206,16 @@ trait Pgp
$privateKey = $this->GetActionParam('privateKey', '');
$result = [
'onServer' => [false, false, false],
'inGnuPG' => [false, false, false]
'onServer' => [false, false],
'inGnuPG' => [false, false]
];
$onServer = (int) $this->GetActionParam('onServer', 0);
if ($publicKey && $onServer & 1) {
$result['onServer'][0] = $this->StorePGPKey($publicKey);
$result['onServer'][0] = Backup::PGPKey($publicKey);
}
if ($privateKey && $onServer & 2) {
$result['onServer'][1] = $this->StorePGPKey($privateKey);
$result['onServer'][1] = Backup::PGPKey($privateKey);
}
$inGnuPG = (int) $this->GetActionParam('inGnuPG', 0);
@ -267,32 +241,6 @@ trait Pgp
{
$key = $this->GetActionParam('key', '');
$keyId = $this->GetActionParam('keyId', '');
return $this->DefaultResponse(($key && $keyId && $this->StorePGPKey($key, $keyId)));
return $this->DefaultResponse(($key && $keyId && Backup::PGPKey($key, $keyId)));
}
private function StorePGPKey(string $key, string $keyId = '') : bool
{
$oAccount = $this->getMainAccountFromToken();
if ($oAccount) {
$keyId = $keyId ? "0x{$keyId}" : \sha1($key);
$dir = $this->StorageProvider()->GenerateFilePath(
$oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::PGP,
true
);
if (\str_contains($key, 'PGP PRIVATE KEY')) {
$hash = $oAccount->CryptKey();
$key = \SnappyMail\Crypt::Encrypt($key, $hash);
$key[1] = \base64_encode($key[1]);
$key[2] = \base64_encode($key[2]);
$key[] = \hash_hmac('sha1', $key[2], $hash);
return !!\file_put_contents("{$dir}{$keyId}.key", \json_encode($key));
}
if (\str_contains($key, 'PGP PUBLIC KEY')) {
return !!\file_put_contents("{$dir}{$keyId}_public.asc", $key);
}
}
return false;
}
}

View file

@ -0,0 +1,80 @@
<?php
/**
* This class is inspired by PEAR Crypt_GPG and PECL gnupg
* It does not support gpg v1 because that is missing ECDH, ECDSA, EDDSA
* It does not support gpg < v2.2.5 as they are from before 2018
*/
namespace SnappyMail\PGP;
class Backup
{
public static function PGPKey(string $key, string $keyId = '') : bool
{
$oActions = \RainLoop\Api::Actions();
$oAccount = $oActions->getMainAccountFromToken();
if ($oAccount) {
$keyId = $keyId ? "0x{$keyId}" : \sha1($key);
$dir = $oActions->StorageProvider()->GenerateFilePath(
$oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::PGP,
true
);
if (\str_contains($key, 'PGP PRIVATE KEY')) {
$hash = $oAccount->CryptKey();
$key = \SnappyMail\Crypt::Encrypt($key, $hash);
$key[1] = \base64_encode($key[1]);
$key[2] = \base64_encode($key[2]);
$key[] = \hash_hmac('sha1', $key[2], $hash);
return !!\file_put_contents("{$dir}{$keyId}.key", \json_encode($key));
}
if (\str_contains($key, 'PGP PUBLIC KEY')) {
return !!\file_put_contents("{$dir}{$keyId}_public.asc", $key);
}
}
return false;
}
public static function getKeys() : array
{
$result = [
'public' => [],
'private' => []
];
$oActions = \RainLoop\Api::Actions();
$oAccount = $oActions->getMainAccountFromToken();
if ($oAccount) {
$keyId = $keyId ? "0x{$keyId}" : \sha1($key);
$dir = $oActions->StorageProvider()->GenerateFilePath(
$oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::PGP,
true
);
$hash = $oAccount->CryptKey();
foreach (\glob("{$dir}*") as $file) {
if (\is_file($file)) {
if ('_public.asc' === \substr($file, -11)) {
$result['public'][] = [
'id' => \basename($file),
'value' => \file_get_contents($file),
];
} else if ('.key' === \substr($file, -4)) {
$key = \json_decode(\file_get_contents($file));
if (\is_array($key)) {
$mac = \array_pop($key);
if (!empty($key[2]) && \hash_hmac('sha1', $key[2], $hash) === $mac) {
$key[1] = \base64_decode($key[1]);
$key[2] = \base64_decode($key[2]);
$result['private'][] = [
'id' => \basename($file),
'value' => \SnappyMail\Crypt::Decrypt($key, $hash),
];
}
}
}
}
}
}
return $result;
}
}