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

IJHack / QtPass / 23666274895

27 Mar 2026 08:32PM UTC coverage: 18.552% (+0.2%) from 18.391%
23666274895

push

github

web-flow
feat: use ed25519 for GPG key generation when available (#790)

* feat: use ed25519 for GPG key generation when available

Fixes #406

- Add gpgSupportsEd25519() to check if GPG 2.1+ is available
- Use --default-new-key-algo ed25519 when supported for faster key generation
- Add unit test for ed25519 support check

* feat: add Generate GPG key button to Config dialog

- Add 'Generate' button next to GPG path in Config dialog
- Opens KeygenDialog directly for easy key generation

Related to #406

* chore: update translation source references

10 of 19 new or added lines in 3 files covered. (52.63%)

167 existing lines in 6 files now uncovered.

930 of 5013 relevant lines covered (18.55%)

7.51 hits per line

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

0.0
/src/keygendialog.cpp
1
// SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
2
// SPDX-License-Identifier: GPL-3.0-or-later
3
#include "keygendialog.h"
4
#include "configdialog.h"
5
#include "pass.h"
6
#include "qprogressindicator.h"
7
#include "qtpasssettings.h"
8
#include "ui_keygendialog.h"
9
#include "util.h"
10
#include <QMessageBox>
11
#include <QRegularExpression>
12

13
#ifdef QT_DEBUG
14
#include "debughelper.h"
15
#endif
16

17
/**
18
 * @brief KeygenDialog::KeygenDialog basic constructor.
19
 * @param parent
20
 */
21
KeygenDialog::KeygenDialog(ConfigDialog *parent)
×
22
    : QDialog(parent), ui(new Ui::KeygenDialog) {
×
23
  ui->setupUi(this);
×
24
  dialog = parent;
×
NEW
25
  ui->plainTextEdit->setPlainText(Pass::getDefaultKeyTemplate());
×
UNCOV
26
}
×
27

28
/**
29
 * @brief KeygenDialog::~KeygenDialog even more basic destructor.
30
 */
31
KeygenDialog::~KeygenDialog() { delete ui; }
×
32

33
/**
34
 * @brief KeygenDialog::on_passphrase1_textChanged see if we want to have
35
 * protection.
36
 * @param arg1
37
 */
38
void KeygenDialog::on_passphrase1_textChanged(const QString &arg1) {
×
39
  bool state = ui->passphrase1->text() == ui->passphrase2->text();
×
40
  if (state) {
×
41
    replace("Passphrase", arg1);
×
42
    no_protection(arg1.isEmpty());
×
43
  }
44

45
  ui->buttonBox->setEnabled(state);
×
46
}
×
47

48
/**
49
 * @brief KeygenDialog::on_passphrase2_textChanged wrapper for
50
 * KeygenDialog::on_passphrase1_textChanged
51
 * @param arg1
52
 */
53
void KeygenDialog::on_passphrase2_textChanged(const QString &arg1) {
×
54
  on_passphrase1_textChanged(arg1);
×
55
}
×
56

57
/**
58
 * @brief KeygenDialog::on_checkBox_stateChanged expert mode enabled / disabled.
59
 * @param arg1
60
 */
61
void KeygenDialog::on_checkBox_stateChanged(int arg1) {
×
62
  ui->plainTextEdit->setReadOnly(!arg1);
×
63
  ui->plainTextEdit->setEnabled(arg1);
×
64
}
×
65

66
/**
67
 * @brief KeygenDialog::on_email_textChanged update the email in keypair
68
 * generation template.
69
 * @param arg1
70
 */
71
void KeygenDialog::on_email_textChanged(const QString &arg1) {
×
72
  replace("Name-Email", arg1);
×
73
}
×
74

75
/**
76
 * @brief KeygenDialog::on_name_textChanged update the name in keypair
77
 * generation template.
78
 * @param arg1
79
 */
80
void KeygenDialog::on_name_textChanged(const QString &arg1) {
×
81
  replace("Name-Real", arg1);
×
82
}
×
83

84
/**
85
 * @brief KeygenDialog::replace do some regex magic. fore replacing Passphrase
86
 * and protection in keypair generation template.
87
 * @param key
88
 * @param value
89
 */
90
void KeygenDialog::replace(const QString &key, const QString &value) {
×
91
  QStringList clear;
×
92
  QString expert = ui->plainTextEdit->toPlainText();
×
93
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
94
  const QStringList lines =
95
      expert.split(Util::newLinesRegex(), Qt::SkipEmptyParts);
×
96
#else
97
  const QStringList lines =
98
      expert.split(Util::newLinesRegex(), QString::SkipEmptyParts);
99
#endif
100
  for (QString line : lines) {
×
101
    line.replace(QRegularExpression(key + ":.*"), key + ": " + value);
×
102
    if (key == "Passphrase") {
×
103
      line.replace("%no-protection", "Passphrase: " + value);
×
104
    }
105
    clear.append(line);
106
  }
107
  ui->plainTextEdit->setPlainText(clear.join("\n"));
×
108
}
×
109

110
/**
111
 * @brief KeygenDialog::no_protection remove protection in keypair generation
112
 * template.
113
 * @param enable
114
 */
115
void KeygenDialog::no_protection(bool enable) {
×
116
  QStringList clear;
×
117
  QString expert = ui->plainTextEdit->toPlainText();
×
118
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
119
  const QStringList lines =
120
      expert.split(Util::newLinesRegex(), Qt::SkipEmptyParts);
×
121
#else
122
  const QStringList lines =
123
      expert.split(Util::newLinesRegex(), QString::SkipEmptyParts);
124
#endif
125
  for (QString line : lines) {
×
126
    bool remove = false;
127
    if (!enable) {
×
128
      if (line.indexOf("%no-protection") == 0) {
×
129
        remove = true;
130
      }
131
    } else {
132
      if (line.indexOf("Passphrase") == 0) {
×
133
        line = "%no-protection";
×
134
      }
135
    }
136
    if (!remove) {
137
      clear.append(line);
138
    }
139
  }
140
  ui->plainTextEdit->setPlainText(clear.join("\n"));
×
141
}
×
142

143
/**
144
 * @brief KeygenDialog::done we are going to create a key pair and show the
145
 * QProgressIndicator and some text since the generation will take some time.
146
 * @param r
147
 */
148
void KeygenDialog::done(int r) {
×
149
  if (QDialog::Accepted == r) { //  ok was pressed
×
150
                                // check name
151
    if (ui->name->text().length() < 5) {
×
152
      QMessageBox::critical(this, tr("Invalid name"),
×
153
                            tr("Name must be at least 5 characters long."));
×
154
      return;
×
155
    }
156

157
    // check email
158
    static const QRegularExpression mailre(
159
        QRegularExpression::anchoredPattern(
×
160
            R"(\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b)"),
161
        QRegularExpression::CaseInsensitiveOption);
×
162
    if (!mailre.match(ui->email->text()).hasMatch()) {
×
163
      QMessageBox::critical(
×
164
          this, tr("Invalid email"),
×
165
          tr("The email address you typed is not a valid email address."));
×
166
      return;
×
167
    }
168

169
    ui->widget->setEnabled(false);
×
170
    ui->buttonBox->setEnabled(false);
×
171
    ui->checkBox->setEnabled(false);
×
172
    ui->plainTextEdit->setEnabled(false);
×
173

174
    auto *pi = new QProgressIndicator();
×
175
    pi->startAnimation();
×
176
    pi->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
×
177

178
    ui->frame->hide();
×
179
    ui->label->setText(
×
180
        tr("This operation can take some minutes.<br />"
×
181
           "We need to generate a lot of random bytes. It is a good idea to "
182
           "perform some other action (type on the keyboard, move the mouse, "
183
           "utilize the disks) during the prime generation; this gives the "
184
           "random number generator a better chance to gain enough entropy."));
185

186
    this->layout()->addWidget(pi);
×
187

188
    this->show();
×
189
    dialog->genKey(ui->plainTextEdit->toPlainText(), this);
×
190
  } else { //  cancel, close or exc was pressed
191
    QDialog::done(r);
×
192
    return;
×
193
  }
194
}
195

196
/**
197
 * @brief KeygenDialog::closeEvent we are done here.
198
 * @param event
199
 */
200
void KeygenDialog::closeEvent(QCloseEvent *event) {
×
201
  // TODO(annejan): save window size or somethign
202
  event->accept();
203
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc