Line data Source code
1 : // SPDX-FileCopyrightText: 2026 Anne Jan Brouwer
2 : // SPDX-License-Identifier: GPL-3.0-or-later
3 : /**
4 : * @file
5 : * @brief Implements ExportPublicKeyDialog: key-id sanitising for the suggested
6 : * file name, the clipboard copy with its "Copied!" flash and the QSaveFile
7 : * write.
8 : */
9 : #include "exportpublickeydialog.h"
10 : #include "ui_exportpublickeydialog.h"
11 :
12 : #include <QApplication>
13 : #include <QClipboard>
14 : #include <QFileDialog>
15 : #include <QFontDatabase>
16 : #include <QMessageBox>
17 : #include <QRegularExpression>
18 : #include <QSaveFile>
19 : #include <QTextStream>
20 : #include <QTimer>
21 :
22 7 : ExportPublicKeyDialog::ExportPublicKeyDialog(const QString &keyId,
23 : const QString &armoredKey,
24 7 : QWidget *parent)
25 7 : : QDialog(parent), ui(new Ui::ExportPublicKeyDialog), m_keyId(keyId) {
26 7 : ui->setupUi(this);
27 14 : ui->keyIdLabel->setText(tr("Public key for %1").arg(keyId));
28 7 : ui->plainTextEdit->setFont(
29 14 : QFontDatabase::systemFont(QFontDatabase::FixedFont));
30 7 : ui->plainTextEdit->setPlainText(armoredKey);
31 7 : m_copyButtonOriginalText = ui->copyButton->text();
32 7 : }
33 :
34 14 : ExportPublicKeyDialog::~ExportPublicKeyDialog() = default;
35 :
36 13 : auto ExportPublicKeyDialog::sanitizeKeyIdForFilename(const QString &keyId)
37 : -> QString {
38 15 : static const QRegularExpression whitespace(QStringLiteral("\\s+"));
39 15 : static const QRegularExpression unsafeChars(QStringLiteral("[^A-Za-z0-9_-]"));
40 13 : const QStringList tokens = keyId.split(whitespace, Qt::SkipEmptyParts);
41 13 : if (tokens.isEmpty()) {
42 2 : return {};
43 : }
44 : QString token = tokens.first();
45 11 : token.remove(unsafeChars);
46 : return token;
47 : }
48 :
49 1 : void ExportPublicKeyDialog::on_copyButton_clicked() {
50 2 : QApplication::clipboard()->setText(ui->plainTextEdit->toPlainText());
51 1 : ui->copyButton->setText(tr("Copied!"));
52 1 : QTimer::singleShot(1500, this, [this]() {
53 1 : ui->copyButton->setText(m_copyButtonOriginalText);
54 1 : });
55 1 : }
56 :
57 3 : void ExportPublicKeyDialog::on_saveButton_clicked() {
58 3 : QString safeKeyId = sanitizeKeyIdForFilename(m_keyId);
59 : QString defaultName = safeKeyId.isEmpty()
60 4 : ? QStringLiteral("public_key.asc")
61 5 : : QStringLiteral("%1.asc").arg(safeKeyId);
62 : QString fileName = QFileDialog::getSaveFileName(
63 3 : this, tr("Save public key"), defaultName,
64 9 : tr("ASCII-armored key (*.asc);;All files (*)"));
65 3 : if (fileName.isEmpty()) {
66 : return;
67 : }
68 2 : QSaveFile file(fileName);
69 2 : if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
70 3 : QMessageBox::warning(this, tr("Save public key"),
71 1 : tr("Could not open %1 for writing: %2")
72 2 : .arg(fileName, file.errorString()));
73 : return;
74 : }
75 1 : QTextStream out(&file);
76 1 : out << ui->plainTextEdit->toPlainText();
77 1 : out.flush();
78 1 : if (out.status() != QTextStream::Ok || !file.commit()) {
79 0 : QMessageBox::warning(
80 0 : this, tr("Save public key"),
81 0 : tr("Could not write to %1: %2").arg(fileName, file.errorString()));
82 : }
83 2 : }
|