summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnne Jan Brouwer <brouwer@annejan.com>2023-08-31 12:42:22 +0200
committerGitHub <noreply@github.com>2023-08-31 12:42:22 +0200
commit58f886eff771dd94768d141aa3b6d63c6ae7fff0 (patch)
tree56604f1b157aef47772328aa33db49c61fb79173
parent695a8999422149d1fe4d4112792fe16cfd631f82 (diff)
parenta45da0a326fa7b3541d82bf7f4b93ec3751648e9 (diff)
Merge pull request #634 from timegrid/feature-passstoresigningkey
Add pass store signing key feature
-rw-r--r--README.md1
-rw-r--r--src/configdialog.cpp33
-rw-r--r--src/configdialog.h4
-rw-r--r--src/configdialog.ui5
-rw-r--r--src/imitatepass.cpp104
-rw-r--r--src/imitatepass.h1
-rw-r--r--src/mainwindow.cpp10
-rw-r--r--src/pass.cpp64
-rw-r--r--src/pass.h1
-rw-r--r--src/qtpasssettings.cpp47
-rw-r--r--src/qtpasssettings.h9
-rw-r--r--src/settingsconstants.cpp1
-rw-r--r--src/settingsconstants.h1
13 files changed, 239 insertions, 42 deletions
diff --git a/README.md b/README.md
index 6ffd46c1..32c1afac 100644
--- a/README.md
+++ b/README.md
@@ -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>
diff --git a/src/configdialog.cpp b/src/configdialog.cpp
index 4a711b03..3794c6f1 100644
--- a/src/configdialog.cpp
+++ b/src/configdialog.cpp
@@ -97,7 +97,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();
@@ -170,7 +171,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;
@@ -181,7 +182,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;
}
@@ -460,8 +461,8 @@ 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("");
@@ -469,15 +470,18 @@ void ConfigDialog::setProfiles(QHash<QString, QString> profiles,
}
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;
@@ -488,17 +492,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;
@@ -512,6 +522,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);
diff --git a/src/configdialog.h b/src/configdialog.h
index a0f162b0..4460d4bf 100644
--- a/src/configdialog.h
+++ b/src/configdialog.h
@@ -31,7 +31,7 @@ public:
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);
@@ -76,7 +76,7 @@ private:
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();
diff --git a/src/configdialog.ui b/src/configdialog.ui
index 874bbb3f..68281ca7 100644
--- a/src/configdialog.ui
+++ b/src/configdialog.ui
@@ -913,6 +913,11 @@
<string>Path</string>
</property>
</column>
+ <column>
+ <property name="text">
+ <string>Signing Key</string>
+ </property>
+ </column>
</widget>
</item>
<item>
diff --git a/src/imitatepass.cpp b/src/imitatepass.cpp
index 1cdb8575..307670de 100644
--- a/src/imitatepass.cpp
+++ b/src/imitatepass.cpp
@@ -89,6 +89,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()) {
@@ -166,6 +172,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;
@@ -196,6 +234,20 @@ 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)
@@ -203,11 +255,52 @@ void ImitatePass::Init(QString path, const QList<UserInfo> &users) {
QString commitPath = gpgIdFile;
commitPath.replace(QRegularExpression("\\.gpg$"), "");
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?
@@ -252,10 +345,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();
}
diff --git a/src/imitatepass.h b/src/imitatepass.h
index 4bfd3a94..d29a25d4 100644
--- a/src/imitatepass.h
+++ b/src/imitatepass.h
@@ -11,6 +11,7 @@
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);
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 60b3d0ca..960fc62d 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -766,7 +766,8 @@ void MainWindow::generateKeyPair(QString batch, QDialog *keygenWindow) {
* select a more appropriate one to view too
*/
void MainWindow::updateProfileBox() {
- QHash<QString, QString> profiles = QtPassSettings::getProfiles();
+ QHash<QString, QHash<QString, QString>> profiles =
+ QtPassSettings::getProfiles();
if (profiles.isEmpty()) {
ui->profileWidget->hide();
@@ -774,7 +775,7 @@ void MainWindow::updateProfileBox() {
ui->profileWidget->show();
ui->profileBox->setEnabled(profiles.size() > 1);
ui->profileBox->clear();
- QHashIterator<QString, QString> i(profiles);
+ QHashIterator<QString, QHash<QString, QString>> i(profiles);
while (i.hasNext()) {
i.next();
if (!i.key().isEmpty())
@@ -800,7 +801,10 @@ void MainWindow::on_profileBox_currentIndexChanged(QString name) {
QtPassSettings::setProfile(name);
- QtPassSettings::setPassStore(QtPassSettings::getProfiles()[name]);
+ QtPassSettings::setPassStore(
+ QtPassSettings::getProfiles().value(name).value("path"));
+ QtPassSettings::setPassSigningKey(
+ QtPassSettings::getProfiles().value(name).value("signingKey"));
ui->statusBar->showMessage(tr("Profile changed to %1").arg(name), 2000);
QtPassSettings::getPass()->updateEnv();
diff --git a/src/pass.cpp b/src/pass.cpp
index f01e71f1..a8770307 100644
--- a/src/pass.cpp
+++ b/src/pass.cpp
@@ -245,8 +245,29 @@ void Pass::finished(int id, int exitCode, const QString &out,
* switching profiles)
*/
void Pass::updateEnv() {
- QStringList store = env.filter("PASSWORD_STORE_DIR=");
+ // put PASSWORD_STORE_SIGNING_KEY in env
+ QStringList envSigningKey = env.filter("PASSWORD_STORE_SIGNING_KEY=");
+ QString currentSigningKey = QtPassSettings::getPassSigningKey();
+ if (envSigningKey.isEmpty()) {
+ if (!currentSigningKey.isEmpty()) {
+ // dbg()<< "Added
+ // PASSWORD_STORE_SIGNING_KEY with" + currentSigningKey;
+ env.append("PASSWORD_STORE_SIGNING_KEY=" + currentSigningKey);
+ }
+ } else {
+ if (currentSigningKey.isEmpty()) {
+ // dbg() << "Removed
+ // PASSWORD_STORE_SIGNING_KEY";
+ env.removeAll(envSigningKey.first());
+ } else {
+ // dbg()<< "Update
+ // PASSWORD_STORE_SIGNING_KEY with " + currentSigningKey;
+ env.replaceInStrings(envSigningKey.first(),
+ "PASSWORD_STORE_SIGNING_KEY=" + currentSigningKey);
+ }
+ }
// put PASSWORD_STORE_DIR in env
+ QStringList store = env.filter("PASSWORD_STORE_DIR=");
if (store.isEmpty()) {
// dbg()<< "Added
// PASSWORD_STORE_DIR";
@@ -261,27 +282,40 @@ void Pass::updateEnv() {
}
/**
- * @brief Pass::getRecipientList return list of gpg-id's to encrypt for
- * @param for_file which file (folder) would you like recepients for
- * @return recepients gpg-id contents
+ * @brief Pass::getGpgIdPath return gpgid file path for some file (folder).
+ * @param for_file which file (folder) would you like the gpgid file path for.
+ * @return path to the gpgid file.
*/
-QStringList Pass::getRecipientList(QString for_file) {
- QDir gpgIdPath(QFileInfo(for_file.startsWith(QtPassSettings::getPassStore())
- ? for_file
- : QtPassSettings::getPassStore() + for_file)
- .absoluteDir());
+QString Pass::getGpgIdPath(QString for_file) {
+ QString passStore =
+ QDir::fromNativeSeparators(QtPassSettings::getPassStore());
+ QDir gpgIdDir(
+ QFileInfo(QDir::fromNativeSeparators(for_file).startsWith(passStore)
+ ? for_file
+ : QtPassSettings::getPassStore() + for_file)
+ .absoluteDir());
bool found = false;
- while (gpgIdPath.exists() &&
- gpgIdPath.absolutePath().startsWith(QtPassSettings::getPassStore())) {
- if (QFile(gpgIdPath.absoluteFilePath(".gpg-id")).exists()) {
+ while (gpgIdDir.exists() && gpgIdDir.absolutePath().startsWith(passStore)) {
+ if (QFile(gpgIdDir.absoluteFilePath(".gpg-id")).exists()) {
found = true;
break;
}
- if (!gpgIdPath.cdUp())
+ if (!gpgIdDir.cdUp())
break;
}
- QFile gpgId(found ? gpgIdPath.absoluteFilePath(".gpg-id")
- : QtPassSettings::getPassStore() + ".gpg-id");
+ QString gpgIdPath(found ? gpgIdDir.absoluteFilePath(".gpg-id")
+ : QtPassSettings::getPassStore() + ".gpg-id");
+
+ return gpgIdPath;
+}
+
+/**
+ * @brief Pass::getRecipientList return list of gpg-id's to encrypt for
+ * @param for_file which file (folder) would you like recepients for
+ * @return recepients gpg-id contents
+ */
+QStringList Pass::getRecipientList(QString for_file) {
+ QFile gpgId(getGpgIdPath(for_file));
if (!gpgId.open(QIODevice::ReadOnly | QIODevice::Text))
return QStringList();
QStringList recipients;
diff --git a/src/pass.h b/src/pass.h
index 3ef3c7db..fb254fde 100644
--- a/src/pass.h
+++ b/src/pass.h
@@ -57,6 +57,7 @@ public:
QList<UserInfo> listKeys(QStringList keystrings, bool secret = false);
QList<UserInfo> listKeys(QString keystring = "", bool secret = false);
void updateEnv();
+ static QString getGpgIdPath(QString for_file);
static QStringList getRecipientList(QString for_file);
// TODO(bezet): getRecipientString is useless, refactor
static QStringList getRecipientString(QString for_file,
diff --git a/src/qtpasssettings.cpp b/src/qtpasssettings.cpp
index b32a6525..e76ae886 100644
--- a/src/qtpasssettings.cpp
+++ b/src/qtpasssettings.cpp
@@ -58,13 +58,30 @@ void QtPassSettings::setPasswordConfiguration(
config.Characters[PasswordConfiguration::CUSTOM]);
}
-QHash<QString, QString> QtPassSettings::getProfiles() {
+QHash<QString, QHash<QString, QString>> QtPassSettings::getProfiles() {
getInstance()->beginGroup(SettingsConstants::profile);
-
- QStringList childrenKeys = getInstance()->childKeys();
- QHash<QString, QString> profiles;
- foreach (QString key, childrenKeys) {
- profiles.insert(key, getInstance()->value(key).toString());
+ QHash<QString, QHash<QString, QString>> profiles;
+
+ // migration from version <= v1.3.2: profiles datastructure
+ QStringList childKeys = getInstance()->childKeys();
+ if (!childKeys.empty()) {
+ foreach (QString key, childKeys) {
+ QHash<QString, QString> profile;
+ profile.insert("path", getInstance()->value(key).toString());
+ profile.insert("signingKey", "");
+ profiles.insert(key, profile);
+ }
+ }
+ // /migration from version <= v1.3.2
+
+ QStringList childGroups = getInstance()->childGroups();
+ foreach (QString group, childGroups) {
+ QHash<QString, QString> profile;
+ profile.insert("path", getInstance()->value(group + "/path").toString());
+ profile.insert("signingKey",
+ getInstance()->value(group + "/signingKey").toString());
+ // profiles.insert(group, getInstance()->value(group).toString());
+ profiles.insert(group, profile);
}
getInstance()->endGroup();
@@ -72,13 +89,16 @@ QHash<QString, QString> QtPassSettings::getProfiles() {
return profiles;
}
-void QtPassSettings::setProfiles(const QHash<QString, QString> &profiles) {
+void QtPassSettings::setProfiles(
+ const QHash<QString, QHash<QString, QString>> &profiles) {
getInstance()->remove(SettingsConstants::profile);
getInstance()->beginGroup(SettingsConstants::profile);
- QHash<QString, QString>::const_iterator i = profiles.begin();
+ QHash<QString, QHash<QString, QString>>::const_iterator i = profiles.begin();
for (; i != profiles.end(); ++i) {
- getInstance()->setValue(i.key(), i.value());
+ getInstance()->setValue(i.key() + "/path", i.value().value("path"));
+ getInstance()->setValue(i.key() + "/signingKey",
+ i.value().value("signingKey"));
}
getInstance()->endGroup();
@@ -303,6 +323,15 @@ void QtPassSettings::setPassStore(const QString &passStore) {
getInstance()->setValue(SettingsConstants::passStore, passStore);
}
+QString QtPassSettings::getPassSigningKey(const QString &defaultValue) {
+ return getInstance()
+ ->value(SettingsConstants::passSigningKey, defaultValue)
+ .toString();
+}
+void QtPassSettings::setPassSigningKey(const QString &passSigningKey) {
+ getInstance()->setValue(SettingsConstants::passSigningKey, passSigningKey);
+}
+
void QtPassSettings::initExecutables() {
QString passExecutable =
QtPassSettings::getPassExecutable(Util::findBinaryInPath("pass"));
diff --git a/src/qtpasssettings.h b/src/qtpasssettings.h
index e3d5b3f0..d63f37fd 100644
--- a/src/qtpasssettings.h
+++ b/src/qtpasssettings.h
@@ -108,6 +108,10 @@ public:
getPassStore(const QString &defaultValue = QVariant().toString());
static void setPassStore(const QString &passStore);
+ static QString
+ getPassSigningKey(const QString &defaultValue = QVariant().toString());
+ static void setPassSigningKey(const QString &passSigningKey);
+
static void initExecutables();
static QString
getPassExecutable(const QString &defaultValue = QVariant().toString());
@@ -210,8 +214,9 @@ public:
isTemplateAllFields(const bool &defaultValue = QVariant().toBool());
static void setTemplateAllFields(const bool &templateAllFields);
- static QHash<QString, QString> getProfiles();
- static void setProfiles(const QHash<QString, QString> &profiles);
+ static QHash<QString, QHash<QString, QString>> getProfiles();
+ static void
+ setProfiles(const QHash<QString, QHash<QString, QString>> &profiles);
static Pass *getPass();
static RealPass *getRealPass();
diff --git a/src/settingsconstants.cpp b/src/settingsconstants.cpp
index 863d110f..00b004fd 100644
--- a/src/settingsconstants.cpp
+++ b/src/settingsconstants.cpp
@@ -32,6 +32,7 @@ const QString SettingsConstants::displayAsIs = "displayAsIs";
const QString SettingsConstants::noLineWrapping = "noLineWrapping";
const QString SettingsConstants::addGPGId = "addGPGId";
const QString SettingsConstants::passStore = "passStore";
+const QString SettingsConstants::passSigningKey = "passSigningKey";
const QString SettingsConstants::passExecutable = "passExecutable";
const QString SettingsConstants::gitExecutable = "gitExecutable";
const QString SettingsConstants::gpgExecutable = "gpgExecutable";
diff --git a/src/settingsconstants.h b/src/settingsconstants.h
index bb237ab3..f95aeba2 100644
--- a/src/settingsconstants.h
+++ b/src/settingsconstants.h
@@ -31,6 +31,7 @@ public:
const static QString noLineWrapping;
const static QString addGPGId;
const static QString passStore;
+ const static QString passSigningKey;
const static QString passExecutable;
const static QString gitExecutable;
const static QString gpgExecutable;