You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
5.1 KiB
147 lines
5.1 KiB
/****************************************************************************** |
|
* Copyright (C) 2016 by Dominik Schreiber <dev@dominikschreiber.de> * |
|
* * |
|
* This library is free software; you can redistribute it and/or modify * |
|
* it under the terms of the GNU General Public License as published * |
|
* by the Free Software Foundation; either version 3 of the License or (at * |
|
* your option) any later version. * |
|
* * |
|
* This library is distributed in the hope that it will be useful, * |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of * |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * |
|
* Library General Public License for more details. * |
|
* * |
|
* You should have received a copy of the GNU General Public License * |
|
* along with this library; see the file LICENSE. * |
|
* If not, see <http://www.gnu.org/licenses/>. * |
|
*****************************************************************************/ |
|
#include <KLocalizedString> |
|
#include <knotification.h> |
|
|
|
#include <QDirIterator> |
|
#include <QProcess> |
|
#include <QRegularExpression> |
|
|
|
#include <stdlib.h> |
|
|
|
#include "pass.h" |
|
|
|
using namespace std; |
|
|
|
Pass::Pass(QObject *parent, const QVariantList &args) |
|
: Plasma::AbstractRunner(parent, args) |
|
{ |
|
Q_UNUSED(args); |
|
|
|
// General runner configuration |
|
setObjectName(QString("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() {} |
|
|
|
void Pass::init() { |
|
this->baseDir = QDir(QDir::homePath() + "/.password-store"); |
|
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); |
|
bool ok; |
|
auto timeout = str.toInt(&ok); |
|
if (ok) { |
|
this->timeout = timeout; |
|
} |
|
} |
|
|
|
initPasswords(); |
|
|
|
connect(&watcher, SIGNAL(directoryChanged(QString)), this, SLOT(reinitPasswords(QString))); |
|
} |
|
|
|
void Pass::initPasswords() { |
|
passwords.clear(); |
|
|
|
watcher.addPath(this->baseDir.absolutePath()); |
|
QDirIterator it(this->baseDir, QDirIterator::Subdirectories); |
|
while (it.hasNext()) { |
|
it.next(); |
|
auto fileInfo = it.fileInfo(); |
|
if (fileInfo.isFile() && fileInfo.suffix() == "gpg") { |
|
QString password = this->baseDir.relativeFilePath(fileInfo.absoluteFilePath()); |
|
// Remove suffix ".gpg" |
|
password.chop(4); |
|
passwords.append(password); |
|
} else if (fileInfo.isDir() && it.fileName() != "." && it.fileName() != "..") { |
|
watcher.addPath(it.filePath()); |
|
} |
|
} |
|
} |
|
|
|
void Pass::reinitPasswords(const QString &path) { |
|
Q_UNUSED(path); |
|
|
|
lock.lockForWrite(); |
|
initPasswords(); |
|
lock.unlock(); |
|
} |
|
|
|
void Pass::match(Plasma::RunnerContext &context) |
|
{ |
|
if (!context.isValid()) return; |
|
|
|
auto input = context.query(); |
|
|
|
QList<Plasma::QueryMatch> matches; |
|
|
|
lock.lockForRead(); |
|
Q_FOREACH (auto password, passwords) { |
|
QRegularExpression re(".*" + input + ".*", QRegularExpression::CaseInsensitiveOption); |
|
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.setIcon(QIcon::fromTheme("object-locked")); |
|
match.setText(password); |
|
matches.append(match); |
|
} |
|
} |
|
lock.unlock(); |
|
|
|
context.addMatches(matches); |
|
} |
|
|
|
void Pass::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) |
|
{ |
|
Q_UNUSED(context); |
|
|
|
this->passOtpIdentifier = "totp::"; |
|
auto passOtpIdentifier = getenv("PASSWORD_STORE_OTP_IDENTIFIER"); |
|
if (passOtpIdentifier != nullptr) { |
|
this->passOtpIdentifier = passOtpIdentifier; |
|
} |
|
|
|
auto ret = match.text().contains(this->passOtpIdentifier, Qt::CaseInsensitive) ? |
|
QProcess::execute(QString("pass otp -c ") + match.text()) : |
|
QProcess::execute(QString("pass -c ") + match.text()); |
|
if (ret == 0) { |
|
QString msg = i18n("Password %1 copied to clipboard for %2 seconds", match.text(), timeout); |
|
KNotification::event("password-unlocked", "Pass", msg, |
|
"object-unlocked", nullptr, KNotification::CloseOnTimeout, |
|
"krunner_pass"); |
|
} |
|
} |
|
|
|
K_EXPORT_PLASMA_RUNNER(pass, Pass) |
|
|
|
#include "pass.moc"
|
|
|