diff options
| author | Carl Hetherington <cth@carlh.net> | 2025-03-01 22:38:03 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2025-03-01 22:38:03 +0100 |
| commit | 88b1b8b47233d8215bb796d6f8836810ed767836 (patch) | |
| tree | 42f45c7b97a62975c052db86fe03cca6cacc8aaa /src | |
| parent | 921b3573e25c42ef3e490c00beee07605c9a0a46 (diff) | |
Move CertificateChainEditor to its own files and format white space.
Diffstat (limited to 'src')
| -rw-r--r-- | src/wx/certificate_chain_editor.cc | 416 | ||||
| -rw-r--r-- | src/wx/certificate_chain_editor.h | 74 | ||||
| -rw-r--r-- | src/wx/config_dialog.cc | 374 | ||||
| -rw-r--r-- | src/wx/config_dialog.h | 43 | ||||
| -rw-r--r-- | src/wx/wscript | 1 |
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 |
