passwordprovider.cpp (4002B)
1 /* 2 * Copyright (C) 2018 Daniel Vrátil <dvratil@kde.org> 3 * 2021 Willy Goiffon <contact@z3bra.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU Library General Public License as 7 * published by the Free Software Foundation; either version 2, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details 14 * 15 * You should have received a copy of the GNU Library General Public 16 * License along with this program; if not, write to the 17 * Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 */ 20 21 #include "passwordprovider.h" 22 #include "settings.h" 23 #include "safe.h" 24 25 #include <QClipboard> 26 #include <QGuiApplication> 27 #include <QDir> 28 #include <QDebug> 29 30 namespace { 31 32 static const auto PasswordTimeoutUpdateInterval = 100; 33 34 35 #define SAFE_DIR "SAFE_DIR" 36 #define SAFE_SOCK "SAFE_SOCK" 37 38 } 39 40 PasswordProvider::PasswordProvider(const QString &path, QObject *parent) 41 : QObject(parent) 42 , mPath(path) 43 {} 44 45 46 PasswordProvider::~PasswordProvider() 47 {} 48 49 bool PasswordProvider::isValid() const 50 { 51 return !mPassword.isNull(); 52 } 53 54 QString PasswordProvider::password() const 55 { 56 return mPassword; 57 } 58 59 void PasswordProvider::setPassword(const QString &password) 60 { 61 qGuiApp->clipboard()->setText(password, QClipboard::Clipboard); 62 63 if (qGuiApp->clipboard()->supportsSelection()) { 64 qGuiApp->clipboard()->setText(password, QClipboard::Selection); 65 } 66 67 mPassword = password; 68 Q_EMIT validChanged(); 69 Q_EMIT passwordChanged(); 70 71 mTimeout = defaultTimeout(); 72 Q_EMIT timeoutChanged(); 73 mTimer.start(); 74 } 75 76 void PasswordProvider::expirePassword() 77 { 78 removePasswordFromClipboard(mPassword); 79 80 mPassword.clear(); 81 mTimer.stop(); 82 Q_EMIT validChanged(); 83 Q_EMIT passwordChanged(); 84 85 // Delete the provider, it's no longer needed 86 deleteLater(); 87 } 88 89 void PasswordProvider::requestPassword() 90 { 91 setError({}); 92 mPassword.clear(); 93 mTimer.stop(); 94 Q_EMIT validChanged(); 95 Q_EMIT passwordChanged(); 96 97 auto *job = Safe::decrypt(mPath); 98 connect(job, &Safe::DecryptTask::finished, 99 this, [this, job]() { 100 if (job->error()) { 101 qWarning() << "Failed to unlock safe: " << job->errorString(); 102 setError(job->errorString()); 103 return; 104 } 105 // .split() always return one argument, so it's used here to remove 106 // trailing \n if any, or keep the whole content otherwise 107 const QStringList lines = job->content().split(QLatin1Char('\n')); 108 setPassword(lines[0]); 109 qDebug() << "requestPassword() got: " << lines[0]; 110 }); 111 112 mTimer.setInterval(PasswordTimeoutUpdateInterval); 113 connect(&mTimer, &QTimer::timeout, 114 this, [this]() { 115 mTimeout -= mTimer.interval(); 116 Q_EMIT timeoutChanged(); 117 if (mTimeout == 0) { 118 expirePassword(); 119 } 120 }); 121 } 122 123 int PasswordProvider::timeout() const 124 { 125 return mTimeout; 126 } 127 128 int PasswordProvider::defaultTimeout() const 129 { 130 return Settings::self()->expirationTimeout() * 1000; 131 } 132 133 QString PasswordProvider::error() const 134 { 135 return mError; 136 } 137 138 bool PasswordProvider::hasError() const 139 { 140 return !mError.isNull(); 141 } 142 143 void PasswordProvider::setError(const QString &error) 144 { 145 mError = error; 146 Q_EMIT errorChanged(); 147 } 148 149 void PasswordProvider::cancel() 150 { 151 setError(tr("Cancelled by user.")); 152 } 153 154 void PasswordProvider::removePasswordFromClipboard(const QString &password) 155 { 156 // Clear the WS clipboard itself 157 const auto clipboard = qGuiApp->clipboard(); 158 if (clipboard->text() == password) { 159 clipboard->clear(); 160 } 161 }