Skip to content

Commit

Permalink
Merge branch 'main' into svuorela/clazy-and-other-minor-fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
annejan authored Aug 31, 2023
2 parents bd1f363 + 1da3f14 commit d591acf
Show file tree
Hide file tree
Showing 16 changed files with 337 additions and 54 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ qmake && make && make install
## Using profiles

Profiles allow to group passwords. Each profile might use a different git repository and/or different gpg key.
Each profile also can be associated with a pass store singing key to verify the detached .gpg-id signature.
A typical use case is to separate personal and work passwords.

> **Hint**<br>
Expand Down
33 changes: 22 additions & 11 deletions src/configdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ ConfigDialog::ConfigDialog(MainWindow *parent)
useTemplate(QtPassSettings::isUseTemplate());

ui->profileTable->verticalHeader()->hide();
ui->profileTable->horizontalHeader()->setStretchLastSection(true);
ui->profileTable->horizontalHeader()->setSectionResizeMode(
1, QHeaderView::Stretch);
ui->label->setText(ui->label->text() + VERSION);
ui->comboBoxClipboard->clear();

Expand Down Expand Up @@ -171,7 +172,7 @@ void ConfigDialog::validate(QTableWidgetItem *item) {
for (int j = 0; j < ui->profileTable->columnCount(); j++) {
QTableWidgetItem *_item = ui->profileTable->item(i, j);

if (_item->text().isEmpty()) {
if (_item->text().isEmpty() && j != 2) {
_item->setBackground(Qt::red);
status = false;
break;
Expand All @@ -182,7 +183,7 @@ void ConfigDialog::validate(QTableWidgetItem *item) {
break;
}
} else {
if (item->text().isEmpty()) {
if (item->text().isEmpty() && item->column() != 2) {
item->setBackground(Qt::red);
status = false;
}
Expand Down Expand Up @@ -461,24 +462,27 @@ void ConfigDialog::genKey(QString batch, QDialog *dialog) {
* @param profiles
* @param profile
*/
void ConfigDialog::setProfiles(QHash<QString, QString> profiles,
QString profile) {
void ConfigDialog::setProfiles(QHash<QString, QHash<QString, QString>> profiles,
QString currentProfile) {
// dbg()<< profiles;
if (profiles.contains("")) {
profiles.remove("");
// remove weird "" key value pairs
}

ui->profileTable->setRowCount(profiles.count());
QHashIterator<QString, QString> i(profiles);
QHashIterator<QString, QHash<QString, QString>> i(profiles);
int n = 0;
while (i.hasNext()) {
i.next();
if (!i.value().isEmpty() && !i.key().isEmpty()) {
ui->profileTable->setItem(n, 0, new QTableWidgetItem(i.key()));
ui->profileTable->setItem(n, 1, new QTableWidgetItem(i.value()));
ui->profileTable->setItem(n, 1,
new QTableWidgetItem(i.value().value("path")));
ui->profileTable->setItem(
n, 2, new QTableWidgetItem(i.value().value("signingKey")));
// dbg()<< "naam:" + i.key();
if (i.key() == profile)
if (i.key() == currentProfile)
ui->profileTable->selectRow(n);
}
++n;
Expand All @@ -489,17 +493,23 @@ void ConfigDialog::setProfiles(QHash<QString, QString> profiles,
* @brief ConfigDialog::getProfiles return profile list.
* @return
*/
QHash<QString, QString> ConfigDialog::getProfiles() {
QHash<QString, QString> profiles;
QHash<QString, QHash<QString, QString>> ConfigDialog::getProfiles() {
QHash<QString, QHash<QString, QString>> profiles;
// Check?
for (int i = 0; i < ui->profileTable->rowCount(); ++i) {
QHash<QString, QString> profile;
QTableWidgetItem *pathItem = ui->profileTable->item(i, 1);
if (nullptr != pathItem) {
QTableWidgetItem *item = ui->profileTable->item(i, 0);
if (item == nullptr) {
continue;
}
profiles.insert(item->text(), pathItem->text());
profile["path"] = pathItem->text();
QTableWidgetItem *signingKeyItem = ui->profileTable->item(i, 2);
if (nullptr != signingKeyItem) {
profile["signingKey"] = signingKeyItem->text();
}
profiles.insert(item->text(), profile);
}
}
return profiles;
Expand All @@ -513,6 +523,7 @@ void ConfigDialog::on_addButton_clicked() {
ui->profileTable->insertRow(n);
ui->profileTable->setItem(n, 0, new QTableWidgetItem());
ui->profileTable->setItem(n, 1, new QTableWidgetItem(ui->storePath->text()));
ui->profileTable->setItem(n, 2, new QTableWidgetItem());
ui->profileTable->selectRow(n);
ui->deleteButton->setEnabled(true);

Expand Down
4 changes: 2 additions & 2 deletions src/configdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class ConfigDialog : public QDialog {
void useSelection(bool useSelection);
void useAutoclear(bool useAutoclear);
void useAutoclearPanel(bool useAutoclearPanel);
QHash<QString, QString> getProfiles();
QHash<QString, QHash<QString, QString>> getProfiles();
void wizard();
void genKey(QString, QDialog *);
void useTrayIcon(bool useSystray);
Expand Down Expand Up @@ -76,7 +76,7 @@ private slots:
QStringList getSecretKeys();

void setGitPath(QString);
void setProfiles(QHash<QString, QString>, QString);
void setProfiles(QHash<QString, QHash<QString, QString>>, QString);
void usePass(bool usePass);

void setGroupBoxState();
Expand Down
5 changes: 5 additions & 0 deletions src/configdialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,11 @@
<string>Path</string>
</property>
</column>
<column>
<property name="text">
<string>Signing Key</string>
</property>
</column>
</widget>
</item>
<item>
Expand Down
131 changes: 131 additions & 0 deletions src/imitatepass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ void ImitatePass::OtpGenerate(QString file) {
*/
void ImitatePass::Insert(QString file, QString newValue, bool overwrite) {
file = file + ".gpg";
QString gpgIdPath = Pass::getGpgIdPath(file);
if (!verifyGpgIdFile(gpgIdPath)) {
emit critical(tr("Check .gpgid file signature!"),
tr("Signature for %1 is invalid.").arg(gpgIdPath));
return;
}
transactionHelper trans(this, PASS_INSERT);
QStringList recipients = Pass::getRecipientList(file);
if (recipients.isEmpty()) {
Expand Down Expand Up @@ -163,6 +169,38 @@ void ImitatePass::Remove(QString file, bool isDir) {
* path
*/
void ImitatePass::Init(QString path, const QList<UserInfo> &users) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
QStringList signingKeys =
QtPassSettings::getPassSigningKey().split(" ", Qt::SkipEmptyParts);
#else
QStringList signingKeys =
QtPassSettings::getPassSigningKey().split(" ", QString::SkipEmptyParts);
#endif
QString gpgIdSigFile = path + ".gpg-id.sig";
bool addSigFile = false;
if (!signingKeys.isEmpty()) {
QString out;
QStringList args =
QStringList{"--status-fd=1", "--list-secret-keys"} + signingKeys;
exec.executeBlocking(QtPassSettings::getGpgExecutable(), args, &out);
bool found = false;
for (auto &key : signingKeys) {
if (out.contains("[GNUPG:] KEY_CONSIDERED " + key)) {
found = true;
break;
}
}
if (!found) {
emit critical(tr("No signing key!"),
tr("None of the secret signing keys is available.\n"
"You will not be able to change the user list!"));
return;
}
QFileInfo checkFile(gpgIdSigFile);
if (!checkFile.exists() || !checkFile.isFile())
addSigFile = true;
}

QString gpgIdFile = path + ".gpg-id";
QFile gpgId(gpgIdFile);
bool addFile = false;
Expand Down Expand Up @@ -193,17 +231,99 @@ void ImitatePass::Init(QString path, const QList<UserInfo> &users) {
return;
}

if (!signingKeys.isEmpty()) {
QStringList args;
for (auto &key : signingKeys) {
args.append(QStringList{"--default-key", key});
}
args.append(QStringList{"--yes", "--detach-sign", gpgIdFile});
exec.executeBlocking(QtPassSettings::getGpgExecutable(), args);
if (!verifyGpgIdFile(gpgIdFile)) {
emit critical(tr("Check .gpgid file signature!"),
tr("Signature for %1 is invalid.").arg(gpgIdFile));
return;
}
}

if (!QtPassSettings::isUseWebDav() && QtPassSettings::isUseGit() &&
!QtPassSettings::getGitExecutable().isEmpty()) {
if (addFile)
executeGit(GIT_ADD, {"add", pgit(gpgIdFile)});
QString commitPath = gpgIdFile;
commitPath.replace(Util::endsWithGpg(), "");
GitCommit(gpgIdFile, "Added " + commitPath + " using QtPass.");
if (!signingKeys.isEmpty()) {
if (addSigFile)
executeGit(GIT_ADD, {"add", pgit(gpgIdSigFile)});
commitPath = gpgIdSigFile;
commitPath.replace(QRegularExpression("\\.gpg$"), "");
GitCommit(gpgIdSigFile, "Added " + commitPath + " using QtPass.");
}
}
reencryptPath(path);
}

/**
* @brief ImitatePass::verifyGpgIdFile verify detached gpgid file signature.
* @param file which gpgid file.
* @return was verification succesful?
*/
bool ImitatePass::verifyGpgIdFile(const QString &file) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
QStringList signingKeys =
QtPassSettings::getPassSigningKey().split(" ", Qt::SkipEmptyParts);
#else
QStringList signingKeys =
QtPassSettings::getPassSigningKey().split(" ", QString::SkipEmptyParts);
#endif
if (signingKeys.isEmpty())
return true;
QString out;
QStringList args =
QStringList{"--verify", "--status-fd=1", pgpg(file) + ".sig", pgpg(file)};
exec.executeBlocking(QtPassSettings::getGpgExecutable(), args, &out);
QRegularExpression re(
"^\\[GNUPG:\\] VALIDSIG ([A-F0-9]{40}) .* ([A-F0-9]{40})\\r?$",
QRegularExpression::MultilineOption);
QRegularExpressionMatch m = re.match(out);
if (!m.hasMatch())
return false;
QStringList fingerprints = m.capturedTexts();
fingerprints.removeFirst();
for (auto &key : signingKeys) {
if (fingerprints.contains(key))
return true;
}
return false;
}

/**
* @brief ImitatePass::removeDir delete folder recursive.
* @param dirName which folder.
* @return was removal succesful?
*/
bool ImitatePass::removeDir(const QString &dirName) {
bool result = true;
QDir dir(dirName);

if (dir.exists(dirName)) {
Q_FOREACH (QFileInfo info,
dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System |
QDir::Hidden | QDir::AllDirs | QDir::Files,
QDir::DirsFirst)) {
if (info.isDir())
result = removeDir(info.absoluteFilePath());
else
result = QFile::remove(info.absoluteFilePath());

if (!result)
return result;
}
result = dir.rmdir(dirName);
}
return result;
}

/**
* @brief ImitatePass::reencryptPath reencrypt all files under the chosen
* directory
Expand All @@ -222,10 +342,21 @@ void ImitatePass::reencryptPath(const QString &dir) {
QDir currentDir;
QDirIterator gpgFiles(dir, QStringList() << "*.gpg", QDir::Files,
QDirIterator::Subdirectories);
QStringList gpgIdFilesVerified;
QStringList gpgId;
while (gpgFiles.hasNext()) {
QString fileName = gpgFiles.next();
if (gpgFiles.fileInfo().path() != currentDir.path()) {
QString gpgIdPath = Pass::getGpgIdPath(fileName);
if (!gpgIdFilesVerified.contains(gpgIdPath)) {
if (!verifyGpgIdFile(gpgIdPath)) {
emit critical(tr("Check .gpgid file signature!"),
tr("Signature for %1 is invalid.").arg(gpgIdPath));
emit endReencryptPath();
return;
}
gpgIdFilesVerified.append(gpgIdPath);
}
gpgId = getRecipientList(fileName);
gpgId.sort();
}
Expand Down
3 changes: 3 additions & 0 deletions src/imitatepass.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
class ImitatePass : public Pass, private simpleTransaction {
Q_OBJECT

bool verifyGpgIdFile(const QString &file);
bool removeDir(const QString &dirName);

void GitCommit(const QString &file, const QString &msg);

void executeGit(PROCESS id, const QStringList &args,
Expand Down
31 changes: 18 additions & 13 deletions src/keygendialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>606</width>
<height>480</height>
<height>497</height>
</rect>
</property>
<property name="windowTitle">
Expand Down Expand Up @@ -72,18 +72,6 @@
</sizepolicy>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="labelEmail">
<property name="sizePolicy">
Expand All @@ -101,6 +89,9 @@
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>email</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
Expand Down Expand Up @@ -130,6 +121,9 @@
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>name</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
Expand Down Expand Up @@ -159,6 +153,9 @@
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>passphrase1</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
Expand Down Expand Up @@ -203,6 +200,13 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Repeat pass</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
Expand Down Expand Up @@ -289,6 +293,7 @@ Expire-Date: 0
</widget>
<tabstops>
<tabstop>email</tabstop>
<tabstop>name</tabstop>
<tabstop>passphrase1</tabstop>
<tabstop>passphrase2</tabstop>
<tabstop>checkBox</tabstop>
Expand Down
Loading

0 comments on commit d591acf

Please sign in to comment.