• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IJHack / QtPass / 25828061834

13 May 2026 09:41PM UTC coverage: 29.068% (-0.02%) from 29.083%
25828061834

Pull #1471

github

web-flow
Merge 1648a4147 into 7c5b11394
Pull Request #1471: test(integration): grep skips files that gpg can't decrypt

1956 of 6729 relevant lines covered (29.07%)

27.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

47.1
/src/passworddialog.cpp
1
// SPDX-FileCopyrightText: 2015 Anne Jan Brouwer
2
// SPDX-License-Identifier: GPL-3.0-or-later
3
#include "passworddialog.h"
4
#include "filecontent.h"
5
#include "pass.h"
6
#include "passwordconfiguration.h"
7
#include "qtpasssettings.h"
8
#include "ui_passworddialog.h"
9
#include "util.h"
10
#include <algorithm>
11

12
#include <QHash>
13
#include <QLabel>
14
#include <QLineEdit>
15
#include <QShortcut>
16
#include <utility>
17

18
#ifdef QT_DEBUG
19
#include "debughelper.h"
20
#endif
21

22
/**
23
 * @brief PasswordDialog::PasswordDialog basic constructor.
24
 * @param passConfig configuration constant
25
 * @param parent
26
 */
27
PasswordDialog::PasswordDialog(PasswordConfiguration passConfig,
8✔
28
                               QWidget *parent)
8✔
29
    : QDialog(parent), ui(new Ui::PasswordDialog),
16✔
30
      m_passConfig(std::move(passConfig)) {
8✔
31
  m_templating = false;
32
  m_isNew = false;
33

34
  ui->setupUi(this);
8✔
35
  setLength(m_passConfig.length);
8✔
36
  setPasswordCharTemplate(m_passConfig.selected);
8✔
37

38
  connect(QtPassSettings::getPass(), &Pass::finishedShow, this,
8✔
39
          &PasswordDialog::setPass);
8✔
40
}
8✔
41

42
/**
43
 * @brief PasswordDialog::PasswordDialog complete constructor.
44
 * @param file
45
 * @param isNew
46
 * @param parent pointer
47
 */
48
PasswordDialog::PasswordDialog(QString file, const bool &isNew, QWidget *parent)
×
49
    : QDialog(parent), ui(new Ui::PasswordDialog), m_file(std::move(file)),
×
50
      m_isNew(isNew) {
×
51

52
  if (!isNew) {
×
53
    QtPassSettings::getPass()->Show(m_file);
×
54
  }
55

56
  ui->setupUi(this);
×
57

58
  setWindowTitle(this->windowTitle() + " " + m_file);
×
59
  m_passConfig = QtPassSettings::getPasswordConfiguration();
×
60
  usePwgen(QtPassSettings::isUsePwgen());
×
61
  setTemplate(QtPassSettings::getPassTemplate(),
×
62
              QtPassSettings::isUseTemplate());
×
63

64
  setLength(m_passConfig.length);
×
65
  setPasswordCharTemplate(m_passConfig.selected);
×
66

67
  connect(QtPassSettings::getPass(), &Pass::finishedShow, this,
×
68
          &PasswordDialog::setPass);
×
69
  connect(QtPassSettings::getPass(), &Pass::processErrorExit, this,
×
70
          &PasswordDialog::close);
×
71
  connect(this, &PasswordDialog::accepted, this, &PasswordDialog::on_accepted);
×
72
  connect(this, &PasswordDialog::rejected, this, &PasswordDialog::on_rejected);
×
73
}
×
74

75
/**
76
 * @brief PasswordDialog::~PasswordDialog basic destructor.
77
 */
78
PasswordDialog::~PasswordDialog() { delete ui; }
32✔
79

80
/**
81
 * @brief PasswordDialog::on_checkBoxShow_stateChanged hide or show passwords.
82
 * @param arg1
83
 */
84
void PasswordDialog::on_checkBoxShow_stateChanged(int arg1) {
×
85
  if (arg1) {
×
86
    ui->lineEditPassword->setEchoMode(QLineEdit::Normal);
×
87
  } else {
88
    ui->lineEditPassword->setEchoMode(QLineEdit::Password);
×
89
  }
90
}
×
91

92
/**
93
 * @brief PasswordDialog::on_createPasswordButton_clicked generate a random
94
 * password.
95
 */
