Merge pull request #17 from alex1701c/master

Fix warnings and deprecations, optimize
master
Lukas Fürmetz 5 years ago committed by GitHub
commit ce0fbda652
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .gitignore
  2. 19
      CMakeLists.txt
  3. 3
      README.md
  4. 91
      config.cpp
  5. 11
      config.h
  6. 42
      config.ui
  7. 8
      install.sh
  8. 137
      pass.cpp
  9. 8
      pass.h
  10. 2
      plasma-runner-pass.desktop
  11. 3
      postinst
  12. 9
      uninstall.sh

2
.gitignore vendored

@ -1 +1,3 @@
/build /build
/cmake-build-debug
/.idea

@ -1,3 +1,5 @@
cmake_minimum_required(VERSION 2.8.12)
project(RunnerPass) project(RunnerPass)
find_package(ECM 5.12.0 REQUIRED NO_MODULE) find_package(ECM 5.12.0 REQUIRED NO_MODULE)
@ -12,6 +14,21 @@ include(KDEInstallDirs)
include(KDECMakeSettings) include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE) 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 set(krunner_pass_SRCS
pass.cpp pass.cpp
) )
@ -42,6 +59,6 @@ target_link_libraries(krunner_pass KF5::Runner Qt5::Widgets
add_dependencies(krunner_pass kcm_krunner_pass) 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 plasma-runner-pass.desktop plasma-runner-pass_config.desktop DESTINATION ${SERVICES_INSTALL_DIR})
install(FILES krunner_pass.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR}) install(FILES krunner_pass.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR})

@ -34,7 +34,8 @@ apt-get install build-essential cmake extra-cmake-modules gettext \
libkf5service-dev \ libkf5service-dev \
libkf5runner-dev \ libkf5runner-dev \
libkf5textwidgets-dev \ libkf5textwidgets-dev \
libkf5notifications-dev libkf5notifications-dev \
libkf5kcmutils-dev
mkdir -p build mkdir -p build
cd build cd build

