/*
- Copyright (C) 2015-2017 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2015-2019 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
#include "wx/editable_list.h"
#include "wx/static_text.h"
#include "wx/dcpomatic_button.h"
+#include "wx/nag_dialog.h"
#include "lib/config.h"
#include "lib/util.h"
#include "lib/screen.h"
#include "lib/job_manager.h"
-#include "lib/screen_kdm.h"
+#include "lib/screen_with_kdm.h"
#include "lib/exceptions.h"
#include "lib/cinema_kdms.h"
#include "lib/send_kdm_email_job.h"
#include "lib/cinema.h"
#include "lib/dkdm_wrapper.h"
#include "lib/cross.h"
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+#include "lib/decrypted_ecinema_kdm.h"
+#endif
#include <dcp/encrypted_kdm.h>
#include <dcp/decrypted_kdm.h>
#include <dcp/exceptions.h>
using boost::optional;
using boost::ref;
using boost::dynamic_pointer_cast;
+using namespace dcpomatic;
enum {
ID_help_report_a_problem = 1,
dkdm_buttons->Add (_add_dkdm_folder, 0, wxALL | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
_remove_dkdm = new Button (overall_panel, _("Remove"));
dkdm_buttons->Add (_remove_dkdm, 0, wxALL | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
+ _export_dkdm = new Button (overall_panel, _("Export..."));
+ dkdm_buttons->Add (_export_dkdm, 0, wxALL | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
dkdm_sizer->Add (dkdm_buttons, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
right->Add (dkdm_sizer, 1, wxEXPAND | wxALL, DCPOMATIC_SIZER_Y_GAP);
_add_dkdm->Bind (wxEVT_BUTTON, bind (&DOMFrame::add_dkdm_clicked, this));
_add_dkdm_folder->Bind (wxEVT_BUTTON, bind (&DOMFrame::add_dkdm_folder_clicked, this));
_remove_dkdm->Bind (wxEVT_BUTTON, bind (&DOMFrame::remove_dkdm_clicked, this));
+ _export_dkdm->Bind (wxEVT_BUTTON, bind (&DOMFrame::export_dkdm_clicked, this));
setup_sensitivity ();
}
if (!dkdm_base) {
return;
}
- shared_ptr<DKDM> dkdm = boost::dynamic_pointer_cast<DKDM> (dkdm_base);
- if (!dkdm) {
- return;
- }
- /* Decrypt the DKDM */
- dcp::DecryptedKDM decrypted (dkdm->dkdm(), Config::instance()->decryption_chain()->key().get());
-
- /* This is the signer for our new KDMs */
- shared_ptr<const dcp::CertificateChain> signer = Config::instance()->signer_chain ();
- if (!signer->valid ()) {
- throw InvalidSignerError ();
+ list<shared_ptr<ScreenWithKDM> > screen_kdms;
+ string title;
+
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+ shared_ptr<ECinemaDKDM> ecinema_dkdm = boost::dynamic_pointer_cast<ECinemaDKDM> (dkdm_base);
+ if (ecinema_dkdm) {
+ DecryptedECinemaKDM decrypted (ecinema_dkdm->dkdm(), Config::instance()->decryption_chain()->key().get());
+ title = decrypted.name ();
+
+ BOOST_FOREACH (shared_ptr<Screen> i, _screens->screens()) {
+
+ if (!i->recipient) {
+ continue;
+ }
+
+ DecryptedECinemaKDM kdm (
+ decrypted.id(),
+ decrypted.name(),
+ decrypted.key(),
+ dcp::LocalTime (_timing->from(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
+ dcp::LocalTime (_timing->until(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute())
+ );
+
+ /* Encrypt */
+ screen_kdms.push_back (
+ shared_ptr<ScreenWithKDM>(
+ new ECinemaScreenWithKDM(i, kdm.encrypt(i->recipient.get()))
+ )
+ );
+ }
}
+#endif
- list<ScreenKDM> screen_kdms;
- BOOST_FOREACH (shared_ptr<Screen> i, _screens->screens()) {
+ shared_ptr<DKDM> dkdm = boost::dynamic_pointer_cast<DKDM> (dkdm_base);
+ if (dkdm) {
- if (!i->recipient) {
- continue;
- }
+ /* Decrypt the DKDM */
+ dcp::DecryptedKDM decrypted (dkdm->dkdm(), Config::instance()->decryption_chain()->key().get());
+ title = decrypted.content_title_text ();
- /* Make an empty KDM */
- dcp::DecryptedKDM kdm (
- dcp::LocalTime (_timing->from(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
- dcp::LocalTime (_timing->until(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
- decrypted.annotation_text().get_value_or (""),
- decrypted.content_title_text(),
- dcp::LocalTime().as_string()
- );
-
- /* Add keys from the DKDM */
- BOOST_FOREACH (dcp::DecryptedKDMKey const & j, decrypted.keys()) {
- kdm.add_key (j);
+ /* This is the signer for our new KDMs */
+ shared_ptr<const dcp::CertificateChain> signer = Config::instance()->signer_chain ();
+ if (!signer->valid ()) {
+ throw InvalidSignerError ();
}
- /* Encrypt */
- screen_kdms.push_back (
- ScreenKDM (
- i,
- kdm.encrypt (
- signer, i->recipient.get(), i->trusted_device_thumbprints(), _output->formulation(),
- !_output->forensic_mark_video(), _output->forensic_mark_audio() ? boost::optional<int>() : 0
+ BOOST_FOREACH (shared_ptr<Screen> i, _screens->screens()) {
+
+ if (!i->recipient) {
+ continue;
+ }
+
+ /* Make an empty KDM */
+ dcp::DecryptedKDM kdm (
+ dcp::LocalTime (_timing->from(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
+ dcp::LocalTime (_timing->until(), i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
+ decrypted.annotation_text().get_value_or (""),
+ decrypted.content_title_text(),
+ dcp::LocalTime().as_string()
+ );
+
+ /* Add keys from the DKDM */
+ BOOST_FOREACH (dcp::DecryptedKDMKey const & j, decrypted.keys()) {
+ kdm.add_key (j);
+ }
+
+ /* Encrypt */
+ screen_kdms.push_back (
+ shared_ptr<ScreenWithKDM>(
+ new DCPScreenWithKDM(
+ i,
+ kdm.encrypt(
+ signer, i->recipient.get(), i->trusted_device_thumbprints(), _output->formulation(),
+ !_output->forensic_mark_video(), _output->forensic_mark_audio() ? boost::optional<int>() : 0
+ )
+ )
)
- )
- );
+ );
+ }
+ }
+
+ if (screen_kdms.empty()) {
+ return;
}
pair<shared_ptr<Job>, int> result = _output->make (
- screen_kdms, decrypted.content_title_text(), _timing, bind (&DOMFrame::confirm_overwrite, this, _1)
+ screen_kdms, title, _timing, bind (&DOMFrame::confirm_overwrite, this, _1)
);
if (result.first) {
_output->setup_sensitivity ();
wxArrayTreeItemIds sel;
_dkdm->GetSelections (sel);
+ shared_ptr<DKDMGroup> group = dynamic_pointer_cast<DKDMGroup>(selected_dkdm());
+ shared_ptr<DKDM> dkdm = dynamic_pointer_cast<DKDM>(selected_dkdm());
_create->Enable (!_screens->screens().empty() && sel.GetCount() > 0);
+ _remove_dkdm->Enable (sel.GetCount() > 0 && (!group || group->name() != "root"));
+ _export_dkdm->Enable (sel.GetCount() > 0 && dkdm);
}
void dkdm_begin_drag (wxTreeEvent& ev)
{
wxFileDialog* d = new wxFileDialog (this, _("Select DKDM file"));
if (d->ShowModal() == wxID_OK) {
- shared_ptr<DKDMBase> new_dkdm;
+ shared_ptr<const dcp::CertificateChain> chain = Config::instance()->decryption_chain();
+ DCPOMATIC_ASSERT (chain->key());
+
+#ifdef DCPOMATIC_VARIANT_SWAROOP
try {
- dcp::EncryptedKDM ekdm(dcp::file_to_string (wx_to_std (d->GetPath ()), MAX_KDM_SIZE));
+ cxml::Document test_doc;
+ string const xml_string = dcp::file_to_string (wx_to_std(d->GetPath()), MAX_KDM_SIZE);
+ test_doc.read_string (xml_string);
+ if (test_doc.root_name() == "ECinemaSecurityMessage") {
+ EncryptedECinemaKDM ekdm(xml_string);
+ /* Decrypt the DKDM to make sure that we can */
+ DecryptedECinemaKDM dkdm(ekdm, chain->key().get());
+
+ shared_ptr<DKDMBase> new_dkdm(new ECinemaDKDM(ekdm));
+ shared_ptr<DKDMGroup> group = dynamic_pointer_cast<DKDMGroup> (selected_dkdm());
+ if (!group) {
+ group = Config::instance()->dkdms();
+ }
+ add_dkdm_model (new_dkdm, group);
+ add_dkdm_view (new_dkdm);
+ d->Destroy ();
+ return;
+ }
+ } catch (KDMError& e) {
+ error_dialog (
+ this, "Could not read file as a KDM. Perhaps it is badly formatted, created with the wrong certificate, or not a KDM at all.",
+ std_to_wx(e.what())
+ );
+ d->Destroy ();
+ return;
+ } catch (dcp::MiscError& e) {
+ error_dialog (
+ this,
+ _("Could not read file as a KDM. It is much too large. Make sure you are loading a DKDM (XML) file."),
+ std_to_wx(e.what())
+ );
+ d->Destroy ();
+ return;
+ }
+#endif
+ try {
+ dcp::EncryptedKDM ekdm(dcp::file_to_string (wx_to_std (d->GetPath ()), MAX_KDM_SIZE));
/* Decrypt the DKDM to make sure that we can */
- shared_ptr<const dcp::CertificateChain> chain = Config::instance()->decryption_chain();
- DCPOMATIC_ASSERT (chain->key());
dcp::DecryptedKDM dkdm(ekdm, chain->key().get());
- new_dkdm.reset(new DKDM(ekdm));
+ shared_ptr<DKDMBase> new_dkdm(new DKDM(ekdm));
shared_ptr<DKDMGroup> group = dynamic_pointer_cast<DKDMGroup> (selected_dkdm ());
if (!group) {
group = Config::instance()->dkdms ();
std_to_wx(e.what())
);
return;
- } catch (dcp::KDMDecryptionError) {
+ } catch (dcp::KDMDecryptionError &) {
error_dialog (
this,
_("Could not decrypt the DKDM. Perhaps it was not created with the correct certificate.")
return;
}
+ if (NagDialog::maybe_nag (
+ this, Config::NAG_DELETE_DKDM,
+ _("You are about to remove a DKDM. This will make it impossible to decrypt the DCP that the DKDM was made for, and it cannot be undone. "
+ "Are you sure?"),
+ true)) {
+ return;
+ }
+
_dkdm->Delete (dkdm_to_id (removed));
shared_ptr<DKDMGroup> dkdms = Config::instance()->dkdms ();
dkdms->remove (removed);
Config::instance()->changed ();
}
+ void export_dkdm_clicked ()
+ {
+ shared_ptr<DKDMBase> removed = selected_dkdm ();
+ if (!removed) {
+ return;
+ }
+
+ shared_ptr<DKDM> dkdm = dynamic_pointer_cast<DKDM>(removed);
+ if (!dkdm) {
+ return;
+ }
+
+ wxFileDialog* d = new wxFileDialog (
+ this, _("Select DKDM File"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"),
+ wxFD_SAVE | wxFD_OVERWRITE_PROMPT
+ );
+
+ if (d->ShowModal() == wxID_OK) {
+ dkdm->dkdm().as_xml(wx_to_std(d->GetPath()));
+ }
+ d->Destroy ();
+ }
+
wxPreferencesEditor* _config_dialog;
ScreensPanel* _screens;
KDMTimingPanel* _timing;
wxButton* _add_dkdm;
wxButton* _add_dkdm_folder;
wxButton* _remove_dkdm;
+ wxButton* _export_dkdm;
wxButton* _create;
KDMOutputPanel* _output;
JobViewDialog* _job_view;