mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-09 17:37:02 +03:00
Revamp PGP management due to implementing Mailvelop and PEAR Crypt_GPG
This commit is contained in:
parent
43a1196dbb
commit
a47397ef09
16 changed files with 885 additions and 633 deletions
|
|
@ -7,19 +7,46 @@ trait Pgp
|
|||
/**
|
||||
* @throws \MailSo\Base\Exceptions\Exception
|
||||
*/
|
||||
public function GnuPG() : ?\gnupg
|
||||
public function GnuPG() : ?\SnappyMail\PGP\GnuPG
|
||||
{
|
||||
if (\class_exists('gnupg')) {
|
||||
$pgp_dir = $this->StorageProvider()->GenerateFilePath(
|
||||
$this->getAccountFromToken(),
|
||||
\RainLoop\Providers\Storage\Enumerations\StorageType::PGP
|
||||
);
|
||||
return new \gnupg(['home_dir' => \dirname($pgp_dir) . '/.gnupg']);
|
||||
}
|
||||
return null;
|
||||
$pgp_dir = $this->StorageProvider()->GenerateFilePath(
|
||||
$this->getAccountFromToken(),
|
||||
\RainLoop\Providers\Storage\Enumerations\StorageType::PGP
|
||||
);
|
||||
return \SnappyMail\PGP\GnuPG::getInstance($pgp_dir);
|
||||
}
|
||||
|
||||
public function DoImportKey() : array
|
||||
public function DoPgpGetKeysEmails() : array
|
||||
{
|
||||
$GPG = $this->GnuPG();
|
||||
if ($GPG) {
|
||||
$sign = $encrypt = $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'];
|
||||
}
|
||||
}
|
||||
if ($info['can_encrypt']) {
|
||||
foreach ($info['uids'] as $uid) {
|
||||
$public[] = $info['email'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$keys[] = $info;
|
||||
}
|
||||
return $this->DefaultResponse(__FUNCTION__, [
|
||||
'sign' => $sign,
|
||||
'encrypt' => $encrypt,
|
||||
'keys' => $keys,
|
||||
'info' => $GPG->getEngineInfo()
|
||||
]);
|
||||
}
|
||||
return $this->FalseResponse(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function DoPgpImportKey() : array
|
||||
{
|
||||
$sKeyId = $this->GetActionParam('KeyId', '');
|
||||
$sPublicKey = $this->GetActionParam('PublicKey', '');
|
||||
|
|
@ -32,6 +59,16 @@ trait Pgp
|
|||
$sEmail = $aMatch[0];
|
||||
}
|
||||
if ($sEmail) {
|
||||
/** https://wiki.gnupg.org/WKD
|
||||
DNS:
|
||||
openpgpkey.example.org. 300 IN CNAME wkd.keys.openpgp.org.
|
||||
|
||||
https://openpgpkey.example.com/.well-known/openpgpkey/example.com/hu/
|
||||
else https://example.com/.well-known/openpgpkey/hu/
|
||||
|
||||
An example: https://example.com/.well-known/openpgpkey/hu/it5sewh54rxz33fwmr8u6dy4bbz8itz4
|
||||
is the direct method URL for "bernhard.reiter@example.com"
|
||||
*/
|
||||
$aKeys = \SnappyMail\PGP\Keyservers::index($sEmail);
|
||||
if ($aKeys) {
|
||||
$sKeyId = $aKeys[0]['keyid'];
|
||||
|
|
@ -46,8 +83,9 @@ trait Pgp
|
|||
}
|
||||
}
|
||||
|
||||
return $sPublicKey
|
||||
? $this->DefaultResponse(__FUNCTION__, $this->GnuPG()->import($sPublicKey))
|
||||
$GPG = $sPublicKey ? $this->GnuPG() : null;
|
||||
return $GPG
|
||||
? $this->DefaultResponse(__FUNCTION__, $GPG->import($sPublicKey))
|
||||
: $this->FalseResponse(__FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
499
snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php
Normal file
499
snappymail/v/0.0.0/app/libraries/snappymail/pgp/gnupg.php
Normal file
|
|
@ -0,0 +1,499 @@
|
|||
<?php
|
||||
|
||||
namespace SnappyMail\PGP;
|
||||
|
||||
class GnuPG
|
||||
{
|
||||
private
|
||||
$homedir,
|
||||
// Instance of gnupg pecl extension
|
||||
$GnuPG,
|
||||
// Instance of PEAR Crypt_GPG
|
||||
$Crypt_GPG;
|
||||
|
||||
public static function getInstance(string $home) : ?self
|
||||
{
|
||||
$self = null;
|
||||
$home .= '/.gnupg';
|
||||
if (\class_exists('gnupg')) {
|
||||
$self = new self;
|
||||
$self->GnuPG = new \gnupg([
|
||||
// It is the file name of the executable program implementing this protocol which is usually path of the gpg executable.
|
||||
// 'file_name' => '/usr/bin/gpg',
|
||||
// It is the directory name of the configuration directory. It also overrides GNUPGHOME environment variable that is used for the same purpose.
|
||||
'home_dir' => $home
|
||||
]);
|
||||
// Output is ASCII
|
||||
$self->GnuPG->setarmor(1);
|
||||
} else {
|
||||
/**
|
||||
* $binary = trim(`which gpg`) ?: trim(`which gpg2`);
|
||||
* \is_executable($binary)
|
||||
*/
|
||||
include_once 'Crypt/GPG.php';
|
||||
if (\class_exists('Crypt_GPG')) {
|
||||
$self = new self;
|
||||
$self->Crypt_GPG = new \Crypt_GPG([
|
||||
// 'debug' => true,
|
||||
// 'binary' => $binary,
|
||||
'homedir' => $home
|
||||
]);
|
||||
}
|
||||
}
|
||||
if ($self) {
|
||||
$self->homedir = $home;
|
||||
// \putenv("GNUPGHOME={$home}");
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a key for decryption
|
||||
*/
|
||||
public function addDecryptKey(string $fingerprint, string $passphrase) : bool
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->adddecryptkey($fingerprint, $passphrase);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
$this->Crypt_GPG->addDecryptKey($fingerprint, $passphrase);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a key for encryption
|
||||
*/
|
||||
public function addEncryptKey(string $fingerprint) : bool
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->addencryptkey($fingerprint);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
$this->Crypt_GPG->addEncryptKey($fingerprint);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a key for signing
|
||||
*/
|
||||
public function addSignKey(string $fingerprint, ?string $passphrase) : bool
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->addsignkey($fingerprint, $passphrase);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
$this->Crypt_GPG->addSignKey($fingerprint, $passphrase);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all keys which were set for decryption before
|
||||
*/
|
||||
public function clearDecryptKeys() : bool
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->cleardecryptkeys();
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
$this->Crypt_GPG->clearDecryptKeys();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all keys which were set for encryption before
|
||||
*/
|
||||
public function clearEncryptKeys() : bool
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->clearencryptkeys();
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
$this->Crypt_GPG->clearEncryptKeys();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all keys which were set for signing before
|
||||
*/
|
||||
public function clearSignKeys() : bool
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->clearsignkeys();
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
$this->Crypt_GPG->clearSignKeys();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a given text
|
||||
*/
|
||||
public function decrypt(string $text) /*: string|false */
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->decrypt($text);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->decrypt($encryptedData);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a given file
|
||||
*/
|
||||
public function decryptFile(string $filename) /*: string|false */
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->decrypt(\file_get_contents($filename));
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->decryptFile($filename, $decryptedFile = null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts and verifies a given text
|
||||
*/
|
||||
public function decryptVerify(string $text, string &$plaintext) /*: array|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->decryptverify($text, $plaintext);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->decryptAndVerify($text, $ignoreVerifyErrors = false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts and verifies a given file
|
||||
*/
|
||||
public function decryptVerifyFile(string $filename, string &$plaintext) /*: array|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->decryptverify(\file_get_contents($filename), $plaintext);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->decryptAndVerifyFile($filename, $decryptedFile = null, $ignoreVerifyErrors = false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a given text
|
||||
*/
|
||||
public function encrypt(string $plaintext) /*: string|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->encrypt($plaintext);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->encrypt($plaintext);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a given text
|
||||
*/
|
||||
public function encryptFile(string $filename) /*: string|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->encrypt(\file_get_contents($filename));
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->encryptFile($filename, $encryptedFile = null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts and signs a given text
|
||||
*/
|
||||
public function encryptSign(string $plaintext) /*: string|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->encryptsign($plaintext);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->encryptAndSign($plaintext);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts and signs a given text
|
||||
*/
|
||||
public function encryptSignFile(string $filename) /*: string|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->encryptsign(\file_get_contents($filename));
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->encryptAndSignFile($filename, $signedFile = null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports a key
|
||||
*/
|
||||
public function export(string $fingerprint) /*: string|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->export($fingerprint);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
$this->Crypt_GPG->exportPrivateKey($fingerprint, $armor = true);
|
||||
$this->Crypt_GPG->exportPublicKey($fingerprint, $armor = true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the engine info
|
||||
*/
|
||||
public function getEngineInfo() : array
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->getengineinfo();
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return [
|
||||
'protocol' => null,
|
||||
'file_name' => null, // $this->Crypt_GPG->binary
|
||||
'home_dir' => $this->homedir,
|
||||
'version' => $this->Crypt_GPG->getVersion()
|
||||
];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the errortext, if a function fails
|
||||
*/
|
||||
public function getError() /*: string|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->geterror();
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error info
|
||||
*/
|
||||
public function getErrorInfo() : array
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->geterrorinfo();
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently active protocol for all operations
|
||||
*/
|
||||
public function getProtocol() : int
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->getprotocol();
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a key
|
||||
*/
|
||||
public function import(string $keydata) /*: array|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->import($keydata);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->importKey($keydata);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a key
|
||||
*/
|
||||
public function importFile(string $filename) /*: array|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->import(\file_get_contents($filename));
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->importKeyFile($filename);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with information about all keys that matches the given pattern
|
||||
*/
|
||||
public function keyInfo(string $pattern) : array
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->keyinfo($pattern);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle armored output
|
||||
* When true the output is ASCII
|
||||
*/
|
||||
public function setArmor(bool $armor = true) : bool
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->setarmor($armor ? 1 : 0);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
//$armor ? \Crypt_GPG::ARMOR_ASCII : \Crypt_GPG::ARMOR_
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mode for error_reporting
|
||||
* GNUPG_ERROR_WARNING, GNUPG_ERROR_EXCEPTION and GNUPG_ERROR_SILENT.
|
||||
* By default GNUPG_ERROR_SILENT is used.
|
||||
*/
|
||||
public function setErrorMode(int $errormode) : void
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
$this->GnuPG->seterrormode($errormode);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mode for signing
|
||||
* GNUPG_SIG_MODE_NORMAL, GNUPG_SIG_MODE_DETACH and GNUPG_SIG_MODE_CLEAR.
|
||||
* By default GNUPG_SIG_MODE_CLEAR
|
||||
*/
|
||||
public function setSignMode(int $signmode) : bool
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->setsignmode($signmode);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs a given text
|
||||
*/
|
||||
public function sign(string $plaintext) /*: string|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->sign($plaintext);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->sign($data, $mode = self::SIGN_MODE_NORMAL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs a given file
|
||||
*/
|
||||
public function signFile(string $filename) /*: string|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->sign(\file_get_contents($filename));
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->signFile($filename, $signedFile = null, $mode = self::SIGN_MODE_NORMAL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a signed text
|
||||
*/
|
||||
public function verify(string $signed_text, string $signature, string &$plaintext = null) /*: array|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->verify($signed_text, $signature, $plaintext);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->verify($signed_text, $signature = '');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a signed file
|
||||
*/
|
||||
public function verifyFile(string $filename, string $signature, string &$plaintext = null) /*: array|false*/
|
||||
{
|
||||
if ($this->GnuPG) {
|
||||
return $this->GnuPG->verify(\file_get_contents($filename), $signature, $plaintext);
|
||||
}
|
||||
if ($this->Crypt_GPG) {
|
||||
return $this->Crypt_GPG->verifyFile($filename, $signature = '');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* RFC 4880
|
||||
* https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.5
|
||||
*/
|
||||
public function signatureIssuer(string $signature) /*: array|false*/
|
||||
{
|
||||
if (preg_match('/-----BEGIN PGP SIGNATURE-----(.+)-----END PGP SIGNATURE-----/', $signature, $match)) {
|
||||
// TODO: use https://github.com/singpolyma/openpgp-php ?
|
||||
$binary = \base64_decode(\trim($match[1]));
|
||||
return \strtoupper(\bin2hex(\substr($binary, 24, 8)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
$this->Crypt_GPG->deletePublicKey($keyId);
|
||||
$this->Crypt_GPG->deletePrivateKey($keyId);
|
||||
$this->Crypt_GPG->getKeys($keyId = '');
|
||||
$this->Crypt_GPG->getFingerprint($keyId, $format = self::FORMAT_NONE);
|
||||
$this->Crypt_GPG->getLastSignatureInfo();
|
||||
$this->Crypt_GPG->addPassphrase($key, $passphrase);
|
||||
$this->Crypt_GPG->clearPassphrases();
|
||||
$this->Crypt_GPG->hasEncryptKeys();
|
||||
$this->Crypt_GPG->hasSignKeys();
|
||||
$this->Crypt_GPG->getWarnings();
|
||||
*/
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ abstract class Keyservers
|
|||
'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',
|
||||
|
|
|
|||
|
|
@ -81,12 +81,20 @@
|
|||
<span data-i18n="COMPOSE/BUTTON_MARK_AS_IMPORTANT"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="dividerbar" data-bind="visible: capaOpenPGP, click: openOpenPgpPopup, css: {'disabled': isHtml()}">
|
||||
<!-- ko if: capaOpenPGP -->
|
||||
<li class="dividerbar" data-bind="click: togglePgpSign, css: {'disabled': !canPgpSign()}">
|
||||
<a>
|
||||
<i class="fontastic">🔑</i>
|
||||
<span data-i18n="COMPOSE/BUTTON_OPEN_PGP"></span>
|
||||
<i class="fontastic" data-bind="text: pgpSign() ? '✍' : '☐'"></i>
|
||||
<span data-i18n="POPUPS_COMPOSE_OPEN_PGP/LABEL_SIGN"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li data-bind="click: togglePgpEncrypt, css: {'disabled': !canPgpEncrypt()}">
|
||||
<a>
|
||||
<i class="fontastic" data-bind="text: pgpEncrypt() ? '🔒' : '☐'"></i>
|
||||
<span data-i18n="POPUPS_COMPOSE_OPEN_PGP/LABEL_ENCRYPT"></span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- /ko -->
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -1,85 +0,0 @@
|
|||
<header>
|
||||
<a href="#" class="close" data-bind="command: cancelCommand">×</a>
|
||||
<h3 data-i18n="POPUPS_COMPOSE_OPEN_PGP/TITLE_COMPOSE_OPEN_PGP"></h3>
|
||||
</header>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="alert" data-bind="visible: '' !== notification(), text: notification"></div>
|
||||
<div data-bind="component: {
|
||||
name: 'Checkbox',
|
||||
params: {
|
||||
label: 'POPUPS_COMPOSE_OPEN_PGP/LABEL_SIGN',
|
||||
value: sign
|
||||
}
|
||||
}, click: updateCommand"></div>
|
||||
|
||||
<div class="key-list" data-bind="visible: sign">
|
||||
<div class="key-list-wrp empty" data-bind="visible: !signKey()">
|
||||
No private key found
|
||||
</div>
|
||||
<div class="key-list-wrp" data-bind="visible: signKey()">
|
||||
<div class="key-list__item">
|
||||
<div class="key-list__item-hash">
|
||||
(<span data-bind="text: signKey() ? signKey().hash : ''"></span>)
|
||||
</div>
|
||||
<div class="key-list__item-names">
|
||||
<!-- ko if: signKey() -->
|
||||
<!-- ko foreach: signKey().users -->
|
||||
<div class="key-list__item-name" data-bind="text: $data"></div>
|
||||
<!-- /ko -->
|
||||
<!-- /ko -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-bind="component: {
|
||||
name: 'Checkbox',
|
||||
params: {
|
||||
label: 'POPUPS_COMPOSE_OPEN_PGP/LABEL_ENCRYPT',
|
||||
value: encrypt
|
||||
}
|
||||
}"></div>
|
||||
|
||||
<div class="key-list" data-bind="visible: encrypt">
|
||||
<div class="key-list-wrp empty" data-bind="visible: encryptKeys().length === 0">
|
||||
No public keys selected
|
||||
</div>
|
||||
<div class="key-list-wrp" data-bind="visible: encryptKeys().length > 0, foreach: encryptKeys">
|
||||
<div class="key-list__item">
|
||||
<div class="key-list__item-hash" data-bind="visible: !empty">
|
||||
(<span data-bind="text: hash"></span>)
|
||||
</div>
|
||||
<div class="key-list__item-names" data-bind="css: {'empty': empty}, foreach: users">
|
||||
<div class="key-list__item-name" data-bind="text: $data"></div>
|
||||
</div>
|
||||
<div class="key-list__item-error" data-bind="visible: empty">
|
||||
(Public key not found)
|
||||
</div>
|
||||
<div class="key-list__item-delete fontastic" data-bind="click: removable() ? $parent.deletePublickKey : null, css: {'disabled': !removable()}">🗑</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="key-actions">
|
||||
<div data-bind="visible: sign()">
|
||||
<input type="password" class="inputPassword input-block-level"
|
||||
autocomplete="current-password" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-i18n="[placeholder]GLOBAL/PASSWORD"
|
||||
data-bind="textInput: password, onEnter: doCommand" />
|
||||
<select class="input-block-level" data-bind="visible: privateKeysOptions().length, options: privateKeysOptions, value: selectedPrivateKey,
|
||||
optionsCaption: privateKeysOptionsCaption, optionsText: 'name', optionsValue: 'id'"></select>
|
||||
</div>
|
||||
<select class="input-block-level" data-bind="visible: encrypt() && publicKeysOptions().length, options: publicKeysOptions, value: selectedPublicKey,
|
||||
optionsCaption: publicKeysOptionsCaption, optionsText: 'name', optionsValue: 'id'"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<button class="btn buttonDo" data-bind="command: doCommand,
|
||||
enable: (sign() || encrypt()) && (!encrypt() || encrypt() && encryptKeys().length > 0)">
|
||||
<i class="fontastic" data-bind="css: {'icon-spinner': submitRequest()}">🔑</i>
|
||||
<span data-bind="visible: sign() && !encrypt()" data-i18n="POPUPS_COMPOSE_OPEN_PGP/BUTTON_SIGN"></span>
|
||||
<span data-bind="visible: !sign() && encrypt()" data-i18n="POPUPS_COMPOSE_OPEN_PGP/BUTTON_ENCRYPT"></span>
|
||||
<span data-bind="visible: (sign() && encrypt()) || (!sign() && !encrypt())" data-i18n="POPUPS_COMPOSE_OPEN_PGP/BUTTON_SIGN_AND_ENCRYPT"></span>
|
||||
</button>
|
||||
</footer>
|
||||
Loading…
Add table
Add a link
Reference in a new issue