96
void PasswordDialog::on_createPasswordButton_clicked() {
×
97
  ui->widget->setEnabled(false);
×
98
  const int currentIndex = ui->passwordTemplateSwitch->currentIndex();
×
99
  if (currentIndex < 0 ||
×
100
      currentIndex >= static_cast<int>(PasswordConfiguration::CHARSETS_COUNT)) {
101
    ui->widget->setEnabled(true);
×
102
    return;
×
103
  }
104

105
  QString newPass = QtPassSettings::getPass()->generatePassword(
×
106
      static_cast<unsigned int>(ui->spinBox_pwdLength->value()),
×
107
      m_passConfig.Characters[static_cast<PasswordConfiguration::characterSet>(
108
          currentIndex)]);
×
109
  if (!newPass.isEmpty()) {
×
110
    ui->lineEditPassword->setText(newPass);
×
111
  }
112
  ui->widget->setEnabled(true);
×
113
}
114

115
/**
116
 * @brief PasswordDialog::on_accepted handle Ok click for QDialog
117
 */
118
void PasswordDialog::on_accepted() {
×
119
  QString newValue = getPassword();
×
120
  if (newValue.isEmpty()) {
×
121
    return;
122
  }
123

124
  if (newValue.right(1) != "\n") {
×
125
    newValue += "\n";
×
126
  }
127

128
  QtPassSettings::getPass()->Insert(m_file, newValue, !m_isNew);
×
129
}
130

131
/**
132
 * @brief PasswordDialog::on_rejected handle Cancel click for QDialog
133
 */
134
void PasswordDialog::on_rejected() { setPassword(QString()); }
×
135

136
/**
137
 * @brief PasswordDialog::setPassword populate the (templated) fields.
138
 * @param password
139
 */
140
void PasswordDialog::setPassword(const QString &password) {
8✔
141
  // Always parse all fields as editable so users can edit any field in the
142
  // password file. This fixes issue #132 where users couldn't edit
143
  // fields without toggling the "Show all fields templated" setting.
144
  FileContent fileContent = FileContent::parse(password, m_fields, true);
8✔
145
  ui->lineEditPassword->setText(fileContent.getPassword());
8✔
146

147
  QWidget *previous = ui->checkBoxShow;
8✔
148
  // first set templated values
149
  NamedValues namedValues = fileContent.getNamedValues();
8✔
150
  for (QLineEdit *line : std::as_const(m_templateLines)) {
9✔
151
    line->setText(namedValues.takeValue(line->objectName()));
2✔
152
    previous = line;
153
  }
154
  // show remaining values (if there are)
155
  // Remove previously created dynamic widgets to prevent duplicates and leaks
156
  for (QLineEdit *line : std::as_const(m_otherLines)) {
8✔
157
    ui->formLayout->removeRow(line);
×
158
  }
159
  m_otherLines.clear();
8✔
160
  for (const NamedValue &nv : std::as_const(namedValues)) {
11✔
161
    auto *line = new QLineEdit();
3✔
162
    line->setObjectName(nv.name);
3✔
163
    line->setText(nv.value);
3✔
164
    ui->formLayout->addRow(new QLabel(nv.name), line);
3✔
165
    setTabOrder(previous, line);
3✔
166
    m_otherLines.append(line);
3✔
167
    previous = line;
168
  }
169

170
  ui->plainTextEdit->insertPlainText(fileContent.getRemainingData());
16✔
171
}
8✔
172

173
/**
174
 * @brief PasswordDialog::getPassword  join the (templated) fields to a QString
175
 * for writing back.
176
 * @return collapsed password.
177
 */
178
auto PasswordDialog::getPassword() -> QString {
8✔
179
  QString passFile = ui->lineEditPassword->text() + "\n";
16✔
180
  QList<QLineEdit *> allLines(m_templateLines);
181
  allLines.append(m_otherLines);
8✔
182
  for (QLineEdit *line : std::as_const(allLines)) {
12✔
183
    QString text = line->text();
4✔
184
    if (text.isEmpty()) {
4✔
185
      continue;
186
    }
187
    passFile += line->objectName() + ": " + text + "\n";
8✔
188
  }
189
  passFile += ui->plainTextEdit->toPlainText();
16✔
190
  return passFile;
8✔
191
}
192

193
/**
194
 * @brief PasswordDialog::setTemplate set the template and create the fields.
195
 * @param rawFields
196
 */
