1
0
mirror of https://github.com/QRouland/UTPass.git synced 2025-05-12 13:30:54 +00:00

Compare commits

...

2 Commits

Author SHA1 Message Date
beaad58af2 Add docsting for pass plugin 2025-01-15 23:40:35 +01:00
e589abd10c Refactor gpg for more clean job handling 2025-01-15 23:15:00 +01:00
12 changed files with 793 additions and 266 deletions

View File

@ -3,6 +3,7 @@
#include <QFile> #include <QFile>
#include <QDir> #include <QDir>
#include <QtCore/QStandardPaths> #include <QtCore/QStandardPaths>
#include <QProcess>
#include <gpgme.h> #include <gpgme.h>
#include <gpgme++/data.h> #include <gpgme++/data.h>
@ -22,9 +23,11 @@
#include <qgpgme/keylistjob.h> #include <qgpgme/keylistjob.h>
#include <qgpgme/changeownertrustjob.h> #include <qgpgme/changeownertrustjob.h>
#include "gpg.h" #include "gpg.h"
#include "passkeymodel.h"
#include "passphraseprovider.h" #include "passphraseprovider.h"
#include "qprocess.h"
@ -32,9 +35,9 @@
using namespace GpgME; using namespace GpgME;
using namespace QGpgME; using namespace QGpgME;
Gpg::Gpg() Gpg::Gpg(QObject* windows)
{ {
m_window = nullptr; this->m_passphrase_provider = new UTPassphraseProvider(windows);
Gpg::initGpgConfig(); Gpg::initGpgConfig();
@ -50,6 +53,11 @@ Gpg::Gpg()
qDebug() << "GNUPG Home is :" << engineInfo(OpenPGP).homeDirectory(); qDebug() << "GNUPG Home is :" << engineInfo(OpenPGP).homeDirectory();
} }
Gpg::~Gpg()
{
delete this->m_passphrase_provider;
}
QString Gpg::initGpgHome() QString Gpg::initGpgHome()
{ {
@ -124,37 +132,28 @@ void Gpg::initGpgConfig()
} }
QPair<Error, QString> Gpg::decrypt(QByteArray cipherText) Error Gpg::decrypt(QByteArray cipher_text)
{ {
auto job = openpgp()->decryptJob(); auto job = openpgp()->decryptJob();
auto ctx = DecryptJob::context(job); auto ctx = DecryptJob::context(job);
auto provider = new UTPassphraseProvider; ctx->setPassphraseProvider(this->m_passphrase_provider);
ctx->setPassphraseProvider(provider);
ctx->setPinentryMode(Context::PinentryLoopback); ctx->setPinentryMode(Context::PinentryLoopback);
QByteArray plain_text; QObject::connect(job, &DecryptJob::result,
auto decResult = job->exec(cipherText, plain_text); this, &Gpg::decryptResultSlot);
delete job; return job->start(cipher_text);
delete provider;
if (decResult.error()) {
qWarning() << "something gone wrong on decrypt";
qDebug() << "Code Error : " << decResult.error().code();
qDebug() << "Error str : " << decResult.error().asString();
}
return QPair<Error, QString>(decResult.error(), QString::fromUtf8(plain_text));
} }
Error Gpg::decryptFromFile(QString path)
QPair<Error, QString> Gpg::decryptFromFile(QString path)
{ {
qDebug() << "Decrypt from " << path; qDebug() << "Decrypt from " << path;
QFile file(path); QFile file(path);
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Can't open the File"; qWarning() << "Can't open the File";
return QPair<Error, QString>(Error(), QString());; return Error();
} }
QByteArray cipherText = file.readAll(); QByteArray cipherText = file.readAll();
file.close(); file.close();
@ -162,77 +161,85 @@ QPair<Error, QString> Gpg::decryptFromFile(QString path)
} }
QPair<Error, QByteArray> Gpg::encrypt(QString str, QString uid, bool ascii_armor, bool text_mode)
void Gpg::decryptResultSlot(const GpgME::DecryptionResult &result, const QByteArray &plainText,
const QString &auditLogAsHtml, const GpgME::Error &auditLogError)
{ {
if (result.error()) {
qDebug() << "Encrypt to QByteArray"; qWarning() << "Something gone wrong on decrypt";
auto keys = getKeys(uid); qDebug() << "Code Error : " << result.error().code();
if (keys.first) { qDebug() << "Error str : " << result.error().asString();
return QPair<Error, QByteArray>(keys.first, QByteArray());
} }
emit decryptResult(result.error(), QString::fromUtf8(plainText));
auto job = std::unique_ptr<EncryptJob>(openpgp()->encryptJob(ascii_armor, text_mode));
QByteArray cipherText;
auto result = job->exec(keys.second, str.toUtf8(), Context::AlwaysTrust, cipherText);
qDebug() << "Encrypted to QByteArray";
return QPair<Error, QByteArray>(result.error(), cipherText);
} }
Error Gpg::encryptToFile(QString str, QString path, QString uid, bool ascii_armor, // QPair<Error, QByteArray> Gpg::encrypt(QString str, QString uid, bool ascii_armor, bool text_mode)
bool text_mode) // {
{
qDebug() << "Encrypting to file " << path; // qDebug() << "Encrypt to QByteArray";
QFile file(path); // auto keys = getKeys(uid);
if (!file.open(QIODevice::WriteOnly)) { // if (keys.first) {
qWarning() << "Can't open the file to write it" ; // return QPair<Error, QByteArray>(keys.first, QByteArray());
return Error(); // }
}
auto encrypt_ret = encrypt(str, uid, ascii_armor, text_mode); // auto job = std::unique_ptr<EncryptJob>(openpgp()->encryptJob(ascii_armor, text_mode));
if (encrypt_ret.first) {
file.write(encrypt_ret.second); // QByteArray cipherText;
} // auto result = job->exec(keys.second, str.toUtf8(), Context::AlwaysTrust, cipherText);
qDebug() << "Encrypting to file " << path;
return encrypt_ret.first; // qDebug() << "Encrypted to QByteArray";
} // return QPair<Error, QByteArray>(result.error(), cipherText);
// }
QPair<Error, std::vector< GpgME::Key >> Gpg::getAllKeys ( bool remote, const bool include_sigs, // Error Gpg::encryptToFile(QString str, QString path, QString uid, bool ascii_armor,
// bool text_mode)
// {
// qDebug() << "Encrypting to file " << path;
// QFile file(path);
// if (!file.open(QIODevice::WriteOnly)) {
// qWarning() << "Can't open the file to write it" ;
// return Error();
// }
// auto encrypt_ret = encrypt(str, uid, ascii_armor, text_mode);
// if (encrypt_ret.first) {
// file.write(encrypt_ret.second);
// }
// qDebug() << "Encrypting to file " << path;
// return encrypt_ret.first;
// }
Error Gpg::getAllKeys ( bool remote, const bool include_sigs,
bool validate ) bool validate )
{ {
return getKeys(QString(""), remote, include_sigs, validate); return getKeys(QString(""), remote, include_sigs, validate);
} }
QPair<Error, std::vector<Key >> Gpg::getKeys(QString pattern_uid, bool remote, bool include_sigs, Error Gpg::getKeys(QString pattern_uid, bool remote, bool include_sigs,
bool validate) bool validate)
{ {
qDebug() << "Getting the keys " << pattern_uid; qDebug() << "Getting the keys " << pattern_uid;
auto job = std::unique_ptr<KeyListJob>(openpgp()->keyListJob(remote, include_sigs, validate)); auto job = openpgp()->keyListJob(remote, include_sigs, validate);
std::vector<Key> keys; QObject::connect(job, &KeyListJob::result,
auto result = job->exec(QStringList() << pattern_uid, false, keys); this, &Gpg::getKeysJobResultSlot);
qDebug() << "Got the keys " << pattern_uid; return job->start(QStringList() << pattern_uid, false);
return QPair<Error, std::vector< Key >> (result.error(), keys);
} }
void Gpg::getKeysJobResultSlot(const GpgME::KeyListResult &result, const std::vector<GpgME::Key> &keys,
QPair<Error, Key> Gpg::getKey(QString uid, bool remote, bool include_sigs, bool validate) const QString &auditLogAsHtml, const GpgME::Error &auditLogError)
{ {
qDebug() << "Getting the key " << uid; if (result.error()) {
auto keys = getKeys(uid, remote, include_sigs, validate); qWarning() << "Something gone wrong on decrypt";
qDebug() << "Code Error : " << result.error().code();
if (keys.first or keys.second.size() != 1) { qDebug() << "Error str : " << result.error().asString();
qWarning() << "Bad id";
return QPair<Error, Key>(keys.first, Key::null);
} }
qDebug() << "Got the key " << uid; emit getKeysResult(result.error(), keys);
return QPair<Error, Key>(keys.first, keys.second.front());
} }
Error Gpg::importKeysFromFile(QString path) Error Gpg::importKeysFromFile(QString path)
{ {
qDebug() << "Importing the key file" << path; qDebug() << "Importing the key file" << path;
@ -242,51 +249,54 @@ Error Gpg::importKeysFromFile(QString path)
qWarning() << "Can't open the File"; qWarning() << "Can't open the File";
return Error(); return Error();
} }
auto data = file.readAll();
file.close();
auto job = openpgp()->importJob(); auto job = openpgp()->importJob();
auto ctx = ImportJob::context(job);
auto result = job->exec(file.readAll()); QObject::connect(job, &ImportJob::result,
this, &Gpg::importKeysFromFileSlot);
return job->start(data);
}
void Gpg::importKeysFromFileSlot(const GpgME::ImportResult &result, const QString &auditLogAsHtml,
const GpgME::Error &auditLogError)
{
qDebug() << "numImported" << result.numImported(); qDebug() << "numImported" << result.numImported();
qDebug() << "numSecretKeysImported" << result.numSecretKeysImported(); qDebug() << "numSecretKeysImported" << result.numSecretKeysImported();
qDebug() << "numSecretKeysConsidered" << result.numSecretKeysConsidered(); qDebug() << "numSecretKeysConsidered" << result.numSecretKeysConsidered();
qDebug() << "numSecretKeysUnchanged" << result.numSecretKeysUnchanged(); qDebug() << "numSecretKeysUnchanged" << result.numSecretKeysUnchanged();
qDebug() << "numUnchanged" << result.numUnchanged(); qDebug() << "numUnchanged" << result.numUnchanged();
file.close();
delete job;
if (result.error()) { if (result.error()) {
qWarning() << "Import go wrong"; qWarning() << "Something gone wrong on decrypt";
qDebug() << "Code Error : " << result.error().code(); qDebug() << "Code Error : " << result.error().code();
qDebug() << "Error str : " << result.error().asString(); qDebug() << "Error str : " << result.error().asString();
} }
qDebug() << "Imported the key file" << path; emit importKeysFromFileResult(result.error());
return result.error();
} }
Error Gpg::deleteKeyId(QString uid) Error Gpg::deleteKey(const Key key)
{ {
qDebug() << "Deleting key id " << uid; auto job = openpgp()->deleteJob();
auto key = getKey(uid);
if (key.first) { QObject::connect(job, &DeleteJob::result,
return key.first; this, &Gpg::deleteKeySlot);
return openpgp()->deleteJob()->start(key, true);
} }
auto ctx = std::unique_ptr<Context>(Context::createForProtocol(OpenPGP)); void Gpg::deleteKeySlot(const GpgME::Error &error, const QString &auditLogAsHtml, const GpgME::Error &auditLogError)
auto err = ctx->deleteKey(key.second, true); {
if (err) { if (error) {
qWarning() << "Delete go wrong"; qWarning() << "Something gone wrong on decrypt";
qDebug() << "Code Error : " << err.code(); qDebug() << "Code Error : " << error.code();
qDebug() << "Error str : " << err.asString(); qDebug() << "Error str : " << error.asString();
return err; }
emit deleteKeyResult(error);
} }
qDebug() << "Deleted key id" << uid;
return err;
}

View File

@ -1,61 +1,228 @@
#ifndef GPG_H #ifndef GPG_H
#define GPG_H #define GPG_H
#include "passkeymodel.h"
#include "passphraseprovider.h"
#include <memory> #include <memory>
#include <QQuickWindow> #include <QQuickWindow>
#include <gpgme++/context.h> #include <gpgme++/context.h>
#include <qgpgme/changeownertrustjob.h> #include <qgpgme/changeownertrustjob.h>
#include <QSemaphore>
#include <gpgme.h>
#include <qgpgme/importjob.h>
#include <qgpgme/deletejob.h>
#include <qgpgme/decryptjob.h>
#include <qgpgme/encryptjob.h>
#include <qgpgme/protocol.h>
#include <qgpgme/keylistjob.h>
#include <qgpgme/changeownertrustjob.h>
using namespace GpgME; using namespace GpgME;
using namespace QGpgME;
class Gpg /**
* @class Gpg
* @brief A class for managing GPG key operations such as key import, decryption, and deletion.
*
* This class integrates with the GPGME (GnuPG Made Easy) library to provide functionalities
* for interacting with GPG keys, including decrypting messages, importing keys from files,
* listing keys, and deleting keys. The class also provides slots for handling results
* of asynchronous GPG operations and communicates with the user via signals.
*/
class Gpg: public QObject
{ {
Q_OBJECT
Q_PROPERTY(UTPassphraseProvider* passphrase_provider READ passphrase_provider MEMBER m_passphrase_provider )
private slots:
/**
* @brief Slot to handle the result of a decryption operation.
* @param result The result of the decryption operation.
* @param plain_text The decrypted text.
* @param auditLogAsHtml The HTML formatted audit log for the operation.
* @param auditLogError The error associated with the audit log, if any.
*/
void decryptResultSlot(
const DecryptionResult &result,
const QByteArray &plain_text,
const QString &auditLogAsHtml,
const Error &auditLogError
);
/**
* @brief Slot to handle the result of a key retrieval operation.
* @param result The result of the key retrieval operation.
* @param keys A vector of keys retrieved.
* @param auditLogAsHtml The HTML formatted audit log for the operation, if any.
* @param auditLogError The error associated with the audit log, if any.
*/
void getKeysJobResultSlot(
const GpgME::KeyListResult &result,
const std::vector<GpgME::Key> &keys,
const QString &auditLogAsHtml,
const GpgME::Error &auditLogError
);
/**
* @brief Slot to handle the result of a key import operation.
* @param result The result of the import operation.
* @param auditLogAsHtml The HTML formatted audit log for the operation, if any.
* @param auditLogError The error associated with the audit log, if any.
*/
void importKeysFromFileSlot(
const GpgME::ImportResult &result,
const QString &auditLogAsHtml,
const GpgME::Error &auditLogError
);
/**
* @brief Slot to handle the result of a key deletion operation.
* @param result The error result of the deletion operation.
* @param auditLogAsHtml The HTML formatted audit log for the operation, if any.
* @param auditLogError The error associated with the audit log, if any.
*/
void deleteKeySlot(
const GpgME::Error &result,
const QString &auditLogAsHtml,
const GpgME::Error &auditLogError
);
signals:
/**
* @brief Signal emitted when keys are imported from a file.
* @param err The error that occurred during the import operation, if any.
*/
void importKeysFromFileResult(Error err);
/**
* @brief Signal emitted when keys are retrieved.
* @param err The error that occurred during the retrieval operation, if any.
* @param keys A vector of keys retrieved.
*/
void getKeysResult(Error err, std::vector<GpgME::Key> keys);
/**
* @brief Signal emitted when a key is deleted.
* @param err The error that occurred during the deletion operation, if any.
*/
void deleteKeyResult(Error err);
/**
* @brief Signal emitted when a decryption operation completes.
* @param err The error that occurred during decryption, if any.
* @param plain_text The decrypted message.
*/
void decryptResult(Error err, QString plain_text);
private: private:
Gpg(); UTPassphraseProvider *m_passphrase_provider; /**< The passphrase provider used for authentication. */
QObject *m_window;
/**
* @brief Finds the path of a command in the system's environment.
* @param command The name of the command to find.
* @return The full path to the command.
*/
QString findCommandPath(const QString &command); QString findCommandPath(const QString &command);
/**
* @brief Initializes the GPG home directory.
* @return The path to the GPG home directory.
*/
QString initGpgHome(); QString initGpgHome();
/**
* @brief Initializes the GPG executable path.
* @return The path to the GPG executable.
*/
QString initGpgExec(); QString initGpgExec();
/**
* @brief Initializes the GPG configuration.
*/
void initGpgConfig(); void initGpgConfig();
/**
* @brief Retrieves a GPG key by UID.
* @param uid The UID of the key to retrieve.
* @param remote Whether to fetch the key from a remote keyserver (default: false).
* @param include_sigs Whether to include signatures (default: false).
* @param validate Whether to validate the key (default: false).
* @return The error result of the operation.
*/
Error getKey(QString uid, bool remote = false, bool include_sigs = false, bool validate = false);
public: public:
static std::shared_ptr<Gpg> instance() /**
* @brief Constructs a Gpg object and initializes necessary resources.
* @param window The window object for interacting with the user interface.
*/
Gpg(QObject* window);
/**
* @brief Destroys the Gpg object and cleans up resources.
*/
~Gpg();
/**
* @brief Gets the passphrase provider used for GPG authentication.
* @return The passphrase provider.
*/
UTPassphraseProvider *passphrase_provider() const
{ {
static std::shared_ptr<Gpg> s{new Gpg}; return m_passphrase_provider;
return s;
} }
Gpg(Gpg const &) = delete;
void operator=(Gpg const &) = delete;
void setWindow(QObject *window)
{
m_window = window;
};
QObject *getWindow()
{
return m_window;
};
QPair<Error, std::vector<Key >> getAllKeys(bool remote = false, bool include_sigs = {}, bool /**
validate = false); * @brief Imports GPG keys from a file.
QPair<Error, std::vector<Key >> getKeys( QString pattern_uid, bool remote = false, * @param path The path to the file containing the keys.
bool include_sigs = false, * @return The error result of the import operation.
bool validate = false); */
QPair<Error, Key> getKey( QString uid, bool remote = false, bool include_sigs = false, Error importKeysFromFile(const QString path);
bool validate = false);
QPair<Error, QString> decrypt( QByteArray cipherText); /**
QPair<Error, QString> decryptFromFile( QString path); * @brief Retrieves keys matching the provided UID pattern.
QPair<Error, QByteArray> encrypt( QString str, QString uid, bool ascii_armor = true, * @param pattern_uid The UID pattern to search for.
bool text_mode = true); * @param remote Whether to fetch the key from a remote keyserver (default: false).
Error encryptToFile( QString str, QString path, QString uid, bool ascii_armor = true, * @param include_sigs Whether to include signatures (default: false).
bool text_mode = true); * @param validate Whether to validate the key (default: false).
Error importKeysFromFile( QString path); * @return The error result of the operation.
Error deleteKeyId( QString uid); */
Error getKeys(const QString pattern_uid, bool remote = false, bool include_sigs = false, bool validate = false);
/**
* @brief Retrieves all keys from the GPG keyring.
* @param remote Whether to fetch the keys from a remote keyserver (default: false).
* @param include_sigs Whether to include signatures (default: false).
* @param validate Whether to validate the keys (default: false).
* @return The error result of the operation.
*/
Error getAllKeys(bool remote = false, bool include_sigs = false, bool validate = false);
/**
* @brief Deletes a specified GPG key.
* @param key The key to delete.
* @return The error result of the deletion operation.
*/
Error deleteKey(const Key key);
/**
* @brief Decrypts a given ciphertext.
* @param cipher_text The ciphertext to decrypt.
* @return The error result of the decryption operation.
*/
Error decrypt(const QByteArray cipher_text);
/**
* @brief Decrypts the contents of a file.
* @param path The path to the file to decrypt.
* @return The error result of the decryption operation.
*/
Error decryptFromFile(const QString path);
// Error encrypt (QString str, QString uid, bool ascii_armor = true, bool text_mode = true);
}; };
#endif #endif

View File

@ -8,8 +8,11 @@
Pass::Pass(): m_password_store (QStandardPaths::writableLocation( Pass::Pass():
QStandardPaths::AppDataLocation).append("/.password-store")) m_password_store (QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation).append("/.password-store")),
m_sem(std::unique_ptr<QSemaphore>(new QSemaphore(1))),
m_show_filename(QString())
{} {}
void Pass::initialize(QObject *window) void Pass::initialize(QObject *window)
@ -18,7 +21,14 @@ void Pass::initialize(QObject *window)
qFatal("window is invalid. Abording."); qFatal("window is invalid. Abording.");
} }
Gpg::instance()->setWindow(window); this->m_gpg = std::unique_ptr<Gpg>(new Gpg(window));
QObject::connect(this, &Pass::responsePassphraseDialogPropagate, this->m_gpg->passphrase_provider(),
&UTPassphraseProvider::handleResponse);
QObject::connect(this->m_gpg.get(), &Gpg::importKeysFromFileResult, this, &Pass::importGPGKeyResult);
QObject::connect(this->m_gpg.get(), &Gpg::getKeysResult, this, &Pass::getAllGPGKeysResult);
QObject::connect(this->m_gpg.get(), &Gpg::deleteKeyResult, this, &Pass::deleteGPGKeyResult);
QObject::connect(this->m_gpg.get(), &Gpg::decryptResult, this, &Pass::showResult);
QDir dir(m_password_store); QDir dir(m_password_store);
if (!dir.exists()) { if (!dir.exists()) {
@ -27,38 +37,91 @@ void Pass::initialize(QObject *window)
qInfo() << "Password Store is :" << m_password_store; qInfo() << "Password Store is :" << m_password_store;
} }
void Pass::show(QUrl url) bool Pass::show(QUrl url)
{ {
qInfo() << "Decrypting"; if (!this->m_sem->tryAcquire(1, 500)) {
auto decrypt_ret = Gpg::instance()->decryptFromFile(url.toLocalFile()); return false;
if (decrypt_ret.first) {
qInfo() << "Decrypt Failed";
emit decryptFailed();
} else if (decrypt_ret.second.isNull()) {
qInfo() << "Decrypt Canceled";
emit decryptCanceled();
} else {
qInfo() << "Decrypt OK";
emit decrypted(url.fileName(), decrypt_ret.second);
} }
auto path = url.toLocalFile();
qInfo() << "Staring decrypting job for " << path;
QFileInfo file_info(path);
this->m_show_filename = file_info.completeBaseName();
return this->m_gpg->decryptFromFile(path);
} }
bool Pass::deleteGPGKey(QString id) void Pass::showResult(Error err, QString plain_text)
{ {
qInfo() << "Deleting Key id " << id; qInfo() << "Result for decrypting job";
return !Gpg::instance()->deleteKeyId(id); if (err) {
qInfo() << "Decrypt Failed";
emit showFailed(err.asString());
} else {
qInfo() << "Decrypt OK";
emit showSucceed(this->m_show_filename, plain_text);
}
this->m_show_filename = QString();
this->m_sem->release(1);
}
bool Pass::deleteGPGKey(Key key)
{
if (!this->m_sem->tryAcquire(1, 500)) {
return false;
}
qInfo() << "Deleting Key";
return this->m_gpg->deleteKey(key);
}
void Pass::deleteGPGKeyResult(Error err)
{
if (err) {
emit deleteGPGKeyFailed(err.asString());
} else {
emit deleteGPGKeySucceed();
}
this->m_sem->release(1);
} }
bool Pass::importGPGKey(QUrl url) bool Pass::importGPGKey(QUrl url)
{ {
if (!this->m_sem->tryAcquire(1, 500)) {
return false;
}
qInfo() << "Importing Key from " << url; qInfo() << "Importing Key from " << url;
return !Gpg::instance()->importKeysFromFile(url.toLocalFile()); return this->m_gpg->importKeysFromFile(url.toLocalFile());
} }
QVariant Pass::getAllGPGKeys() void Pass::importGPGKeyResult(Error err)
{ {
qInfo() << "Getting all key form gpg "; if (err) {
return QVariant::fromValue(PassKeyModel::keysToPassKey( emit importGPGKeyFailed(err.asString());
Gpg::instance()->getAllKeys().second)); // TODO Error handling } else {
emit importGPGKeySucceed();
}
this->m_sem->release(1);
} }
bool Pass::getAllGPGKeys()
{
if (!this->m_sem->tryAcquire(1, 500)) {
return false;
}
qInfo() << "Getting all key form gpg ";
return this->m_gpg->getAllKeys();
}
void Pass::getAllGPGKeysResult(Error err, std::vector<GpgME::Key> keys_info)
{
if (err) {
emit getAllGPGKeysFailed(err.asString());
} else {
emit getAllGPGKeysSucceed(QVariant::fromValue(PassKeyModel::keysToPassKey(keys_info)));
}
this->m_sem->release(1);
}
void Pass::responsePassphraseDialog(bool cancel, QString passphrase)
{
qDebug() << "responsePassphraseDialog";
emit responsePassphraseDialogPropagate(cancel, passphrase);
}