@ -20,14 +20,15 @@
#include <KPluginFactory> #include <KPluginFactory>
#include <krunner/abstractrunner.h> #include <krunner/abstractrunner.h>
#include <QToolButton> #include <QToolButton>
#include <QtCore/QDir>
#include "kcmutils_version.h"
#include "config.h" #include "config.h"
K_PLUGIN_FACTORY(PassConfigFactory, registerPlugin<PassConfig>("kcm_krunner_pass");) K_PLUGIN_FACTORY(PassConfigFactory, registerPlugin<PassConfig>("kcm_krunner_pass");)
PassConfigForm::PassConfigForm(QWidget *parent)
: QWidget(parent)
PassConfigForm::PassConfigForm(QWidget *parent) : QWidget(parent)
{ {
setupUi(this); setupUi(this);
this->listSavedActions->setDragEnabled(true); this->listSavedActions->setDragEnabled(true);
@ -46,32 +47,36 @@ PassConfigForm::PassConfigForm(QWidget *parent) : QWidget(parent)
connect(this->buttonAddAction, &QPushButton::clicked, [this]() { connect(this->buttonAddAction, &QPushButton::clicked, [this]() {
this->addPassAction(this->lineName->text(), this->lineIcon->text(), this->lineRegEx->text()); 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, &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 &regex, bool isNew /* = true */) void
PassConfigForm::addPassAction(const QString &name, const QString &icon, const QString &regex, bool isNew /* = true */)
{ {
// Checks // Checks
for (auto act: this->passActions()) for (const auto &act: this->passActions())
if (act.name == name) if (act.name == name)
return; return;
if (name.isEmpty() || icon.isEmpty() || regex.isEmpty())
return;
// Widgets // Widgets
auto *listWidget = new QWidget(this); auto *listWidget = new QWidget(this);
auto *layoutAction = new QHBoxLayout(listWidget); auto *layoutAction = new QHBoxLayout(listWidget);
auto *buttonRemoveAction = new QToolButton(listWidget); auto *buttonRemoveAction = new QToolButton(listWidget);
buttonRemoveAction->setIcon(QIcon::fromTheme("remove")); buttonRemoveAction->setIcon(QIcon::fromTheme("delete"));
layoutAction->setMargin(0); layoutAction->setMargin(0);
layoutAction->addStretch(); layoutAction->addStretch();
layoutAction->addWidget(buttonRemoveAction); layoutAction->addWidget(buttonRemoveAction);
listWidget->setLayout(layoutAction); listWidget->setLayout(layoutAction);
// Item // Item
auto *item = new QListWidgetItem(name + (isNew ? "*":""), this->listSavedActions); auto *item = new QListWidgetItem(name + (isNew ? "*" : ""), this->listSavedActions);
item->setData(Qt::UserRole, QVariant::fromValue(PassAction {name, icon, regex})); item->setData(Qt::UserRole, QVariant::fromValue(PassAction{name, icon, regex}));
this->listSavedActions->setItemWidget(item, listWidget); this->listSavedActions->setItemWidget(item, listWidget);
this->clearInputs(); this->clearInputs();
@ -91,8 +96,8 @@ void PassConfigForm::addPassAction(const QString &name, const QString &icon, con
QVector<PassAction> PassConfigForm::passActions() QVector<PassAction> PassConfigForm::passActions()
{ {
QVector<PassAction> passActions; QVector<PassAction> passActions;
for(int i = 0; i < this->listSavedActions->count(); ++i) { for (int i = 0; i < listSavedActions->count(); ++i) {
QListWidgetItem* item = this->listSavedActions->item(i); QListWidgetItem *item = this->listSavedActions->item(i);
passActions << item->data(Qt::UserRole).value<PassAction>(); passActions << item->data(Qt::UserRole).value<PassAction>();
} }
return passActions; return passActions;
@ -100,8 +105,8 @@ QVector<PassAction> PassConfigForm::passActions()
void PassConfigForm::clearPassActions() void PassConfigForm::clearPassActions()
{ {
for(int i = 0; i < this->listSavedActions->count(); ++i) { for (int i = 0; i < listSavedActions->count(); ++i) {
QListWidgetItem* item = this->listSavedActions->item(i); QListWidgetItem *item = this->listSavedActions->item(i);
delete this->listSavedActions->itemWidget(item); delete this->listSavedActions->itemWidget(item);
} }
@ -115,21 +120,30 @@ void PassConfigForm::clearInputs()
this->lineRegEx->clear(); 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) : PassConfig::PassConfig(QWidget *parent, const QVariantList &args)
:
KCModule(parent, args) KCModule(parent, args)
{ {
this->ui = new PassConfigForm(this); this->ui = new PassConfigForm(this);
QGridLayout* layout = new QGridLayout(this); QGridLayout *layout = new QGridLayout(this);
layout->addWidget(ui, 0, 0); layout->addWidget(ui, 0, 0);
#if KCMUTILS_VERSION >= QT_VERSION_CHECK(5, 64, 0)
load(); const auto changedSlotPointer = &PassConfig::markAsChanged;
#else
connect(this->ui,SIGNAL(passActionAdded()),this,SLOT(changed())); const auto changedSlotPointer = static_cast<void (PassConfig::*)()>(&PassConfig::changed);
connect(this->ui,SIGNAL(passActionRemoved()),this,SLOT(changed())); #endif
connect(this->ui->checkAdditionalActions,SIGNAL(stateChanged(int)),this,SLOT(changed())); connect(this->ui, &PassConfigForm::passActionAdded, this, changedSlotPointer);
connect(this->ui->checkShowFileContentAction,SIGNAL(stateChanged(int)),this,SLOT(changed())); connect(this->ui, &PassConfigForm::passActionRemoved, this, changedSlotPointer);
connect(this->ui->listSavedActions,SIGNAL(itemSelectionChanged()), this, SLOT(changed())); 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() void PassConfig::load()
@ -137,9 +151,7 @@ void PassConfig::load()
KCModule::load(); KCModule::load();
KSharedConfig::Ptr cfg = KSharedConfig::openConfig(QStringLiteral("krunnerrc")); KSharedConfig::Ptr cfg = KSharedConfig::openConfig(QStringLiteral("krunnerrc"));
KConfigGroup passCfg = cfg->group("Runners"); KConfigGroup passCfg = cfg->group("Runners").group("Pass");
passCfg = KConfigGroup(&passCfg, "Pass");
bool showActions = passCfg.readEntry(Config::showActions, false); bool showActions = passCfg.readEntry(Config::showActions, false);
bool showFileContentAction = passCfg.readEntry(Config::showFileContentAction, false); bool showFileContentAction = passCfg.readEntry(Config::showFileContentAction, false);
@ -150,16 +162,12 @@ void PassConfig::load()
// Load saved actions // Load saved actions
this->ui->clearPassActions(); this->ui->clearPassActions();
auto actionGroup = passCfg.group(Config::Group::Actions); const auto actionGroup = passCfg.group(Config::Group::Actions);
auto groups = actionGroup.groupList(); for (const auto &name: actionGroup.groupList()) {
Q_FOREACH (auto name, groups) {
auto group = actionGroup.group(name); auto group = actionGroup.group(name);
auto passAction = PassAction::fromConfig(group); auto passAction = PassAction::fromConfig(group);
this->ui->addPassAction(passAction.name, passAction.icon, passAction.regex, false); this->ui->addPassAction(passAction.name, passAction.icon, passAction.regex, false);
} }
emit changed(false);
} }
void PassConfig::save() void PassConfig::save()
@ -167,28 +175,23 @@ void PassConfig::save()
KCModule::save(); KCModule::save();
KSharedConfig::Ptr cfg = KSharedConfig::openConfig(QStringLiteral("krunnerrc")); KSharedConfig::Ptr cfg = KSharedConfig::openConfig(QStringLiteral("krunnerrc"));
KConfigGroup passCfg = cfg->group("Runners"); KConfigGroup passCfg = cfg->group("Runners").group("Pass");
passCfg = KConfigGroup(&passCfg, "Pass");
auto showActions = this->ui->checkAdditionalActions->isChecked(); auto showActions = this->ui->checkAdditionalActions->isChecked();
auto showFileContentAction = this->ui->checkShowFileContentAction->isChecked(); auto showFileContentAction = this->ui->checkShowFileContentAction->isChecked();
passCfg.writeEntry(Config::showActions, showActions); passCfg.writeEntry(Config::showActions, showActions);
passCfg.writeEntry(Config::showFileContentAction, showFileContentAction); passCfg.writeEntry(Config::showFileContentAction, showFileContentAction);
passCfg.deleteGroup(Config::Group::Actions); passCfg.deleteGroup(Config::Group::Actions);
if (showActions) { if (showActions) {
int i = 0; 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++)); auto group = passCfg.group(Config::Group::Actions).group(QString::number(i++));
act.writeToConfig(group); act.writeToConfig(group);
} }
} }
emit changed(false);
} }
void PassConfig::defaults() void PassConfig::defaults()
@ -200,7 +203,11 @@ void PassConfig::defaults()
ui->clearPassActions(); ui->clearPassActions();
ui->clearInputs(); ui->clearInputs();
#if KCMUTILS_VERSION >= QT_VERSION_CHECK(5, 64, 0)
markAsChanged();
#else
emit changed(true); emit changed(true);
#endif
} }

@ -76,6 +76,9 @@ public:
signals: signals:
void passActionRemoved(); void passActionRemoved();
void passActionAdded(); void passActionAdded();
private slots:
void validateAddButton();
}; };
@ -84,12 +87,12 @@ class PassConfig : public KCModule
Q_OBJECT Q_OBJECT
public: public:
explicit PassConfig(QWidget* parent = 0, const QVariantList& args = QVariantList()); explicit PassConfig(QWidget* parent = nullptr, const QVariantList& args = QVariantList());
public Q_SLOTS: public Q_SLOTS:
void save(); void save() override;
void load(); void load() override;
void defaults(); void defaults() override;
private: private:
PassConfigForm *ui; PassConfigForm *ui;

@ -6,32 +6,37 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>314</width> <width>356</width>
<height>420</height> <height>421</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Pass Config</string> <string>Pass Config</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0"> <item row="4" column="0">
<widget class="QCheckBox" name="checkAdditionalActions"> <widget class="QGroupBox" name="boxSavedActions">
<property name="text"> <property name="enabled">
<string>Show additional actions</string> <bool>false</bool>
</property>
<property name="title">
<string>Saved Actions</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QListWidget" name="listSavedActions"/>
</item>
</layout>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="checkShowFileContentAction"> <widget class="QCheckBox" name="checkAdditionalActions">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text"> <property name="text">
<string>Show an action for displaying full file content</string> <string>Show additional actions</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="3" column="0">
<widget class="QGroupBox" name="boxNewAction"> <widget class="QGroupBox" name="boxNewAction">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
@ -93,19 +98,14 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="2" column="0">
<widget class="QGroupBox" name="boxSavedActions"> <widget class="QCheckBox" name="checkShowFileContentAction">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="title"> <property name="text">
<string>Saved Actions</string> <string>Show an action for displaying full file content</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QListWidget" name="listSavedActions"/>
</item>
</layout>
</widget> </widget>
</item> </item>
</layout> </layout>

@ -5,11 +5,11 @@ set -e
mkdir -p build mkdir -p build
cd build cd build
cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_INSTALL_PREFIX=`kf5-config --prefix` -DQT_PLUGIN_INSTALL_DIR=`kf5-config --qt-plugins` cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_INSTALL_PREFIX=`kf5-config --prefix` -DCMAKE_BUILD_TYPE=Release
make make -j$(nproc)
sudo make install sudo make install
set +e set +e
kquitapp5 krunner 2> /dev/null kquitapp5 krunner
kstart5 --windowclass krunner krunner > /dev/null 2>&1 & kstart5 --windowclass krunner krunner

@ -17,7 +17,7 @@
*****************************************************************************/ *****************************************************************************/
#include <KSharedConfig> #include <KSharedConfig>
#include <KLocalizedString> #include <KLocalizedString>
#include <knotification.h> #include <KNotification>
#include <QAction> #include <QAction>
#include <QDirIterator> #include <QDirIterator>
@ -27,8 +27,9 @@
#include <QMessageBox> #include <QMessageBox>
#include <QClipboard> #include <QClipboard>
#include <QDebug> #include <QDebug>
#include <QApplication>
#include <stdlib.h> #include <cstdlib>
#include "pass.h" #include "pass.h"
#include "config.h" #include "config.h"
@ -39,41 +40,40 @@ using namespace std;
Pass::Pass(QObject *parent, const QVariantList &args) Pass::Pass(QObject *parent, const QVariantList &args)
: Plasma::AbstractRunner(parent, args) : Plasma::AbstractRunner(parent, args)
{ {
Q_UNUSED(args);
// General runner configuration // General runner configuration
setObjectName(QString("Pass")); setObjectName(QStringLiteral("Pass"));
setSpeed(AbstractRunner::NormalSpeed); setSpeed(AbstractRunner::NormalSpeed);
setPriority(HighestPriority); 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() {} Pass::~Pass() = default;
void Pass::reloadConfiguration() void Pass::reloadConfiguration()
{ {
actions().clear(); clearActions();
orderedActions.clear(); orderedActions.clear();
KConfigGroup cfg = config(); KConfigGroup cfg = config();
cfg.config()->reparseConfiguration(); // Just to be sure
this->showActions = cfg.readEntry(Config::showActions, false); this->showActions = cfg.readEntry(Config::showActions, false);
if (showActions) { if (showActions) {
auto configActions = cfg.group(Config::Group::Actions); const auto configActions = cfg.group(Config::Group::Actions);
// Create actions for every additional field // Create actions for every additional field
auto groups = configActions.groupList(); const auto configActionsList = configActions.groupList();
Q_FOREACH (auto name, groups) { for (const auto &name: configActionsList) {
auto group = configActions.group(name); auto group = configActions.group(name);
auto passAction = PassAction::fromConfig(group); auto passAction = PassAction::fromConfig(group);
auto icon = QIcon::fromTheme(passAction.icon, QIcon::fromTheme("object-unlocked")); 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); act->setData(passAction.regex);
this->orderedActions << act; this->orderedActions << act;
} }
} else {
this->orderedActions.clear();
} }
if (cfg.readEntry(Config::showFileContentAction, false)) { if (cfg.readEntry(Config::showFileContentAction, false)) {
@ -82,6 +82,12 @@ void Pass::reloadConfiguration()
act->setData(Config::showFileContentAction); act->setData(Config::showFileContentAction);
this->orderedActions << act; 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() void Pass::init()
@ -89,42 +95,43 @@ void Pass::init()
reloadConfiguration(); reloadConfiguration();
this->baseDir = QDir(QDir::homePath() + "/.password-store"); this->baseDir = QDir(QDir::homePath() + "/.password-store");
auto baseDir = getenv("PASSWORD_STORE_DIR"); auto _baseDir = getenv("PASSWORD_STORE_DIR");
if (baseDir != nullptr) { if (_baseDir != nullptr) {
this->baseDir = QDir(baseDir); this->baseDir = QDir(_baseDir);
} }
this->timeout = 45; this->timeout = 45;
auto timeout = getenv("PASSWORD_STORE_CLIP_TIME"); auto _timeout = getenv("PASSWORD_STORE_CLIP_TIME");
if (timeout != nullptr) { if (_timeout != nullptr) {
QString str(timeout); QString str(_timeout);
bool ok; bool ok;
auto timeout = str.toInt(&ok); auto _timeoutParsed = str.toInt(&ok);
if (ok) { if (ok) {
this->timeout = timeout; this->timeout = _timeoutParsed;
} }
} }
this->passOtpIdentifier = "totp::"; this->passOtpIdentifier = "totp::";
auto passOtpIdentifier = getenv("PASSWORD_STORE_OTP_IDENTIFIER"); auto _passOtpIdentifier = getenv("PASSWORD_STORE_OTP_IDENTIFIER");
if (passOtpIdentifier != nullptr) { if (_passOtpIdentifier != nullptr) {
this->passOtpIdentifier = passOtpIdentifier; this->passOtpIdentifier = _passOtpIdentifier;
} }
initPasswords(); 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(); passwords.clear();
watcher.addPath(this->baseDir.absolutePath()); watcher.addPath(this->baseDir.absolutePath());
QDirIterator it(this->baseDir, QDirIterator::Subdirectories); QDirIterator it(this->baseDir, QDirIterator::Subdirectories);
while (it.hasNext()) { while (it.hasNext()) {
it.next(); it.next();
auto fileInfo = it.fileInfo(); 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()); QString password = this->baseDir.relativeFilePath(fileInfo.absoluteFilePath());
// Remove suffix ".gpg" // Remove suffix ".gpg"
password.chop(4); password.chop(4);
@ -135,8 +142,9 @@ void Pass::initPasswords() {
} }
} }
void Pass::reinitPasswords(const QString &path) { void Pass::reinitPasswords(const QString &path)
Q_UNUSED(path); {
Q_UNUSED(path)
lock.lockForWrite(); lock.lockForWrite();
initPasswords(); initPasswords();
@ -145,22 +153,26 @@ void Pass::reinitPasswords(const QString &path) {
void Pass::match(Plasma::RunnerContext &context) void Pass::match(Plasma::RunnerContext &context)
{ {
if (!context.isValid()) return; if (!context.isValid()) {
return;
}
auto input = context.query(); auto input = context.query();
// If we use the prefix we want to remove it
if (input.contains(queryPrefix)) {
input = input.remove(QLatin1String("pass")).simplified();
} else if (input.count() < 3 && !context.singleRunnerQueryMode()) {
return;
}
QList<Plasma::QueryMatch> matches; QList<Plasma::QueryMatch> matches;
lock.lockForRead(); lock.lockForRead();
Q_FOREACH (auto password, passwords) { for (const auto &password: qAsConst(passwords)) {
QRegularExpression re(".*" + input + ".*", QRegularExpression::CaseInsensitiveOption); if (password.contains(input, Qt::CaseInsensitive)) {
if (re.match(password).hasMatch()) {
Plasma::QueryMatch match(this); Plasma::QueryMatch match(this);
if (input.length() == password.length()) { match.setType(input.length() == password.length() ?
match.setType(Plasma::QueryMatch::ExactMatch); Plasma::QueryMatch::ExactMatch : Plasma::QueryMatch::CompletionMatch);
} else {
match.setType(Plasma::QueryMatch::CompletionMatch);
}
match.setIcon(QIcon::fromTheme("object-locked")); match.setIcon(QIcon::fromTheme("object-locked"));
match.setText(password); match.setText(password);
matches.append(match); matches.append(match);
@ -176,42 +188,37 @@ void Pass::clip(const QString &msg)
QClipboard *cb = QApplication::clipboard(); QClipboard *cb = QApplication::clipboard();
cb->setText(msg); cb->setText(msg);
QTimer::singleShot(timeout * 1000, cb, [cb]() { QTimer::singleShot(timeout * 1000, cb, [cb]() {
cb->clear(); cb->setText(QString());
}); });
} }
void Pass::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) void Pass::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match)
{ {
Q_UNUSED(context); Q_UNUSED(context);
auto regexp = QRegularExpression("^" + QRegularExpression::escape(this->passOtpIdentifier) + ".*"); const auto regexp = QRegularExpression("^" + QRegularExpression::escape(this->passOtpIdentifier) + ".*");
auto isOtp = match.text().split('/').filter(regexp).size() > 0; const auto isOtp = !match.text().split('/').filter(regexp).isEmpty();
QProcess *pass = new QProcess(); auto *pass = new QProcess();
QStringList args; QStringList args;
if (isOtp) { if (isOtp) {
args << "otp" << "show" << match.text(); args << "otp";
} else {
args << "show" << match.text();
} }
args << "show" << match.text();
pass->start("pass", args); pass->start("pass", args);
connect(pass, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), connect(pass, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
[=](int exitCode, QProcess::ExitStatus exitStatus) { [=](int exitCode, QProcess::ExitStatus exitStatus) {
Q_UNUSED(exitCode); Q_UNUSED(exitStatus)
Q_UNUSED(exitStatus);
if (exitCode == 0) { if (exitCode == 0) {
const auto output = pass->readAllStandardOutput(); const auto output = pass->readAllStandardOutput();
if (match.selectedAction() != nullptr) { if (match.selectedAction() != nullptr) {
const auto data = match.selectedAction()->data().toString(); const auto data = match.selectedAction()->data().toString();
if (data == Config::showFileContentAction) { if (data == Config::showFileContentAction) {
QMessageBox::information(nullptr, match.text(), output); QMessageBox::information(nullptr, match.text(), output);
} else { } else {
QRegularExpression re(data, QRegularExpression::MultilineOption); QRegularExpression re(data, QRegularExpression::MultilineOption);
auto matchre = re.match(output); const auto matchre = re.match(output);
if (matchre.hasMatch()) { if (matchre.hasMatch()) {
clip(matchre.captured(1)); clip(matchre.captured(1));
@ -225,9 +232,9 @@ void Pass::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &m
} }
} }
} else { } else {
auto string = QString::fromUtf8(output.data()); const auto string = QString::fromUtf8(output.data());
auto lines = string.split('\n', QString::SkipEmptyParts); const auto lines = string.split('\n', QString::SkipEmptyParts);
if (lines.count() > 0) { if (!lines.isEmpty()) {
clip(lines[0]); clip(lines[0]);
this->showNotification(match.text()); this->showNotification(match.text());
} }
@ -243,20 +250,16 @@ QList<QAction *> Pass::actionsForMatch(const Plasma::QueryMatch &match)
{ {
Q_UNUSED(match) Q_UNUSED(match)
if (showActions) return this->orderedActions;
return this->orderedActions;
return QList<QAction *>();
} }
void Pass::showNotification(const QString &text, const QString &actionName /* = "" */) void Pass::showNotification(const QString &text, const QString &actionName)
{ {
QString msgPrefix = actionName.isEmpty() ? "":actionName + i18n(" of "); const QString msgPrefix = actionName.isEmpty() ? "" : actionName + i18n(" of ");
QString msg = i18n("Password %1 copied to clipboard for %2 seconds", text, timeout); const QString msg = i18n("Password %1 copied to clipboard for %2 seconds", text, timeout);
auto notification = KNotification::event("password-unlocked", "Pass", msgPrefix + msg, KNotification::event("password-unlocked", "Pass", msgPrefix + msg,
"object-unlocked", nullptr, KNotification::CloseOnTimeout, "object-unlocked", nullptr, KNotification::CloseOnTimeout,
"krunner_pass"); "krunner_pass");
QTimer::singleShot(timeout * 1000, notification, SLOT(quit));
} }
K_EXPORT_PLASMA_RUNNER(pass, Pass) K_EXPORT_PLASMA_RUNNER(pass, Pass)

@ -23,6 +23,7 @@
#include <QDir> #include <QDir>
#include <QReadWriteLock> #include <QReadWriteLock>
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
#include <QRegularExpression>
class Pass : public Plasma::AbstractRunner class Pass : public Plasma::AbstractRunner
{ {
@ -30,7 +31,7 @@ class Pass : public Plasma::AbstractRunner
public: public:
Pass(QObject *parent, const QVariantList &args); Pass(QObject *parent, const QVariantList &args);
~Pass(); ~Pass() override;
void clip(const QString &msg); void clip(const QString &msg);
void match(Plasma::RunnerContext &) override; void match(Plasma::RunnerContext &) override;
@ -39,13 +40,13 @@ public:
void reloadConfiguration() override; void reloadConfiguration() override;
public slots: public Q_SLOTS:
void reinitPasswords(const QString &path); void reinitPasswords(const QString &path);
protected: protected:
void init() override; void init() override;
void initPasswords(); void initPasswords();
void showNotification(const QString &, const QString & = ""); void showNotification(const QString &, const QString & = QString());
private: private:
QDir baseDir; QDir baseDir;
@ -58,6 +59,7 @@ private:
bool showActions; bool showActions;
QList<QAction *> orderedActions; QList<QAction *> orderedActions;
const QRegularExpression queryPrefix = QRegularExpression("^pass( .+)?$");
}; };
#endif #endif

@ -8,7 +8,7 @@ X-KDE-Library=krunner_pass
X-KDE-PluginInfo-Author=Lukas Fürmetz X-KDE-PluginInfo-Author=Lukas Fürmetz
X-KDE-PluginInfo-Email=fuermetz@mailbox.org X-KDE-PluginInfo-Email=fuermetz@mailbox.org
X-KDE-PluginInfo-Name=Pass 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-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-AdvertiseSingleRunnerQueryMode=true X-Plasma-AdvertiseSingleRunnerQueryMode=true

@ -0,0 +1,3 @@
#!/bin/bash
killall krunner

@ -0,0 +1,9 @@
#!/bin/bash
# Exit immediately if something fails
set -e
cd build
sudo make uninstall
kquitapp5 krunner
kstart5 --windowclass krunner krunner
Loading…
Cancel
Save