1 #include "certificatemanagementdialog.hpp"
2 #include "ui_certificatemanagementdialog.h"
3
4 #include "kristall.hpp"
5
6 #include "newidentitiydialog.hpp"
7 #include "certificateiodialog.hpp"
8 #include "ioutil.hpp"
9
10 #include <QCryptographicHash>
11 #include <QMessageBox>
12
CertificateManagementDialog(QWidget * parent)13 CertificateManagementDialog::CertificateManagementDialog(QWidget *parent) :
14 QDialog(parent),
15 ui(new Ui::CertificateManagementDialog),
16 selected_identity { nullptr }
17 {
18 ui->setupUi(this);
19
20 connect( // connect with "this" as context, so the connection will die when the window is destroyed
21 kristall::globals().localization.get(), &Localization::translationChanged,
__anon513544430102() 22 this, [this]() { this->ui->retranslateUi(this); },
23 Qt::DirectConnection
24 );
25
26 this->ui->certificates->setModel(&identity_set);
27 this->ui->certificates->expandAll();
28
29 connect(
30 this->ui->certificates->selectionModel(),
31 &QItemSelectionModel::currentChanged,
32 this,
33 &CertificateManagementDialog::on_certificates_selected
34 );
35 on_certificates_selected(QModelIndex { }, QModelIndex { });
36 }
37
~CertificateManagementDialog()38 CertificateManagementDialog::~CertificateManagementDialog()
39 {
40 delete ui;
41 }
42
identitySet() const43 IdentityCollection CertificateManagementDialog::identitySet() const
44 {
45 return this->identity_set;
46 }
47
setIdentitySet(const IdentityCollection & src)48 void CertificateManagementDialog::setIdentitySet(const IdentityCollection &src)
49 {
50 this->identity_set = src;
51 this->ui->certificates->expandAll();
52
53 }
54
on_certificates_selected(QModelIndex const & index,QModelIndex const & previous)55 void CertificateManagementDialog::on_certificates_selected(QModelIndex const& index, QModelIndex const & previous)
56 {
57 Q_UNUSED(previous);
58
59 selected_identity = identity_set.getMutableIdentity(index);
60
61 this->ui->export_cert_button->setEnabled(selected_identity != nullptr);
62
63 if(selected_identity != nullptr)
64 {
65 auto & cert = *selected_identity;
66 this->ui->groupBox->setEnabled(true);
67 this->ui->cert_display_name->setText(cert.display_name);
68 this->ui->cert_common_name->setText(cert.certificate.subjectInfo(QSslCertificate::CommonName).join(", "));
69 this->ui->cert_expiration_date->setDateTime(cert.certificate.expiryDate());
70 auto days = QDateTime::currentDateTime().daysTo(cert.certificate.expiryDate());
71 this->ui->cert_livetime->setText(tr("%1 day","%1 days", days).arg(days));
72 this->ui->cert_fingerprint->setPlainText(toFingerprintString(cert.certificate));
73 this->ui->cert_notes->setPlainText(cert.user_notes);
74
75 this->ui->cert_host_filter->setText(cert.host_filter);
76 this->ui->cert_auto_enable->setEnabled(not cert.host_filter.isEmpty());
77 this->ui->cert_auto_enable->setChecked(cert.auto_enable);
78
79 this->ui->delete_cert_button->setEnabled(true);
80 }
81 else
82 {
83 this->ui->groupBox->setEnabled(false);
84 this->ui->cert_display_name->setText("");
85 this->ui->cert_common_name->setText("");
86 this->ui->cert_expiration_date->setDateTime(QDateTime { });
87 this->ui->cert_livetime->setText("");
88 this->ui->cert_fingerprint->setPlainText("");
89 this->ui->cert_host_filter->setText("");
90 this->ui->cert_auto_enable->setChecked(false);
91
92 if(auto group_name = identity_set.group(index); not group_name.isEmpty()) {
93 this->ui->delete_cert_button->setEnabled(identity_set.canDeleteGroup(group_name));
94 } else {
95 this->ui->delete_cert_button->setEnabled(false);
96 }
97 }
98 }
99
on_cert_notes_textChanged()100 void CertificateManagementDialog::on_cert_notes_textChanged()
101 {
102 if(this->selected_identity != nullptr) {
103 this->selected_identity->user_notes = this->ui->cert_notes->toPlainText();
104 }
105 }
106
on_cert_display_name_textChanged(const QString & arg1)107 void CertificateManagementDialog::on_cert_display_name_textChanged(const QString &arg1)
108 {
109 Q_UNUSED(arg1)
110 if(this->selected_identity != nullptr) {
111 this->selected_identity->display_name = this->ui->cert_display_name->text();
112 }
113 }
114
on_delete_cert_button_clicked()115 void CertificateManagementDialog::on_delete_cert_button_clicked()
116 {
117 auto index = this->ui->certificates->currentIndex();
118
119 if(identity_set.getMutableIdentity(index) != nullptr)
120 {
121 auto answer = QMessageBox::question(
122 this,
123 tr("Kristall"),
124 tr("Do you really want to delete this certificate?\r\n\r\nYou will not be able to restore the identity after this!"),
125 QMessageBox::Yes | QMessageBox::No,
126 QMessageBox::No
127 );
128 if(answer != QMessageBox::Yes)
129 return;
130 if(not identity_set.destroyIdentity(index)) {
131 QMessageBox::warning(this, tr("Kristall"), tr("Could not destroy identity!"));
132 }
133 }
134 else if(auto group_name = identity_set.group(index); not group_name.isEmpty()) {
135
136 auto answer = QMessageBox::question(
137 this,
138 tr("Kristall"),
139 tr("Do you want to delete the group '%1'").arg(group_name)
140 );
141 if(answer != QMessageBox::Yes)
142 return;
143
144 if(not identity_set.deleteGroup(group_name)) {
145 QMessageBox::warning(this, tr("Kristall"), tr("Could not delete group!"));
146 }
147 }
148 }
149
on_export_cert_button_clicked()150 void CertificateManagementDialog::on_export_cert_button_clicked()
151 {
152 if(this->selected_identity == nullptr)
153 return;
154 CertificateIoDialog dialog { this };
155
156 dialog.setKeyAlgorithm(this->selected_identity->private_key.algorithm());
157 dialog.setIoMode(CertificateIoDialog::Export);
158
159 if(dialog.exec() != QDialog::Accepted)
160 return;
161
162 {
163 QFile cert_file { dialog.certificateFileName() };
164 if(not cert_file.open(QFile::WriteOnly)) {
165 QMessageBox::warning(
166 this,
167 tr("Kristall"),
168 tr("The file %1 could not be found!").arg(dialog.certificateFileName())
169 );
170 return;
171 }
172
173 QByteArray cert_blob;
174 if(dialog.certificateFileName().endsWith(".der")) {
175 cert_blob = this->selected_identity->certificate.toDer();
176 } else {
177 cert_blob = this->selected_identity->certificate.toPem();
178 }
179
180 if(not IoUtil::writeAll(cert_file, cert_blob)) {
181 QMessageBox::warning(
182 this,
183 tr("Kristall"),
184 tr("The file %1 could not be created found!").arg(dialog.certificateFileName())
185 );
186 return;
187 }
188 }
189
190 {
191 QFile key_file { dialog.keyFileName() };
192 if(not key_file.open(QFile::WriteOnly)) {
193 QMessageBox::warning(
194 this,
195 tr("Kristall"),
196 tr("The file %1 could not be found!").arg(dialog.keyFileName())
197 );
198 return;
199 }
200
201 QByteArray key_blob;
202 if(dialog.keyFileName().endsWith(".der")) {
203 key_blob = this->selected_identity->private_key.toDer();
204 } else {
205 key_blob = this->selected_identity->private_key.toPem();
206 }
207
208 if(not IoUtil::writeAll(key_file, key_blob)) {
209 QMessageBox::warning(
210 this,
211 tr("Kristall"),
212 tr("The file %1 could not be created!").arg(dialog.keyFileName())
213 );
214 return;
215 }
216 }
217 }
218
on_import_cert_button_clicked()219 void CertificateManagementDialog::on_import_cert_button_clicked()
220 {
221 CertificateIoDialog dialog { this };
222
223 dialog.setIoMode(CertificateIoDialog::Import);
224
225 if(dialog.exec() != QDialog::Accepted)
226 return;
227
228 QFile cert_file { dialog.certificateFileName() };
229 if(not cert_file.open(QFile::ReadOnly)) {
230 QMessageBox::warning(
231 this,
232 tr("Kristall"),
233 tr("The file %1 could not be found!").arg(dialog.certificateFileName())
234 );
235 return;
236 }
237
238 QFile key_file { dialog.keyFileName() };
239 if(not key_file.open(QFile::ReadOnly)) {
240 QMessageBox::warning(
241 this,
242 tr("Kristall"),
243 tr("The file %1 could not be found!").arg(dialog.keyFileName())
244 );
245 return;
246 }
247
248 CryptoIdentity ident;
249 ident.private_key = QSslKey {
250 &key_file,
251 dialog.keyAlgorithm(),
252 dialog.keyFileName().endsWith(".der") ? QSsl::Der : QSsl::Pem,
253 QSsl::PrivateKey
254 };
255 ident.certificate = QSslCertificate {
256 &cert_file,
257 dialog.keyFileName().endsWith(".der") ? QSsl::Der : QSsl::Pem,
258 };
259 ident.user_notes = tr("Imported from:\r\nkey: %1\r\n:cert: %2").arg(dialog.keyFileName(), dialog.certificateFileName());
260 //: Default name
261 ident.display_name = tr("Imported Certificate");
262 ident.auto_enable = false;
263 ident.host_filter = "";
264 ident.is_persistent = true;
265
266 if(ident.private_key.isNull()) {
267 QMessageBox::warning(
268 this,
269 tr("Kristall"),
270 tr("The key file %1 could not be loaded. Please verify your key file.").arg(dialog.keyFileName())
271 );
272 return;
273 }
274
275 if(ident.certificate.isNull()) {
276 QMessageBox::warning(
277 this,
278 tr("Kristall"),
279 tr("The certificate file %1 could not be loaded. Please verify your certificate.").arg(dialog.keyFileName())
280 );
281 return;
282 }
283
284 if(not identity_set.addCertificate(tr("Imported Certificates"), ident)) {
285 QMessageBox::warning(
286 this,
287 tr("Kristall"),
288 tr("Failed to import the certificate.")
289 );
290 }
291 }
292
on_create_cert_button_clicked()293 void CertificateManagementDialog::on_create_cert_button_clicked()
294 {
295 NewIdentitiyDialog dialog { this };
296
297 dialog.setGroupName(identity_set.group(this->ui->certificates->currentIndex()));
298
299 if(dialog.exec() != QDialog::Accepted)
300 return;
301
302 auto id = dialog.createIdentity();
303 if(not id.isValid())
304 return;
305 id.is_persistent = true;
306
307 identity_set.addCertificate(
308 dialog.groupName(),
309 id);
310 }
311
on_cert_host_filter_textChanged(const QString & host_filter)312 void CertificateManagementDialog::on_cert_host_filter_textChanged(const QString &host_filter)
313 {
314 if(this->selected_identity != nullptr) {
315 this->ui->cert_auto_enable->setEnabled(not host_filter.isEmpty());
316 this->selected_identity->host_filter = host_filter;
317 } else {
318 this->ui->cert_auto_enable->setEnabled(false);
319 }
320
321 }
322
on_cert_auto_enable_clicked(bool checked)323 void CertificateManagementDialog::on_cert_auto_enable_clicked(bool checked)
324 {
325 if(this->selected_identity != nullptr) {
326 this->selected_identity->auto_enable = checked;
327 }
328 }
329