View File

@ -4,35 +4,180 @@
#include <QObject> #include <QObject>
#include <QUrl> #include <QUrl>
#include <QVariant> #include <QVariant>
#include <gpgme++/context.h>
#include "gpg.h"
using namespace GpgME;
/**
* @class Pass
* @brief A class for managing password storage using GPG encryption.
*
* This class provides functionalities for interacting with password storage, including
* storing, showing, importing, and deleting passwords securely using GPG encryption.
* It communicates asynchronously with GPG operations, using signals and slots to propagate results.
* The class interacts with the `Gpg` class to perform GPG key operations and provides an interface
* for the user to manage the passwords.
*/
class Pass : public QObject class Pass : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString password_store READ password_store) Q_PROPERTY(QString password_store READ password_store MEMBER m_password_store CONSTANT)
private: private slots:
QString m_password_store; /**
* @brief Slot to handle the result of a GPG decryption operation (to show password).
* @param err The error that occurred during the operation.
* @param plain_text The decrypted plain text (password).
*/
void showResult(Error err, QString plain_text);
/**
* @brief Slot to handle the result of a GPG key deletion operation.
* @param err The error that occurred during the operation.
*/
void deleteGPGKeyResult(Error err);
/**
* @brief Slot to handle the result of a GPG key import operation.
* @param err The error that occurred during the operation.
*/
void importGPGKeyResult(Error err);
/**
* @brief Slot to handle the result of retrieving all GPG keys.
* @param err The error that occurred during the operation.
* @param keys_info The list of GPG keys retrieved.
*/
void getAllGPGKeysResult(Error err, std::vector<GpgME::Key> keys_info);
signals: signals:
void decrypted(QString name, QString text); // GPG-related signals
void decryptCanceled(); /**
void decryptFailed(); * @brief Emitted when a GPG key is successfully deleted.
*/
void deleteGPGKeySucceed();
/**
* @brief Emitted when a GPG key deletion fails.
* @param message The error message describing the failure.
*/
void deleteGPGKeyFailed(QString message);
/**
* @brief Emitted when a GPG key is successfully imported.
*/
void importGPGKeySucceed();
/**
* @brief Emitted when a GPG key import fails.
* @param message The error message describing the failure.
*/
void importGPGKeyFailed(QString message);
/**
* @brief Emitted when all GPG keys are successfully retrieved.
* @param keys_info The list of retrieved keys.
*/
void getAllGPGKeysSucceed(QVariant keys_info);
/**
* @brief Emitted when retrieving GPG keys fails.
* @param message The error message describing the failure.
*/
void getAllGPGKeysFailed(QString message);
// Pass-related signals
/**
* @brief Emitted to propagate passphrase dialog response.
* @param cancel Whether the dialog was cancelled.
* @param passphrase The passphrase entered, if not cancelled.
*/
void responsePassphraseDialogPropagate(bool cancel, QString passphrase);
/**
* @brief Emitted when a password is successfully retrieved and shown.
* @param name The name of the password (e.g., service).
* @param text The password text.
*/
void showSucceed(QString name, QString text);
/**
* @brief Emitted when showing a password fails.
* @param message The error message describing the failure.
*/
void showFailed(QString message);
private:
QString m_password_store; /**< The path to the password store. */
std::unique_ptr<Gpg> m_gpg; /**< The GPG instance used for encryption/decryption. */
std::unique_ptr<QSemaphore> m_sem; /**< Semaphore for managing concurrent operations. */
QString m_show_filename; /**< The filename associated with the password to show. */
public: public:
/**
* @brief Constructs the Pass object and initializes necessary resources.
*/
Pass(); Pass();
/**
* @brief Destructor for cleaning up resources used by the Pass object.
*/
~Pass() override = default; ~Pass() override = default;
/**
* @brief Gets the path to the password store.
* @return The path to the password store.
*/
QString password_store() const QString password_store() const
{ {
return m_password_store; return m_password_store;
} };
/**
* @brief Initializes the Pass object with the given window.
* @param window The QObject window to interact with.
*/
Q_INVOKABLE void initialize(QObject *window); Q_INVOKABLE void initialize(QObject *window);
Q_INVOKABLE void show(QUrl url);
Q_INVOKABLE bool deleteGPGKey(QString id); // GPG-related methods
/**
* @brief Deletes the specified GPG key.
* @param key The GPG key to delete.
* @return True if the operation was successful, false otherwise.
*/
Q_INVOKABLE bool deleteGPGKey(Key key);
/**
* @brief Imports a GPG key from the given URL.
* @param url The URL to import the GPG key from.
* @return True if the operation was successful, false otherwise.
*/
Q_INVOKABLE bool importGPGKey(QUrl url); Q_INVOKABLE bool importGPGKey(QUrl url);
Q_INVOKABLE QVariant getAllGPGKeys();
/**
* @brief Retrieves all GPG keys.
* @return True if the operation was successful, false otherwise.
*/
Q_INVOKABLE bool getAllGPGKeys();
/**
* @brief Return the response from the passphrase dialog.
* @param cancel Whether the dialog was cancelled.
* @param passphrase The passphrase entered, if not cancelled.
*/
Q_INVOKABLE void responsePassphraseDialog(bool cancel, QString passphrase);
// Password store-related methods
/**
* @brief Shows the password associated with the specified URL.
* @param url The URL pointing to the password store entry.
* @return True if the operation was successful, false otherwise.
*/
Q_INVOKABLE bool show(QUrl url);
}; };
#endif #endif

View File

@ -6,49 +6,91 @@
using namespace GpgME; using namespace GpgME;
/**
* @class UserIdModel
* @brief A model representing a user ID associated with a GPG key.
*
* This class encapsulates the user ID information (UID) for a GPG key, providing access
* to the UID's identifier, name, and email. It is used as a model for user IDs in the
* `PassKeyModel` class.
*/
class UserIdModel : public QObject class UserIdModel : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString uid READ uid MEMBER m_uid CONSTANT) Q_PROPERTY(QString uid READ uid CONSTANT)
Q_PROPERTY(QString name READ name MEMBER m_name CONSTANT) Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(QString email READ email MEMBER m_email CONSTANT) Q_PROPERTY(QString email READ email CONSTANT)
private:
UserID m_user_id; /**< The GPG UserID associated with the model. */
UserID m_user_id;
public: public:
/**
* @brief Constructs a UserIdModel for the given UserID.
* @param key The GPG UserID to model.
*/
UserIdModel(UserID key) : m_user_id(key) {}
/**
UserIdModel(UserID key): * @brief Gets the unique identifier (UID) for this user ID.
m_user_id(key) * @return The UID as a QString.
{}; */
QString uid() const QString uid() const
{ {
return QString::fromUtf8(m_user_id.id()); return QString::fromUtf8(m_user_id.id());
}; };
/**
* @brief Gets the name associated with this user ID.
* @return The name as a QString.
*/
QString name() const QString name() const
{ {
return QString::fromUtf8(m_user_id.name()); return QString::fromUtf8(m_user_id.name());
}; };
/**
* @brief Gets the email associated with this user ID.
* @return The email as a QString.
*/
QString email() const QString email() const
{ {
return QString::fromUtf8(m_user_id.email()); return QString::fromUtf8(m_user_id.email());
}; };
}; };
/**
* @class PassKeyModel
* @brief A model representing a GPG key.
*
* This class encapsulates the properties of a GPG key, including its key ID, associated
* user IDs, secret key status, and expiration status. It is used as a model for managing
* GPG keys within an application, providing access to the key's data and its associated user IDs.
*/
class PassKeyModel : public QObject class PassKeyModel : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString uid READ uid MEMBER m_uid CONSTANT) Q_PROPERTY(Key key READ key MEMBER m_key CONSTANT)
Q_PROPERTY(QList<QObject *> userIds READ userIds MEMBER m_user_ids CONSTANT) Q_PROPERTY(QString uid READ uid CONSTANT)
Q_PROPERTY(bool isSecret READ isSecret MEMBER m_secret CONSTANT) Q_PROPERTY(QList<QObject *> userIds READ userIds CONSTANT)
Q_PROPERTY(bool isExpired READ isExpired MEMBER m_expired CONSTANT) Q_PROPERTY(bool isSecret READ isSecret CONSTANT)
Q_PROPERTY(bool isExpired READ isExpired CONSTANT)
private:
Key m_key; /**< The GPG key associated with the model. */
Key m_key;
public: public:
PassKeyModel(Key key): /**
m_key(key) * @brief Constructs a PassKeyModel for the given GPG key.
{}; * @param key The GPG key to model.
*/
PassKeyModel(Key key) : m_key(key) {}
/**
* @brief Converts a vector of GPG keys into a list of PassKeyModel objects.
* @param keys The vector of GPG keys to convert.
* @return A QList of PassKeyModel objects representing the keys.
*/
static QList<QObject *> keysToPassKey(std::vector<Key> keys) static QList<QObject *> keysToPassKey(std::vector<Key> keys)
{ {
QList<QObject *> ret; QList<QObject *> ret;
@ -58,11 +100,28 @@ public:
return ret; return ret;
}; };
/**
* @brief Gets the GPG key associated with this model.
* @return The GPG key.
*/
Key key() const
{
return m_key;
};
/**
* @brief Gets the unique identifier (UID) for this GPG key.
* @return The UID as a QString.
*/
QString uid() const QString uid() const
{ {
return QString::fromUtf8(m_key.keyID()); return QString::fromUtf8(m_key.keyID());
}; };
/**
* @brief Gets the list of user IDs associated with this GPG key.
* @return A list of UserIdModel objects representing the user IDs.
*/
QList<QObject *> userIds() const QList<QObject *> userIds() const
{ {
auto user_ids = m_key.userIDs(); auto user_ids = m_key.userIDs();
@ -73,17 +132,23 @@ public:
return ret; return ret;
}; };
/**
* @brief Checks if the GPG key is a secret key.
* @return True if the key is a secret key, false otherwise.
*/
bool isSecret() const bool isSecret() const
{ {
return m_key.hasSecret(); return m_key.hasSecret();
}; };
/**
* @brief Checks if the GPG key is expired.
* @return True if the key is expired, false otherwise.
*/
bool isExpired() const bool isExpired() const
{ {
return m_key.hasSecret(); return m_key.isExpired();
}; };
}; };
#endif #endif

