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

IJHack / QtPass / 24939459383

25 Apr 2026 08:02PM UTC coverage: 26.827% (-0.8%) from 27.609%
24939459383

Pull #1170

github

web-flow
Merge db49679bc into 9048d2bb3
Pull Request #1170: feat: add Import key dialog to UsersDialog for issue #1167

0 of 96 new or added lines in 3 files covered. (0.0%)

33 existing lines in 2 files now uncovered.

1722 of 6419 relevant lines covered (26.83%)

27.62 hits per line

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

0.0
/src/importkeydialog.cpp
1
// SPDX-FileCopyrightText: 2026 Anne Jan Brouwer
2
// SPDX-License-Identifier: GPL-3.0-or-later
3
#include "importkeydialog.h"
4

5
#include "executor.h"
6
#include "qtpasssettings.h"
7
#include "ui_importkeydialog.h"
8

9
#include <QApplication>
10
#include <QClipboard>
11
#include <QFile>
12
#include <QFileDialog>
13
#include <QMessageBox>
14
#include <QPlainTextEdit>
15
#include <QRegularExpression>
16
#include <QString>
17

18
static const QRegularExpression
19
    KEY_IMPORTED_EXACT(QStringLiteral(R"(gpg: key ([0-9A-Fa-f]+): imported)"));
20
static const QRegularExpression KEY_IMPORTED_GENERAL(
21
    QStringLiteral(R"(gpg: key ([0-9A-Fa-f]+):.*imported)"));
22

NEW
23
ImportKeyDialog::ImportKeyDialog(QWidget *parent)
×
NEW
24
    : QDialog(parent), ui(new Ui::ImportKeyDialog) {
×
NEW
25
  ui->setupUi(this);
×
26

NEW
27
  ui->inputTextEdit->setPlaceholderText(
×
NEW
28
      tr("Paste an ASCII-armored GPG key here..."));
×
29

NEW
30
  ui->importButton->setEnabled(false);
×
NEW
31
}
×
32

NEW
33
ImportKeyDialog::~ImportKeyDialog() = default;
×
34

NEW
35
QString ImportKeyDialog::importedKeyFingerprint() const {
×
NEW
36
  return m_importedKeyId;
×
37
}
38

NEW
39
void ImportKeyDialog::on_fileButton_clicked() {
×
40
  const QString fileName = QFileDialog::getOpenFileName(
NEW
41
      this, tr("Import GPG Key"), QString(),
×
NEW
42
      tr("GPG Key Files") + " (*.asc *.key);;" + tr("All Files") + " (*)");
×
43

NEW
44
  if (fileName.isEmpty()) {
×
45
    return;
46
  }
47

NEW
48
  QFile file(fileName);
×
NEW
49
  if (!file.open(QIODevice::ReadOnly)) {
×
NEW
50
    QMessageBox::warning(this, tr("Import Key"),
×
NEW
51
                         tr("Could not open file: %1").arg(fileName));
×
52
    return;
53
  }
54

NEW
55
  QByteArray bytes = file.readAll();
×
NEW
56
  file.close();
×
57

NEW
58
  ui->inputTextEdit->setPlainText(QString::fromUtf8(bytes));
×
NEW
59
}
×
60

NEW
61
void ImportKeyDialog::on_pasteButton_clicked() {
×
NEW
62
  QClipboard *clipboard = QApplication::clipboard();
×
NEW
63
  const QString text = clipboard->text();
×
64

NEW
65
  ui->inputTextEdit->setPlainText(text);
×
NEW
66
}
×
67

NEW
68
void ImportKeyDialog::on_importButton_clicked() {
×
NEW
69
  const QString input = ui->inputTextEdit->toPlainText().trimmed();
×
NEW
70
  if (input.isEmpty()) {
×
71
    return;
72
  }
73

NEW
74
  if (importFromString(input)) {
×
NEW
75
    accept();
×
76
  }
77
}
78

NEW
79
void ImportKeyDialog::on_inputTextEdit_textChanged() {
×
NEW
80
  const bool hasInput = !ui->inputTextEdit->toPlainText().trimmed().isEmpty();
×
NEW
81
  ui->importButton->setEnabled(hasInput);
×
NEW
82
}
×
83

NEW
84
bool ImportKeyDialog::importFromString(const QString &input) {
×
NEW
85
  QString gpgExe = QtPassSettings::getGpgExecutable();
×
NEW
86
  if (gpgExe.isEmpty()) {
×
NEW
87
    gpgExe = "gpg";
×
88
  }
NEW
89
  QStringList args = {"--status-fd", "1", "--import", "--batch", "--yes"};
×
90

NEW
91
  QString stdOut;
×
NEW
92
  QString stdErr;
×
93

NEW
94
  int result = Executor::executeBlocking(gpgExe, args, input, &stdOut, &stdErr);
×
95

NEW
96
  if (result != 0) {
×
NEW
97
    showError(tr("GPG import failed:\n%1").arg(stdErr));
×
NEW
98
    return false;
×
99
  }
100

NEW
101
  QString keyId = parseGpgImportOutput(stdOut);
×
NEW
102
  if (keyId.isEmpty()) {
×
NEW
103
    keyId = parseGpgImportOutput(stdErr);
×
104
  }
105

NEW
106
  if (keyId.isEmpty()) {
×
NEW
107
    showError(tr("Could not parse imported key id from GPG output."));
×
NEW
108
    return false;
×
109
  }
110

NEW
111
  m_importedKeyId = keyId;
×
NEW
112
  showSuccess(keyId);
×
113
  return true;
NEW
114
}
×
115

NEW
116
QString ImportKeyDialog::parseGpgImportOutput(const QString &output) {
×
NEW
117
  const QStringList lines = output.split('\n', Qt::SkipEmptyParts);
×
NEW
118
  for (const QString &line : lines) {
×
NEW
119
    QRegularExpressionMatch match = KEY_IMPORTED_EXACT.match(line);
×
NEW
120
    if (match.hasMatch()) {
×
NEW
121
      return match.captured(1);
×
122
    }
NEW
123
    match = KEY_IMPORTED_GENERAL.match(line);
×
NEW
124
    if (match.hasMatch()) {
×
NEW
125
      return match.captured(1);
×
126
    }
NEW
127
  }
×
128
  return QString();
129
}
130

NEW
131
void ImportKeyDialog::showError(const QString &message) {
×
NEW
132
  QMessageBox::warning(this, tr("Import Key"), message);
×
NEW
133
}
×
134

NEW
135
void ImportKeyDialog::showSuccess(const QString &keyId) {
×
NEW
136
  QMessageBox::information(this, tr("Import Key"),
×
NEW
137
                           tr("Successfully imported key: %1").arg(keyId));
×
NEW
138
}
×
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