From c273784c3efad395a913715c793feffc91f16743 Mon Sep 17 00:00:00 2001 From: Fabian Dellwing Date: Mon, 27 Mar 2023 20:04:24 +0200 Subject: [PATCH] CertificateSettings: Create basic Cert Store application This commit adds a new application named CertificateSettings that houses our Cert Store. It should be expanded in the future. --- Base/res/apps/CertificatesSettings.af | 6 ++ Base/res/icons/16x16/certificate.png | Bin 0 -> 291 bytes Base/res/icons/32x32/certificate.png | Bin 0 -> 975 bytes Userland/Applications/CMakeLists.txt | 1 + .../CertificateSettings/CMakeLists.txt | 19 ++++ .../CertificateSettings/CertificateStore.cpp | 85 ++++++++++++++++++ .../CertificateSettings/CertificateStore.gml | 40 +++++++++ .../CertificateSettings/CertificateStore.h | 52 +++++++++++ .../Applications/CertificateSettings/main.cpp | 34 +++++++ 9 files changed, 237 insertions(+) create mode 100644 Base/res/apps/CertificatesSettings.af create mode 100644 Base/res/icons/16x16/certificate.png create mode 100644 Base/res/icons/32x32/certificate.png create mode 100644 Userland/Applications/CertificateSettings/CMakeLists.txt create mode 100644 Userland/Applications/CertificateSettings/CertificateStore.cpp create mode 100644 Userland/Applications/CertificateSettings/CertificateStore.gml create mode 100644 Userland/Applications/CertificateSettings/CertificateStore.h create mode 100644 Userland/Applications/CertificateSettings/main.cpp diff --git a/Base/res/apps/CertificatesSettings.af b/Base/res/apps/CertificatesSettings.af new file mode 100644 index 0000000000..1ba704c966 --- /dev/null +++ b/Base/res/apps/CertificatesSettings.af @@ -0,0 +1,6 @@ +[App] +Name=Certificate Settings +Executable=/bin/CertificateSettings +Category=Settings +Description=Access and change the system's certificates +ExcludeFromSystemMenu=true diff --git a/Base/res/icons/16x16/certificate.png b/Base/res/icons/16x16/certificate.png new file mode 100644 index 0000000000000000000000000000000000000000..720f00d66c19da3d1501643e18ac22587d58eee6 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QUzDtBa{ixf|9@xoHPQT&3=9lRB|(0{43Q}+Dj5t64B4J8jv*3~tOp&rnixb_ z5B&TU-NEJfeSc!NSX#%6Y&Nj<3}2O)4!T=2T$q~nsr7W#y%GcAhPE3itX3_oe&W5l zYpnh{yNg*Ie{bP0l+XkKcjs~_ literal 0 HcmV?d00001 diff --git a/Base/res/icons/32x32/certificate.png b/Base/res/icons/32x32/certificate.png new file mode 100644 index 0000000000000000000000000000000000000000..6346e7eaf5bcee1a5db82b680329b0b28b9df441 GIT binary patch literal 975 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfEt$^F0iMpz3I#>^X_+~x z3=A3*YbV-z9Cna78XxRBQHFqN1tS*OYzm zVE@ro&E1>V@vUo8_`&$-)uSaZlvMxeYi{ZI_+W?p`**hQ?lC&8J{GcBpKryi)Rak_ zhVc=i>~Rm>B^-N{wG4y(Q^kuv$i#pD@bRnOvCVtV|FvxLx|q`7uhM6HcSDDHN4mN0 z+|PD}9ib|%Kju_iTEH!2Uld#Rv$yzWVqvZh8AY`F7rXhJWb~yk7r$ zt()*}@|U#mZW+eIw+|dG4WInI;k0bR7tiTDCnx?fX$|76uwR_7#h|?Xz=c`2qtoS= z^E>qIirUA>$JdxKbJKO(d$u=j-`<~Y_4hBs=@~_*HklXPXJBApOY(MiVffE*lOauX z-8MxA1_sUokH}&M20djEW~^9hU&g?|z+U3%>&pI|S%%lpr1W&LB?AM4WQl7;iF1B# zZfaf$gL6@8Vo7R>LV0FMhJw4NZ$Nk>pEv^pW3Q)+V@Sl|x1qk?haCiJHLp2&f7DvE zXyXfC4lO6XSNA=5zPvbj|KWRqrbnJ1F33Mv+I7|8V0VXx(orXeOuIFiJ?&?&<#3oi zo5b>4Z};SxvPSREo?}Yx`FQ`JWdHNHDajue8gILOJz2Fx=6m@6FTdo(w{T|~8#tQJ zjZ=NXb+h$ng{1ez`K$km-SzrcHAk0CBkiZ?v3=R`N4>6?vi0b8DKR))_k17W@AqWq z7s($lzj>t``1H!{$#;E&vprFV-g))k`l#uDPbKbSV35nx zXJ9xgd#EAtTd@^;hQ37G!8Ibw-!U;b#I81+`gsu(L%^(9h68nmuP0B~cYVFNuUbOe zz2tNIkB4rO*^|r2aBI5D=cQ~HfB4)}n;NfgR2Mn_v>NllLiMAT8>%l^afPM5vR(9d zp^|#1|J=qS4_>c2em(Sjx}TTS{CKuUVRl+}rEL2cEmuu?+PXQel7WGNFEzq5&DWPf Zi-CcGg8>3A1y2SsJYD@<);T3K0RUoVtFZt8 literal 0 HcmV?d00001 diff --git a/Userland/Applications/CMakeLists.txt b/Userland/Applications/CMakeLists.txt index 1750029d35..fd5e5a0742 100644 --- a/Userland/Applications/CMakeLists.txt +++ b/Userland/Applications/CMakeLists.txt @@ -7,6 +7,7 @@ add_subdirectory(BrowserSettings) add_subdirectory(Calculator) add_subdirectory(Calendar) add_subdirectory(CalendarSettings) +add_subdirectory(CertificateSettings) add_subdirectory(CharacterMap) add_subdirectory(ClockSettings) add_subdirectory(CrashReporter) diff --git a/Userland/Applications/CertificateSettings/CMakeLists.txt b/Userland/Applications/CertificateSettings/CMakeLists.txt new file mode 100644 index 0000000000..26d4e6fec9 --- /dev/null +++ b/Userland/Applications/CertificateSettings/CMakeLists.txt @@ -0,0 +1,19 @@ +serenity_component( + CertificateSettings + REQUIRED + TARGETS CertificateSettings +) + +compile_gml(CertificateStore.gml CertificateStoreGML.h certificate_store_gml) + +set(SOURCES + CertificateStore.cpp + main.cpp +) + +set(GENERATED_SOURCES + CertificateStoreGML.h +) + +serenity_app(CertificateSettings ICON certificate) +target_link_libraries(CertificateSettings PRIVATE LibCore LibCrypto LibGfx LibGUI LibMain LibTLS) diff --git a/Userland/Applications/CertificateSettings/CertificateStore.cpp b/Userland/Applications/CertificateSettings/CertificateStore.cpp new file mode 100644 index 0000000000..4101bbed03 --- /dev/null +++ b/Userland/Applications/CertificateSettings/CertificateStore.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023, Fabian Dellwing + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "CertificateStore.h" +#include +#include + +namespace CertificateSettings { + +NonnullRefPtr CertificateStoreModel::create() { return adopt_ref(*new CertificateStoreModel); } + +ErrorOr CertificateStoreModel::load() +{ + // FIXME: In the future, we will allow users to import their own certificates. To support this, we would need to change this logic + auto cacert_file = TRY(Core::File::open("/etc/cacert.pem"sv, Core::File::OpenMode::Read)); + auto data = TRY(cacert_file->read_until_eof()); + m_certificates = TRY(DefaultRootCACertificates::the().reload_certificates(data)); + + return {}; +} + +DeprecatedString CertificateStoreModel::column_name(int column) const +{ + switch (column) { + case Column::IssuedTo: + return "Issued To"; + case Column::IssuedBy: + return "Issued By"; + case Column::Expire: + return "Expiration Date"; + default: + VERIFY_NOT_REACHED(); + } +} + +GUI::Variant CertificateStoreModel::data(GUI::ModelIndex const& index, GUI::ModelRole role) const +{ + if (role != GUI::ModelRole::Display) + return {}; + if (m_certificates.is_empty()) + return {}; + + auto cert = m_certificates.at(index.row()); + + switch (index.column()) { + case Column::IssuedTo: + return cert.subject.subject.is_empty() ? cert.subject.unit : cert.subject.subject; + case Column::IssuedBy: + return cert.issuer.subject.is_empty() ? cert.issuer.unit : cert.issuer.subject; + case Column::Expire: + return cert.not_after.to_deprecated_string("%Y-%m-%d"sv); + default: + VERIFY_NOT_REACHED(); + } + + return {}; +} + +ErrorOr> CertificateStoreWidget::try_create() +{ + auto widget = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) CertificateStoreWidget())); + TRY(widget->initialize()); + return widget; +} + +ErrorOr CertificateStoreWidget::initialize() +{ + TRY(load_from_gml(certificate_store_gml)); + + m_root_ca_tableview = find_descendant_of_type_named("root_ca_tableview"); + m_root_ca_tableview->set_highlight_selected_rows(true); + m_root_ca_tableview->set_alternating_row_colors(false); + + m_root_ca_model = CertificateStoreModel::create(); + TRY(m_root_ca_model->load()); + m_root_ca_tableview->set_model(m_root_ca_model); + m_root_ca_tableview->set_column_width(CertificateStoreModel::Column::IssuedTo, 150); + m_root_ca_tableview->set_column_width(CertificateStoreModel::Column::IssuedBy, 150); + + return {}; +} +} diff --git a/Userland/Applications/CertificateSettings/CertificateStore.gml b/Userland/Applications/CertificateSettings/CertificateStore.gml new file mode 100644 index 0000000000..4385b34109 --- /dev/null +++ b/Userland/Applications/CertificateSettings/CertificateStore.gml @@ -0,0 +1,40 @@ +@GUI::Widget { + fill_with_background_color: true + layout: @GUI::VerticalBoxLayout { + margins: [8] + } + + @GUI::GroupBox { + title: "Trusted Root Certification Authorities" + fixed_height: 500 + fixed_width: 465 + layout: @GUI::VerticalBoxLayout { + margins: [8] + } + + @GUI::TableView { + name: "root_ca_tableview" + } + + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + spacing: 6 + } + preferred_height: "fit" + + @GUI::Button { + name: "import_button" + text: "Import" + fixed_width: 80 + enabled: false + } + + @GUI::Button { + name: "export_button" + text: "Export" + fixed_width: 80 + enabled: false + } + } + } +} diff --git a/Userland/Applications/CertificateSettings/CertificateStore.h b/Userland/Applications/CertificateSettings/CertificateStore.h new file mode 100644 index 0000000000..ffcc3fd4f1 --- /dev/null +++ b/Userland/Applications/CertificateSettings/CertificateStore.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023, Fabian Dellwing + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace CertificateSettings { + +class CertificateStoreModel : public GUI::Model { +public: + enum Column { + IssuedTo, + IssuedBy, + Expire, + __Count + }; + + static NonnullRefPtr create(); + virtual ~CertificateStoreModel() override = default; + + virtual int row_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return m_certificates.size(); } + virtual int column_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return Column::__Count; } + virtual DeprecatedString column_name(int) const override; + virtual GUI::Variant data(GUI::ModelIndex const&, GUI::ModelRole) const override; + virtual ErrorOr load(); + +private: + Vector m_certificates; +}; + +class CertificateStoreWidget : public GUI::SettingsWindow::Tab { + C_OBJECT_ABSTRACT(CertStoreWidget) +public: + virtual ~CertificateStoreWidget() override = default; + static ErrorOr> try_create(); + virtual void apply_settings() override {}; + +private: + CertificateStoreWidget() = default; + ErrorOr initialize(); + + RefPtr m_root_ca_model; + RefPtr m_root_ca_tableview; +}; +} diff --git a/Userland/Applications/CertificateSettings/main.cpp b/Userland/Applications/CertificateSettings/main.cpp new file mode 100644 index 0000000000..e434f6c88c --- /dev/null +++ b/Userland/Applications/CertificateSettings/main.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, Fabian Dellwing + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "CertificateStore.h" + +#include +#include +#include +#include +#include +#include + +ErrorOr serenity_main(Main::Arguments args) +{ + TRY(Core::System::pledge("stdio rpath wpath cpath recvfd sendfd unix")); + + auto app = TRY(GUI::Application::try_create(args)); + + TRY(Core::System::unveil("/res", "r")); + TRY(Core::System::unveil("/etc/cacert.pem", "r")); + TRY(Core::System::unveil("/etc/timezone", "r")); + TRY(Core::System::unveil(nullptr, nullptr)); + + auto app_icon = GUI::Icon::default_icon("certificate"sv); + auto window = TRY(GUI::SettingsWindow::create("Certificates", GUI::SettingsWindow::ShowDefaultsButton::No)); + auto cert_store_widget = TRY(window->add_tab(TRY("Certificate Store"_string), "certificate"sv)); + window->set_icon(app_icon.bitmap_for_size(16)); + + window->show(); + return app->exec(); +}