View File

@ -1,6 +1,7 @@
#ifndef UTPASSPHRASEPROVIDER_H #ifndef UTPASSPHRASEPROVIDER_H
#define UTPASSPHRASEPROVIDER_H #define UTPASSPHRASEPROVIDER_H
#include <QDebug>
#include <stdio.h> #include <stdio.h>
#include <QObject> #include <QObject>
#include <QQmlProperty> #include <QQmlProperty>
@ -9,53 +10,104 @@
#include <gpgme++/interfaces/passphraseprovider.h> #include <gpgme++/interfaces/passphraseprovider.h>
#include "gpg.h" #include "gpg.h"
/**
* @class UTPassphraseProvider
* @brief A passphrase provider for GPG operations that interacts with a QML dialog.
*
* This class implements the `PassphraseProvider` interface from GPGME and is responsible for
* obtaining passphrases for GPG operations. It does so by triggering a QML dialog to prompt the user
* for their passphrase. The response is then handled asynchronously, and the passphrase is returned to
* the calling GPGME function.
*/
class UTPassphraseProvider : public QObject, public PassphraseProvider class UTPassphraseProvider : public QObject, public PassphraseProvider
{ {
Q_OBJECT Q_OBJECT
private:
std::unique_ptr<QEventLoop> m_loop;
std::unique_ptr<QSemaphore> m_sem;
char *m_passphrase;
bool m_canceled;
public slots: public slots:
void handleResponse(bool canceled, QString p) /**
* @brief Slot to handle the user's response from the passphrase dialog.
*
* This method processes the response from the passphrase dialog. If the user provides a passphrase,
* it is stored; if the operation is canceled, a flag is set.
*
* @param canceled Whether the user canceled the passphrase entry.
* @param passphrase The passphrase entered by the user.
*/
void handleResponse(bool canceled, QString passphrase)
{ {
qDebug() << "call handleResponse";
if (!canceled) if (!canceled)
gpgrt_asprintf(&m_passphrase, "%s", p.toUtf8().constData()); gpgrt_asprintf(&m_passphrase, "%s", passphrase.toUtf8().constData());
else else
m_canceled = true; m_canceled = true;
m_loop->quit(); emit unlockEventLoop();
}; };
signals:
/**
* @brief Signal to unlock the event loop.
*
* This signal is emitted when the passphrase has been entered or the operation has been canceled,
* unlocking the event loop waiting for the response.
*/
void unlockEventLoop();
private:
std::unique_ptr<QSemaphore> m_sem; /**< Semaphore for managing access. */
char *m_passphrase; /**< The passphrase provided by the user. */
bool m_canceled; /**< Flag indicating whether the passphrase operation was canceled. */
QObject *m_window; /**< The window object that triggers the QML dialog. */
public: public:
UTPassphraseProvider(): /**
m_loop(std::unique_ptr<QEventLoop>(new QEventLoop)), * @brief Constructs a UTPassphraseProvider.
m_sem(std::unique_ptr<QSemaphore>(new QSemaphore(1))), *
* Initializes the semaphore, passphrase, and canceled flag. Sets the window object that will
* trigger the passphrase dialog.
*
* @param window The QObject representing the window that interacts with QML.
*/
UTPassphraseProvider(QObject* window)
: m_sem(std::make_unique<QSemaphore>(1)),
m_passphrase(nullptr), m_passphrase(nullptr),
m_canceled(false) m_canceled(false),
{} m_window(window)
{
qDebug() << "Initialize UTPassphraseProvider";
}
/**
* @brief Implements the PassphraseProvider's `getPassphrase` method.
*
* This method is called by GPGME to retrieve the passphrase needed for GPG operations. It triggers
* a QML dialog for the user to input their passphrase. The method waits for the response and returns
* the passphrase if successful, or null if canceled.
*
* @param useridHint A hint for the user ID to which the passphrase corresponds.
* @param description A description of the passphrase request.
* @param previousWasBad Flag indicating whether the previous passphrase attempt was incorrect.
* @param canceled Reference to a boolean flag that will be set if the operation is canceled.
*
* @return The passphrase as a `char *` or `nullptr` if canceled.
*/
char *getPassphrase(const char *useridHint, char *getPassphrase(const char *useridHint,
const char *description, const char *description,
bool previousWasBad, bool previousWasBad,
bool &canceled) Q_DECL_OVERRIDE { bool &canceled) Q_DECL_OVERRIDE {
if (!m_sem->tryAcquire(1, 3000)) qDebug() << "Call the getPassphrase";
if (!this->m_sem->tryAcquire(1, 500))
{ {
qWarning() << "Cannot acquire UTPassphraseProvider semaphore."; qWarning() << "Cannot acquire UTPassphraseProvider semaphore.";
canceled = true; canceled = true;
return nullptr; return nullptr;
} }
m_passphrase = nullptr; this->m_passphrase = nullptr;
m_canceled = false; this->m_canceled = false;
qDebug() << "Call the QML Dialog Passphrase Provider"; qDebug() << "Call the QML Dialog Passphrase Provider";
QMetaObject::invokeMethod( QMetaObject::invokeMethod(
Gpg::instance()->getWindow(), "callPassphraseDialog", this->m_window, "callPassphraseDialog",
Q_ARG(QVariant, useridHint), Q_ARG(QVariant, useridHint),
Q_ARG(QVariant, description), Q_ARG(QVariant, description),
Q_ARG(QVariant, previousWasBad) Q_ARG(QVariant, previousWasBad)
@ -63,25 +115,24 @@ public:
qDebug() << "Waiting for response"; qDebug() << "Waiting for response";
QObject::connect( QEventLoop loop;
Gpg::instance()->getWindow(), SIGNAL(responsePassphraseDialog(bool, QString)), QObject::connect(this, &UTPassphraseProvider::unlockEventLoop, &loop, &QEventLoop::quit);
this, SLOT(handleResponse(bool, QString)) loop.exec();
);
m_loop->exec();
qDebug() << "Prepare Returns"; qDebug() << "Prepare Returns";
char *ret; char *ret;
gpgrt_asprintf(&ret, "%s", m_passphrase); gpgrt_asprintf(&ret, "%s", m_passphrase);
canceled = m_canceled; canceled = this->m_canceled;
qDebug() << "Clean"; qDebug() << "Clean";
if (m_passphrase) if (this->m_passphrase)
{ {
free(m_passphrase); free(m_passphrase);
} }
m_canceled = false; this->m_canceled = false;
m_sem->release(1); this->m_sem->release(1);
return ret; return ret;
}; };
}; };
#endif #endif

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: utpass.qrouland\n" "Project-Id-Version: utpass.qrouland\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-14 13:57+0100\n" "POT-Creation-Date: 2025-01-15 23:39+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,10 +17,6 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n" "Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: ../qml/components/FileDir.qml:59
msgid "Decryption failed !"
msgstr ""
#: ../qml/dialogs/ErrorDialog.qml:12 #: ../qml/dialogs/ErrorDialog.qml:12
msgid "Error !" msgid "Error !"
msgstr "" msgstr ""
@ -83,17 +79,21 @@ msgstr ""
msgid "Info" msgid "Info"
msgstr "" msgstr ""
#: ../qml/pages/PasswordList.qml:22 #: ../qml/pages/PasswordList.qml:37
msgid "" msgid ""
"No password found<br>You can import a password store by cloning or importing " "No password found<br>You can import a password store by cloning or importing "
"a zip in the settings" "a zip in the settings"
msgstr "" msgstr ""
#: ../qml/pages/PasswordList.qml:61 #: ../qml/pages/PasswordList.qml:71 ../qml/pages/settings/InfoKeys.qml:169
msgid "Decryption failed !"
msgstr ""
#: ../qml/pages/PasswordList.qml:85
msgid "Back" msgid "Back"
msgstr "" msgstr ""
#: ../qml/pages/PasswordList.qml:68 ../qml/pages/headers/MainHeader.qml:9 #: ../qml/pages/PasswordList.qml:92 ../qml/pages/headers/MainHeader.qml:9
#: ../qml/pages/headers/StackHeader.qml:9 UTPass.desktop.in.h:1 #: ../qml/pages/headers/StackHeader.qml:9 UTPass.desktop.in.h:1
msgid "UTPass" msgid "UTPass"
msgstr "" msgstr ""
@ -126,7 +126,7 @@ msgstr ""
#: ../qml/pages/settings/ImportGitClone.qml:91 #: ../qml/pages/settings/ImportGitClone.qml:91
#: ../qml/pages/settings/ImportZip.qml:62 #: ../qml/pages/settings/ImportZip.qml:62
#: ../qml/pages/settings/InfoKeys.qml:122 #: ../qml/pages/settings/InfoKeys.qml:131
msgid "Yes" msgid "Yes"
msgstr "" msgstr ""
@ -168,31 +168,31 @@ msgstr ""
msgid "Zip Password Store Import" msgid "Zip Password Store Import"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:39 #: ../qml/pages/settings/InfoKeys.qml:48
msgid "Key ID :" msgid "Key ID :"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:73 #: ../qml/pages/settings/InfoKeys.qml:82
msgid "Users IDs : " msgid "Users IDs : "
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:99 #: ../qml/pages/settings/InfoKeys.qml:108
msgid "Delete this key" msgid "Delete this key"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:121 #: ../qml/pages/settings/InfoKeys.qml:130
msgid "You're are about to delete<br>%1<br>Continue ?" msgid "You're are about to delete<br>%1<br>Continue ?"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:139 #: ../qml/pages/settings/InfoKeys.qml:148
msgid "Key removal failed !" msgid "Key removal failed !"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:148 #: ../qml/pages/settings/InfoKeys.qml:157
msgid "Key successfully deleted !" msgid "Key successfully deleted !"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:159 #: ../qml/pages/settings/InfoKeys.qml:177
msgid "Info Keys" msgid "Info Keys"
msgstr "" msgstr ""

View File

@ -10,8 +10,6 @@ MainView {
id: root id: root
signal responsePassphraseDialog(bool canceled, string passphrase)
function initPass(rootView) { function initPass(rootView) {
Pass.initialize(rootView); Pass.initialize(rootView);
pageStack.push(Qt.resolvedUrl("pages/PasswordList.qml")); pageStack.push(Qt.resolvedUrl("pages/PasswordList.qml"));
@ -19,30 +17,36 @@ MainView {
function callPassphraseDialog(useridHint, description, previousWasBad) { function callPassphraseDialog(useridHint, description, previousWasBad) {
//TODO use parameters to impove passphrase dialog //TODO use parameters to impove passphrase dialog
var passphraseDialog = PopupUtils.open(Qt.resolvedUrl("dialogs/PassphraseDialog.qml")); var pop = PopupUtils.open(passphraseDialog);
passphraseDialog.activateFocus(); pop.activateFocus();
var validated = function validated(passphrase) {
responsePassphraseDialog(false, passphrase);
};
var canceled = function canceled() {
responsePassphraseDialog(true, "");
};
passphraseDialog.validated.connect(validated);
passphraseDialog.canceled.connect(canceled);
} }
objectName: "mainView" objectName: "mainView"
applicationName: "utpass.qrouland" applicationName: "utpass.qrouland"
automaticOrientation: false automaticOrientation: true
width: units.gu(48) width: units.gu(45)
height: units.gu(80) height: units.gu(75)
PageStack { PageStack {
id: pageStack id: pageStack
anchors.fill: parent anchors.fill: parent
Component.onCompleted: { }
Component {
id: passphraseDialog
PassphraseDialog {
onValidated: {
console.info("valided");
Pass.responsePassphraseDialog(false, passphrase);
}
onCanceled: {
console.info("canceled");
Pass.responsePassphraseDialog(true, "");
} }
} }
} }
}

View File

@ -33,12 +33,14 @@ Component {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
var path = folderModel.folder + "/" + fileName;
if (fileIsDir) { if (fileIsDir) {
folderModel.folder = folderModel.folder + "/" + fileName; folderModel.folder = path;
backAction.visible = true; backAction.visible = true;
passwordListHeader.title = fileName; passwordListHeader.title = fileName;
} else { } else {
Pass.show(folderModel.folder + "/" + fileName); console.debug("pass show %1".arg(path));
Pass.show(path);
} }
} }
} }
@ -52,15 +54,6 @@ Component {
borderColor: LomiriColors.warmGrey borderColor: LomiriColors.warmGrey
} }
Component {
id: passwordPageDecryptError
ErrorDialog {
textError: i18n.tr("Decryption failed !")
}
}
} }
} }

