summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2025-03-01 22:38:03 +0100
committerCarl Hetherington <cth@carlh.net>2025-03-01 22:38:03 +0100
commit88b1b8b47233d8215bb796d6f8836810ed767836 (patch)
tree42f45c7b97a62975c052db86fe03cca6cacc8aaa /src
parent921b3573e25c42ef3e490c00beee07605c9a0a46 (diff)
Move CertificateChainEditor to its own files and format white space.
Diffstat (limited to 'src')
-rw-r--r--src/wx/certificate_chain_editor.cc416
-rw-r--r--src/wx/certificate_chain_editor.h74
-rw-r--r--src/wx/config_dialog.cc374
-rw-r--r--src/wx/config_dialog.h43
-rw-r--r--src/wx/wscript1
5 files changed, 492 insertions, 416 deletions
diff --git a/src/wx/certificate_chain_editor.cc b/src/wx/certificate_chain_editor.cc
new file mode 100644
index 000000000..97275cc79
--- /dev/null
+++ b/src/wx/certificate_chain_editor.cc
@@ -0,0 +1,416 @@
+/*
+ Copyright (C) 2025 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ DCP-o-matic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "certificate_chain_editor.h"
+#include "dcpomatic_button.h"
+#include "make_chain_dialog.h"
+#include "static_text.h"
+#include "wx_util.h"
+#include <dcp/certificate_chain.h>
+#include <dcp/exceptions.h>
+#include <dcp/file.h>
+#include <dcp/filesystem.h>
+#include <wx/listctrl.h>
+
+
+using std::function;
+using std::make_shared;
+using std::shared_ptr;
+using std::string;
+using boost::bind;
+#if BOOST_VERSION >= 106100
+using namespace boost::placeholders;
+#endif
+
+
+CertificateChainEditor::CertificateChainEditor(
+ wxWindow* parent,
+ wxString title,
+ int border,
+ function<void (shared_ptr<dcp::CertificateChain>)> set,
+ function<shared_ptr<const dcp::CertificateChain> (void)> get,
+ function<bool (void)> nag_alter
+ )
+ : wxDialog(parent, wxID_ANY, title)
+ , _set(set)
+ , _get(get)
+ , _nag_alter(nag_alter)
+{
+ _sizer = new wxBoxSizer(wxVERTICAL);
+
+ auto certificates_sizer = new wxBoxSizer(wxHORIZONTAL);
+ _sizer->Add(certificates_sizer, 0, wxALL, border);
+
+ _certificates = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
+
+ {
+ wxListItem ip;
+ ip.SetId(0);
+ ip.SetText(_("Type"));
+ ip.SetWidth(100);
+ _certificates->InsertColumn(0, ip);
+ }
+
+ {
+ wxListItem ip;
+ ip.SetId(1);
+ ip.SetText(_("Thumbprint"));
+ ip.SetWidth(340);
+
+ auto font = ip.GetFont();
+ font.SetFamily(wxFONTFAMILY_TELETYPE);
+ ip.SetFont(font);
+
+ _certificates->InsertColumn(1, ip);
+ }
+
+ certificates_sizer->Add(_certificates, 1, wxEXPAND);
+
+ {
+ auto s = new wxBoxSizer(wxVERTICAL);
+ _add_certificate = new Button(this, _("Add..."));
+ s->Add(_add_certificate, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
+ _remove_certificate = new Button(this, _("Remove"));
+ s->Add(_remove_certificate, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
+ _export_certificate = new Button(this, _("Export certificate..."));
+ s->Add(_export_certificate, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
+ _export_chain = new Button(this, _("Export chain..."));
+ s->Add(_export_chain, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
+ certificates_sizer->Add(s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
+ }
+
+ auto table = new wxGridBagSizer(DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+ _sizer->Add(table, 1, wxALL | wxEXPAND, border);
+ int r = 0;
+
+ add_label_to_sizer(table, this, _("Leaf private key"), true, wxGBPosition(r, 0));
+ _private_key = new StaticText(this, {});
+ wxFont font = _private_key->GetFont();
+ font.SetFamily(wxFONTFAMILY_TELETYPE);
+ _private_key->SetFont(font);
+ table->Add(_private_key, wxGBPosition(r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+ _import_private_key = new Button(this, _("Import..."));
+ table->Add(_import_private_key, wxGBPosition(r, 2));
+ _export_private_key = new Button(this, _("Export..."));
+ table->Add(_export_private_key, wxGBPosition(r, 3));
+ ++r;
+
+ _button_sizer = new wxBoxSizer(wxHORIZONTAL);
+ _remake_certificates = new Button(this, _("Re-make certificates and key..."));
+ _button_sizer->Add(_remake_certificates, 1, wxRIGHT, border);
+ table->Add(_button_sizer, wxGBPosition(r, 0), wxGBSpan(1, 4));
+ ++r;
+
+ _private_key_bad = new StaticText(this, _("Leaf private key does not match leaf certificate!"));
+ font = *wxSMALL_FONT;
+ font.SetWeight(wxFONTWEIGHT_BOLD);
+ _private_key_bad->SetFont(font);
+ table->Add(_private_key_bad, wxGBPosition(r, 0), wxGBSpan(1, 3));
+ ++r;
+
+ _add_certificate->Bind(wxEVT_BUTTON, bind(&CertificateChainEditor::add_certificate, this));
+ _remove_certificate->Bind(wxEVT_BUTTON, bind(&CertificateChainEditor::remove_certificate, this));
+ _export_certificate->Bind(wxEVT_BUTTON, bind(&CertificateChainEditor::export_certificate, this));
+ _certificates->Bind(wxEVT_LIST_ITEM_SELECTED, bind(&CertificateChainEditor::update_sensitivity, this));
+ _certificates->Bind(wxEVT_LIST_ITEM_DESELECTED, bind(&CertificateChainEditor::update_sensitivity, this));
+ _remake_certificates->Bind(wxEVT_BUTTON, bind(&CertificateChainEditor::remake_certificates, this));
+ _export_chain->Bind(wxEVT_BUTTON, bind(&CertificateChainEditor::export_chain, this));
+ _import_private_key->Bind(wxEVT_BUTTON, bind(&CertificateChainEditor::import_private_key, this));
+ _export_private_key->Bind(wxEVT_BUTTON, bind(&CertificateChainEditor::export_private_key, this));
+
+ auto buttons = CreateSeparatedButtonSizer(wxCLOSE);
+ if (buttons) {
+ _sizer->Add(buttons, wxSizerFlags().Expand().DoubleBorder());
+ }
+
+ SetSizerAndFit(_sizer);
+
+ update_certificate_list();
+ update_private_key();
+ update_sensitivity();
+}
+
+void
+CertificateChainEditor::add_button(wxWindow* button)
+{
+ _button_sizer->Add(button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
+ _sizer->Layout();
+}
+
+void
+CertificateChainEditor::add_certificate()
+{
+ wxFileDialog dialog(this, _("Select Certificate file"), {}, {}, char_to_wx("PEM files (*.pem)|*.pem|KEY files (*.key)|*.key|All files (*.*)|*.*"));
+
+ if (dialog.ShowModal() == wxID_OK) {
+ try {
+ dcp::Certificate c;
+ string extra;
+ try {
+ extra = c.read_string(dcp::file_to_string(wx_to_std(dialog.GetPath())));
+ } catch (boost::filesystem::filesystem_error& e) {
+ error_dialog(this, _("Could not import certificate (%s)"), dialog.GetPath());
+ return;
+ }
+
+ if (!extra.empty()) {
+ message_dialog(
+ this,
+ _("This file contains other certificates (or other data) after its first certificate. "
+ "Only the first certificate will be used.")
+ );
+ }
+ auto chain = make_shared<dcp::CertificateChain>(*_get().get());
+ chain->add(c);
+ if (!chain->chain_valid()) {
+ error_dialog(
+ this,
+ _("Adding this certificate would make the chain inconsistent, so it will not be added. "
+ "Add certificates in order from root to intermediate to leaf.")
+ );
+ chain->remove(c);
+ } else {
+ _set(chain);
+ update_certificate_list();
+ }
+ } catch (dcp::MiscError& e) {
+ error_dialog(this, _("Could not read certificate file."), std_to_wx(e.what()));
+ }
+ }
+
+ update_sensitivity();
+}
+
+void
+CertificateChainEditor::remove_certificate()
+{
+ if (_nag_alter()) {
+ /* Cancel was clicked */
+ return;
+ }
+
+ int i = _certificates->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+ if (i == -1) {
+ return;
+ }
+
+ _certificates->DeleteItem(i);
+ auto chain = make_shared<dcp::CertificateChain>(*_get().get());
+ chain->remove(i);
+ _set(chain);
+
+ update_sensitivity();
+ update_certificate_list();
+}
+
+void
+CertificateChainEditor::export_certificate()
+{
+ int i = _certificates->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+ if (i == -1) {
+ return;
+ }
+
+ auto all = _get()->root_to_leaf();
+
+ wxString default_name;
+ if (i == 0) {
+ default_name = char_to_wx("root.pem");
+ } else if (i == static_cast<int>(all.size() - 1)) {
+ default_name = char_to_wx("leaf.pem");
+ } else {
+ default_name = char_to_wx("intermediate.pem");
+ }
+
+ wxFileDialog dialog(
+ this, _("Select Certificate File"), wxEmptyString, default_name, char_to_wx("PEM files (*.pem)|*.pem"),
+ wxFD_SAVE | wxFD_OVERWRITE_PROMPT
+ );
+
+ auto j = all.begin();
+ for (int k = 0; k < i; ++k) {
+ ++j;
+ }
+
+ if (dialog.ShowModal() != wxID_OK) {
+ return;
+ }
+
+ boost::filesystem::path path(wx_to_std(dialog.GetPath()));
+ if (path.extension() != ".pem") {
+ path += ".pem";
+ }
+ dcp::File f(path, "w");
+ if (!f) {
+ throw OpenFileError(path, f.open_error(), OpenFileError::WRITE);
+ }
+
+ string const s = j->certificate(true);
+ f.checked_write(s.c_str(), s.length());
+}
+
+void
+CertificateChainEditor::export_chain()
+{
+ wxFileDialog dialog(
+ this, _("Select Chain File"), wxEmptyString, char_to_wx("certificate_chain.pem"), char_to_wx("PEM files (*.pem)|*.pem"),
+ wxFD_SAVE | wxFD_OVERWRITE_PROMPT
+ );
+
+ if (dialog.ShowModal() != wxID_OK) {
+ return;
+ }
+
+ boost::filesystem::path path(wx_to_std(dialog.GetPath()));
+ if (path.extension() != ".pem") {
+ path += ".pem";
+ }
+ dcp::File f(path, "w");
+ if (!f) {
+ throw OpenFileError(path, f.open_error(), OpenFileError::WRITE);
+ }
+
+ auto const s = _get()->chain();
+ f.checked_write(s.c_str(), s.length());
+}
+
+void
+CertificateChainEditor::update_certificate_list()
+{
+ _certificates->DeleteAllItems();
+ size_t n = 0;
+ auto certs = _get()->root_to_leaf();
+ for (auto const& i: certs) {
+ wxListItem item;
+ item.SetId(n);
+ _certificates->InsertItem(item);
+ _certificates->SetItem(n, 1, std_to_wx(i.thumbprint()));
+
+ if (n == 0) {
+ _certificates->SetItem(n, 0, _("Root"));
+ } else if (n == (certs.size() - 1)) {
+ _certificates->SetItem(n, 0, _("Leaf"));
+ } else {
+ _certificates->SetItem(n, 0, _("Intermediate"));
+ }
+
+ ++n;
+ }
+
+ static wxColour normal = _private_key_bad->GetForegroundColour();
+
+ if (_get()->private_key_valid()) {
+ _private_key_bad->Hide();
+ _private_key_bad->SetForegroundColour(normal);
+ } else {
+ _private_key_bad->Show();
+ _private_key_bad->SetForegroundColour(wxColour(255, 0, 0));
+ }
+}
+
+void
+CertificateChainEditor::remake_certificates()
+{
+ if (_nag_alter()) {
+ /* Cancel was clicked */
+ return;
+ }
+
+ MakeChainDialog dialog(this, _get());
+
+ if (dialog.ShowModal() == wxID_OK) {
+ _set(dialog.get());
+ update_certificate_list();
+ update_private_key();
+ }
+}
+
+void
+CertificateChainEditor::update_sensitivity()
+{
+ /* We can only remove the leaf certificate */
+ _remove_certificate->Enable(_certificates->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) == (_certificates->GetItemCount() - 1));
+ _export_certificate->Enable(_certificates->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
+}
+
+void
+CertificateChainEditor::update_private_key()
+{
+ checked_set(_private_key, dcp::private_key_fingerprint(_get()->key().get()));
+ _sizer->Layout();
+}
+
+void
+CertificateChainEditor::import_private_key()
+{
+ wxFileDialog dialog(this, _("Select Key file"), {}, {}, char_to_wx("PEM files (*.pem)|*.pem|KEY files (*.key)|*.key|All files (*.*)|*.*"));
+
+ if (dialog.ShowModal() == wxID_OK) {
+ try {
+ boost::filesystem::path p(wx_to_std(dialog.GetPath()));
+ if (dcp::filesystem::file_size(p) > 8192) {
+ error_dialog(
+ this,
+ wxString::Format(_("Could not read key file; file is too long (%s)"), std_to_wx(p.string()))
+ );
+ return;
+ }
+
+ auto chain = make_shared<dcp::CertificateChain>(*_get().get());
+ chain->set_key(dcp::file_to_string(p));
+ _set(chain);
+ update_private_key();
+ } catch (std::exception& e) {
+ error_dialog(this, _("Could not read certificate file."), std_to_wx(e.what()));
+ }
+ }
+
+ update_sensitivity();
+}
+
+void
+CertificateChainEditor::export_private_key()
+{
+ auto key = _get()->key();
+ if (!key) {
+ return;
+ }
+
+ wxFileDialog dialog(
+ this, _("Select Key File"), wxEmptyString, char_to_wx("private_key.pem"), char_to_wx("PEM files (*.pem)|*.pem"),
+ wxFD_SAVE | wxFD_OVERWRITE_PROMPT
+ );
+
+ if (dialog.ShowModal() == wxID_OK) {
+ boost::filesystem::path path(wx_to_std(dialog.GetPath()));
+ if (path.extension() != ".pem") {
+ path += ".pem";
+ }
+ dcp::File f(path, "w");
+ if (!f) {
+ throw OpenFileError(path, f.open_error(), OpenFileError::WRITE);
+ }
+
+ auto const s = _get()->key().get();
+ f.checked_write(s.c_str(), s.length());
+ }
+}
+
diff --git a/src/wx/certificate_chain_editor.h b/src/wx/certificate_chain_editor.h
new file mode 100644
index 000000000..56750ee29
--- /dev/null
+++ b/src/wx/certificate_chain_editor.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2025 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ DCP-o-matic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include <wx/wx.h>
+#include <memory>
+
+
+namespace dcp {
+ class CertificateChain;
+}
+
+class wxListCtrl;
+
+
+class CertificateChainEditor : public wxDialog
+{
+public:
+ CertificateChainEditor(
+ wxWindow* parent,
+ wxString title,
+ int border,
+ std::function<void (std::shared_ptr<dcp::CertificateChain>)> set,
+ std::function<std::shared_ptr<const dcp::CertificateChain> (void)> get,
+ std::function<bool (void)> nag_alter
+ );
+
+ void add_button(wxWindow* button);
+
+private:
+ void add_certificate();
+ void remove_certificate();
+ void export_certificate();
+ void update_certificate_list();
+ void remake_certificates();
+ void update_sensitivity();
+ void update_private_key();
+ void import_private_key();
+ void export_private_key();
+ void export_chain();
+
+ wxListCtrl* _certificates;
+ wxButton* _add_certificate;
+ wxButton* _export_certificate;
+ wxButton* _remove_certificate;
+ wxButton* _remake_certificates;
+ wxStaticText* _private_key;
+ wxButton* _import_private_key;
+ wxButton* _export_private_key;
+ wxButton* _export_chain;
+ wxStaticText* _private_key_bad;
+ wxSizer* _sizer;
+ wxBoxSizer* _button_sizer;
+ std::function<void (std::shared_ptr<dcp::CertificateChain>)> _set;
+ std::function<std::shared_ptr<const dcp::CertificateChain> (void)> _get;
+ std::function<bool (void)> _nag_alter;
+};
diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc
index 0022ee4f0..6a01cdc4d 100644
--- a/src/wx/config_dialog.cc
+++ b/src/wx/config_dialog.cc
@@ -21,6 +21,7 @@
#include "audio_backend.h"
#include "audio_mapping_view.h"
+#include "certificate_chain_editor.h"
#include "check_box.h"
#include "config_dialog.h"
#include "dcpomatic_button.h"
@@ -255,379 +256,6 @@ GeneralPage::check_for_test_updates_changed ()
Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
}
-CertificateChainEditor::CertificateChainEditor (
- wxWindow* parent,
- wxString title,
- int border,
- function<void (shared_ptr<dcp::CertificateChain>)> set,
- function<shared_ptr<const dcp::CertificateChain> (void)> get,
- function<bool (void)> nag_alter
- )
- : wxDialog (parent, wxID_ANY, title)
- , _set (set)
- , _get (get)
- , _nag_alter (nag_alter)
-{
- _sizer = new wxBoxSizer (wxVERTICAL);
-
- auto certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
- _sizer->Add (certificates_sizer, 0, wxALL, border);
-
- _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
-
- {
- wxListItem ip;
- ip.SetId (0);
- ip.SetText (_("Type"));
- ip.SetWidth (100);
- _certificates->InsertColumn (0, ip);
- }
-
- {
- wxListItem ip;
- ip.SetId (1);
- ip.SetText (_("Thumbprint"));
- ip.SetWidth (340);
-
- wxFont font = ip.GetFont ();
- font.SetFamily (wxFONTFAMILY_TELETYPE);
- ip.SetFont (font);
-
- _certificates->InsertColumn (1, ip);
- }
-
- certificates_sizer->Add (_certificates, 1, wxEXPAND);
-
- {
- auto s = new wxBoxSizer (wxVERTICAL);
- _add_certificate = new Button (this, _("Add..."));
- s->Add (_add_certificate, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
- _remove_certificate = new Button (this, _("Remove"));
- s->Add (_remove_certificate, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
- _export_certificate = new Button (this, _("Export certificate..."));
- s->Add (_export_certificate, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
- _export_chain = new Button (this, _("Export chain..."));
- s->Add (_export_chain, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
- certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
- }
-
- auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
- _sizer->Add (table, 1, wxALL | wxEXPAND, border);
- int r = 0;
-
- add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
- _private_key = new StaticText(this, {});
- wxFont font = _private_key->GetFont ();
- font.SetFamily (wxFONTFAMILY_TELETYPE);
- _private_key->SetFont (font);
- table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
- _import_private_key = new Button (this, _("Import..."));
- table->Add (_import_private_key, wxGBPosition (r, 2));
- _export_private_key = new Button (this, _("Export..."));
- table->Add (_export_private_key, wxGBPosition (r, 3));
- ++r;
-
- _button_sizer = new wxBoxSizer (wxHORIZONTAL);
- _remake_certificates = new Button (this, _("Re-make certificates and key..."));
- _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
- table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
- ++r;
-
- _private_key_bad = new StaticText (this, _("Leaf private key does not match leaf certificate!"));
- font = *wxSMALL_FONT;
- font.SetWeight (wxFONTWEIGHT_BOLD);
- _private_key_bad->SetFont (font);
- table->Add (_private_key_bad, wxGBPosition (r, 0), wxGBSpan (1, 3));
- ++r;
-
- _add_certificate->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::add_certificate, this));
- _remove_certificate->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::remove_certificate, this));
- _export_certificate->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::export_certificate, this));
- _certificates->Bind (wxEVT_LIST_ITEM_SELECTED, bind (&CertificateChainEditor::update_sensitivity, this));
- _certificates->Bind (wxEVT_LIST_ITEM_DESELECTED, bind (&CertificateChainEditor::update_sensitivity, this));
- _remake_certificates->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::remake_certificates, this));
- _export_chain->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::export_chain, this));
- _import_private_key->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::import_private_key, this));
- _export_private_key->Bind (wxEVT_BUTTON, bind (&CertificateChainEditor::export_private_key, this));
-
- auto buttons = CreateSeparatedButtonSizer (wxCLOSE);
- if (buttons) {
- _sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
- }
-
- SetSizerAndFit (_sizer);
-
- update_certificate_list ();
- update_private_key ();
- update_sensitivity ();
-}
-
-void
-CertificateChainEditor::add_button (wxWindow* button)
-{
- _button_sizer->Add (button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
- _sizer->Layout ();
-}
-
-void
-CertificateChainEditor::add_certificate ()
-{
- wxFileDialog dialog(this, _("Select Certificate file"), {}, {}, char_to_wx("PEM files (*.pem)|*.pem|KEY files (*.key)|*.key|All files (*.*)|*.*"));
-
- if (dialog.ShowModal() == wxID_OK) {
- try {
- dcp::Certificate c;
- string extra;
- try {
- extra = c.read_string(dcp::file_to_string(wx_to_std(dialog.GetPath())));
- } catch (boost::filesystem::filesystem_error& e) {
- error_dialog(this, _("Could not import certificate (%s)"), dialog.GetPath());
- return;
- }
-
- if (!extra.empty ()) {
- message_dialog (
- this,
- _("This file contains other certificates (or other data) after its first certificate. "
- "Only the first certificate will be used.")
- );
- }
- auto chain = make_shared<dcp::CertificateChain>(*_get().get());
- chain->add (c);
- if (!chain->chain_valid ()) {
- error_dialog (
- this,
- _("Adding this certificate would make the chain inconsistent, so it will not be added. "
- "Add certificates in order from root to intermediate to leaf.")
- );
- chain->remove (c);
- } else {
- _set (chain);
- update_certificate_list ();
- }
- } catch (dcp::MiscError& e) {
- error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
- }
- }
-
- update_sensitivity ();
-}
-
-void
-CertificateChainEditor::remove_certificate ()
-{
- if (_nag_alter()) {
- /* Cancel was clicked */
- return;
- }
-
- int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
- if (i == -1) {
- return;
- }
-
- _certificates->DeleteItem (i);
- auto chain = make_shared<dcp::CertificateChain>(*_get().get());
- chain->remove (i);
- _set (chain);
-
- update_sensitivity ();
- update_certificate_list ();
-}
-
-void
-CertificateChainEditor::export_certificate ()
-{
- int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
- if (i == -1) {
- return;
- }
-
- auto all = _get()->root_to_leaf();
-
- wxString default_name;
- if (i == 0) {
- default_name = char_to_wx("root.pem");
- } else if (i == static_cast<int>(all.size() - 1)) {
- default_name = char_to_wx("leaf.pem");
- } else {
- default_name = char_to_wx("intermediate.pem");
- }
-
- wxFileDialog dialog(
- this, _("Select Certificate File"), wxEmptyString, default_name, char_to_wx("PEM files (*.pem)|*.pem"),
- wxFD_SAVE | wxFD_OVERWRITE_PROMPT
- );
-
- auto j = all.begin ();
- for (int k = 0; k < i; ++k) {
- ++j;
- }
-
- if (dialog.ShowModal() != wxID_OK) {
- return;
- }
-
- boost::filesystem::path path(wx_to_std(dialog.GetPath()));
- if (path.extension() != ".pem") {
- path += ".pem";
- }
- dcp::File f(path, "w");
- if (!f) {
- throw OpenFileError(path, f.open_error(), OpenFileError::WRITE);
- }
-
- string const s = j->certificate(true);
- f.checked_write(s.c_str(), s.length());
-}
-
-void
-CertificateChainEditor::export_chain ()
-{
- wxFileDialog dialog(
- this, _("Select Chain File"), wxEmptyString, char_to_wx("certificate_chain.pem"), char_to_wx("PEM files (*.pem)|*.pem"),
- wxFD_SAVE | wxFD_OVERWRITE_PROMPT
- );
-
- if (dialog.ShowModal() != wxID_OK) {
- return;
- }
-
- boost::filesystem::path path(wx_to_std(dialog.GetPath()));
- if (path.extension() != ".pem") {
- path += ".pem";
- }
- dcp::File f(path, "w");
- if (!f) {
- throw OpenFileError(path, f.open_error(), OpenFileError::WRITE);
- }
-
- auto const s = _get()->chain();
- f.checked_write(s.c_str(), s.length());
-}
-
-void
-CertificateChainEditor::update_certificate_list ()
-{
- _certificates->DeleteAllItems ();
- size_t n = 0;
- auto certs = _get()->root_to_leaf();
- for (auto const& i: certs) {
- wxListItem item;
- item.SetId (n);
- _certificates->InsertItem (item);
- _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
-
- if (n == 0) {
- _certificates->SetItem (n, 0, _("Root"));
- } else if (n == (certs.size() - 1)) {
- _certificates->SetItem (n, 0, _("Leaf"));
- } else {
- _certificates->SetItem (n, 0, _("Intermediate"));
- }
-
- ++n;
- }
-
- static wxColour normal = _private_key_bad->GetForegroundColour ();
-
- if (_get()->private_key_valid()) {
- _private_key_bad->Hide ();
- _private_key_bad->SetForegroundColour (normal);
- } else {
- _private_key_bad->Show ();
- _private_key_bad->SetForegroundColour (wxColour (255, 0, 0));
- }
-}
-
-void
-CertificateChainEditor::remake_certificates ()
-{
- if (_nag_alter()) {
- /* Cancel was clicked */
- return;
- }
-
- MakeChainDialog dialog(this, _get());
-
- if (dialog.ShowModal() == wxID_OK) {
- _set(dialog.get());
- update_certificate_list ();
- update_private_key ();
- }
-}
-
-void
-CertificateChainEditor::update_sensitivity ()
-{
- /* We can only remove the leaf certificate */
- _remove_certificate->Enable (_certificates->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) == (_certificates->GetItemCount() - 1));
- _export_certificate->Enable (_certificates->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
-}
-
-void
-CertificateChainEditor::update_private_key ()
-{
- checked_set (_private_key, dcp::private_key_fingerprint (_get()->key().get()));
- _sizer->Layout ();
-}
-
-void
-CertificateChainEditor::import_private_key ()
-{
- wxFileDialog dialog(this, _("Select Key file"), {}, {}, char_to_wx("PEM files (*.pem)|*.pem|KEY files (*.key)|*.key|All files (*.*)|*.*"));
-
- if (dialog.ShowModal() == wxID_OK) {
- try {
- boost::filesystem::path p(wx_to_std(dialog.GetPath()));
- if (dcp::filesystem::file_size(p) > 8192) {
- error_dialog (
- this,
- wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
- );
- return;
- }
-
- auto chain = make_shared<dcp::CertificateChain>(*_get().get());
- chain->set_key (dcp::file_to_string (p));
- _set (chain);
- update_private_key ();
- } catch (std::exception& e) {
- error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
- }
- }
-
- update_sensitivity ();
-}
-
-void
-CertificateChainEditor::export_private_key ()
-{
- auto key = _get()->key();
- if (!key) {
- return;
- }
-
- wxFileDialog dialog(
- this, _("Select Key File"), wxEmptyString, char_to_wx("private_key.pem"), char_to_wx("PEM files (*.pem)|*.pem"),
- wxFD_SAVE | wxFD_OVERWRITE_PROMPT
- );
-
- if (dialog.ShowModal() == wxID_OK) {
- boost::filesystem::path path(wx_to_std(dialog.GetPath()));
- if (path.extension() != ".pem") {
- path += ".pem";
- }
- dcp::File f(path, "w");
- if (!f) {
- throw OpenFileError(path, f.open_error(), OpenFileError::WRITE);
- }
-
- auto const s = _get()->key().get ();
- f.checked_write(s.c_str(), s.length());
- }
-}
-
wxString
KeysPage::GetName () const
{
diff --git a/src/wx/config_dialog.h b/src/wx/config_dialog.h
index ce2686864..87205a70f 100644
--- a/src/wx/config_dialog.h
+++ b/src/wx/config_dialog.h
@@ -111,49 +111,6 @@ private:
};
-class CertificateChainEditor : public wxDialog
-{
-public:
- CertificateChainEditor (
- wxWindow* parent,
- wxString title,
- int border,
- std::function<void (std::shared_ptr<dcp::CertificateChain>)> set,
- std::function<std::shared_ptr<const dcp::CertificateChain> (void)> get,
- std::function<bool (void)> nag_alter
- );
-
- void add_button (wxWindow* button);
-
-private:
- void add_certificate ();
- void remove_certificate ();
- void export_certificate ();
- void update_certificate_list ();
- void remake_certificates ();
- void update_sensitivity ();
- void update_private_key ();
- void import_private_key ();
- void export_private_key ();
- void export_chain ();
-
- wxListCtrl* _certificates;
- wxButton* _add_certificate;
- wxButton* _export_certificate;
- wxButton* _remove_certificate;
- wxButton* _remake_certificates;
- wxStaticText* _private_key;
- wxButton* _import_private_key;
- wxButton* _export_private_key;
- wxButton* _export_chain;
- wxStaticText* _private_key_bad;
- wxSizer* _sizer;
- wxBoxSizer* _button_sizer;
- std::function<void (std::shared_ptr<dcp::CertificateChain>)> _set;
- std::function<std::shared_ptr<const dcp::CertificateChain> (void)> _get;
- std::function<bool (void)> _nag_alter;
-};
-
class KeysPage : public Page
{
public:
diff --git a/src/wx/wscript b/src/wx/wscript
index 091e3c4e1..4b0af253a 100644
--- a/src/wx/wscript
+++ b/src/wx/wscript
@@ -35,6 +35,7 @@ sources = """
auto_crop_dialog.cc
barco_alchemy_certificate_panel.cc
batch_job_view.cc
+ certificate_chain_editor.cc
check_box.cc
christie_certificate_panel.cc
cinema_dialog.cc