From cd2987635b9483c4bd941cab048b493fdb8c67b3 Mon Sep 17 00:00:00 2001 From: alex1701c Date: Thu, 5 Dec 2019 08:39:18 +0100 Subject: [PATCH 1/7] Fix warnings and deprecations, optimize --- .gitignore | 2 ++ CMakeLists.txt | 2 ++ config.cpp | 36 +++++++++++++++----------- config.h | 11 +++++--- install.sh | 4 +-- pass.cpp | 68 ++++++++++++++++++++++++-------------------------- pass.h | 2 +- 7 files changed, 68 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index 796b96d..f4774b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /build +/cmake-build-debug +/.idea diff --git a/CMakeLists.txt b/CMakeLists.txt index aa7050a..1718abc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,5 @@ +cmake_minimum_required(VERSION 2.8.12) + project(RunnerPass) find_package(ECM 5.12.0 REQUIRED NO_MODULE) diff --git a/config.cpp b/config.cpp index e342161..c218e58 100644 --- a/config.cpp +++ b/config.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "config.h" @@ -46,24 +47,27 @@ PassConfigForm::PassConfigForm(QWidget *parent) : QWidget(parent) connect(this->buttonAddAction, &QPushButton::clicked, [this]() { this->addPassAction(this->lineName->text(), this->lineIcon->text(), this->lineRegEx->text()); }); + + // Disable add button if the necessary field are not filled out + connect(this->lineIcon, SIGNAL(textChanged(QString)), this, SLOT(validateAddButton())); + connect(this->lineName, SIGNAL(textChanged(QString)), this, SLOT(validateAddButton())); + connect(this->lineRegEx, SIGNAL(textChanged(QString)), this, SLOT(validateAddButton())); + validateAddButton(); } void PassConfigForm::addPassAction(const QString &name, const QString &icon, const QString ®ex, bool isNew /* = true */) { // Checks - for (auto act: this->passActions()) + for (const auto& act: this->passActions()) if (act.name == name) return; - if (name.isEmpty() || icon.isEmpty() || regex.isEmpty()) - return; - // Widgets auto *listWidget = new QWidget(this); auto *layoutAction = new QHBoxLayout(listWidget); auto *buttonRemoveAction = new QToolButton(listWidget); - buttonRemoveAction->setIcon(QIcon::fromTheme("remove")); + buttonRemoveAction->setIcon(QIcon::fromTheme("delete")); layoutAction->setMargin(0); layoutAction->addStretch(); layoutAction->addWidget(buttonRemoveAction); @@ -91,7 +95,8 @@ void PassConfigForm::addPassAction(const QString &name, const QString &icon, con QVector PassConfigForm::passActions() { QVector passActions; - for(int i = 0; i < this->listSavedActions->count(); ++i) { + const int listSavedActionsCount = this->listSavedActions->count(); + for(int i = 0; i < listSavedActionsCount; ++i) { QListWidgetItem* item = this->listSavedActions->item(i); passActions << item->data(Qt::UserRole).value(); } @@ -100,7 +105,8 @@ QVector PassConfigForm::passActions() void PassConfigForm::clearPassActions() { - for(int i = 0; i < this->listSavedActions->count(); ++i) { + const int listSavedActionsCount = this->listSavedActions->count(); + for(int i = 0; i < listSavedActionsCount; ++i) { QListWidgetItem* item = this->listSavedActions->item(i); delete this->listSavedActions->itemWidget(item); } @@ -115,6 +121,12 @@ void PassConfigForm::clearInputs() this->lineRegEx->clear(); } +void PassConfigForm::validateAddButton() { + this->buttonAddAction->setDisabled(this->lineIcon->text().isEmpty() || + this->lineName->text().isEmpty() || + this->lineRegEx->text().isEmpty()); +} + PassConfig::PassConfig(QWidget *parent, const QVariantList &args) : KCModule(parent, args) @@ -123,8 +135,6 @@ PassConfig::PassConfig(QWidget *parent, const QVariantList &args) : QGridLayout* layout = new QGridLayout(this); layout->addWidget(ui, 0, 0); - load(); - connect(this->ui,SIGNAL(passActionAdded()),this,SLOT(changed())); connect(this->ui,SIGNAL(passActionRemoved()),this,SLOT(changed())); connect(this->ui->checkAdditionalActions,SIGNAL(stateChanged(int)),this,SLOT(changed())); @@ -150,9 +160,8 @@ void PassConfig::load() // Load saved actions this->ui->clearPassActions(); - auto actionGroup = passCfg.group(Config::Group::Actions); - auto groups = actionGroup.groupList(); - Q_FOREACH (auto name, groups) { + const auto actionGroup = passCfg.group(Config::Group::Actions); + for (const auto& name: actionGroup.groupList()) { auto group = actionGroup.group(name); auto passAction = PassAction::fromConfig(group); @@ -177,12 +186,11 @@ void PassConfig::save() passCfg.writeEntry(Config::showActions, showActions); passCfg.writeEntry(Config::showFileContentAction, showFileContentAction); - passCfg.deleteGroup(Config::Group::Actions); if (showActions) { int i = 0; - for (PassAction act: this->ui->passActions()) { + for (PassAction& act: this->ui->passActions()) { auto group = passCfg.group(Config::Group::Actions).group(QString::number(i++)); act.writeToConfig(group); } diff --git a/config.h b/config.h index f11e293..474c7cd 100644 --- a/config.h +++ b/config.h @@ -76,6 +76,9 @@ public: signals: void passActionRemoved(); void passActionAdded(); + +private slots: + void validateAddButton(); }; @@ -84,12 +87,12 @@ class PassConfig : public KCModule Q_OBJECT public: - explicit PassConfig(QWidget* parent = 0, const QVariantList& args = QVariantList()); + explicit PassConfig(QWidget* parent = nullptr, const QVariantList& args = QVariantList()); public Q_SLOTS: - void save(); - void load(); - void defaults(); + void save() override; + void load() override; + void defaults() override; private: PassConfigForm *ui; diff --git a/install.sh b/install.sh index 7d6331c..32ede4d 100755 --- a/install.sh +++ b/install.sh @@ -5,8 +5,8 @@ set -e mkdir -p build cd build -cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_INSTALL_PREFIX=`kf5-config --prefix` -DQT_PLUGIN_INSTALL_DIR=`kf5-config --qt-plugins` -make +cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_INSTALL_PREFIX=`kf5-config --prefix` -DQT_PLUGIN_INSTALL_DIR=`kf5-config --qt-plugins` -DCMAKE_BUILD_TYPE=Release +make -j$(nproc) sudo make install set +e diff --git a/pass.cpp b/pass.cpp index c02f9d0..4ab38a6 100644 --- a/pass.cpp +++ b/pass.cpp @@ -27,8 +27,9 @@ #include #include #include +#include -#include +#include #include "pass.h" #include "config.h" @@ -49,7 +50,7 @@ Pass::Pass(QObject *parent, const QVariantList &args) setDefaultSyntax(Plasma::RunnerSyntax(QString(":q:"), comment)); } -Pass::~Pass() {} +Pass::~Pass() = default; void Pass::reloadConfiguration() { @@ -60,11 +61,10 @@ void Pass::reloadConfiguration() this->showActions = cfg.readEntry(Config::showActions, false); if (showActions) { - auto configActions = cfg.group(Config::Group::Actions); + const auto configActions = cfg.group(Config::Group::Actions); // Create actions for every additional field - auto groups = configActions.groupList(); - Q_FOREACH (auto name, groups) { + for (const auto& name: configActions.groupList() ) { auto group = configActions.group(name); auto passAction = PassAction::fromConfig(group); @@ -89,26 +89,26 @@ void Pass::init() reloadConfiguration(); this->baseDir = QDir(QDir::homePath() + "/.password-store"); - auto baseDir = getenv("PASSWORD_STORE_DIR"); - if (baseDir != nullptr) { - this->baseDir = QDir(baseDir); + auto _baseDir = getenv("PASSWORD_STORE_DIR"); + if (_baseDir != nullptr) { + this->baseDir = QDir(_baseDir); } this->timeout = 45; - auto timeout = getenv("PASSWORD_STORE_CLIP_TIME"); - if (timeout != nullptr) { - QString str(timeout); + auto _timeout = getenv("PASSWORD_STORE_CLIP_TIME"); + if (_timeout != nullptr) { + QString str(_timeout); bool ok; - auto timeout = str.toInt(&ok); + auto _timeoutParsed = str.toInt(&ok); if (ok) { - this->timeout = timeout; + this->timeout = _timeoutParsed; } } this->passOtpIdentifier = "totp::"; - auto passOtpIdentifier = getenv("PASSWORD_STORE_OTP_IDENTIFIER"); - if (passOtpIdentifier != nullptr) { - this->passOtpIdentifier = passOtpIdentifier; + auto _passOtpIdentifier = getenv("PASSWORD_STORE_OTP_IDENTIFIER"); + if (_passOtpIdentifier != nullptr) { + this->passOtpIdentifier = _passOtpIdentifier; } initPasswords(); @@ -123,7 +123,7 @@ void Pass::initPasswords() { QDirIterator it(this->baseDir, QDirIterator::Subdirectories); while (it.hasNext()) { it.next(); - auto fileInfo = it.fileInfo(); + const auto fileInfo = it.fileInfo(); if (fileInfo.isFile() && fileInfo.suffix() == "gpg") { QString password = this->baseDir.relativeFilePath(fileInfo.absoluteFilePath()); // Remove suffix ".gpg" @@ -147,20 +147,17 @@ void Pass::match(Plasma::RunnerContext &context) { if (!context.isValid()) return; - auto input = context.query(); + const auto input = context.query(); QList matches; lock.lockForRead(); - Q_FOREACH (auto password, passwords) { - QRegularExpression re(".*" + input + ".*", QRegularExpression::CaseInsensitiveOption); + QRegularExpression re(".*" + input + ".*", QRegularExpression::CaseInsensitiveOption); + for (const auto& password: passwords) { if (re.match(password).hasMatch()) { Plasma::QueryMatch match(this); - if (input.length() == password.length()) { - match.setType(Plasma::QueryMatch::ExactMatch); - } else { - match.setType(Plasma::QueryMatch::CompletionMatch); - } + match.setType(input.length() == password.length() ? + Plasma::QueryMatch::ExactMatch : Plasma::QueryMatch::CompletionMatch); match.setIcon(QIcon::fromTheme("object-locked")); match.setText(password); matches.append(match); @@ -183,10 +180,10 @@ void Pass::clip(const QString &msg) void Pass::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) { Q_UNUSED(context); - auto regexp = QRegularExpression("^" + QRegularExpression::escape(this->passOtpIdentifier) + ".*"); - auto isOtp = match.text().split('/').filter(regexp).size() > 0; + const auto regexp = QRegularExpression("^" + QRegularExpression::escape(this->passOtpIdentifier) + ".*"); + const auto isOtp = !match.text().split('/').filter(regexp).isEmpty(); - QProcess *pass = new QProcess(); + auto *pass = new QProcess(); QStringList args; if (isOtp) { args << "otp" << "show" << match.text(); @@ -211,7 +208,7 @@ void Pass::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &m QMessageBox::information(nullptr, match.text(), output); } else { QRegularExpression re(data, QRegularExpression::MultilineOption); - auto matchre = re.match(output); + const auto matchre = re.match(output); if (matchre.hasMatch()) { clip(matchre.captured(1)); @@ -225,9 +222,9 @@ void Pass::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &m } } } else { - auto string = QString::fromUtf8(output.data()); - auto lines = string.split('\n', QString::SkipEmptyParts); - if (lines.count() > 0) { + const auto string = QString::fromUtf8(output.data()); + const auto lines = string.split('\n', QString::SkipEmptyParts); + if (!lines.isEmpty()) { clip(lines[0]); this->showNotification(match.text()); } @@ -251,12 +248,11 @@ QList Pass::actionsForMatch(const Plasma::QueryMatch &match) void Pass::showNotification(const QString &text, const QString &actionName /* = "" */) { - QString msgPrefix = actionName.isEmpty() ? "":actionName + i18n(" of "); - QString msg = i18n("Password %1 copied to clipboard for %2 seconds", text, timeout); - auto notification = KNotification::event("password-unlocked", "Pass", msgPrefix + msg, + const QString msgPrefix = actionName.isEmpty() ? "":actionName + i18n(" of "); + const QString msg = i18n("Password %1 copied to clipboard for %2 seconds", text, timeout); + KNotification::event("password-unlocked", "Pass", msgPrefix + msg, "object-unlocked", nullptr, KNotification::CloseOnTimeout, "krunner_pass"); - QTimer::singleShot(timeout * 1000, notification, SLOT(quit)); } K_EXPORT_PLASMA_RUNNER(pass, Pass) diff --git a/pass.h b/pass.h index 7b1da33..134be0f 100644 --- a/pass.h +++ b/pass.h @@ -30,7 +30,7 @@ class Pass : public Plasma::AbstractRunner public: Pass(QObject *parent, const QVariantList &args); - ~Pass(); + ~Pass() override; void clip(const QString &msg); void match(Plasma::RunnerContext &) override; From c0c88e97d182a52966a6cba6faf0024009f9c781 Mon Sep 17 00:00:00 2001 From: alex1701c Date: Fri, 6 Dec 2019 21:52:44 +0100 Subject: [PATCH 2/7] Use contains instead of regex --- pass.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pass.cpp b/pass.cpp index 4ab38a6..ed84bd1 100644 --- a/pass.cpp +++ b/pass.cpp @@ -152,9 +152,8 @@ void Pass::match(Plasma::RunnerContext &context) QList matches; lock.lockForRead(); - QRegularExpression re(".*" + input + ".*", QRegularExpression::CaseInsensitiveOption); for (const auto& password: passwords) { - if (re.match(password).hasMatch()) { + if (password.contains(input,Qt::CaseInsensitive)) { Plasma::QueryMatch match(this); match.setType(input.length() == password.length() ? Plasma::QueryMatch::ExactMatch : Plasma::QueryMatch::CompletionMatch); From 7194271cecbe92229dba0de5b5e742ad0cb2d759 Mon Sep 17 00:00:00 2001 From: alex1701c Date: Fri, 14 Feb 2020 13:06:00 +0100 Subject: [PATCH 3/7] Add config options, remove deprecations, optimize --- CMakeLists.txt | 2 +- README.md | 3 +- config.cpp | 89 ++++++++++++++++++++++++++------------------------ config.h | 1 + config.ui | 49 +++++++++++++++------------ install.sh | 2 +- pass.cpp | 61 ++++++++++++++++++++-------------- pass.h | 6 ++-- 8 files changed, 120 insertions(+), 93 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1718abc..45b6e0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,6 @@ target_link_libraries(krunner_pass KF5::Runner Qt5::Widgets add_dependencies(krunner_pass kcm_krunner_pass) -install(TARGETS krunner_pass kcm_krunner_pass DESTINATION ${PLUGIN_INSTALL_DIR}) +install(TARGETS krunner_pass kcm_krunner_pass DESTINATION ${KDE_INSTALL_QTPLUGINDIR}) install(FILES plasma-runner-pass.desktop plasma-runner-pass_config.desktop DESTINATION ${SERVICES_INSTALL_DIR}) install(FILES krunner_pass.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR}) diff --git a/README.md b/README.md index b9f7159..3af8614 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ apt-get install build-essential cmake extra-cmake-modules gettext \ libkf5service-dev \ libkf5runner-dev \ libkf5textwidgets-dev \ - libkf5notifications-dev + libkf5notifications-dev \ + libkf5kcmutils-dev mkdir -p build cd build diff --git a/config.cpp b/config.cpp index c218e58..73f0bc3 100644 --- a/config.cpp +++ b/config.cpp @@ -22,13 +22,13 @@ #include #include +#include "kcmutils_version.h" #include "config.h" K_PLUGIN_FACTORY(PassConfigFactory, registerPlugin("kcm_krunner_pass");) - - -PassConfigForm::PassConfigForm(QWidget *parent) : QWidget(parent) +PassConfigForm::PassConfigForm(QWidget *parent) + : QWidget(parent) { setupUi(this); this->listSavedActions->setDragEnabled(true); @@ -49,16 +49,17 @@ PassConfigForm::PassConfigForm(QWidget *parent) : QWidget(parent) }); // Disable add button if the necessary field are not filled out - connect(this->lineIcon, SIGNAL(textChanged(QString)), this, SLOT(validateAddButton())); - connect(this->lineName, SIGNAL(textChanged(QString)), this, SLOT(validateAddButton())); - connect(this->lineRegEx, SIGNAL(textChanged(QString)), this, SLOT(validateAddButton())); + connect(this->lineIcon, &QLineEdit::textChanged, this, &PassConfigForm::validateAddButton); + connect(this->lineName, &QLineEdit::textChanged, this, &PassConfigForm::validateAddButton); + connect(this->lineRegEx, &QLineEdit::textChanged, this, &PassConfigForm::validateAddButton); validateAddButton(); } -void PassConfigForm::addPassAction(const QString &name, const QString &icon, const QString ®ex, bool isNew /* = true */) +void +PassConfigForm::addPassAction(const QString &name, const QString &icon, const QString ®ex, bool isNew /* = true */) { // Checks - for (const auto& act: this->passActions()) + for (const auto &act: this->passActions()) if (act.name == name) return; @@ -74,8 +75,8 @@ void PassConfigForm::addPassAction(const QString &name, const QString &icon, con listWidget->setLayout(layoutAction); // Item - auto *item = new QListWidgetItem(name + (isNew ? "*":""), this->listSavedActions); - item->setData(Qt::UserRole, QVariant::fromValue(PassAction {name, icon, regex})); + auto *item = new QListWidgetItem(name + (isNew ? "*" : ""), this->listSavedActions); + item->setData(Qt::UserRole, QVariant::fromValue(PassAction{name, icon, regex})); this->listSavedActions->setItemWidget(item, listWidget); this->clearInputs(); @@ -95,9 +96,8 @@ void PassConfigForm::addPassAction(const QString &name, const QString &icon, con QVector PassConfigForm::passActions() { QVector passActions; - const int listSavedActionsCount = this->listSavedActions->count(); - for(int i = 0; i < listSavedActionsCount; ++i) { - QListWidgetItem* item = this->listSavedActions->item(i); + for (int i = 0; i < listSavedActions->count(); ++i) { + QListWidgetItem *item = this->listSavedActions->item(i); passActions << item->data(Qt::UserRole).value(); } return passActions; @@ -105,9 +105,8 @@ QVector PassConfigForm::passActions() void PassConfigForm::clearPassActions() { - const int listSavedActionsCount = this->listSavedActions->count(); - for(int i = 0; i < listSavedActionsCount; ++i) { - QListWidgetItem* item = this->listSavedActions->item(i); + for (int i = 0; i < listSavedActions->count(); ++i) { + QListWidgetItem *item = this->listSavedActions->item(i); delete this->listSavedActions->itemWidget(item); } @@ -121,25 +120,31 @@ void PassConfigForm::clearInputs() this->lineRegEx->clear(); } -void PassConfigForm::validateAddButton() { +void PassConfigForm::validateAddButton() +{ this->buttonAddAction->setDisabled(this->lineIcon->text().isEmpty() || - this->lineName->text().isEmpty() || - this->lineRegEx->text().isEmpty()); + this->lineName->text().isEmpty() || + this->lineRegEx->text().isEmpty()); } - -PassConfig::PassConfig(QWidget *parent, const QVariantList &args) : +PassConfig::PassConfig(QWidget *parent, const QVariantList &args) + : KCModule(parent, args) { this->ui = new PassConfigForm(this); - QGridLayout* layout = new QGridLayout(this); + QGridLayout *layout = new QGridLayout(this); layout->addWidget(ui, 0, 0); - - connect(this->ui,SIGNAL(passActionAdded()),this,SLOT(changed())); - connect(this->ui,SIGNAL(passActionRemoved()),this,SLOT(changed())); - connect(this->ui->checkAdditionalActions,SIGNAL(stateChanged(int)),this,SLOT(changed())); - connect(this->ui->checkShowFileContentAction,SIGNAL(stateChanged(int)),this,SLOT(changed())); - connect(this->ui->listSavedActions,SIGNAL(itemSelectionChanged()), this, SLOT(changed())); +#if KCMUTILS_VERSION >= QT_VERSION_CHECK(5, 64, 0) + const auto changedSlotPointer = &PassConfig::markAsChanged; +#else + const auto changedSlotPointer = static_cast(&PassConfig::changed); +#endif + connect(this->ui, &PassConfigForm::passActionAdded, this, changedSlotPointer); + connect(this->ui, &PassConfigForm::passActionRemoved, this, changedSlotPointer); + connect(this->ui->checkShowOnlyPrefixed, &QCheckBox::stateChanged, this, changedSlotPointer); + connect(this->ui->checkAdditionalActions, &QCheckBox::stateChanged, this, changedSlotPointer); + connect(this->ui->checkShowFileContentAction, &QCheckBox::stateChanged, this, changedSlotPointer); + connect(this->ui->listSavedActions, &QListWidget::itemSelectionChanged, this, changedSlotPointer); } void PassConfig::load() @@ -147,13 +152,13 @@ void PassConfig::load() KCModule::load(); KSharedConfig::Ptr cfg = KSharedConfig::openConfig(QStringLiteral("krunnerrc")); - KConfigGroup passCfg = cfg->group("Runners"); - passCfg = KConfigGroup(&passCfg, "Pass"); - + KConfigGroup passCfg = cfg->group("Runners").group("Pass"); + bool showOnlyPrefixed = passCfg.readEntry(Config::showOnlyPrefixed, false); bool showActions = passCfg.readEntry(Config::showActions, false); bool showFileContentAction = passCfg.readEntry(Config::showFileContentAction, false); + this->ui->checkShowOnlyPrefixed->setChecked(showOnlyPrefixed); this->ui->checkAdditionalActions->setChecked(showActions); this->ui->checkShowFileContentAction->setChecked(showFileContentAction); @@ -161,14 +166,11 @@ void PassConfig::load() this->ui->clearPassActions(); const auto actionGroup = passCfg.group(Config::Group::Actions); - for (const auto& name: actionGroup.groupList()) { + for (const auto &name: actionGroup.groupList()) { auto group = actionGroup.group(name); auto passAction = PassAction::fromConfig(group); - this->ui->addPassAction(passAction.name, passAction.icon, passAction.regex, false); } - - emit changed(false); } void PassConfig::save() @@ -176,13 +178,13 @@ void PassConfig::save() KCModule::save(); KSharedConfig::Ptr cfg = KSharedConfig::openConfig(QStringLiteral("krunnerrc")); - KConfigGroup passCfg = cfg->group("Runners"); - passCfg = KConfigGroup(&passCfg, "Pass"); - + KConfigGroup passCfg = cfg->group("Runners").group("Pass"); + auto showOnlyPrefixed = this->ui->checkShowOnlyPrefixed->isChecked(); auto showActions = this->ui->checkAdditionalActions->isChecked(); - auto showFileContentAction = this->ui->checkShowFileContentAction->isChecked(); + auto showFileContentAction = this->ui->checkShowFileContentAction->isChecked(); + passCfg.writeEntry(Config::showOnlyPrefixed, showOnlyPrefixed); passCfg.writeEntry(Config::showActions, showActions); passCfg.writeEntry(Config::showFileContentAction, showFileContentAction); @@ -190,25 +192,28 @@ void PassConfig::save() if (showActions) { int i = 0; - for (PassAction& act: this->ui->passActions()) { + for (PassAction &act: this->ui->passActions()) { auto group = passCfg.group(Config::Group::Actions).group(QString::number(i++)); act.writeToConfig(group); } } - - emit changed(false); } void PassConfig::defaults() { KCModule::defaults(); + ui->checkShowOnlyPrefixed->setChecked(false); ui->checkAdditionalActions->setChecked(false); ui->checkShowFileContentAction->setChecked(false); ui->clearPassActions(); ui->clearInputs(); +#if KCMUTILS_VERSION >= QT_VERSION_CHECK(5, 64, 0) + emit markAsChanged(); +#else emit changed(true); +#endif } diff --git a/config.h b/config.h index 474c7cd..4a3c267 100644 --- a/config.h +++ b/config.h @@ -25,6 +25,7 @@ struct Config { + constexpr static const char *showOnlyPrefixed = "showOnlyPrefixed"; constexpr static const char *showActions = "showAdditionalActions"; constexpr static const char *showFileContentAction = "showFullFileContentAction"; struct Group { diff --git a/config.ui b/config.ui index f712d23..761d5dc 100644 --- a/config.ui +++ b/config.ui @@ -6,32 +6,37 @@ 0 0 - 314 - 420 + 356 + 421 Pass Config - - - - Show additional actions + + + + false + + Saved Actions + + + + + + - - - false - + - Show an action for displaying full file content + Show additional actions - + false @@ -93,19 +98,21 @@ - - + + false - - Saved Actions + + Show an action for displaying full file content + + + + + + + Show only options when query starts with "pass" - - - - - diff --git a/install.sh b/install.sh index 32ede4d..6d24456 100755 --- a/install.sh +++ b/install.sh @@ -5,7 +5,7 @@ set -e mkdir -p build cd build -cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_INSTALL_PREFIX=`kf5-config --prefix` -DQT_PLUGIN_INSTALL_DIR=`kf5-config --qt-plugins` -DCMAKE_BUILD_TYPE=Release +cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_INSTALL_PREFIX=`kf5-config --prefix` -DCMAKE_BUILD_TYPE=Release make -j$(nproc) sudo make install diff --git a/pass.cpp b/pass.cpp index ed84bd1..422416e 100644 --- a/pass.cpp +++ b/pass.cpp @@ -17,7 +17,7 @@ *****************************************************************************/ #include #include -#include +#include #include #include @@ -60,20 +60,24 @@ void Pass::reloadConfiguration() KConfigGroup cfg = config(); this->showActions = cfg.readEntry(Config::showActions, false); + this->showOnlyPrefixed = cfg.readEntry(Config::showOnlyPrefixed, false); + if (showActions) { const auto configActions = cfg.group(Config::Group::Actions); // Create actions for every additional field - for (const auto& name: configActions.groupList() ) { + for (const auto &name: configActions.groupList()) { auto group = configActions.group(name); auto passAction = PassAction::fromConfig(group); auto icon = QIcon::fromTheme(passAction.icon, QIcon::fromTheme("object-unlocked")); - QAction *act = addAction(passAction.name, icon , passAction.name); + QAction *act = addAction(passAction.name, icon, passAction.name); act->setData(passAction.regex); this->orderedActions << act; } + } else { + this->orderedActions.clear(); } if (cfg.readEntry(Config::showFileContentAction, false)) { @@ -113,10 +117,11 @@ void Pass::init() initPasswords(); - connect(&watcher, SIGNAL(directoryChanged(QString)), this, SLOT(reinitPasswords(QString))); + connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &Pass::reinitPasswords); } -void Pass::initPasswords() { +void Pass::initPasswords() +{ passwords.clear(); watcher.addPath(this->baseDir.absolutePath()); @@ -124,7 +129,7 @@ void Pass::initPasswords() { while (it.hasNext()) { it.next(); const auto fileInfo = it.fileInfo(); - if (fileInfo.isFile() && fileInfo.suffix() == "gpg") { + if (fileInfo.isFile() && fileInfo.suffix() == QLatin1String("gpg")) { QString password = this->baseDir.relativeFilePath(fileInfo.absoluteFilePath()); // Remove suffix ".gpg" password.chop(4); @@ -135,7 +140,8 @@ void Pass::initPasswords() { } } -void Pass::reinitPasswords(const QString &path) { +void Pass::reinitPasswords(const QString &path) +{ Q_UNUSED(path); lock.lockForWrite(); @@ -145,18 +151,27 @@ void Pass::reinitPasswords(const QString &path) { void Pass::match(Plasma::RunnerContext &context) { - if (!context.isValid()) return; + if (!context.isValid()) { + return; + } - const auto input = context.query(); + auto input = context.query(); + if (showOnlyPrefixed) { + if (input.startsWith(queryPrefix)) { + input = input.remove(queryPrefix).simplified(); + } else { + return; + } + } QList matches; lock.lockForRead(); - for (const auto& password: passwords) { - if (password.contains(input,Qt::CaseInsensitive)) { + for (const auto &password: qAsConst(passwords)) { + if (password.contains(input, Qt::CaseInsensitive)) { Plasma::QueryMatch match(this); match.setType(input.length() == password.length() ? - Plasma::QueryMatch::ExactMatch : Plasma::QueryMatch::CompletionMatch); + Plasma::QueryMatch::ExactMatch : Plasma::QueryMatch::CompletionMatch); match.setIcon(QIcon::fromTheme("object-locked")); match.setText(password); matches.append(match); @@ -172,8 +187,8 @@ void Pass::clip(const QString &msg) QClipboard *cb = QApplication::clipboard(); cb->setText(msg); QTimer::singleShot(timeout * 1000, cb, [cb]() { - cb->clear(); - }); + cb->setText(QString()); + }); } void Pass::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) @@ -185,10 +200,9 @@ void Pass::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &m auto *pass = new QProcess(); QStringList args; if (isOtp) { - args << "otp" << "show" << match.text(); - } else { - args << "show" << match.text(); + args << "otp"; } + args << "show" << match.text(); pass->start("pass", args); connect(pass, static_cast(&QProcess::finished), @@ -239,19 +253,16 @@ QList Pass::actionsForMatch(const Plasma::QueryMatch &match) { Q_UNUSED(match) - if (showActions) - return this->orderedActions; - - return QList(); + return this->orderedActions; } -void Pass::showNotification(const QString &text, const QString &actionName /* = "" */) +void Pass::showNotification(const QString &text, const QString &actionName) { - const QString msgPrefix = actionName.isEmpty() ? "":actionName + i18n(" of "); + const QString msgPrefix = actionName.isEmpty() ? "" : actionName + i18n(" of "); const QString msg = i18n("Password %1 copied to clipboard for %2 seconds", text, timeout); KNotification::event("password-unlocked", "Pass", msgPrefix + msg, - "object-unlocked", nullptr, KNotification::CloseOnTimeout, - "krunner_pass"); + "object-unlocked", nullptr, KNotification::CloseOnTimeout, + "krunner_pass"); } K_EXPORT_PLASMA_RUNNER(pass, Pass) diff --git a/pass.h b/pass.h index 134be0f..38aa2ea 100644 --- a/pass.h +++ b/pass.h @@ -45,7 +45,7 @@ public slots: protected: void init() override; void initPasswords(); - void showNotification(const QString &, const QString & = ""); + void showNotification(const QString &, const QString & = QString()); private: QDir baseDir; @@ -57,7 +57,9 @@ private: bool showActions; QList orderedActions; - + + bool showOnlyPrefixed; + QLatin1String queryPrefix = QLatin1String("pass"); }; #endif From 74ace8c22701b37dd9c4f3c7eaefe8aa55ff0eb9 Mon Sep 17 00:00:00 2001 From: alex1701c Date: Mon, 17 Aug 2020 16:22:45 +0200 Subject: [PATCH 4/7] Add uninstall script! --- uninstall.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 uninstall.sh diff --git a/uninstall.sh b/uninstall.sh new file mode 100755 index 0000000..7e9fbfc --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Exit immediately if something fails +set -e + +cd build +sudo make uninstall +kquitapp5 krunner +kstart5 --windowclass krunner krunner + From 89490957bb4e37a631a75cb05b298bfd3d752d1b Mon Sep 17 00:00:00 2001 From: alex1701c Date: Mon, 17 Aug 2020 17:39:55 +0200 Subject: [PATCH 5/7] Add config for CPACK --- CMakeLists.txt | 15 +++++++++++++++ plasma-runner-pass.desktop | 2 +- postinst | 3 +++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 postinst diff --git a/CMakeLists.txt b/CMakeLists.txt index 45b6e0b..fb0e438 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,21 @@ include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) +# CPack configuration +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Copies a password from the password store (https://www.passwordstore.org/) to the clipboard") +set(CPACK_PACKAGE_NAME krunner-pass) +set(CPACK_PACKAGE_VERSION "1.1.0") +set(CPACK_DEBIAN_PACKAGE_SECTION "utils") +set(CPACK_DEBIAN_PACKAGE_MAINTAINER "alex1701c") +set(CPACK_RPM_PACKAGE_ARCHITECTURE "x86_64") +set(CPACK_GENERATOR "DEB;RPM") +set(CPACK_RPM_PACKAGE_ARCHITECTURE "x86_64") + +set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst") +set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/postinst") + +INCLUDE(CPack) + set(krunner_pass_SRCS pass.cpp ) diff --git a/plasma-runner-pass.desktop b/plasma-runner-pass.desktop index fd4cb89..1606799 100644 --- a/plasma-runner-pass.desktop +++ b/plasma-runner-pass.desktop @@ -8,7 +8,7 @@ X-KDE-Library=krunner_pass X-KDE-PluginInfo-Author=Lukas Fürmetz X-KDE-PluginInfo-Email=fuermetz@mailbox.org X-KDE-PluginInfo-Name=Pass -X-KDE-PluginInfo-Version=1.0.3 +X-KDE-PluginInfo-Version=1.1.0 X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true X-Plasma-AdvertiseSingleRunnerQueryMode=true diff --git a/postinst b/postinst new file mode 100644 index 0000000..3100ccd --- /dev/null +++ b/postinst @@ -0,0 +1,3 @@ +#!/bin/bash + +killall krunner From 5325780f768c9bb75924c08b4663b84b86e12bd9 Mon Sep 17 00:00:00 2001 From: alex1701c Date: Tue, 18 Aug 2020 15:34:46 +0200 Subject: [PATCH 6/7] Cleanup, set better default behavior The prefix is by default enabled, but cant be foreced. Also the plugin requires at least three characters typed, unless the single runner mode is used. --- config.cpp | 8 +------- config.h | 1 - config.ui | 7 ------- install.sh | 4 ++-- pass.cpp | 39 ++++++++++++++++++--------------------- pass.h | 5 ++--- uninstall.sh | 1 - 7 files changed, 23 insertions(+), 42 deletions(-) diff --git a/config.cpp b/config.cpp index 73f0bc3..6eff86f 100644 --- a/config.cpp +++ b/config.cpp @@ -141,7 +141,6 @@ PassConfig::PassConfig(QWidget *parent, const QVariantList &args) #endif connect(this->ui, &PassConfigForm::passActionAdded, this, changedSlotPointer); connect(this->ui, &PassConfigForm::passActionRemoved, this, changedSlotPointer); - connect(this->ui->checkShowOnlyPrefixed, &QCheckBox::stateChanged, this, changedSlotPointer); connect(this->ui->checkAdditionalActions, &QCheckBox::stateChanged, this, changedSlotPointer); connect(this->ui->checkShowFileContentAction, &QCheckBox::stateChanged, this, changedSlotPointer); connect(this->ui->listSavedActions, &QListWidget::itemSelectionChanged, this, changedSlotPointer); @@ -154,11 +153,9 @@ void PassConfig::load() KSharedConfig::Ptr cfg = KSharedConfig::openConfig(QStringLiteral("krunnerrc")); KConfigGroup passCfg = cfg->group("Runners").group("Pass"); - bool showOnlyPrefixed = passCfg.readEntry(Config::showOnlyPrefixed, false); bool showActions = passCfg.readEntry(Config::showActions, false); bool showFileContentAction = passCfg.readEntry(Config::showFileContentAction, false); - this->ui->checkShowOnlyPrefixed->setChecked(showOnlyPrefixed); this->ui->checkAdditionalActions->setChecked(showActions); this->ui->checkShowFileContentAction->setChecked(showFileContentAction); @@ -180,11 +177,9 @@ void PassConfig::save() KSharedConfig::Ptr cfg = KSharedConfig::openConfig(QStringLiteral("krunnerrc")); KConfigGroup passCfg = cfg->group("Runners").group("Pass"); - auto showOnlyPrefixed = this->ui->checkShowOnlyPrefixed->isChecked(); auto showActions = this->ui->checkAdditionalActions->isChecked(); auto showFileContentAction = this->ui->checkShowFileContentAction->isChecked(); - passCfg.writeEntry(Config::showOnlyPrefixed, showOnlyPrefixed); passCfg.writeEntry(Config::showActions, showActions); passCfg.writeEntry(Config::showFileContentAction, showFileContentAction); @@ -203,14 +198,13 @@ void PassConfig::defaults() { KCModule::defaults(); - ui->checkShowOnlyPrefixed->setChecked(false); ui->checkAdditionalActions->setChecked(false); ui->checkShowFileContentAction->setChecked(false); ui->clearPassActions(); ui->clearInputs(); #if KCMUTILS_VERSION >= QT_VERSION_CHECK(5, 64, 0) - emit markAsChanged(); + markAsChanged(); #else emit changed(true); #endif diff --git a/config.h b/config.h index 4a3c267..474c7cd 100644 --- a/config.h +++ b/config.h @@ -25,7 +25,6 @@ struct Config { - constexpr static const char *showOnlyPrefixed = "showOnlyPrefixed"; constexpr static const char *showActions = "showAdditionalActions"; constexpr static const char *showFileContentAction = "showFullFileContentAction"; struct Group { diff --git a/config.ui b/config.ui index 761d5dc..8a06b41 100644 --- a/config.ui +++ b/config.ui @@ -108,13 +108,6 @@ - - - - Show only options when query starts with "pass" - - - diff --git a/install.sh b/install.sh index 6d24456..73144ae 100755 --- a/install.sh +++ b/install.sh @@ -11,5 +11,5 @@ sudo make install set +e -kquitapp5 krunner 2> /dev/null -kstart5 --windowclass krunner krunner > /dev/null 2>&1 & +kquitapp5 krunner +kstart5 --windowclass krunner krunner diff --git a/pass.cpp b/pass.cpp index 422416e..a4cf786 100644 --- a/pass.cpp +++ b/pass.cpp @@ -40,33 +40,29 @@ using namespace std; Pass::Pass(QObject *parent, const QVariantList &args) : Plasma::AbstractRunner(parent, args) { - Q_UNUSED(args); - // General runner configuration - setObjectName(QString("Pass")); + setObjectName(QStringLiteral("Pass")); setSpeed(AbstractRunner::NormalSpeed); setPriority(HighestPriority); - auto comment = i18n("Looks for a password matching :q:. Pressing ENTER copies the password to the clipboard."); - setDefaultSyntax(Plasma::RunnerSyntax(QString(":q:"), comment)); } Pass::~Pass() = default; void Pass::reloadConfiguration() { - actions().clear(); + clearActions(); orderedActions.clear(); KConfigGroup cfg = config(); + cfg.config()->reparseConfiguration(); // Just to be sure this->showActions = cfg.readEntry(Config::showActions, false); - this->showOnlyPrefixed = cfg.readEntry(Config::showOnlyPrefixed, false); - if (showActions) { const auto configActions = cfg.group(Config::Group::Actions); // Create actions for every additional field - for (const auto &name: configActions.groupList()) { + const auto configActionsList = configActions.groupList(); + for (const auto &name: configActionsList) { auto group = configActions.group(name); auto passAction = PassAction::fromConfig(group); @@ -86,6 +82,12 @@ void Pass::reloadConfiguration() act->setData(Config::showFileContentAction); this->orderedActions << act; } + + setDefaultSyntax(Plasma::RunnerSyntax(QString(":q:"), + i18n("Looks for a password matching :q:. Pressing ENTER copies the password to the clipboard."))); + + addSyntax(Plasma::RunnerSyntax(QString("pass :q:"), + i18n("Looks for a password matching :q:. This way you avoid results from other runners"))); } void Pass::init() @@ -142,7 +144,7 @@ void Pass::initPasswords() void Pass::reinitPasswords(const QString &path) { - Q_UNUSED(path); + Q_UNUSED(path) lock.lockForWrite(); initPasswords(); @@ -156,12 +158,11 @@ void Pass::match(Plasma::RunnerContext &context) } auto input = context.query(); - if (showOnlyPrefixed) { - if (input.startsWith(queryPrefix)) { - input = input.remove(queryPrefix).simplified(); - } else { - return; - } + // If we use the prefix we want to remove it + if (input.startsWith(queryPrefix)) { + input = input.remove(queryPrefix).simplified(); + } else if (input.count() < 3 && !context.singleRunnerQueryMode()) { + return; } QList matches; @@ -207,16 +208,12 @@ void Pass::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &m connect(pass, static_cast(&QProcess::finished), [=](int exitCode, QProcess::ExitStatus exitStatus) { - Q_UNUSED(exitCode); - Q_UNUSED(exitStatus); + Q_UNUSED(exitStatus) if (exitCode == 0) { - const auto output = pass->readAllStandardOutput(); - if (match.selectedAction() != nullptr) { const auto data = match.selectedAction()->data().toString(); - if (data == Config::showFileContentAction) { QMessageBox::information(nullptr, match.text(), output); } else { diff --git a/pass.h b/pass.h index 38aa2ea..a12c737 100644 --- a/pass.h +++ b/pass.h @@ -39,7 +39,7 @@ public: void reloadConfiguration() override; -public slots: +public Q_SLOTS: void reinitPasswords(const QString &path); protected: @@ -58,8 +58,7 @@ private: bool showActions; QList orderedActions; - bool showOnlyPrefixed; - QLatin1String queryPrefix = QLatin1String("pass"); + const QLatin1String queryPrefix = QLatin1String("pass"); }; #endif diff --git a/uninstall.sh b/uninstall.sh index 7e9fbfc..e3efe5b 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -7,4 +7,3 @@ cd build sudo make uninstall kquitapp5 krunner kstart5 --windowclass krunner krunner - From 8e80b5de54606be94ccd358251f5f0962dae1e7b Mon Sep 17 00:00:00 2001 From: Alexander Lohnau Date: Wed, 19 Aug 2020 20:42:58 +0200 Subject: [PATCH 7/7] improve search behavior in edge cases --- pass.cpp | 4 ++-- pass.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pass.cpp b/pass.cpp index a4cf786..da6adb9 100644 --- a/pass.cpp +++ b/pass.cpp @@ -159,8 +159,8 @@ void Pass::match(Plasma::RunnerContext &context) auto input = context.query(); // If we use the prefix we want to remove it - if (input.startsWith(queryPrefix)) { - input = input.remove(queryPrefix).simplified(); + if (input.contains(queryPrefix)) { + input = input.remove(QLatin1String("pass")).simplified(); } else if (input.count() < 3 && !context.singleRunnerQueryMode()) { return; } diff --git a/pass.h b/pass.h index a12c737..1218b87 100644 --- a/pass.h +++ b/pass.h @@ -23,6 +23,7 @@ #include #include #include +#include class Pass : public Plasma::AbstractRunner { @@ -58,7 +59,7 @@ private: bool showActions; QList orderedActions; - const QLatin1String queryPrefix = QLatin1String("pass"); + const QRegularExpression queryPrefix = QRegularExpression("^pass( .+)?$"); }; #endif