View File

@ -49,11 +49,11 @@ Page {
iconName: "back" iconName: "back"
text: "Back" text: "Back"
onTriggered: { onTriggered: {
// passwordPage.plainText = ""; passwordPage.plainText = null;
// for (var object in objects) { for (var object in objects) {
// object.text = ""; object.text = null;
// object.destroy(); object.destroy();
// } }
pageStack.pop(); pageStack.pop();
} }
} }

View File

@ -1,5 +1,7 @@
import "../components" import "../components"
import "../dialogs"
import Lomiri.Components 1.3 import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import Pass 1.0 import Pass 1.0
import Qt.labs.folderlistmodel 2.1 import Qt.labs.folderlistmodel 2.1
import QtQuick 2.4 import QtQuick 2.4
@ -13,13 +15,13 @@ Page {
anchors.fill: parent anchors.fill: parent
Component.onCompleted: { Component.onCompleted: {
passwordStorePath = "file:" + Pass.password_store; passwordStorePath = "file:" + Pass.password_store;
Pass.onDecrypted.connect(function(filename, text) { Pass.onShowSucceed.connect(function(filename, text) {
pageStack.push(Qt.resolvedUrl("../pages/Password.qml"), { pageStack.push(Qt.resolvedUrl("../pages/Password.qml"), {
"plainText": text, "plainText": text,
"title": filename "title": filename
}); });
}); });
Pass.onDecryptFailed.connect(function() { Pass.onShowFailed.connect(function(message) {
PopupUtils.open(passwordPageDecryptError); PopupUtils.open(passwordPageDecryptError);
}); });
} }
@ -62,6 +64,15 @@ Page {
} }
Component {
id: passwordPageDecryptError
ErrorDialog {
textError: i18n.tr("Decryption failed !")
}
}
header: MainHeader { header: MainHeader {
id: passwordListHeader id: passwordListHeader

View File

@ -11,6 +11,16 @@ Page {
property string currentKey property string currentKey
Component.onCompleted: {
Pass.onGetAllGPGKeysSucceed.connect(function(keys_info) {
infoKeysListView.model = keys_info;
});
Pass.getAllGPGKeysFailed.connect(function(message) {
PopupUtils.open(infoKeysPageGetAllError);
});
Pass.getAllGPGKeys();
}
ListView { ListView {
id: infoKeysListView id: infoKeysListView
@ -18,7 +28,6 @@ Page {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
model: Pass.getAllGPGKeys()
delegate: Grid { delegate: Grid {
columns: 1 columns: 1
@ -153,6 +162,15 @@ Page {
} }
Component {
id: infoKeysPageGetAllError
ErrorDialog {
textError: i18n.tr("Decryption failed !")
}
}
header: StackHeader { header: StackHeader {
id: infoKeysHeader id: infoKeysHeader