Improved GnuPG error handling

This commit is contained in:
the-djmaze 2024-02-27 18:45:25 +01:00
parent c73e3637a3
commit 3d176d4e4f
9 changed files with 110 additions and 56 deletions

View file

@ -69,10 +69,10 @@ export const GnuPGUserStore = new class {
}
};
if (isPrivate) {
key.password = async (btnTxt = 'SIGN') => {
key.password = async (btnTxt = 'CRYPTO/SIGN') => {
const pass = await Passphrases.ask(key,
'GnuPG key<br>' + key.id + ' ' + key.emails[0],
'OPENPGP/'+btnTxt
btnTxt
);
pass && pass.remember && Passphrases.set(key, pass.password);
return pass?.password;
@ -82,7 +82,7 @@ export const GnuPGUserStore = new class {
if (key.armor) {
callback && callback();
} else {
let pass = isPrivate ? await key.password('POPUP_VIEW_TITLE') : '';
let pass = isPrivate ? await key.password('OPENPGP/POPUP_VIEW_TITLE') : '';
if (null != pass) try {
const result = await Remote.post('GnupgExportKey', null, {
keyId: key.id,
@ -184,15 +184,20 @@ export const GnuPGUserStore = new class {
uid: message.uid,
partId: pgpInfo.partId,
keyId: key.id,
passphrase: await key.password('DECRYPT'),
passphrase: await key.password('CRYPTO/DECRYPT'),
data: '' // message.plain() optional
}
if (null !== params.passphrase) {
const result = await Remote.post('GnupgDecrypt', null, params);
if (result?.Result?.data) {
return result.Result;
if (null != params.passphrase) {
try {
const response = await Remote.post('GnupgDecrypt', null, params);
if (response?.Result?.data) {
return response.Result;
}
throw response;
} catch (e) {
Passphrases.delete(key);
throw e;
}
Passphrases.delete(key);
}
}
}

View file

@ -587,10 +587,13 @@ export class MailMessageView extends AbstractViewRight {
}
} else {
// TODO: translate
alert('Decryption failed, canceled or not possible');
throw 'Decryption failed, canceled or not possible';
}
})
.catch(e => console.error(e));
.catch(e => {
console.error(e)
alert(e.message);
});
}
pgpVerify(/*self, event*/) {

View file

@ -120,7 +120,7 @@ trait Pgp
$sData = $this->GetActionParam('data', '');
$oPart = null;
$result = [
'data' => '',
'data' => null,
'signatures' => []
];
if ($sData) {
@ -130,11 +130,13 @@ trait Pgp
$this->initMailClientConnection();
$this->MailClient()->MessageMimeStream(
function ($rResource) use ($GPG, &$result, &$oPart) {
if (\is_resource($rResource)) {
if (\is_resource($rResource)) try {
$result['data'] = $GPG->decryptStream($rResource);
// $oPart = \MailSo\Mime\Part::FromString($result);
// $GPG->decryptStream($rResource, $rStreamHandle);
// $oPart = \MailSo\Mime\Part::FromStream($rStreamHandle);
} catch (\Throwable $e) {
$result = $e;
}
},
$this->GetActionParam('folder', ''),
@ -148,6 +150,10 @@ trait Pgp
// $result['signatures'] = $oPart->SubParts[0];
}
if ($result instanceof \Throwable) {
throw $result;
}
return $this->DefaultResponse($result);
}

View file

@ -45,9 +45,10 @@ trait Response
public function ExceptionResponse(\Throwable $oException) : array
{
$iErrorCode = 0;
$sErrorMessage = '';
$iErrorCode = Notifications::UnknownError;
$sErrorMessage = $oException->getMessage();
$sErrorMessageAdditional = '';
$iExceptionCode = 0;
if ($oException instanceof \RainLoop\Exceptions\ClientException) {
$iErrorCode = $oException->getCode();
@ -56,8 +57,7 @@ trait Response
}
$sErrorMessageAdditional = $oException->getAdditionalMessage();
} else {
$iErrorCode = Notifications::UnknownError;
$sErrorMessage = $oException->getCode().' - '.$oException->getMessage();
$iExceptionCode = $oException->getCode();
}
$this->logException($oException->getPrevious() ?: $oException);
@ -65,7 +65,8 @@ trait Response
return $this->DefaultResponse(false, [
'ErrorCode' => $iErrorCode,
'ErrorMessage' => $sErrorMessage,
'ErrorMessageAdditional' => $sErrorMessageAdditional
'ErrorMessageAdditional' => $sErrorMessageAdditional,
'ExceptionCode' => $iExceptionCode
]);
}

View file

@ -114,14 +114,15 @@ class ServiceActions
if ($_POST) {
$this->oActions->SetActionParams($_POST, $sMethodName);
foreach ($_POST as $key => $value) {
$aPost = $_POST;
foreach ($aPost as $key => $value) {
// password & passphrase
if (false !== \stripos($key, 'pass')) {
// $_POST[$key] = '*******';
$this->oActions->logMask($value);
$aPost[$key] = '*******';
// $this->oActions->logMask($value);
}
}
$this->oActions->logWrite(Utils::jsonEncode($_POST), \LOG_INFO, 'POST');
$this->oActions->logWrite(Utils::jsonEncode($aPost), \LOG_INFO, 'POST');
} else if (3 < \count($this->aPaths) && $this->oHttp->IsGet()) {
$this->oActions->SetActionParams(array(
'RawKey' => empty($this->aPaths[3]) ? '' : $this->aPaths[3]

View file

@ -243,7 +243,7 @@ abstract class Base
/**
* Signs a given file
*/
public function signStream($fp, /*string|resource*/ $output = null) /*: array|false*/
public function signStream($fp, /*string|resource*/ $output = null) /*: string|false*/
{
return false;
}

View file

@ -666,7 +666,7 @@ class PGP extends Base
/**
* Signs a given file
*/
public function signStream($fp, /*string|resource*/ $output = null) /*: array|false*/
public function signStream($fp, /*string|resource*/ $output = null) /*: string|false*/
{
if (!$fp || !\is_resource($fp)) {
throw new \Exception('Invalid stream resource');
@ -674,7 +674,7 @@ class PGP extends Base
return $this->_sign($fp, $output);
}
protected function _verify($input, string $signature)
protected function _verify($input, string $signature) /*: array|false*/
{
$arguments = ['--verify'];
if ($signature) {

View file

@ -540,7 +540,7 @@ class SMIME extends Base
/**
* Signs a given file
*/
public function signStream($fp, /*string|resource*/ $output = null) /*: array|false*/
public function signStream($fp, /*string|resource*/ $output = null) /*: string|false*/
{
if (!$fp || !\is_resource($fp)) {
throw new \Exception('Invalid stream resource');
@ -548,7 +548,7 @@ class SMIME extends Base
return $this->_sign($fp, $output);
}
protected function _verify($input, string $signature)
protected function _verify($input, string $signature) /*: array|false*/
{
$arguments = ['--verify'];
if ($signature) {

View file

@ -36,6 +36,7 @@ class GnuPG
]);
// Output is ASCII
$this->GnuPG->setarmor(1);
\SnappyMail\Log::info('GnuPG', 'Using PECL');
} else {
$this->getGPG();
}
@ -52,6 +53,12 @@ class GnuPG
*/
}
function __destruct()
{
$this->clearDecryptKeys();
$this->clearSignKeys();
}
public static function isSupported() : bool
{
return \class_exists('gnupg') || GPG::isSupported();
@ -71,11 +78,20 @@ class GnuPG
return $this->GnuPG ?: $this->GPG;
}
public function gnupgError()
{
$error = $this->GnuPG ? $this->GnuPG->geterrorinfo() : null;
if ($error) {
throw new \Exception("{$error['gpgme_source']} {$error['generic_message']}. {$error['gpgme_message']}", $error['gpgme_code']);
}
}
public function getGPG(bool $throw = true) : ?GPG
{
if (!$this->GPG) {
if (GPG::isSupported()) {
$this->GPG = new GPG($this->homedir);
\SnappyMail\Log::info('GnuPG', 'Using ' . GPG::class);
} else if ($throw) {
throw new \Exception('GnuPG not supported');
}
@ -88,7 +104,9 @@ class GnuPG
*/
public function addDecryptKey(string $fingerprint, \SnappyMail\SensitiveString $passphrase) : bool
{
return $this->handler()->adddecryptkey($fingerprint, $passphrase);
return $this->GnuPG
? $this->GnuPG->adddecryptkey($fingerprint, \strval($passphrase)) || $this->gnupgError()
: $this->GPG->addDecryptKey($fingerprint, $passphrase);
}
/**
@ -104,7 +122,9 @@ class GnuPG
*/
public function addSignKey(string $fingerprint, \SnappyMail\SensitiveString $passphrase) : bool
{
return $this->handler()->addsignkey($fingerprint, $passphrase);
return $this->GnuPG
? $this->GnuPG->addsignkey($fingerprint, \strval($passphrase)) || $this->gnupgError()
: $this->GPG->addSignKey($fingerprint, $passphrase);
}
/**
@ -136,9 +156,12 @@ class GnuPG
*/
public function decrypt(string $text) /*: string|false */
{
return $this->GnuPG
? $this->GnuPG->decrypt($text)
: $this->GPG->decrypt($text);
if ($this->GnuPG) {
$result = $this->GnuPG->decrypt($text);
(false === $result) && $this->gnupgError();
return $result;
}
return $this->GPG->decrypt($text);
}
/**
@ -146,9 +169,12 @@ class GnuPG
*/
public function decryptFile(string $filename) /*: string|false */
{
return $this->GnuPG
? $this->GnuPG->decrypt(\file_get_contents($filename))
: $this->GPG->decryptFile($filename);
if ($this->GnuPG) {
$result = $this->GnuPG->decrypt(\file_get_contents($filename));
(false === $result) && $this->gnupgError();
return $result;
}
return $this->GPG->decryptFile($filename);
}
/**
@ -159,9 +185,12 @@ class GnuPG
if (!$fp || !\is_resource($fp)) {
throw new \Exception('Invalid stream resource');
}
return $this->GnuPG
? $this->GnuPG->decrypt(\stream_get_contents($fp))
: $this->GPG->decryptStream($fp, $output);
if ($this->GnuPG) {
$result = $this->GnuPG->decrypt(\stream_get_contents($fp));
(false === $result) && $this->gnupgError();
return $result;
}
return $this->GPG->decryptStream($fp, $output);
}
/**
@ -169,9 +198,12 @@ class GnuPG
*/
public function decryptVerify(string $text, string &$plaintext) /*: array|false*/
{
return $this->GnuPG
? $this->GnuPG->decryptverify($text, $plaintext)
: $this->GPG->decryptverify($text, $plaintext);
if ($this->GnuPG) {
$result = $this->GnuPG->decryptverify($text, $plaintext);
(false === $result) && $this->gnupgError();
return $result;
}
return $this->GPG->decryptverify($text, $plaintext);
}
/**
@ -179,9 +211,12 @@ class GnuPG
*/
public function decryptVerifyFile(string $filename, string &$plaintext) /*: array|false*/
{
return $this->GnuPG
? $this->GnuPG->decryptverify(\file_get_contents($filename), $plaintext)
: $this->GPG->decryptverifyFile($filename, $plaintext);
if ($this->GnuPG) {
$result = $this->GnuPG->decryptverify(\file_get_contents($filename), $plaintext);
(false === $result) && $this->gnupgError();
return $result;
}
return $this->GPG->decryptverifyFile($filename, $plaintext);
}
public function deleteKey(string $keyId, bool $private) : bool
@ -195,7 +230,7 @@ class GnuPG
public function encrypt(string $plaintext) /*: string|false*/
{
return $this->GnuPG
? $this->GnuPG->encrypt($plaintext)
? $this->GnuPG->encrypt($plaintext) ?: $this->gnupgError()
: $this->GPG->encrypt($plaintext);
}
@ -205,7 +240,7 @@ class GnuPG
public function encryptFile(string $filename) /*: string|false*/
{
return $this->GnuPG
? $this->GnuPG->encrypt(\file_get_contents($filename))
? $this->GnuPG->encrypt(\file_get_contents($filename)) ?: $this->gnupgError()
: $this->GPG->encryptFile($filename);
}
@ -213,7 +248,7 @@ class GnuPG
{
\rewind($fp);
return $this->GnuPG
? $this->GnuPG->encrypt(\stream_get_contents($fp))
? $this->GnuPG->encrypt(\stream_get_contents($fp)) ?: $this->gnupgError()
: $this->GPG->encryptStream($fp);
}
@ -228,7 +263,7 @@ class GnuPG
->exportPrivateKey($fingerprint);
}
return $this->GnuPG
? $this->GnuPG->export($fingerprint)
? $this->GnuPG->export($fingerprint) ?: $this->gnupgError()
: $this->GPG->export($fingerprint);
}
@ -287,7 +322,7 @@ class GnuPG
public function importFile(string $filename) /*: array|false*/
{
return $this->GnuPG
? $this->GnuPG->import(\file_get_contents($filename))
? $this->GnuPG->import(\file_get_contents($filename)) ?: $this->gnupgError()
: $this->GPG->importFile($filename);
}
@ -350,7 +385,7 @@ class GnuPG
public function sign(string $plaintext) /*: string|false*/
{
return $this->GnuPG
? $this->GnuPG->sign($plaintext)
? $this->GnuPG->sign($plaintext) ?: $this->gnupgError()
: $this->GPG->sign($plaintext);
}
@ -360,18 +395,18 @@ class GnuPG
public function signFile(string $filename) /*: string|false*/
{
return $this->GnuPG
? $this->GnuPG->sign(\file_get_contents($filename))
? $this->GnuPG->sign(\file_get_contents($filename)) ?: $this->gnupgError()
: $this->GPG->signFile($filename);
}
/**
* Signs a given file
*/
public function signStream($fp, /*string|resource*/ $output = null) /*: array|false*/
public function signStream($fp, /*string|resource*/ $output = null) /*: string|false*/
{
\rewind($fp);
return $this->GnuPG
? $this->GnuPG->sign(\stream_get_contents($fp))
? $this->GnuPG->sign(\stream_get_contents($fp)) ?: $this->gnupgError()
: $this->GPG->signStream($fp);
}
@ -381,7 +416,7 @@ class GnuPG
public function verify(string $signed_text, string $signature, string &$plaintext = null) /*: array|false*/
{
$result = $this->GnuPG
? $this->GnuPG->verify($signed_text, $signature ?: false, $plaintext)
? $this->GnuPG->verify($signed_text, $signature ?: false, $plaintext) ?: $this->gnupgError()
: $this->GPG->verify($signed_text, $signature, $plaintext);
if (!$result) {
if ($this->GnuPG) {
@ -400,18 +435,21 @@ class GnuPG
public function verifyFile(string $filename, string $signature, string &$plaintext = null) /*: array|false*/
{
return $this->GnuPG
? $this->GnuPG->verify(\file_get_contents($filename), $signature, $plaintext)
? $this->GnuPG->verify(\file_get_contents($filename), $signature, $plaintext) ?: $this->gnupgError()
: $this->GPG->verifyFile($filename, $signature, $plaintext);
}
/**
* Verifies a given resource
*/
public function verifyStream(/*resource*/ $fp, string $signature, string &$plaintext = null) /*: string|false */
public function verifyStream(/*resource*/ $fp, string $signature, string &$plaintext = null) /*: array|false */
{
if (!$fp || !\is_resource($fp)) {
throw new \Exception('Invalid stream resource');
}
// return $this->GnuPG
// ? $this->GnuPG->verify(\stream_get_contents($fp), $signature, $plaintext) ?: $this->gnupgError()
// : $this->GPG->verifyStream($fp, $signature, $plaintext);
return $this->getGPG()->verifyStream($fp, $signature, $plaintext);
}