diff options
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | data.qrc | 1 | ||||
| -rw-r--r-- | data/ui/key_generate_dialog.ui | 56 | ||||
| -rw-r--r-- | data/ui/options_dialog.ui | 41 | ||||
| -rw-r--r-- | src/widgets/aooptionsdialog.cpp | 47 | ||||
| -rw-r--r-- | src/widgets/aooptionsdialog.h | 6 | ||||
| -rw-r--r-- | src/widgets/key_generate_dialog.cpp | 53 | ||||
| -rw-r--r-- | src/widgets/key_generate_dialog.h | 26 |
8 files changed, 231 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 32a4b87..167d827 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,8 @@ qt_add_executable(Attorney_Online src/widgets/direct_connect_dialog.h src/widgets/server_editor_dialog.cpp src/widgets/server_editor_dialog.h + src/widgets/key_generate_dialog.h + src/widgets/key_generate_dialog.cpp data.qrc src/widgets/playerlistwidget.h src/widgets/playerlistwidget.cpp src/widgets/moderator_dialog.h src/widgets/moderator_dialog.cpp @@ -16,6 +16,7 @@ <file>data/ui/lobby_assets/down-arrow.png</file> <file>data/ui/lobby_assets/up-arrow.png</file> <file>data/ui/moderator_action_dialog.ui</file> + <file>data/ui/key_generate_dialog.ui</file> <file>data/icons/https.svg</file> <file>data/icons/noencryption.svg</file> </qresource> diff --git a/data/ui/key_generate_dialog.ui b/data/ui/key_generate_dialog.ui new file mode 100644 index 0000000..29c6234 --- /dev/null +++ b/data/ui/key_generate_dialog.ui @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>key_generate_dialog</class> + <widget class="QWidget" name="key_generate_dialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>394</width> + <height>200</height> + </rect> + </property> + <property name="windowTitle"> + <string>Generate key</string> + </property> + <layout class="QFormLayout" name="verticalLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="key_name_lbl"> + <property name="text"> + <string>Key name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="key_name"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="key_password_lbl"> + <property name="text"> + <string>Passphrase:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="key_password"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="key_password_confirm_lbl"> + <property name="text"> + <string>Confirm:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="key_password_confirm"/> + </item> + <item row="3" column="1"> + <widget class="QDialogButtonBox" name="key_gen_buttons"> + <property name="standardButtons"> + <set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> +</ui> diff --git a/data/ui/options_dialog.ui b/data/ui/options_dialog.ui index dbb6171..81f94b7 100644 --- a/data/ui/options_dialog.ui +++ b/data/ui/options_dialog.ui @@ -1117,6 +1117,47 @@ Default: 0.</string> </item> </layout> </widget> + <widget class="QWidget" name="keyring_tab"> + <attribute name="title"> + <string>Keyring</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_8"> + <item> + <widget class="QLabel" name="keyring_info"> + <property name="text"> + <string>Manage key pairs used for server authentication. Keys are encrypted with a passphrase that you specify and are unlocked on demand. Server admin must specify your certificate in your staff profile. Certificates don't need to be kept secret. Name can be anything, it's not tied to a staff profile and provided for convenience. </string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="key_buttons_layout"> + <item> + <widget class="QPushButton" name="key_generate"> + <property name="text"> + <string>Generate new key</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="key_delete"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Delete key</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QTableView" name="keyring_table"/> + </item> + </layout> + </widget> </widget> </item> <item> diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index 760dccf..d9cbcb8 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -8,10 +8,13 @@ #include "networkmanager.h" #include "options.h" +// Hopefully temporary. +#include "widgets/key_generate_dialog.h" #include <QCollator> #include <QDoubleSpinBox> #include <QGroupBox> +#include <QHeaderView> #include <QResource> #include <QUiLoader> #include <QVBoxLayout> @@ -594,7 +597,49 @@ void AOOptionsDialog::setupUI() FROM_UI(QTextBrowser, privacy_policy); ui_privacy_policy->setPlainText(tr("Getting privacy policy...")); FROM_UI(QCheckBox, privacy_optout_cb); - registerOption<QCheckBox, bool>("privacy_optout", &Options::playerCountOptout, &Options::setPlayerCountOptout); + registerOption<QCheckBox, bool>("privacy_optout_cb", &Options::playerCountOptout, &Options::setPlayerCountOptout); + + // Keyring tab + + FROM_UI(QPushButton, key_generate); + connect(ui_key_generate, &QPushButton::clicked, this, [=, this] { + // this should be coupled + KeyGenerateDialog keygen_dialog(this); + if (keygen_dialog.exec() == QDialog::Accepted) + { + int err = generate_key(keygen_dialog.key_name(), keygen_dialog.key_password()); + if (err) + { + QMessageBox::warning(this, "Error", QString("Key generation failed, code %1").arg(err)); + } + ao_app->keyring_model.load_keys(); + } + }); + FROM_UI(QPushButton, key_delete); + + FROM_UI(QTableView, keyring_table); + ui_keyring_table->setModel(&ao_app->keyring_model); + ui_keyring_table->setSelectionMode(QAbstractItemView::SingleSelection); + ui_keyring_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + + // This assumes something is selected, and emptiness of selection is thus + // unchecked. + connect(ui_key_delete, &QPushButton::clicked, this, [=, this] { + int row = ui_keyring_table->selectionModel()->selectedIndexes().first().row(); + QString key_note = ao_app->keyring_model.data(ao_app->keyring_model.index(row, 0)).toString(); + QString del_text = QString("Are you sure you want to delete the key pair \"%1\"? If it's an active key that you use to authenticate on a server, and you want to delete it due to suspected compromise (or otherwise want it to never be used for authentication by anyone), revoke it on the server first.").arg(key_note); + if (QMessageBox::question(this, "Confirm deletion", del_text, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) + { + QByteArray key_id = ao_app->keyring_model.data(ao_app->keyring_model.index(row, 0), 0x0100).toByteArray(); + delete_key(key_id); + ao_app->keyring_model.load_keys(); + } + }); + + connect(ui_keyring_table->selectionModel(), &QItemSelectionModel::selectionChanged, this, [=, this] { + bool selected = !ui_keyring_table->selectionModel()->selectedIndexes().isEmpty(); + ui_key_delete->setEnabled(selected); + }); updateValues(); } diff --git a/src/widgets/aooptionsdialog.h b/src/widgets/aooptionsdialog.h index ab59916..bc9f282 100644 --- a/src/widgets/aooptionsdialog.h +++ b/src/widgets/aooptionsdialog.h @@ -15,6 +15,7 @@ #include <QScrollArea> #include <QSpinBox> #include <QTabWidget> +#include <QTableView> #include <QTextBrowser> #include <QVariant> @@ -123,6 +124,11 @@ private: QFrame *ui_privacy_separator; QTextBrowser *ui_privacy_policy; + // The keyring tab + QPushButton *ui_key_generate; + QPushButton *ui_key_delete; + QTableView *ui_keyring_table; + bool asset_cache_dirty = false; void populateAudioDevices(); diff --git a/src/widgets/key_generate_dialog.cpp b/src/widgets/key_generate_dialog.cpp new file mode 100644 index 0000000..1e9790e --- /dev/null +++ b/src/widgets/key_generate_dialog.cpp @@ -0,0 +1,53 @@ +#include "key_generate_dialog.h" + +#include <QFile> +#include <QPushButton> +#include <QUiLoader> +#include <QVBoxLayout> + +#include "options.h" + +KeyGenerateDialog::KeyGenerateDialog(QWidget *parent) + : QDialog(parent) +{ + QUiLoader l_loader(this); + QFile l_uiFile(Options::getInstance().getUIAsset("key_generate_dialog.ui")); + if (!l_uiFile.open(QFile::ReadOnly)) + { + qCritical() << "Unable to open file " << l_uiFile.fileName(); + return; + } + ui_widget = l_loader.load(&l_uiFile, this); + auto l_layout = new QVBoxLayout(this); + l_layout->addWidget(ui_widget); + setWindowTitle("Generate key"); + + FROM_UI(QLineEdit, key_name); + FROM_UI(QLineEdit, key_password); + ui_key_password->setEchoMode(QLineEdit::Password); + connect(ui_key_password, &QLineEdit::textChanged, this, &KeyGenerateDialog::validate); + FROM_UI(QLineEdit, key_password_confirm); + ui_key_password_confirm->setEchoMode(QLineEdit::Password); + connect(ui_key_password_confirm, &QLineEdit::textChanged, this, &KeyGenerateDialog::validate); + FROM_UI(QDialogButtonBox, key_gen_buttons); + connect(ui_key_gen_buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(ui_key_gen_buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); + + validate(); +} + +// Empty passwords should be also checked. +void KeyGenerateDialog::validate() +{ + ui_key_gen_buttons->button(QDialogButtonBox::Ok)->setEnabled(!ui_key_password->text().isEmpty() && (ui_key_password->text() == ui_key_password_confirm->text())); +} + +QStringView KeyGenerateDialog::key_name() +{ + return ui_key_name->text(); +} + +QByteArray KeyGenerateDialog::key_password() +{ + return ui_key_password->text().toUtf8(); +} diff --git a/src/widgets/key_generate_dialog.h b/src/widgets/key_generate_dialog.h new file mode 100644 index 0000000..dd366fc --- /dev/null +++ b/src/widgets/key_generate_dialog.h @@ -0,0 +1,26 @@ +#pragma once + +#include <QDialog> +#include <QDialogButtonBox> +#include <QLineEdit> + +#include "gui_utils.h" + +class KeyGenerateDialog : public QDialog +{ + Q_OBJECT + +public: + explicit KeyGenerateDialog(QWidget *parent = nullptr); + QStringView key_name(); + QByteArray key_password(); + +private: + QWidget *ui_widget; + QLineEdit *ui_key_name; + QLineEdit *ui_key_password; + QLineEdit *ui_key_password_confirm; + QDialogButtonBox *ui_key_gen_buttons; + + void validate(void); +}; |
