12#include "qprogressindicator.h"
14#include "ui_keygendialog.h"
19#include <QRegularExpression>
28 connect(
ui->checkBox, &QCheckBox::toggled,
this,
30 connect(
ui->noPassphrase, &QCheckBox::toggled,
this,
40 ui->plainTextEdit->setVisible(
ui->checkBox->isChecked());
54 const QString passphrase =
ui->passphrase1->text();
55 const bool agreed = passphrase ==
ui->passphrase2->text();
56 return agreed && (!passphrase.isEmpty() ||
ui->noPassphrase->isChecked());
65 ui->passphrase1->clear();
66 ui->passphrase2->clear();
68 ui->passphrase1->setEnabled(!checked);
69 ui->passphrase2->setEnabled(!checked);
78 ui->plainTextEdit->setReadOnly(!checked);
79 ui->plainTextEdit->setEnabled(checked);
80 ui->plainTextEdit->setVisible(checked);
99 QString expert =
ui->plainTextEdit->toPlainText();
100 const QStringList lines =
102 for (QString line : lines) {
103 line.replace(QRegularExpression(key +
":.*"), key +
": " + value);
106 ui->plainTextEdit->setPlainText(clear.join(
"\n"));
120 const QString trimmed = line.trimmed();
121 if (!trimmed.startsWith(control, Qt::CaseInsensitive))
123 return trimmed.size() == control.size() ||
124 trimmed.at(control.size()).isSpace();
131 const QString &passphrase) {
132 static const QString noProtection = QStringLiteral(
"%no-protection");
133 static const QString commit = QStringLiteral(
"%commit");
134 static const QString passphraseKey = QStringLiteral(
"Passphrase:");
135 const QString protection =
136 passphrase.isEmpty() ? noProtection : passphraseKey +
" " + passphrase;
139 bool spliced =
false;
140 const QStringList lines =
142 for (QString line : lines) {
146 if (
const qsizetype nul = line.indexOf(QChar::Null); nul >= 0) {
150 line.trimmed().startsWith(passphraseKey, Qt::CaseInsensitive)) {
152 clear.append(protection);
160 if (!spliced && !passphrase.isEmpty()) {
162 const auto commitLine =
163 std::find_if(clear.cbegin(), clear.cend(), [](
const QString &line) {
164 return isControlStatement(line, commit);
166 clear.insert(commitLine - clear.cbegin(), protection);
168 return clear.join(
"\n");
172 return !value.contains(QLatin1Char(
'\n')) &&
173 !value.contains(QLatin1Char(
'\r')) && !value.contains(QChar::Null);
177 if (QDialog::Accepted == r) {
190 QMessageBox::critical(
this, tr(
"Invalid input"),
191 tr(
"The name and the passphrase cannot contain "
195 if (
ui->name->text().length() < 5) {
196 QMessageBox::critical(
this, tr(
"Invalid name"),
197 tr(
"Name must be at least 5 characters long."));
201 static const QRegularExpression mailre(
202 QRegularExpression::anchoredPattern(
203 R
"(\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b)"),
204 QRegularExpression::CaseInsensitiveOption);
205 if (!mailre.match(
ui->email->text()).hasMatch()) {
206 QMessageBox::critical(
207 this, tr(
"Invalid email"),
208 tr(
"The email address you typed is not a valid email address."));
212 ui->widget->setEnabled(
false);
213 ui->buttonBox->setEnabled(
false);
214 ui->checkBox->setEnabled(
false);
215 ui->plainTextEdit->setEnabled(
false);
221 QSizePolicy::Expanding);
230 tr(
"This operation can take some minutes.<br />"
231 "We need to generate a lot of random bytes. It is a good idea to "
232 "perform some other action (type on the keyboard, move the mouse, "
233 "utilize the disks) during the prime generation; this gives the "
234 "random number generator a better chance to gain enough entropy."));
238 ui->passphrase1->text()));
255 [
this](
const QString &,
const QString &) {
258 QDialog::done(QDialog::Accepted);
264 [
this](
const QString &error) {
278 ui->widget->setEnabled(
true);
279 ui->checkBox->setEnabled(
true);
280 ui->plainTextEdit->setEnabled(
true);
285 tr(
"Key generation failed: %1").arg(error.toHtmlEscaped()));
static QString applyPassphrase(const QString &batch, const QString &passphrase)
Splice a passphrase into a GPG batch template.
void replace(const QString &key, const QString &value)
Rewrites every <key>: ... line of the batch template to carry value. Values that fail isBatchValue() ...
std::unique_ptr< QProgressIndicator > m_progressIndicator
Spinner shown while gpg works; created lazily on the first attempt, reused (hidden) across retries.
KeygenDialog(const QString &gpgExe, Pass *pass, QWidget *parent=nullptr)
Construct a KeygenDialog.
void setExpertMode(bool checked)
Enable or disable expert mode (the editable batch template).
void setNoPassphrase(bool checked)
Ticking "no passphrase" clears and disables the passphrase fields and makes OK available; unticking i...
void on_passphrase1_textChanged(const QString &arg1)
First passphrase field edited: re-evaluates whether OK may be enabled. The text itself stays out of t...
void generationFailed(const QString &error)
Stops and hides the progress indicator, re-enables the form under the usual OK rule and shows error i...
void done(int r) override
On Accepted, validates the form (passphrase chosen, no line breaks, name of 5+ characters,...
QMetaObject::Connection m_failed
Connection to Pass::generateGPGKeysFailed, live only during an attempt.
void startGeneration(const QString &batch)
Connects to the backend's finished/failed signals for this one attempt and calls Pass::GenerateGPGKey...
void on_email_textChanged(const QString &arg1)
Mirrors the e-mail field into the template's Name-Email: line.
QScopedPointer< Ui::KeygenDialog > ui
Generated form (keygendialog.ui); owned.
~KeygenDialog() override
Destroys the dialog and its generated UI.
void updateOkState()
OK is available when a passphrase is typed twice the same, or when no passphrase was asked for explic...
Pass * m_pass
Backend that runs gpg; not owned, may be nullptr.
void on_name_textChanged(const QString &arg1)
Mirrors the name field into the template's Name-Real: line.
QMetaObject::Connection m_finished
Connection to Pass::finishedGenerateGPGKeys, live only during an attempt.
auto passphraseChosen() const -> bool
Whether the passphrase question has an answer: typed twice the same, or waived with the checkbox....
void on_passphrase2_textChanged(const QString &arg1)
Confirmation field edited: same as on_passphrase1_textChanged().
static auto isBatchValue(const QString &value) -> bool
Whether value can go into a GPG batch line as one value.
Abstract base class for password store operations.
void GenerateGPGKeys(QString batch)
Generate GPG keys using batch script.
static QString getDefaultKeyTemplate(const QString &gpgExecutable={})
Get default key template for new GPG keys.
void finishedGenerateGPGKeys(const QString &out, const QString &err)
GenerateGPGKeys() succeeded; the new key pair is in the keyring.
void generateGPGKeysFailed(const QString &err)
Emitted when GPG key generation fails, alongside the generic processErrorExit(); lets the keygen dial...
static auto newLinesRegex() -> const QRegularExpression &
Returns a regex to match newline characters.
Settings dialog: every page of the configuration window and the profile table, with the validation th...
static bool isControlStatement(const QString &line, const QString &control)
Whether a batch line is the control statement control.
Dialog that collects name, e-mail and passphrase for a new GPG keypair and drives gpg --gen-key --bat...
void attach(QDialog &dialog, const QString &key)
restore() now, save() whenever the dialog finishes.
Pass, the abstract password-store backend that RealPass and ImitatePass implement,...
The "qtpass" logging category.
QtPassSettings, the QSettings singleton behind every saved setting, the profiles and the Pass backend...
Util: static helpers for the process environment, binary discovery, store paths, URL safety and the l...
WindowStateStore: saves and restores top-level window geometry through QtPassSettings,...