QtPass  1.2.0-pre
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 "debughelper.h"
3 #include "qtpasssettings.h"
4 #include "util.h"
5 #include <QTextCodec>
6 #include <map>
7 
8 using namespace std;
9 using namespace Enums;
10 
14 Pass::Pass() : wrapperRunning(false), env(QProcess::systemEnvironment()) {
15  connect(&exec,
16  static_cast<void (Executor::*)(int, int, const QString &,
17  const QString &)>(&Executor::finished),
18  this, &Pass::finished);
19 
20  // TODO(bezet): stop using process
21  // connect(&process, SIGNAL(error(QProcess::ProcessError)), this,
22  // SIGNAL(error(QProcess::ProcessError)));
23 
25 }
26 
27 void Pass::executeWrapper(PROCESS id, const QString &app,
28  const QStringList &args, bool readStdout,
29  bool readStderr) {
30  executeWrapper(id, app, args, QString(), readStdout, readStderr);
31 }
32 
33 void Pass::executeWrapper(PROCESS id, const QString &app,
34  const QStringList &args, QString input,
35  bool readStdout, bool readStderr) {
36  dbg() << app << args;
37  exec.execute(id, QtPassSettings::getPassStore(), app, args, input, readStdout,
38  readStderr);
39 }
40 
41 void Pass::init() {
42 #ifdef __APPLE__
43  // If it exists, add the gpgtools to PATH
44  if (QFile("/usr/local/MacGPG2/bin").exists())
45  env.replaceInStrings("PATH=", "PATH=/usr/local/MacGPG2/bin:");
46  // Add missing /usr/local/bin
47  if (env.filter("/usr/local/bin").isEmpty())
48  env.replaceInStrings("PATH=", "PATH=/usr/local/bin:");
49 #endif
50 
51  if (!QtPassSettings::getGpgHome().isEmpty()) {
52  QDir absHome(QtPassSettings::getGpgHome());
53  absHome.makeAbsolute();
54  env << "GNUPGHOME=" + absHome.path();
55  }
56 }
57 
65 QString Pass::Generate_b(int length, const QString &charset) {
66  QString passwd;
68  // --secure goes first as it overrides --no-* otherwise
69  QStringList args;
70  args.append("-1");
72  args.append("--secure");
73  args.append(QtPassSettings::isAvoidCapitals() ? "--no-capitalize"
74  : "--capitalize");
75  args.append(QtPassSettings::isAvoidNumbers() ? "--no-numerals"
76  : "--numerals");
78  args.append("--symbols");
79  args.append(QString::number(length));
80  QString p_out;
81  // TODO(bezet): try-catch here(2 statuses to merge o_O)
83  &passwd) == 0)
84  passwd.remove(QRegExp("[\\n\\r]"));
85  else {
86  passwd.clear();
87  qDebug() << __FILE__ << ":" << __LINE__ << "\t"
88  << "pwgen fail";
89  // TODO(bezet): emit critical ?
90  }
91  } else {
92  if (charset.length() > 0) {
93  for (int i = 0; i < length; ++i) {
94  int index = Util::rand() % charset.length();
95  QChar nextChar = charset.at(index);
96  passwd.append(nextChar);
97  }
98  } else {
99  emit critical(
100  tr("No characters chosen"),
101  tr("Can't generate password, there are no characters to choose from "
102  "set in the configuration!"));
103  }
104  }
105  return passwd;
106 }
107 
112 void Pass::GenerateGPGKeys(QString batch) {
114  {"--gen-key", "--no-tty", "--batch"}, batch);
115  // TODO check status / error messages - probably not here, it's just started
116  // here, see finished for details
117  // https://github.com/IJHack/QtPass/issues/202#issuecomment-251081688
118 }
119 
126 QList<UserInfo> Pass::listKeys(QString keystring, bool secret) {
127  QList<UserInfo> users;
128  QStringList args = {"--no-tty", "--with-colons"};
129  args.append(secret ? "--list-secret-keys" : "--list-keys");
130  if (!keystring.isEmpty())
131  args.append(keystring);
132  QString p_out;
134  0)
135  return users;
136  QStringList keys = p_out.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);
137  UserInfo current_user;
138  foreach (QString key, keys) {
139  QStringList props = key.split(':');
140  if (props.size() < 10)
141  continue;
142  if (props[0] == (secret ? "sec" : "pub")) {
143  if (!current_user.key_id.isEmpty())
144  users.append(current_user);
145  current_user = UserInfo();
146  current_user.key_id = props[4];
147  current_user.name = props[9].toUtf8();
148  current_user.validity = props[1][0].toLatin1();
149  current_user.created.setTime_t(props[5].toUInt());
150  current_user.expiry.setTime_t(props[6].toUInt());
151  } else if (current_user.name.isEmpty() && props[0] == "uid") {
152  current_user.name = props[9];
153  }
154  }
155  if (!current_user.key_id.isEmpty())
156  users.append(current_user);
157  return users;
158 }
159 
170 void Pass::finished(int id, int exitCode, const QString &out,
171  const QString &err) {
172  // TODO(bezet): remove !
173  dbg() << id << exitCode << out << err;
174 
175  PROCESS pid = static_cast<PROCESS>(id);
176  if (exitCode != 0) {
177  emit processErrorExit(exitCode, err);
178  return;
179  }
180  switch (pid) {
181  case GIT_INIT:
182  emit finishedGitInit(out, err);
183  break;
184  case GIT_PULL:
185  emit finishedGitPull(out, err);
186  break;
187  case GIT_PUSH:
188  emit finishedGitPush(out, err);
189  break;
190  case PASS_SHOW:
191  emit finishedShow(out);
192  break;
193  case PASS_INSERT:
194  emit finishedInsert(out, err);
195  break;
196  case PASS_REMOVE:
197  emit finishedRemove(out, err);
198  break;
199  case PASS_INIT:
200  emit finishedInit(out, err);
201  break;
202  case PASS_MOVE:
203  emit finishedMove(out, err);
204  break;
205  case PASS_COPY:
206  emit finishedCopy(out, err);
207  break;
208  default:
209  dbg() << "Unhandled process type" << pid;
210  break;
211  }
212 }
213 
219  QStringList store = env.filter("PASSWORD_STORE_DIR");
220  // put PASSWORD_STORE_DIR in env
221  if (store.isEmpty()) {
222  // dbg()<< "Added
223  // PASSWORD_STORE_DIR";
224  env.append("PASSWORD_STORE_DIR=" + QtPassSettings::getPassStore());
225  } else {
226  // dbg()<< "Update
227  // PASSWORD_STORE_DIR with " + passStore;
228  env.replaceInStrings(
229  store.first(), "PASSWORD_STORE_DIR=" + QtPassSettings::getPassStore());
230  }
231  exec.setEnvironment(env);
232 }
233 
239 QStringList Pass::getRecipientList(QString for_file) {
240  QDir gpgIdPath(QFileInfo(for_file.startsWith(QtPassSettings::getPassStore())
241  ? for_file
242  : QtPassSettings::getPassStore() + for_file)
243  .absoluteDir());
244  bool found = false;
245  while (gpgIdPath.exists() &&
246  gpgIdPath.absolutePath().startsWith(QtPassSettings::getPassStore())) {
247  if (QFile(gpgIdPath.absoluteFilePath(".gpg-id")).exists()) {
248  found = true;
249  break;
250  }
251  if (!gpgIdPath.cdUp())
252  break;
253  }
254  QFile gpgId(found ? gpgIdPath.absoluteFilePath(".gpg-id")
255  : QtPassSettings::getPassStore() + ".gpg-id");
256  if (!gpgId.open(QIODevice::ReadOnly | QIODevice::Text))
257  return QStringList();
258  QStringList recipients;
259  while (!gpgId.atEnd()) {
260  QString recipient(gpgId.readLine());
261  recipient = recipient.trimmed();
262  if (!recipient.isEmpty())
263  recipients += recipient;
264  }
265  return recipients;
266 }
267 
275 QString Pass::getRecipientString(QString for_file, QString separator,
276  int *count) {
277  QString recipients_str;
278  QStringList recipients_list = Pass::getRecipientList(for_file);
279  if (count)
280  *count = recipients_list.size();
281  foreach (const QString recipient, recipients_list)
282  recipients_str += separator + '"' + recipient + '"';
283  return recipients_str;
284 }
void finishedMove(const QString &, const QString &)
void finishedCopy(const QString &, const QString &)
QDateTime expiry
UserInfo::expiry date/time key expires.
Definition: datahelpers.h:89
static bool isLessRandom(const bool &defaultValue=QVariant().toBool())
QDateTime created
UserInfo::created date/time key was created.
Definition: datahelpers.h:93
void GenerateGPGKeys(QString batch)
Pass::GenerateGPGKeys internal gpg keypair generator . .
Definition: pass.cpp:112
PROCESS
Definition: enums.h:16
static QString getGpgHome(const QString &defaultValue=QVariant().toString())
void finishedGitPush(const QString &, const QString &)
#define dbg()
Definition: debughelper.h:7
QList< UserInfo > listKeys(QString keystring="", bool secret=false)
Pass::listKeys list users.
Definition: pass.cpp:126
void setEnvironment(const QStringList &env)
Executor::setEnvironment set environment variables for executor processes.
Definition: executor.cpp:171
QString key_id
UserInfo::key_id hexadecimal representation.
Definition: datahelpers.h:71
void finishedInsert(const QString &, const QString &)
Executes external commands for handleing password, git and other data.
Definition: executor.h:12
static bool isAvoidNumbers(const bool &defaultValue=QVariant().toBool())
char validity
UserInfo::validity GnuPG representation of validity http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob_plain;f=doc/DETAILS.
Definition: datahelpers.h:76
Pass()
Pass::Pass wrapper for using either pass or the pass imitation.
Definition: pass.cpp:14
void finishedRemove(const QString &, const QString &)
Executor exec
Definition: pass.h:25
void execute(int id, const QString &app, const QStringList &args, bool readStdout, bool readStderr=true)
Executor::execute execute an app.
Definition: executor.cpp:50
static QString getPassStore(const QString &defaultValue=QVariant().toString())
Enumerators for configuration and runtime items.
void finishedGitPull(const QString &, const QString &)
void critical(QString, QString)
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:170
virtual QString Generate_b(int length, const QString &charset)
Pass::Generate use either pwgen or internal password generator.
Definition: pass.cpp:65
static QString getRecipientString(QString for_file, QString separator=" ", int *count=NULL)
Pass::getRecipientString formated string for use with GPG.
Definition: pass.cpp:275
static int rand()
Definition: util.cpp:181
void init()
Definition: pass.cpp:41
static QStringList getRecipientList(QString for_file)
Pass::getRecipientList return list of gpg-id&#39;s to encrypt for.
Definition: pass.cpp:239
static bool isAvoidCapitals(const bool &defaultValue=QVariant().toBool())
void starting()
starting signal that is emited when process starts
void finishedInit(const QString &, const QString &)
static bool isUsePwgen(const bool &defaultValue=QVariant().toBool())
static QString getPwgenExecutable(const QString &defaultValue=QVariant().toString())
static bool isUseSymbols(const bool &defaultValue=QVariant().toBool())
void executeWrapper(PROCESS id, const QString &app, const QStringList &args, bool readStdout=true, bool readStderr=true)
Definition: pass.cpp:27
void updateEnv()
Pass::updateEnv update the execution environment (used when switching profiles)
Definition: pass.cpp:218
QString name
UserInfo::name full name.
Definition: datahelpers.h:67
Stores key info lines including validity, creation date and more.
Definition: datahelpers.h:46
static QString getGpgExecutable(const QString &defaultValue=QVariant().toString())
void finishedShow(const QString &)
void finishedGitInit(const QString &, const QString &)
void startingExecuteWrapper()
void processErrorExit(int exitCode, const QString &err)
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:124