Skip to content

Commit

Permalink
Merge pull request #1605 from CastagnaIT/drmProp_omega
Browse files Browse the repository at this point in the history
[backport][KodiProps] New drm_legacy, removed drm property
  • Loading branch information
CastagnaIT authored Jul 25, 2024
2 parents 450b953 + a85ac8b commit e41fcb0
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 7 deletions.
2 changes: 1 addition & 1 deletion inputstream.adaptive/addon.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
name="adaptive"
extension=""
tags="true"
listitemprops="drm|license_type|license_key|license_url|license_url_append|license_data|license_flags|manifest_type|server_certificate|manifest_update_parameter|manifest_upd_params|manifest_params|manifest_headers|stream_params|stream_headers|original_audio_language|play_timeshift_buffer|pre_init_data|stream_selection_type|chooser_bandwidth_max|chooser_resolution_max|chooser_resolution_secure_max|live_delay|internal_cookies|config|manifest_config"
listitemprops="drm_legacy|license_type|license_key|license_url|license_url_append|license_data|license_flags|manifest_type|server_certificate|manifest_update_parameter|manifest_upd_params|manifest_params|manifest_headers|stream_params|stream_headers|original_audio_language|play_timeshift_buffer|pre_init_data|stream_selection_type|chooser_bandwidth_max|chooser_resolution_max|chooser_resolution_secure_max|live_delay|internal_cookies|config|manifest_config"
library_@PLATFORM@="@LIBRARY_FILENAME@"/>
<extension point="xbmc.addon.metadata">
<platform>@PLATFORM@</platform>
Expand Down
111 changes: 106 additions & 5 deletions src/CompKodiProps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "CompSettings.h"
#include "decrypters/Helpers.h"
#include "utils/StringUtils.h"
#include "utils/UrlUtils.h"
#include "utils/Utils.h"
#include "utils/log.h"

Expand Down Expand Up @@ -55,6 +56,8 @@ constexpr std::string_view PROP_PRE_INIT_DATA = "inputstream.adaptive.pre_init_d

constexpr std::string_view PROP_CONFIG = "inputstream.adaptive.config";
constexpr std::string_view PROP_DRM = "inputstream.adaptive.drm";
constexpr std::string_view PROP_DRM_LEGACY = "inputstream.adaptive.drm_legacy";

constexpr std::string_view PROP_INTERNAL_COOKIES = "inputstream.adaptive.internal_cookies"; //! @todo: to remove on Kodi 22

// Chooser's properties
Expand Down Expand Up @@ -230,6 +233,7 @@ ADP::KODI_PROPS::CCompKodiProps::CCompKodiProps(const std::map<std::string, std:
{
ParseManifestConfig(prop.second);
}
/* for future DRM properties rework
else if (prop.first == PROP_DRM && !prop.second.empty())
{
if (!ParseDrmConfig(prop.second))
Expand All @@ -238,6 +242,15 @@ ADP::KODI_PROPS::CCompKodiProps::CCompKodiProps(const std::map<std::string, std:
logPropValRedacted = true;
}
*/
else if (prop.first == PROP_DRM_LEGACY && !prop.second.empty())
{
if (!ParseDrmLegacyConfig(prop.second))
LOG::LogF(LOGERROR, "Cannot parse \"%s\" property, wrong or malformed data.",
prop.first.c_str());

logPropValRedacted = true;
}
else
{
LOG::Log(LOGWARNING, "Property found \"%s\" is not supported", prop.first.c_str());
Expand All @@ -263,7 +276,7 @@ ADP::KODI_PROPS::CCompKodiProps::CCompKodiProps(const std::map<std::string, std:
LOG::Log(
LOGERROR,
"The \"inputstream.adaptive.license_key\" property cannot be used to configure ClearKey DRM,\n"
"use \"inputstream.adaptive.drm\" instead.\nSee Wiki integration page for more details.");
"use \"inputstream.adaptive.drm_legacy\" instead.\nSee Wiki integration page for more details.");
m_licenseKey.clear();
}
}
Expand Down Expand Up @@ -394,15 +407,103 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmConfig(const std::string& data)
continue;
}

if (jDictVal.HasMember("keyids") && jDictVal["keyids"].IsObject())
if (jDictVal.HasMember("license") && jDictVal["license"].IsObject())
{
auto& jDictLic = jDictVal["license"];

if (jDictLic.HasMember("keyids") && jDictLic["keyids"].IsArray())
{
for (auto const& keyid : jDictLic["keyids"].GetObject())
{
if (keyid.name.IsString() && keyid.value.IsString())
drmCfg.m_keys[keyid.name.GetString()] = (keyid.value.GetString());
}
}
}
}

return true;
}

bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmLegacyConfig(const std::string& data)
{
// Legacy way to configure a DRM.
// Designed to have a minimal configuration for the most common use cases using a single DRM.

/* Expected TEXT structure:
* [DRM KeySystem] | [License server URL or KeyId's] | [License server headers]
*
* From 1 to 3 fields, splitted by pipes
*/

std::vector<std::string> pipedCfg = STRING::SplitToVec(data, '|');
if (pipedCfg.size() > 3)
{
LOG::LogF(LOGERROR, "Malformed value on the DRM legacy property");
return false;
}

std::string keySystem = STRING::Trim(pipedCfg[0]);

std::string licenseStr;
if (pipedCfg.size() > 1)
licenseStr = STRING::Trim(pipedCfg[1]);

std::string licenseHeaders;
if (pipedCfg.size() > 2)
licenseHeaders = STRING::Trim(pipedCfg[2]);

if (!DRM::IsKeySystemSupported(keySystem))
{
LOG::LogF(LOGERROR, "Unknown key system \"%s\" on DRM legacy property", keySystem.data());
return false;
}

m_licenseType = keySystem;

// Clear existing value to prevent possible mix with other similar properties
m_licenseKey.clear();

if (!licenseStr.empty())
{
if (URL::IsValidUrl(licenseStr)) // License server URL
{
m_licenseKey = licenseStr;
}
else // Assume are keyid's for ClearKey DRM
{
for (auto const& keyid : jDictVal["keyids"].GetObject())
// Expected TEXT structure: "kid1:key1,kid2:key2,..."
DrmCfg& drmCfg = m_drmConfigs[keySystem];
std::vector<std::string> keyIdPair = STRING::SplitToVec(licenseStr, ',');

for (const std::string& keyPairStr : keyIdPair)
{
if (keyid.name.IsString() && keyid.value.IsString())
drmCfg.m_keys[keyid.name.GetString()] = (keyid.value.GetString());
std::vector<std::string> keyPair = STRING::SplitToVec(keyPairStr, ':');
if (keyPair.size() != 2)
{
LOG::LogF(LOGERROR, "Ignored malformed ClearKey kid/key pair");
continue;
}
drmCfg.m_keys[STRING::Trim(keyPair[0])] = STRING::Trim(keyPair[1]);
}
}
}

//! @todo: temporary stored default DRM values here just for convenience
//! since we need to construct the "license key" string
//! these values are stored also on DRM's implementation,
//! they must be placed in an appropriate place with the future DRM config rework
if (licenseHeaders.empty())
{
if (keySystem == DRM::KS_WIDEVINE)
licenseHeaders = "Content-Type=application%2Foctet-stream";
else if (keySystem == DRM::KS_PLAYREADY)
licenseHeaders = "Content-Type=text%2Fxml&SOAPAction=http%3A%2F%2Fschemas.microsoft.com%"
"2FDRM%2F2007%2F03%2Fprotocols%2FAcquireLicense";
else if (keySystem == DRM::KS_WISEPLAY)
licenseHeaders = "Content-Type=application/json";
}

m_licenseKey += "|" + licenseHeaders + "|R{SSM}|R";
return true;
}
1 change: 1 addition & 0 deletions src/CompKodiProps.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ class ATTR_DLL_LOCAL CCompKodiProps
void ParseManifestConfig(const std::string& data);

bool ParseDrmConfig(const std::string& data);
bool ParseDrmLegacyConfig(const std::string& data);

std::string m_licenseType;
std::string m_licenseKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ CClearKeyCencSingleSampleDecrypter::CClearKeyCencSingleSampleDecrypter(
if (STRING::KeyExists(keys, hexDefKid))
UTILS::STRING::ToHexBytes(keys.at(hexDefKid), hexKey);
else
LOG::LogF(LOGERROR, "Missing KeyId \"%s\" on DRM configuration");
LOG::LogF(LOGERROR, "Missing KeyId \"%s\" on DRM configuration", defaultKeyId.data());
}

const AP4_UI08* ap4Key = reinterpret_cast<const AP4_UI08*>(hexKey.data());
Expand Down

0 comments on commit e41fcb0

Please sign in to comment.