mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 21:17:44 +00:00
CertificateSettings: Update to be more consistent with other settings
This commit is contained in:
parent
0060b8c4e5
commit
ef5cca71dc
5 changed files with 8 additions and 9 deletions
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Fabian Dellwing <fabian@dellwing.net>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "CertificateStoreWidget.h"
|
||||
#include <AK/String.h>
|
||||
#include <Applications/CertificateSettings/CertificateStoreWidgetGML.h>
|
||||
#include <LibCrypto/ASN1/PEM.h>
|
||||
#include <LibFileSystem/FileSystem.h>
|
||||
#include <LibFileSystemAccessClient/Client.h>
|
||||
#include <LibGUI/MessageBox.h>
|
||||
#include <LibGUI/SortingProxyModel.h>
|
||||
|
||||
namespace CertificateSettings {
|
||||
|
||||
NonnullRefPtr<CertificateStoreModel> CertificateStoreModel::create()
|
||||
{
|
||||
return adopt_ref(*new CertificateStoreModel);
|
||||
}
|
||||
|
||||
void CertificateStoreProxyModel::sort(int column, GUI::SortOrder sort_order)
|
||||
{
|
||||
SortingProxyModel::sort(column, sort_order);
|
||||
m_parent_table_view->set_column_width(CertificateStoreModel::Column::IssuedTo, 150);
|
||||
m_parent_table_view->set_column_width(CertificateStoreModel::Column::IssuedBy, 150);
|
||||
}
|
||||
|
||||
ErrorOr<void> CertificateStoreModel::load()
|
||||
{
|
||||
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 {};
|
||||
}
|
||||
|
||||
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: {
|
||||
auto issued_to = cert.subject.common_name();
|
||||
if (issued_to.is_empty()) {
|
||||
issued_to = cert.subject.organizational_unit();
|
||||
}
|
||||
|
||||
return issued_to;
|
||||
}
|
||||
case Column::IssuedBy: {
|
||||
auto issued_by = cert.issuer.common_name();
|
||||
if (issued_by.is_empty()) {
|
||||
issued_by = cert.issuer.organizational_unit();
|
||||
}
|
||||
|
||||
return issued_by;
|
||||
}
|
||||
case Column::Expire:
|
||||
return cert.validity.not_after.to_deprecated_string("%Y-%m-%d"sv);
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
Certificate CertificateStoreModel::get(int index)
|
||||
{
|
||||
return m_certificates.at(index);
|
||||
}
|
||||
|
||||
ErrorOr<void> CertificateStoreWidget::export_pem()
|
||||
{
|
||||
auto index = m_root_ca_tableview->selection().first();
|
||||
auto real_index = m_root_ca_proxy_model->map_to_source(index);
|
||||
auto cert = m_root_ca_model->get(real_index.row());
|
||||
|
||||
String filename = cert.subject.common_name();
|
||||
if (filename.is_empty()) {
|
||||
filename = cert.subject.organizational_unit();
|
||||
}
|
||||
|
||||
filename = TRY(filename.replace(" "sv, "_"sv, ReplaceMode::All));
|
||||
|
||||
auto file = FileSystemAccessClient::Client::the().save_file(window(), filename.to_deprecated_string(), "pem"sv);
|
||||
if (file.is_error())
|
||||
return {};
|
||||
|
||||
auto data = TRY(Crypto::encode_pem(cert.original_asn1));
|
||||
|
||||
TRY(file.release_value().release_stream()->write_until_depleted(data));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<CertificateStoreWidget>> CertificateStoreWidget::try_create()
|
||||
{
|
||||
auto widget = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) CertificateStoreWidget()));
|
||||
TRY(widget->initialize());
|
||||
return widget;
|
||||
}
|
||||
|
||||
ErrorOr<void> CertificateStoreWidget::initialize()
|
||||
{
|
||||
TRY(load_from_gml(certificate_store_widget_gml));
|
||||
|
||||
m_root_ca_tableview = find_descendant_of_type_named<GUI::TableView>("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();
|
||||
m_root_ca_proxy_model = TRY(CertificateStoreProxyModel::create(*m_root_ca_model, *m_root_ca_tableview));
|
||||
m_root_ca_proxy_model->set_sort_role(GUI::ModelRole::Display);
|
||||
TRY(m_root_ca_model->load());
|
||||
m_root_ca_tableview->set_model(m_root_ca_proxy_model);
|
||||
m_root_ca_tableview->set_column_width(CertificateStoreModel::Column::IssuedTo, 150);
|
||||
m_root_ca_tableview->set_column_width(CertificateStoreModel::Column::IssuedBy, 150);
|
||||
|
||||
m_root_ca_tableview->on_selection_change = [&]() {
|
||||
m_export_ca_button->set_enabled(m_root_ca_tableview->selection().size() == 1);
|
||||
};
|
||||
|
||||
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()));
|
||||
}
|
||||
};
|
||||
|
||||
m_export_ca_button = find_descendant_of_type_named<GUI::Button>("export_button");
|
||||
m_export_ca_button->on_click = [&](auto) {
|
||||
auto export_result = export_pem();
|
||||
if (export_result.is_error()) {
|
||||
GUI::MessageBox::show_error(window(), DeprecatedString::formatted("{}", export_result.release_error()));
|
||||
}
|
||||
};
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue