mirror of
https://github.com/QRouland/UTPass.git
synced 2025-02-11 15:07:16 +00:00
248 lines
7.6 KiB
C++
248 lines
7.6 KiB
C++
#include <QUrl>
|
|
#include <QtCore/QStandardPaths>
|
|
#include <QtCore/QDir>
|
|
#include <QDirIterator>
|
|
#include <QtConcurrent/QtConcurrent>
|
|
#include "jobs/decryptjob.h"
|
|
#include "jobs/deletekeyjob.h"
|
|
#include "jobs/getkeysjob.h"
|
|
#include "jobs/importkeyjob.h"
|
|
#include "jobs/rmjob.h"
|
|
#include "pass.h"
|
|
#include "passphraseprovider.h"
|
|
|
|
|
|
|
|
Pass::Pass():
|
|
m_password_store (QStandardPaths::writableLocation(
|
|
QStandardPaths::AppDataLocation).append("/.password-store")),
|
|
m_gpg_home (QStandardPaths::writableLocation(
|
|
QStandardPaths::AppDataLocation).append("/.rnp")),
|
|
m_passphrase_provider(&UTPassphraseProvider::get_pass_provider),
|
|
m_sem(std::unique_ptr<QSemaphore>(new QSemaphore(1)))
|
|
{
|
|
this->initGpgHome();
|
|
this->initPasswordStore();
|
|
QObject::connect(this, &Pass::responsePassphraseDialogPropagate,
|
|
&UTPassphraseProvider::instance(), &UTPassphraseProvider::handleResponse);
|
|
}
|
|
|
|
void Pass::initialize(QObject *window)
|
|
{
|
|
if (!window) {
|
|
qWarning("[Pass] Window should be null only for testing");
|
|
} else {
|
|
UTPassphraseProvider::instance().setWindow(window);
|
|
}
|
|
}
|
|
|
|
|
|
void Pass::initGpgHome()
|
|
{
|
|
// delete gpghome from previous version using GPGME
|
|
QString path = QStandardPaths::writableLocation(
|
|
QStandardPaths::AppDataLocation).append("/.gpghome");
|
|
QDir dir(path);
|
|
dir.removeRecursively();
|
|
|
|
// create gpghome for rnp
|
|
QDir dir_gpg_home(this->m_gpg_home);
|
|
if (!dir_gpg_home.exists()) {
|
|
dir_gpg_home.mkpath(".");
|
|
}
|
|
qInfo() << "[Pass] GPG Home is :" << m_gpg_home;
|
|
}
|
|
|
|
void Pass::initPasswordStore()
|
|
{
|
|
QDir dir_password_store(this->m_password_store);
|
|
if (!dir_password_store.exists()) {
|
|
dir_password_store.mkpath(".");
|
|
}
|
|
qInfo() << "[Pass] Password Store is :" << m_password_store;
|
|
}
|
|
|
|
void Pass::lsJob()
|
|
{
|
|
QDirIterator it(this->m_password_store, QStringList() << "*.gpg", QDir::Files, QDirIterator::Subdirectories);
|
|
QList<QString> ret;
|
|
while (it.hasNext()) {
|
|
QFile f(it.next());
|
|
QString fname = f.fileName();
|
|
fname.remove(0, this->m_password_store.length() + 1); // remove system path
|
|
ret.append(fname);
|
|
}
|
|
qInfo() << "[Pass] ls Succeed";
|
|
emit lsSucceed(ret);
|
|
this->m_sem->release(1);
|
|
}
|
|
|
|
bool Pass::ls()
|
|
{
|
|
qInfo() << "[Pass] ls";
|
|
if (!this->m_sem->tryAcquire(1, 500)) {
|
|
qInfo() << "[Pass] A command is already running";
|
|
return false;
|
|
}
|
|
QtConcurrent::run(this, &Pass::lsJob );
|
|
return true;
|
|
}
|
|
|
|
bool Pass::show(QUrl url)
|
|
{
|
|
qInfo() << "[Pass] Show";
|
|
if (!this->m_sem->tryAcquire(1, 500)) {
|
|
qInfo() << "[Pass] A command is already running";
|
|
return false;
|
|
}
|
|
auto job = new DecryptJob(this->m_gpg_home, url.toLocalFile());
|
|
job->setPassProvider(this->m_passphrase_provider);
|
|
QObject::connect(job, &DecryptJob::resultError, this, &Pass::slotShowError);
|
|
QObject::connect(job, &DecryptJob::resultSuccess, this, &Pass::slotShowSucceed);
|
|
connect(job, &DecryptJob::finished, job, &QObject::deleteLater);
|
|
job->start();
|
|
return true;
|
|
}
|
|
|
|
|
|
void Pass::slotShowError(rnp_result_t err)
|
|
{
|
|
qInfo() << "[Pass] Show Failed";
|
|
emit showFailed(rnp_result_to_string(err));
|
|
this->m_sem->release(1);
|
|
}
|
|
|
|
|
|
void Pass::slotShowSucceed(QString encrypted_file_path, QString plain_text)
|
|
{
|
|
qDebug() << "[Pass] Show Succeed";
|
|
QFileInfo file_info(encrypted_file_path);
|
|
emit showSucceed(file_info.completeBaseName(), plain_text);
|
|
this->m_sem->release(1);
|
|
}
|
|
|
|
bool Pass::deletePasswordStore()
|
|
{
|
|
qInfo() << "[Pass] Delete Password Store at" << this->m_password_store;
|
|
if (!this->m_sem->tryAcquire(1, 500)) {
|
|
qInfo() << "[Pass] A command is already running";
|
|
return false;
|
|
}
|
|
auto job = new RmJob(this->m_password_store);
|
|
connect(job, &RmJob::resultReady, this, &Pass::slotDeletePasswordStoreResult);
|
|
connect(job, &RmJob::finished, job, &QObject::deleteLater);
|
|
job->start();
|
|
return true;
|
|
}
|
|
|
|
void Pass::slotDeletePasswordStoreResult(bool err)
|
|
{
|
|
this->initPasswordStore(); // reinit an empty password-store
|
|
if (err) {
|
|
qInfo() << "[Pass] Delete Password Store Failed";
|
|
emit deletePasswordStoreFailed("failed to delete password store");
|
|
} else {
|
|
qInfo() << "[Pass] Delete Password Store Succeed";
|
|
emit deletePasswordStoreSucceed();
|
|
}
|
|
this->m_sem->release(1);
|
|
}
|
|
|
|
|
|
bool Pass::deleteGPGKey(PassKeyModel* key)
|
|
{
|
|
qInfo() << "[Pass] Delete GPG key fingerprint " << key->property("keyid").toString();
|
|
if (!this->m_sem->tryAcquire(1, 500)) {
|
|
qInfo() << "[Pass] A command is already running";
|
|
return false;
|
|
}
|
|
auto job = new DeleteKeyJob(this->m_gpg_home, key->property("fingerprint").toString());
|
|
QObject::connect(job, &DeleteKeyJob::resultError, this, &Pass::slotDeleteGPGKeyError);
|
|
QObject::connect(job, &DeleteKeyJob::resultSuccess, this, &Pass::slotDeleteGPGKeySucceed);
|
|
connect(job, &DeleteKeyJob::finished, job, &QObject::deleteLater);
|
|
job->start();
|
|
return true;
|
|
}
|
|
|
|
void Pass::slotDeleteGPGKeyError(rnp_result_t err)
|
|
{
|
|
qInfo() << "[Pass] Delete GPG key Failed";
|
|
emit deleteGPGKeyFailed(rnp_result_to_string(err));
|
|
this->m_sem->release(1);
|
|
}
|
|
|
|
void Pass::slotDeleteGPGKeySucceed()
|
|
{
|
|
qInfo() << "[Pass] Delete GPG key Succesfull";
|
|
emit deleteGPGKeySucceed();
|
|
this->m_sem->release(1);
|
|
}
|
|
|
|
|
|
bool Pass::importGPGKey(QUrl url)
|
|
{
|
|
qInfo() << "[Pass] Import GPG Key from " << url;
|
|
if (!this->m_sem->tryAcquire(1, 500)) {
|
|
qInfo() << "[Pass] A command is already running";
|
|
return false;
|
|
}
|
|
auto job = new ImportKeyJob(this->m_gpg_home, url.toLocalFile());
|
|
QObject::connect(job, &ImportKeyJob::resultError, this, &Pass::slotImportGPGKeyError);
|
|
QObject::connect(job, &ImportKeyJob::resultSuccess, this, &Pass::slotImportGPGKeySucceed);
|
|
connect(job, &ImportKeyJob::finished, job, &QObject::deleteLater);
|
|
job->start();
|
|
return true;
|
|
}
|
|
|
|
void Pass::slotImportGPGKeyError(rnp_result_t err)
|
|
{
|
|
qInfo() << "[Pass] Import GPG Key Failed";
|
|
emit importGPGKeyFailed(rnp_result_to_string(err));
|
|
this->m_sem->release(1);
|
|
}
|
|
|
|
void Pass::slotImportGPGKeySucceed()
|
|
{
|
|
qInfo() << "[Pass] Import GPG Key Succesfull";
|
|
emit importGPGKeySucceed();
|
|
this->m_sem->release(1);
|
|
}
|
|
|
|
bool Pass::getAllGPGKeys()
|
|
{
|
|
qInfo() << "[Pass] Get all GPG Keys";
|
|
if (!this->m_sem->tryAcquire(1, 500)) {
|
|
qInfo() << "[Pass] A command is already running";
|
|
return false;
|
|
}
|
|
this->m_keyring_model = nullptr;
|
|
auto job = new GetKeysJob(this->m_gpg_home);
|
|
QObject::connect(job, &GetKeysJob::resultError, this, &Pass::slotGetAllGPGKeysError);
|
|
QObject::connect(job, &GetKeysJob::resultSuccess, this, &Pass::slotGetAllGPGKeysSucceed);
|
|
connect(job, &ImportKeyJob::finished, job, &QObject::deleteLater);
|
|
job->start();
|
|
return true;
|
|
}
|
|
|
|
void Pass::slotGetAllGPGKeysError(rnp_result_t err)
|
|
{
|
|
qInfo() << "[Pass] Get all GPG Keys Failed";
|
|
this->m_keyring_model = nullptr;
|
|
emit getAllGPGKeysFailed(rnp_result_to_string(err));
|
|
this->m_sem->release(1);
|
|
}
|
|
|
|
void Pass::slotGetAllGPGKeysSucceed(QList<QJsonDocument> result)
|
|
{
|
|
qInfo() << "[Pass] Get all GPG Keys Succeed";
|
|
this->m_keyring_model = std::unique_ptr<PassKeyringModel>(new PassKeyringModel(result));
|
|
emit getAllGPGKeysSucceed(this->m_keyring_model.get());
|
|
this->m_sem->release(1);
|
|
}
|
|
|
|
void Pass::responsePassphraseDialog(bool cancel, QString passphrase)
|
|
{
|
|
qDebug() << "[Pass] Propagate responsePassphraseDialog to UTPassphraseProvider";
|
|
emit responsePassphraseDialogPropagate(cancel, passphrase);
|
|
}
|