197
void PasswordDialog::setTemplate(const QString &rawFields, bool useTemplate) {
7✔
198
  m_fields = rawFields.split('\n');
7✔
199
  m_templating = useTemplate;
7✔
200

201
  for (QLineEdit *line : std::as_const(m_templateLines)) {
7✔
202
    ui->formLayout->removeRow(line);
×
203
  }
204
  m_templateLines.clear();
7✔
205

206
  // Defensively remove all rows tracked in m_otherLines to prevent accumulation
207
  // when cycling templates or applying new templates after setPassword
208
  for (QLineEdit *line : std::as_const(m_otherLines)) {
7✔
209
    ui->formLayout->removeRow(line);
×
210
  }
211
  m_otherLines.clear();
7✔
212

213
  if (m_templating) {
7✔
214
    QWidget *previous = ui->checkBoxShow;
1✔
215
    for (const QString &field : std::as_const(m_fields)) {
2✔
216
      if (field.isEmpty()) {
1✔
217
        continue;
×
218
      }
219
      auto *line = new QLineEdit();
1✔
220
      auto *label = new QLabel(field);
1✔
221
      line->setObjectName(field);
1✔
222
      ui->formLayout->addRow(label, line);
1✔
223
      setTabOrder(previous, line);
1✔
224
      m_templateLines.append(line);
1✔
225
      previous = line;
226
    }
227
  }
228
}
7✔
229

230
/**
231
 * @brief PasswordDialog::setLength
232
 * PasswordDialog::setLength password length.
233
 * @param length
234
 */
235
void PasswordDialog::setLength(int length) {
8✔
236
  ui->spinBox_pwdLength->setValue(length);
8✔
237
}
8✔
238

239
/**
240
 * @brief PasswordDialog::setPasswordCharTemplate
241
 * PasswordDialog::setPasswordCharTemplate chose the template style.
242
 * @param templateIndex
243
 */
244
void PasswordDialog::setPasswordCharTemplate(int templateIndex) {
8✔
245
  ui->passwordTemplateSwitch->setCurrentIndex(templateIndex);
8✔
246
}
8✔
247

248
/**
249
 * @brief PasswordDialog::usePwgen
250
 * PasswordDialog::usePwgen don't use own password generator.
251
 * @param usePwgen
252
 */
253
void PasswordDialog::usePwgen(bool usePwgen) {
×
254
  ui->passwordTemplateSwitch->setDisabled(usePwgen);
×
255
  ui->label_characterset->setDisabled(usePwgen);
×
256
}
×
257

258
/**
259
 * @brief Set available templates from .templates file and apply default.
260
 * @param templates Hash of template name to field list.
261
 * @param defaultTemplate Name of default template to select.
262
 */
263
void PasswordDialog::setAvailableTemplates(
×
264
    const QHash<QString, QStringList> &templates,
265
    const QString &defaultTemplate) {
266
  m_availableTemplates = templates;
×
267
  QStringList templateNames = templates.keys();
×
268
  if (templateNames.isEmpty()) {
×
269
    return;
270
  }
271
  std::sort(templateNames.begin(), templateNames.end());
×
272
  QString selected = defaultTemplate;
273
  if (!templateNames.contains(selected)) {
×
274
    selected = templateNames.first();
×
275
  }
276
  applyTemplate(selected);
×
277
}
278

279
/**
280
 * @brief Apply a template by name.
281
 * @param templateName Name of template to apply.
282
 */
283
void PasswordDialog::applyTemplate(const QString &templateName) {
×
284
  auto it = m_availableTemplates.constFind(templateName);
×
285
  if (it != m_availableTemplates.constEnd()) {
286
    m_currentTemplateName = templateName;
×
287
    QString fields = it.value().join("\n");
×
288
    setTemplate(fields, true);
×
289
  }
290
}
×
291

292
/**
293
 * @brief Cycle to next template (Ctrl+T).
294
 */
295
void PasswordDialog::cycleTemplate() {
×
296
  if (m_availableTemplates.isEmpty()) {
297
    return;
×
298
  }
299
  QStringList names = m_availableTemplates.keys();
×
300
  std::sort(names.begin(), names.end());
×
301

302
  qsizetype currentIdx = names.indexOf(m_currentTemplateName);
303
  qsizetype nextIdx;
304
  if (currentIdx < 0) {
×
305
    nextIdx = 0;
306
  } else {
307
    nextIdx = (currentIdx + 1) % names.size();
×
308
  }
309
  applyTemplate(names.at(nextIdx));
×
310
}
311

312
/**
313
 * @brief Sets the password from pass show output.
314
 * @param output Output from pass show command
315
 */
316
void PasswordDialog::setPass(const QString &output) {
8✔
317
  setPassword(output);
8✔
318
  // UI is enabled by default when password is set - no additional action needed
319
}
8✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc