Skip to content

Commit

Permalink
CertificateSettings: Add import functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
fdellwing authored and ADKaster committed Apr 4, 2023
1 parent c273784 commit 7ce75ee
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Userland/Applications/CertificateSettings/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ set(GENERATED_SOURCES
)

serenity_app(CertificateSettings ICON certificate)
target_link_libraries(CertificateSettings PRIVATE LibCore LibCrypto LibGfx LibGUI LibMain LibTLS)
target_link_libraries(CertificateSettings PRIVATE LibCore LibCrypto LibFileSystem LibFileSystemAccessClient LibGfx LibGUI LibMain LibTLS)
57 changes: 56 additions & 1 deletion Userland/Applications/CertificateSettings/CertificateStore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,25 @@
#include "CertificateStore.h"
#include <Applications/CertificateSettings/CertificateStoreGML.h>
#include <LibCrypto/ASN1/PEM.h>
#include <LibFileSystem/FileSystem.h>
#include <LibFileSystemAccessClient/Client.h>
#include <LibGUI/MessageBox.h>

namespace CertificateSettings {

NonnullRefPtr<CertificateStoreModel> CertificateStoreModel::create() { return adopt_ref(*new CertificateStoreModel); }

ErrorOr<void> 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());

auto user_cert_path = TRY(String::formatted("{}/.config/certs.pem", Core::StandardPaths::home_directory()));
if (FileSystem::exists(user_cert_path)) {
auto user_cert_file = TRY(Core::File::open(user_cert_path, Core::File::OpenMode::Read));
TRY(data.try_append(TRY(user_cert_file->read_until_eof())));
}

m_certificates = TRY(DefaultRootCACertificates::the().reload_certificates(data));

return {};
Expand Down Expand Up @@ -59,6 +68,44 @@ GUI::Variant CertificateStoreModel::data(GUI::ModelIndex const& index, GUI::Mode
return {};
}

ErrorOr<size_t> CertificateStoreModel::add(Vector<Certificate> const& certificates)
{
auto size = m_certificates.size();
TRY(m_certificates.try_extend(certificates));
return m_certificates.size() - size;
}

ErrorOr<void> CertificateStoreWidget::import_pem()
{
auto fsac_result = FileSystemAccessClient::Client::the().open_file(window(), "Choose PEM to import...");
if (fsac_result.is_error())
return {};

auto fsac_file = fsac_result.release_value();
auto filename = fsac_file.filename();
if (!(filename.ends_with_bytes(".pem"sv) || filename.ends_with_bytes(".crt"sv)))
return Error::from_string_view("File is not a .pem or .crt file."sv);

auto data = TRY(fsac_file.release_stream()->read_until_eof());
auto count = TRY(m_root_ca_model->add(TRY(DefaultRootCACertificates::the().reload_certificates(data))));

if (count == 0) {
return Error::from_string_view("No valid CA found to import."sv);
}

auto cert_file = TRY(Core::File::open(TRY(String::formatted("{}/.config/certs.pem", Core::StandardPaths::home_directory())), Core::File::OpenMode::Write | Core::File::OpenMode::Append));
TRY(cert_file->write_until_depleted(data.bytes()));
cert_file->close();

m_root_ca_model->invalidate();
m_root_ca_tableview->set_column_width(CertificateStoreModel::Column::IssuedTo, 150);
m_root_ca_tableview->set_column_width(CertificateStoreModel::Column::IssuedBy, 150);

GUI::MessageBox::show(window(), TRY(String::formatted("Successfully imported {} CAs.", count)), "Success"sv);

return {};
}

ErrorOr<NonnullRefPtr<CertificateStoreWidget>> CertificateStoreWidget::try_create()
{
auto widget = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) CertificateStoreWidget()));
Expand All @@ -80,6 +127,14 @@ ErrorOr<void> CertificateStoreWidget::initialize()
m_root_ca_tableview->set_column_width(CertificateStoreModel::Column::IssuedTo, 150);
m_root_ca_tableview->set_column_width(CertificateStoreModel::Column::IssuedBy, 150);

m_import_ca_button = find_descendant_of_type_named<GUI::Button>("import_button");
m_import_ca_button->on_click = [&](auto) {
auto import_result = import_pem();
if (import_result.is_error()) {
GUI::MessageBox::show_error(window(), DeprecatedString::formatted("{}", import_result.release_error()));
}
};

return {};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
name: "import_button"
text: "Import"
fixed_width: 80
enabled: false
}

@GUI::Button {
Expand Down
3 changes: 3 additions & 0 deletions Userland/Applications/CertificateSettings/CertificateStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class CertificateStoreModel : public GUI::Model {
virtual DeprecatedString column_name(int) const override;
virtual GUI::Variant data(GUI::ModelIndex const&, GUI::ModelRole) const override;
virtual ErrorOr<void> load();
virtual ErrorOr<size_t> add(Vector<Certificate> const&);

private:
Vector<Certificate> m_certificates;
Expand All @@ -45,8 +46,10 @@ class CertificateStoreWidget : public GUI::SettingsWindow::Tab {
private:
CertificateStoreWidget() = default;
ErrorOr<void> initialize();
ErrorOr<void> import_pem();

RefPtr<CertificateStoreModel> m_root_ca_model;
RefPtr<GUI::TableView> m_root_ca_tableview;
RefPtr<GUI::Button> m_import_ca_button;
};
}
5 changes: 4 additions & 1 deletion Userland/Applications/CertificateSettings/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "CertificateStore.h"

#include <LibCore/StandardPaths.h>
#include <LibCore/System.h>
#include <LibGUI/Application.h>
#include <LibGUI/Icon.h>
Expand All @@ -19,9 +20,11 @@ ErrorOr<int> serenity_main(Main::Arguments args)

auto app = TRY(GUI::Application::try_create(args));

TRY(Core::System::unveil("/res", "r"));
TRY(Core::System::unveil(TRY(String::formatted("{}/.config/certs.pem", Core::StandardPaths::home_directory())), "rwc"_short_string));
TRY(Core::System::unveil("/tmp/session/%sid/portal/filesystemaccess", "rw"));
TRY(Core::System::unveil("/etc/cacert.pem", "r"));
TRY(Core::System::unveil("/etc/timezone", "r"));
TRY(Core::System::unveil("/res", "r"));
TRY(Core::System::unveil(nullptr, nullptr));

auto app_icon = GUI::Icon::default_icon("certificate"sv);
Expand Down

0 comments on commit 7ce75ee

Please sign in to comment.