QtPass  1.3.3
Multi-platform GUI for pass, the standard unix password manager.
pass.cpp
Go to the documentation of this file.
1 #include "pass.h"
2 #include "qtpasssettings.h"
3 #include "util.h"
4 
5 #ifdef QT_DEBUG
6 #include "debughelper.h"
7 #endif
8 
9 using namespace std;
10 using namespace Enums;
11 
15 Pass::Pass() : wrapperRunning(false), env(QProcess::systemEnvironment()) {
16  connect(&exec,
17  static_cast<void (Executor::*)(int, int, const QString &,
18  const QString &)>(&Executor::finished),
19  this, &Pass::finished);
20 
21  // TODO(bezet): stop using process
22  // connect(&process, SIGNAL(error(QProcess::ProcessError)), this,
23  // SIGNAL(error(QProcess::ProcessError)));
24 
26  env.append("WSLENV=PASSWORD_STORE_DIR/p");
27 }
28 
29 void Pass::executeWrapper(PROCESS id, const QString &app,
30  const QStringList &args, bool readStdout,
31  bool readStderr) {
32  executeWrapper(id, app, args, QString(), readStdout, readStderr);
33 }
34 
35 void Pass::executeWrapper(PROCESS id, const QString &app,
36  const QStringList &args, QString input,
37  bool readStdout, bool readStderr) {
38 #ifdef QT_DEBUG
39  dbg() << app << args;
40 #endif
41  exec.execute(id, QtPassSettings::getPassStore(), app, args, input, readStdout,
42  readStderr);
43 }
44 
45 void Pass::init() {
46 #ifdef __APPLE__
47  // If it exists, add the gpgtools to PATH
48  if (QFile("/usr/local/MacGPG2/bin").exists())
49  env.replaceInStrings("PATH=", "PATH=/usr/local/MacGPG2/bin:");
50  // Add missing /usr/local/bin
51  if (env.filter("/usr/local/bin").isEmpty())
52  env.replaceInStrings("PATH=", "PATH=/usr/local/bin:");
53 #endif
54 
55  if (!QtPassSettings::getGpgHome().isEmpty()) {
56  QDir absHome(QtPassSettings::getGpgHome());
57  absHome.makeAbsolute();
58  env << "GNUPGHOME=" + absHome.path();
59  }
60 }
61 
69 QString Pass::Generate_b(unsigned int length, const QString &charset) {
70  QString passwd;
72  // --secure goes first as it overrides --no-* otherwise
73  QStringList args;
74  args.append("-1");
76  args.append("--secure");
77  args.append(QtPassSettings::isAvoidCapitals() ? "--no-capitalize"
78  : "--capitalize");
79  args.append(QtPassSettings::isAvoidNumbers() ? "--no-numerals"
80  : "--numerals");
82  args.append("--symbols");
83  args.append(QString::number(length));
84  QString p_out;
85  // TODO(bezet): try-catch here(2 statuses to merge o_O)
87  &passwd) == 0)
88  passwd.remove(QRegExp("[\\n\\r]"));
89  else {
90  passwd.clear();
91 #ifdef QT_DEBUG
92  qDebug() << __FILE__ << ":" << __LINE__ << "\t"
93  << "pwgen fail";
94 #endif
95  // TODO(bezet): emit critical ?
96  }
97  } else {
98  if (charset.length() > 0) {
99  passwd = generateRandomPassword(charset, length);
100  } else {
101  emit critical(
102  tr("No characters chosen"),
103  tr("Can't generate password, there are no characters to choose from "
104  "set in the configuration!"));
105  }
106  }
107  return passwd;
108 }
109 
114 void Pass::GenerateGPGKeys(QString batch) {
116  {"--gen-key", "--no-tty", "--batch"}, batch);
117  // TODO check status / error messages - probably not here, it's just started
118  // here, see finished for details
119  // https://github.com/IJHack/QtPass/issues/202#issuecomment-251081688
120 }
121 
128 QList<UserInfo> Pass::listKeys(QStringList keystrings, bool secret) {
129  QList<UserInfo> users;
130  QStringList args = {"--no-tty", "--with-colons", "--with-fingerprint"};
131  args.append(secret ? "--list-secret-keys" : "--list-keys");
132 
133  foreach (QString keystring, keystrings) {
134  if (!keystring.isEmpty()) {
135  args.append(keystring);
136  }
137  }
138  QString p_out;
140  0)
141  return users;
142  QStringList keys = p_out.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);
143  UserInfo current_user;
144  foreach (QString key, keys) {
145  QStringList props = key.split(':');
146  if (props.size() < 10)
147  continue;
148  if (props[0] == (secret ? "sec" : "pub")) {
149  if (!current_user.key_id.isEmpty())
150  users.append(current_user);
151  current_user = UserInfo();
152  current_user.key_id = props[4];
153  current_user.name = props[9].toUtf8();
154  current_user.validity = props[1][0].toLatin1();
155  current_user.created.setTime_t(props[5].toUInt());
156  current_user.expiry.setTime_t(props[6].toUInt());
157  } else if (current_user.name.isEmpty() && props[0] == "uid") {
158  current_user.name = props[9];
159  } else if ((props[0] == "fpr") && props[9].endsWith(current_user.key_id)) {
160  current_user.key_id = props[9];
161  }
162  }
163  if (!current_user.key_id.isEmpty())
164  users.append(current_user);
165  return users;
166 }
167 
174 QList<UserInfo> Pass::listKeys(QString keystring, bool secret) {
175  return listKeys(QStringList(keystring), secret);
176 }
177 
188 void Pass::finished(int id, int exitCode, const QString &out,
189  const QString &err) {
190  auto pid = static_cast<PROCESS>(id);
191  if (exitCode != 0) {
192  emit processErrorExit(exitCode, err);
193  return;
194  }
195  switch (pid) {
196  case GIT_INIT:
197  emit finishedGitInit(out, err);
198  break;
199  case GIT_PULL:
200  emit finishedGitPull(out, err);
201  break;
202  case GIT_PUSH:
203  emit finishedGitPush(out, err);
204  break;
205  case PASS_SHOW:
206  emit finishedShow(out);
207  break;
208  case PASS_OTP_GENERATE:
209  emit finishedOtpGenerate(out);
210  break;
211  case PASS_INSERT:
212  emit finishedInsert(out, err);
213  break;
214  case PASS_REMOVE:
215  emit finishedRemove(out, err);
216  break;
217  case PASS_INIT:
218  emit finishedInit(out, err);
219  break;
220  case PASS_MOVE:
221  emit finishedMove(out, err);
222  break;
223  case PASS_COPY:
224  emit finishedCopy(out, err);
225  break;
226  default:
227 #ifdef QT_DEBUG
228  dbg() << "Unhandled process type" << pid;
229 #endif
230  break;
231  }
232 }
233 
239  QStringList store = env.filter("PASSWORD_STORE_DIR=");
240  // put PASSWORD_STORE_DIR in env
241  if (store.isEmpty()) {
242  // dbg()<< "Added
243  // PASSWORD_STORE_DIR";
244  env.append("PASSWORD_STORE_DIR=" + QtPassSettings::getPassStore());
245  } else {
246  // dbg()<< "Update
247  // PASSWORD_STORE_DIR with " + passStore;
248  env.replaceInStrings(store.first(), "PASSWORD_STORE_DIR=" +
250  }
251  exec.setEnvironment(env);
252 }
253 
259 QStringList Pass::getRecipientList(QString for_file) {
260  QDir gpgIdPath(QFileInfo(for_file.startsWith(QtPassSettings::getPassStore())
261  ? for_file
262  : QtPassSettings::getPassStore() + for_file)
263  .absoluteDir());
264  bool found = false;
265  while (gpgIdPath.exists() &&
266  gpgIdPath.absolutePath().startsWith(QtPassSettings::getPassStore())) {
267  if (QFile(gpgIdPath.absoluteFilePath(".gpg-id")).exists()) {
268  found = true;
269  break;
270  }
271  if (!gpgIdPath.cdUp())
272  break;
273  }
274  QFile gpgId(found ? gpgIdPath.absoluteFilePath(".gpg-id")
275  : QtPassSettings::getPassStore() + ".gpg-id");
276  if (!gpgId.open(QIODevice::ReadOnly | QIODevice::Text))
277  return QStringList();
278  QStringList recipients;
279  while (!gpgId.atEnd()) {
280  QString recipient(gpgId.readLine());
281  recipient = recipient.trimmed();
282  if (!recipient.isEmpty())
283  recipients += recipient;
284  }
285  return recipients;
286 }
287 
295 QStringList Pass::getRecipientString(QString for_file, QString separator,
296  int *count) {
297  Q_UNUSED(separator)
298  Q_UNUSED(count)
299  return Pass::getRecipientList(for_file);
300 }
301 
302 /* Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
303  */
304 
305 quint32 Pass::boundedRandom(quint32 bound) {
306  if (bound < 2) {
307  return 0;
308  }
309 
310  quint32 randval;
311  const quint32 max_mod_bound = (1 + ~bound) % bound;
312 
313 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
314  static int fd = -1;
315  if (fd == -1) {
316  assert((fd = open("/dev/urandom", O_RDONLY)) >= 0);
317  }
318 #endif
319 
320  do {
321 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
322  assert(read(fd, &randval, sizeof(randval)) == sizeof(randval));
323 #else
324  randval = QRandomGenerator::system()->generate();
325 #endif
326  } while (randval < max_mod_bound);
327 
328  return randval % bound;
329 }
330 
331 QString Pass::generateRandomPassword(const QString &charset,
332  unsigned int length) {
333  QString out;
334  for (unsigned int i = 0; i < length; ++i) {
335  out.append(charset.at(static_cast<int>(
336  boundedRandom(static_cast<quint32>(charset.length())))));
337  }
338  return out;
339 }
UserInfo::expiry
QDateTime expiry
UserInfo::expiry date/time key expires.
Definition: userinfo.h:54
Pass::processErrorExit
void processErrorExit(int exitCode, const QString &err)
UserInfo::created
QDateTime created
UserInfo::created date/time key was created.
Definition: userinfo.h:58
QtPassSettings::isLessRandom
static bool isLessRandom(const bool &defaultValue=QVariant().toBool())
Definition: qtpasssettings.cpp:445
Enums::GPG_GENKEYS
@ GPG_GENKEYS
Definition: enums.h:27
QtPassSettings::getPwgenExecutable
static QString getPwgenExecutable(const QString &defaultValue=QVariant().toString())
Definition: qtpasssettings.cpp:323
Enums::PASS_OTP_GENERATE
@ PASS_OTP_GENERATE
Definition: enums.h:34
Enums::GIT_PULL
@ GIT_PULL
Definition: enums.h:21
Pass::finishedGitPush
void finishedGitPush(const QString &, const QString &)
Executor
Executes external commands for handleing password, git and other data.
Definition: executor.h:12
Enums::PASS_COPY
@ PASS_COPY
Definition: enums.h:29
Pass::GenerateGPGKeys
void GenerateGPGKeys(QString batch)
Pass::GenerateGPGKeys internal gpg keypair generator . .
Definition: pass.cpp:114
Pass::listKeys
QList< UserInfo > listKeys(QStringList keystrings, bool secret=false)
Pass::listKeys list users.
Definition: pass.cpp:128
Pass::finishedInsert
void finishedInsert(const QString &, const QString &)
UserInfo::key_id
QString key_id
UserInfo::key_id hexadecimal representation.
Definition: userinfo.h:36
QtPassSettings::getGpgExecutable
static QString getGpgExecutable(const QString &defaultValue=QVariant().toString())
Definition: qtpasssettings.cpp:314
Executor::execute
void execute(int id, const QString &app, const QStringList &args, bool readStdout, bool readStderr=true)
Executor::execute execute an app.
Definition: executor.cpp:63
UserInfo::validity
char validity
UserInfo::validity GnuPG representation of validity http://git.gnupg.org/cgi-bin/gitweb....
Definition: userinfo.h:41
Executor::executeBlocking
static int executeBlocking(QString app, const QStringList &args, QString input=QString(), QString *process_out=Q_NULLPTR, QString *process_err=Q_NULLPTR)
Executor::executeBlocking blocking version of the executor, takes input and presents it as stdin.
Definition: executor.cpp:160
QtPassSettings::isUsePwgen
static bool isUsePwgen(const bool &defaultValue=QVariant().toBool())
Definition: qtpasssettings.cpp:418
Pass::Pass
Pass()
Pass::Pass wrapper for using either pass or the pass imitation.
Definition: pass.cpp:15
debughelper.h
Pass::critical
void critical(QString, QString)
Enums::PASS_INIT
@ PASS_INIT
Definition: enums.h:26
Enums::PASS_SHOW
@ PASS_SHOW
Definition: enums.h:23
Pass::finished
virtual void finished(int id, int exitCode, const QString &out, const QString &err)
Pass::processFinished reemits specific signal based on what process has finished.
Definition: pass.cpp:188
Pass::generateRandomPassword
QString generateRandomPassword(const QString &charset, unsigned int length)
Definition: pass.cpp:331
Executor::setEnvironment
void setEnvironment(const QStringList &env)
Executor::setEnvironment set environment variables for executor processes.
Definition: executor.cpp:212
Pass::finishedRemove
void finishedRemove(const QString &, const QString &)
Pass::finishedGitPull
void finishedGitPull(const QString &, const QString &)
Pass::getRecipientList
static QStringList getRecipientList(QString for_file)
Pass::getRecipientList return list of gpg-id's to encrypt for.
Definition: pass.cpp:259
Enums::PROCESS
PROCESS
Definition: enums.h:16
QtPassSettings::getGpgHome
static QString getGpgHome(const QString &defaultValue=QVariant().toString())
Definition: qtpasssettings.cpp:332
Pass::exec
Executor exec
Definition: pass.h:32
Pass::updateEnv
void updateEnv()
Pass::updateEnv update the execution environment (used when switching profiles)
Definition: pass.cpp:238
Pass::getRecipientString
static QStringList getRecipientString(QString for_file, QString separator=" ", int *count=NULL)
Pass::getRecipientString formated string for use with GPG.
Definition: pass.cpp:295
Enums
Enumerators for configuration and runtime items.
QtPassSettings::isAvoidCapitals
static bool isAvoidCapitals(const bool &defaultValue=QVariant().toBool())
Definition: qtpasssettings.cpp:427
Enums::PASS_MOVE
@ PASS_MOVE
Definition: enums.h:28
Pass::finishedGitInit
void finishedGitInit(const QString &, const QString &)
QtPassSettings::isAvoidNumbers
static bool isAvoidNumbers(const bool &defaultValue=QVariant().toBool())
Definition: qtpasssettings.cpp:436
Pass::Generate_b
virtual QString Generate_b(unsigned int length, const QString &charset)
Pass::Generate use either pwgen or internal password generator.
Definition: pass.cpp:69
Pass::init
void init()
Definition: pass.cpp:45
Enums::GIT_INIT
@ GIT_INIT
Definition: enums.h:17
UserInfo::name
QString name
UserInfo::name full name.
Definition: userinfo.h:32
Pass::executeWrapper
void executeWrapper(PROCESS id, const QString &app, const QStringList &args, bool readStdout=true, bool readStderr=true)
Definition: pass.cpp:29
QtPassSettings::isUseSymbols
static bool isUseSymbols(const bool &defaultValue=QVariant().toBool())
Definition: qtpasssettings.cpp:454
Pass::finishedInit
void finishedInit(const QString &, const QString &)
Pass::startingExecuteWrapper
void startingExecuteWrapper()
Enums::GIT_PUSH
@ GIT_PUSH
Definition: enums.h:22
Pass::finishedOtpGenerate
void finishedOtpGenerate(const QString &)
dbg
#define dbg()
Definition: debughelper.h:7
Pass::finishedMove
void finishedMove(const QString &, const QString &)
UserInfo
Stores key info lines including validity, creation date and more.
Definition: userinfo.h:11
Executor::starting
void starting()
starting signal that is emited when process starts
Pass::boundedRandom
quint32 boundedRandom(quint32 bound)
Definition: pass.cpp:305
Enums::PASS_INSERT
@ PASS_INSERT
Definition: enums.h:24
Pass::finishedCopy
void finishedCopy(const QString &, const QString &)
QtPassSettings::getPassStore
static QString getPassStore(const QString &defaultValue=QVariant().toString())
Definition: qtpasssettings.cpp:254
Pass::finishedShow
void finishedShow(const QString &)
util.h
qtpasssettings.h
Enums::PASS_REMOVE
@ PASS_REMOVE
Definition: enums.h:25
pass.h