Allow KDMRecipient and hence Screen to convert certs to dcp::Certificate lazily.
authorCarl Hetherington <cth@carlh.net>
Fri, 17 Jan 2025 00:31:38 +0000 (01:31 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 22 Jan 2025 13:34:25 +0000 (14:34 +0100)
This is pretty slow (as it runs the certificate through OpenSSL) and we
don't need to do it for every certificate in a database when we load the
database.

12 files changed:
src/lib/cinema_list.cc
src/lib/dkdm_recipient.cc
src/lib/dkdm_recipient_list.cc
src/lib/kdm_cli.cc
src/lib/kdm_recipient.cc
src/lib/kdm_recipient.h
src/lib/screen.cc
src/lib/screen.h
src/wx/recipients_panel.cc
src/wx/screens_panel.cc
test/cinema_list_test.cc
test/dkdm_recipient_list_test.cc

index f59a8f4f8ce69ea43c9f88587c4e2b47f3e9ac30..01824ca549aa0ac1ef765e95eeac9515c08f889c 100644 (file)
@@ -309,7 +309,7 @@ CinemaList::add_screen(CinemaID cinema_id, dcpomatic::Screen const& screen)
        add_screen.bind_int64(1, cinema_id.get());
        add_screen.bind_text(2, screen.name);
        add_screen.bind_text(3, screen.notes);
-       add_screen.bind_text(4, screen.recipient->certificate(true));
+       add_screen.bind_text(4, screen.recipient()->certificate(true));
        add_screen.bind_text(5, screen.recipient_file.get_value_or(""));
 
        add_screen.execute();
@@ -332,7 +332,7 @@ dcpomatic::Screen
 CinemaList::screen_from_result(SQLiteStatement& statement, ScreenID screen_id) const
 {
        auto certificate_string = statement.column_text(4);
-       optional<dcp::Certificate> certificate = certificate_string.empty() ? optional<dcp::Certificate>() : dcp::Certificate(certificate_string);
+       optional<string> certificate = certificate_string.empty() ? optional<string>() : certificate_string;
        auto recipient_file_string = statement.column_text(5);
        optional<string> recipient_file = recipient_file_string.empty() ? optional<string>() : recipient_file_string;
 
@@ -429,7 +429,7 @@ CinemaList::update_screen(CinemaID cinema_id, ScreenID screen_id, dcpomatic::Scr
        statement.bind_int64(1, cinema_id.get());
        statement.bind_text(2, screen.name);
        statement.bind_text(3, screen.notes);
-       statement.bind_text(4, screen.recipient->certificate(true));
+       statement.bind_text(4, screen.recipient()->certificate(true));
        statement.bind_text(5, screen.recipient_file.get_value_or(""));
        statement.bind_int64(6, screen_id.get());
 
index 4ab532f3d8dfa04c5011176237d32aa992954f5f..bd14aedea1dcd914b22b7554d3205b748853f76f 100644 (file)
@@ -41,7 +41,7 @@ kdm_for_dkdm_recipient (
        dcp::LocalTime valid_to
        )
 {
-       if (!recipient.recipient) {
+       if (!recipient.recipient()) {
                return {};
        }
 
@@ -51,7 +51,7 @@ kdm_for_dkdm_recipient (
        }
 
        auto const decrypted_kdm = film->make_kdm(cpl, valid_from, valid_to);
-       auto const kdm = decrypted_kdm.encrypt(signer, recipient.recipient.get(), {}, dcp::Formulation::MODIFIED_TRANSITIONAL_1, true, 0);
+       auto const kdm = decrypted_kdm.encrypt(signer, recipient.recipient().get(), {}, dcp::Formulation::MODIFIED_TRANSITIONAL_1, true, 0);
 
        dcp::NameFormat::Map name_values;
        name_values['f'] = kdm.content_title_text();
index 34179337e5f8d7568b6a67a16f251ae851542600..f67379122dd9155eabd64a12548c5a57d2bbf90d 100644 (file)
@@ -154,7 +154,7 @@ DKDMRecipientList::add_dkdm_recipient(DKDMRecipient const& dkdm_recipient)
 
        add_dkdm_recipient.bind_text(1, dkdm_recipient.name);
        add_dkdm_recipient.bind_text(2, dkdm_recipient.notes);
-       add_dkdm_recipient.bind_text(3, dkdm_recipient.recipient ? dkdm_recipient.recipient->certificate(true) : "");
+       add_dkdm_recipient.bind_text(3, dkdm_recipient.recipient() ? dkdm_recipient.recipient()->certificate(true) : "");
        add_dkdm_recipient.bind_text(4, join_strings(dkdm_recipient.emails));
 
        add_dkdm_recipient.execute();
@@ -170,7 +170,7 @@ DKDMRecipientList::update_dkdm_recipient(DKDMRecipientID id, DKDMRecipient const
 
        add_dkdm_recipient.bind_text(1, dkdm_recipient.name);
        add_dkdm_recipient.bind_text(2, dkdm_recipient.notes);
-       add_dkdm_recipient.bind_text(3, dkdm_recipient.recipient ? dkdm_recipient.recipient->certificate(true) : "");
+       add_dkdm_recipient.bind_text(3, dkdm_recipient.recipient() ? dkdm_recipient.recipient()->certificate(true) : "");
        add_dkdm_recipient.bind_text(4, join_strings(dkdm_recipient.emails));
        add_dkdm_recipient.bind_int64(5, id.get());
 
index 686d2b4a1b0c0999bb3c05597f23b6784f871031..c820fb22afbc845ba7889163e2582f120bd304e9 100644 (file)
@@ -380,13 +380,13 @@ from_dkdm (
        try {
                list<KDMWithMetadataPtr> kdms;
                for (auto const& screen_details: screens) {
-                       if (!screen_details.screen.recipient) {
+                       if (!screen_details.screen.recipient()) {
                                continue;
                        }
 
                        auto const kdm = kdm_from_dkdm(
                                                        dkdm,
-                                                       screen_details.screen.recipient.get(),
+                                                       screen_details.screen.recipient().get(),
                                                        screen_details.screen.trusted_device_thumbprints(),
                                                        valid_from,
                                                        valid_to,
index c33eb1b9fa962fcd0e308af21d4770aad10c08dc..7e7e14324a2ef60c1d488d1b5d47276b9812ca2f 100644 (file)
 #include "kdm_recipient.h"
 
 
+using boost::optional;
+
+
 KDMRecipient::KDMRecipient (cxml::ConstNodePtr node)
        : name (node->string_child("Name"))
        , notes (node->optional_string_child("Notes").get_value_or(""))
 {
        if (node->optional_string_child("Certificate")) {
-               recipient = dcp::Certificate (node->string_child("Certificate"));
+               _recipient = dcp::Certificate(node->string_child("Certificate"));
        } else if (node->optional_string_child("Recipient")) {
-               recipient = dcp::Certificate (node->string_child("Recipient"));
+               _recipient = dcp::Certificate(node->string_child("Recipient"));
        }
 
        recipient_file = node->optional_string_child("RecipientFile");
@@ -40,8 +43,8 @@ void
 KDMRecipient::as_xml (xmlpp::Element* parent) const
 {
        cxml::add_text_child(parent, "Name", name);
-       if (recipient) {
-               cxml::add_text_child(parent, "Recipient", recipient->certificate(true));
+       if (auto const r = recipient()) {
+               cxml::add_text_child(parent, "Recipient", r->certificate(true));
        }
        if (recipient_file) {
                cxml::add_text_child(parent, "RecipientFile", *recipient_file);
@@ -50,3 +53,26 @@ KDMRecipient::as_xml (xmlpp::Element* parent) const
        cxml::add_text_child(parent, "Notes", notes);
 }
 
+
+boost::optional<dcp::Certificate>
+KDMRecipient::recipient() const
+{
+       if (_recipient) {
+               return _recipient;
+       }
+
+       if (_recipient_string) {
+               return dcp::Certificate(*_recipient_string);
+       }
+
+       return {};
+}
+
+
+void
+KDMRecipient::set_recipient(optional<dcp::Certificate> certificate)
+{
+       _recipient = certificate;
+       _recipient_string = {};
+}
+
index f18e714290d0a530a68ba7757cf066fd70b11ed3..9fe75874d07728252122417dd9984fecbb7b99f2 100644 (file)
@@ -36,11 +36,18 @@ LIBDCP_ENABLE_WARNINGS
 class KDMRecipient
 {
 public:
-       KDMRecipient (std::string const& name_, std::string const& notes_, boost::optional<dcp::Certificate> recipient_, boost::optional<std::string> recipient_file_)
+       KDMRecipient (std::string const& name_, std::string const& notes_, boost::optional<dcp::Certificate> recipient, boost::optional<std::string> recipient_file_)
                : name (name_)
                , notes (notes_)
-               , recipient (recipient_)
                , recipient_file (recipient_file_)
+               , _recipient(recipient)
+       {}
+
+       KDMRecipient(std::string const& name_, std::string const& notes_, boost::optional<std::string> recipient, boost::optional<std::string> recipient_file_)
+               : name(name_)
+               , notes(notes_)
+               , recipient_file(recipient_file_)
+               , _recipient_string(recipient)
        {}
 
        explicit KDMRecipient (cxml::ConstNodePtr);
@@ -49,13 +56,22 @@ public:
 
        virtual void as_xml (xmlpp::Element *) const;
 
+       boost::optional<dcp::Certificate> recipient() const;
+       void set_recipient(boost::optional<dcp::Certificate> certificate);
+
        std::string name;
        std::string notes;
-       boost::optional<dcp::Certificate> recipient;
        /** The pathname or URL that the recipient certificate was obtained from; purely
         *  to inform the user.
         */
        boost::optional<std::string> recipient_file;
+
+private:
+       /* The recipient certificate may be stored as either a string or a dcp::Certificate;
+        * the string is useful if we want to be lazy about constructing the dcp::Certificate.
+        */
+       boost::optional<dcp::Certificate> _recipient;
+       boost::optional<std::string> _recipient_string;
 };
 
 
index b77eb6b52aee89659f9f985375f95f9550359b58..304fb52f31fa2e125b1b4872ff2fb39d19da02e6 100644 (file)
@@ -65,11 +65,11 @@ kdm_for_screen (
        vector<KDMCertificatePeriod>& period_checks
        )
 {
-       if (!screen.recipient) {
+       if (!screen.recipient()) {
                return {};
        }
 
-       period_checks.push_back(check_kdm_and_certificate_validity_periods(cinema.name, screen.name, screen.recipient.get(), valid_from, valid_to));
+       period_checks.push_back(check_kdm_and_certificate_validity_periods(cinema.name, screen.name, screen.recipient().get(), valid_from, valid_to));
 
        auto signer = Config::instance()->signer_chain();
        if (!signer->valid()) {
@@ -77,7 +77,7 @@ kdm_for_screen (
        }
 
        auto kdm = make_kdm(valid_from, valid_to).encrypt(
-               signer, screen.recipient.get(), screen.trusted_device_thumbprints(), formulation, disable_forensic_marking_picture, disable_forensic_marking_audio
+               signer, screen.recipient().get(), screen.trusted_device_thumbprints(), formulation, disable_forensic_marking_picture, disable_forensic_marking_audio
                );
 
        dcp::NameFormat::Map name_values;
index 89ebc3ab4c1bc8ce8ca7e0da27ebc53a060fbd60..326bc94039626c475731f892137b5a0eb203cda7 100644 (file)
@@ -64,6 +64,17 @@ public:
                , trusted_devices (trusted_devices_)
        {}
 
+       Screen(
+               std::string const & name_,
+               std::string const & notes_,
+               boost::optional<std::string> recipient_,
+               boost::optional<std::string> recipient_file_,
+               std::vector<TrustedDevice> trusted_devices_
+              )
+               : KDMRecipient(name_, notes_, recipient_, recipient_file_)
+               , trusted_devices(trusted_devices_)
+       {}
+
        std::vector<std::string> trusted_device_thumbprints () const;
        std::vector<TrustedDevice> trusted_devices;
 };
index 33b715260dcbf4e089517428bb999cb4057693b0..ff19c02273de4dde685407c965ee5546ad9565cf 100644 (file)
@@ -149,14 +149,14 @@ RecipientsPanel::edit_recipient_clicked ()
                recipient->name,
                recipient->notes,
                recipient->emails,
-               recipient->recipient
+               recipient->recipient()
                );
 
        if (dialog.ShowModal() == wxID_OK) {
                recipient->name = dialog.name();
                recipient->emails = dialog.emails();
                recipient->notes = dialog.notes();
-               recipient->recipient = dialog.recipient();
+               recipient->set_recipient(dialog.recipient());
                recipients.update_dkdm_recipient(recipient_id, *recipient);
                _targets->SetItemText(selection.first, std_to_wx(dialog.name()));
        }
index 221af30b7b8566fa3c9530a56fa99fa06b40a5a6..6de1d86f0f6c0d5e75c59493ca0e608f53b13ad6 100644 (file)
@@ -415,7 +415,7 @@ ScreensPanel::edit_screen(CinemaID cinema_id, ScreenID screen_id)
                GetParent(), _("Edit screen"),
                screen->name,
                screen->notes,
-               screen->recipient,
+               screen->recipient(),
                screen->recipient_file,
                screen->trusted_devices
                );
@@ -439,7 +439,7 @@ ScreensPanel::edit_screen(CinemaID cinema_id, ScreenID screen_id)
 
        screen->name = dialog.name();
        screen->notes = dialog.notes();
-       screen->recipient = dialog.recipient();
+       screen->set_recipient(dialog.recipient());
        screen->recipient_file = dialog.recipient_file();
        screen->trusted_devices = dialog.trusted_devices();
        _cinema_list.update_screen(cinema_id, screen_id, *screen);
index c19b8831544b3ec85221b6a234f63796a8c4b287..58af7839a09786779c2d5aefe00c9b38feb47b34 100644 (file)
@@ -177,7 +177,7 @@ BOOST_AUTO_TEST_CASE(add_screen_test)
        BOOST_CHECK(check[0].first == screen_id);
        BOOST_CHECK_EQUAL(check[0].second.name, "Screen 1");
        BOOST_CHECK_EQUAL(check[0].second.notes, "Smells of popcorn");
-       BOOST_CHECK(check[0].second.recipient == dcp::Certificate(dcp::file_to_string("test/data/cert.pem")));
+       BOOST_CHECK(check[0].second.recipient() == dcp::Certificate(dcp::file_to_string("test/data/cert.pem")));
        BOOST_CHECK(check[0].second.recipient_file == string("test/data/cert.pem"));
 }
 
@@ -208,7 +208,7 @@ BOOST_AUTO_TEST_CASE(update_screen_test)
        BOOST_CHECK(check[0].first == screen_id);
        BOOST_CHECK_EQUAL(check[0].second.name, "Screen 1 updated");
        BOOST_CHECK_EQUAL(check[0].second.notes, "Smells of popcorn and hope");
-       BOOST_CHECK(check[0].second.recipient == dcp::Certificate(dcp::file_to_string("test/data/cert.pem")));
+       BOOST_CHECK(check[0].second.recipient() == dcp::Certificate(dcp::file_to_string("test/data/cert.pem")));
        BOOST_CHECK(check[0].second.recipient_file == string("test/data/cert.pem"));
 }
 
@@ -247,11 +247,11 @@ BOOST_AUTO_TEST_CASE(cinemas_list_copy_from_xml_test)
        BOOST_CHECK_EQUAL(screens.size(), 2U);
        auto screen_iter = screens.begin();
        BOOST_CHECK_EQUAL(screen_iter->second.name, "1");
-       BOOST_CHECK(screen_iter->second.recipient);
-       BOOST_CHECK_EQUAL(screen_iter->second.recipient->subject_dn_qualifier(), "CVsuuv9eYsQZSl8U4fDpvOmzZhI=");
+       BOOST_CHECK(screen_iter->second.recipient());
+       BOOST_CHECK_EQUAL(screen_iter->second.recipient()->subject_dn_qualifier(), "CVsuuv9eYsQZSl8U4fDpvOmzZhI=");
        ++screen_iter;
        BOOST_CHECK_EQUAL(screen_iter->second.name, "2");
-       BOOST_CHECK(screen_iter->second.recipient);
-       BOOST_CHECK_EQUAL(screen_iter->second.recipient->subject_dn_qualifier(), "CVsuuv9eYsQZSl8U4fDpvOmzZhI=");
+       BOOST_CHECK(screen_iter->second.recipient());
+       BOOST_CHECK_EQUAL(screen_iter->second.recipient()->subject_dn_qualifier(), "CVsuuv9eYsQZSl8U4fDpvOmzZhI=");
 }
 
index 406d181a1db54a0944f5d0c33a591dd5012c1881..9d4486595ed92ba08b327d182d296e28c3d1c2ae 100644 (file)
@@ -45,12 +45,12 @@ BOOST_AUTO_TEST_CASE(dkdm_receipient_list_copy_from_xml_test)
        BOOST_CHECK_EQUAL(dkdm_recipient_iter->second.emails.size(), 2U);
        BOOST_CHECK_EQUAL(dkdm_recipient_iter->second.emails[0], "epicbob@gmail.com");
        BOOST_CHECK_EQUAL(dkdm_recipient_iter->second.emails[1], "boblikesemlong@cinema-bob.com");
-       BOOST_CHECK_EQUAL(dkdm_recipient_iter->second.recipient->subject_dn_qualifier(), "r5/Q5f3UTm7qzoF5QzNZP6aEuvI=");
+       BOOST_CHECK_EQUAL(dkdm_recipient_iter->second.recipient()->subject_dn_qualifier(), "r5/Q5f3UTm7qzoF5QzNZP6aEuvI=");
        ++dkdm_recipient_iter;
 
        BOOST_CHECK_EQUAL(dkdm_recipient_iter->second.name, "Sharon's Shorts");
        BOOST_CHECK_EQUAL(dkdm_recipient_iter->second.notes, "Even if it sucks, at least it's over quickly");
-       BOOST_CHECK_EQUAL(dkdm_recipient_iter->second.recipient->subject_dn_qualifier(), "FHerM3Us/DWuqD1MnztStSlFJO0=");
+       BOOST_CHECK_EQUAL(dkdm_recipient_iter->second.recipient()->subject_dn_qualifier(), "FHerM3Us/DWuqD1MnztStSlFJO0=");
        ++dkdm_recipient_iter;
 }