Automated update of OPK code
Included changes: - 676ac7be8548d80c420591fc0b4fb9a11723ef34 Backwards compatibility script for CDM v18 and OPK v19 by Vicky Min <vickymin@google.com> - 3cd4f71fda91245ac0b61c4c847950952f3021c0 Change BuildInformation ree fields to optional by Matt Feddersen <mattfedd@google.com> - a2259e95dea40c27a4be02ad479aec8f1fc84737 Created a DICE CBOR Cert parser/serializer. by Alex Dale <sigquit@google.com> - b8f2c364afeb6279e5aee6488d4527e189ac42ff Don't create invalid enum value by John "Juce" Bruce <juce@google.com> - b0aed212a3b2dd8f752d8fc43982848c1aa6c152 Created an HLS Key type. by Alex Dale <sigquit@google.com> - f8cfc54b41f124ba849596dbe6438b7f271a72b7 Specify C/C++ standard when running clang-tidy on OPK by John "Juce" Bruce <juce@google.com> GitOrigin-RevId: 676ac7be8548d80c420591fc0b4fb9a11723ef34
This commit is contained in:
210
util/include/hls_key.h
Normal file
210
util/include/hls_key.h
Normal file
@@ -0,0 +1,210 @@
|
||||
// Copyright 2025 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
#ifndef WVCDM_UTIL_HLS_KEY_H_
|
||||
#define WVCDM_UTIL_HLS_KEY_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvutil {
|
||||
class HlsAttributeList;
|
||||
|
||||
// Data wrapper types for HLS Key fields.
|
||||
//
|
||||
// Ensures that the values of each attribute of an
|
||||
// HLS key is valid. The class does not enforce contextual
|
||||
// requirements between attributes; however, IsWellFormed()
|
||||
// can optionally be called to ensure some fields are set
|
||||
// appropriately based on the values of other fields.
|
||||
//
|
||||
// This class is based on RFC 8216 section 4.3.2.4.
|
||||
class HlsKey {
|
||||
public:
|
||||
// HLS Tag for key data.
|
||||
static constexpr char kTag[] = "EXT-X-KEY";
|
||||
|
||||
// Attribute names for HLS keys.
|
||||
// METHOD is an enumerated string with three known values
|
||||
// of NONE, AES-128, or SAMPLE-AES.
|
||||
// METHOD may be a different value so long as it is a
|
||||
// valid enum string.
|
||||
// METHOD is required, if set to NONE, then the other
|
||||
// fields SHOULD NOT be set.
|
||||
static constexpr char kMethodName[] = "METHOD";
|
||||
// URI is a quoted string containing be a valid URI which
|
||||
// identifies where to find the key(s) used for content
|
||||
// decryption.
|
||||
// Must be set if METHOD is not NONE.
|
||||
// Should not be set if METHOD is NONE.
|
||||
static constexpr char kUriName[] = "URI";
|
||||
// IV is a hex sequence for a 128-bit initialization vector
|
||||
// used for decryption of media content.
|
||||
// Must be set if METHOD is not NONE.
|
||||
// Should not be set if METHOD is NONE.
|
||||
static constexpr char kIvName[] = "IV";
|
||||
// The key format is a quoted string which identifies the
|
||||
// format of the key acquired by the URI.
|
||||
// Optionally set if METHOD is not NONE, if not set, then
|
||||
// it is assumed the URI will directly acquire the key.
|
||||
// Should not be set if METHOD is NONE.
|
||||
static constexpr char kKeyFormatName[] = "KEYFORMAT";
|
||||
// The key format versions is a quoted string containing one
|
||||
// or more positive integers (of HLS integer format) separated
|
||||
// by a '/', which indicates the vendor-specific versions of the
|
||||
// key acquired via the URI.
|
||||
// Optionally set if METHOD is not NONE, assumed to contain
|
||||
// a value of 1 if not set but a version is required.
|
||||
// Should not be set if METHOD is NONE.
|
||||
static constexpr char kKeyFormatVersionsName[] = "KEYFORMATVERSIONS";
|
||||
|
||||
// List of known METHOD values.
|
||||
static constexpr char kMethodNone[] = "NONE";
|
||||
static constexpr char kMethodAes128[] = "AES-128";
|
||||
static constexpr char kMethodSampleAes[] = "SAMPLE-AES";
|
||||
|
||||
// HLS keys require an IV length of 128-bits / 16 octets.
|
||||
static constexpr size_t kIvLength = 16;
|
||||
|
||||
// Checks if the provided |method| is one of the known
|
||||
// values for the enumerated string METHOD.
|
||||
static bool IsKnownMethod(const std::string& method);
|
||||
// Checks if the provided |method| is a valid HLS enum
|
||||
// string value.
|
||||
static bool IsValidMethod(const std::string& method);
|
||||
// Simply checks that the provided URI is a valid HLS quoted
|
||||
// string value. Does not valid URI format.
|
||||
static bool IsValidUriValue(const std::string& uri);
|
||||
// Checks that the specified IV length (in octets) is a supported
|
||||
// length.
|
||||
static constexpr bool IsValidIvLength(size_t iv_length) {
|
||||
return iv_length == kIvLength;
|
||||
}
|
||||
static bool IsValidIv(const std::string& iv) {
|
||||
return IsValidIvLength(iv.size());
|
||||
}
|
||||
static bool IsValidIv(const std::vector<uint8_t>& iv) {
|
||||
return IsValidIvLength(iv.size());
|
||||
}
|
||||
// Checks that the provided key format conforms to the quoted
|
||||
// string value requirements of HLS.
|
||||
static bool IsValidKeyFormat(const std::string& key_format);
|
||||
// Checks if the specified |version| is a valid key format
|
||||
// version (must be positive).
|
||||
static constexpr bool IsValidKeyFormatVersion(uint64_t version) {
|
||||
return version > 0;
|
||||
}
|
||||
// Checks that all the values in the set of |versions| is a valid
|
||||
// versions.
|
||||
// The set of versions cannot be empty, and all versions must be a
|
||||
// positive value.
|
||||
static bool IsValidKeyFormatVersions(const std::set<uint64_t>& versions);
|
||||
// Checks that the provided formatted version list is a valid
|
||||
// representation of key format versions.
|
||||
// Note: There is no requirement that the versions are unique.
|
||||
static bool IsValidKeyFormatVersionListRep(
|
||||
const std::string& version_list_rep);
|
||||
|
||||
HlsKey() = default;
|
||||
WVCDM_DEFAULT_COPY_AND_MOVE(HlsKey);
|
||||
|
||||
const std::string& method() const { return method_; }
|
||||
bool HasMethod() const { return !method_.empty(); }
|
||||
bool SetMethod(const std::string& method);
|
||||
void ClearMethod() { method_.clear(); }
|
||||
|
||||
// URIs are only validated that they are valid quoted string
|
||||
// values; not that they are well formed URIs.
|
||||
const std::string& uri() const { return uri_; }
|
||||
bool HasUri() const { return !uri_.empty(); }
|
||||
bool SetUri(const std::string& uri);
|
||||
void ClearUri() { uri_.clear(); }
|
||||
|
||||
const std::vector<uint8_t>& iv() const { return iv_; }
|
||||
bool HasIv() const { return !iv_.empty(); }
|
||||
bool SetIv(const std::vector<uint8_t>& iv);
|
||||
bool SetIv(const std::string& iv);
|
||||
bool SetIvHex(const std::string& iv_hex);
|
||||
void ClearIv() { iv_.clear(); }
|
||||
|
||||
const std::string& key_format() const { return key_format_; }
|
||||
bool HasKeyFormat() const { return !key_format_.empty(); }
|
||||
bool SetKeyFormat(const std::string& key_format);
|
||||
void ClearKeyFormat() { key_format_.clear(); }
|
||||
|
||||
const std::set<uint64_t>& key_format_versions() const {
|
||||
return key_format_versions_;
|
||||
}
|
||||
bool HasKeyFormatVersions() const { return !key_format_versions_.empty(); }
|
||||
bool HasKeyFormatVersion(uint64_t version) const;
|
||||
bool SetKeyFormatVersions(const std::set<uint64_t>& versions);
|
||||
bool SetKeyFormatVersions(const std::vector<uint64_t>& versions);
|
||||
bool AddKeyFormatVersion(uint64_t version);
|
||||
void ClearKeyFormatVersions() { key_format_versions_.clear(); }
|
||||
|
||||
void Clear() {
|
||||
ClearMethod();
|
||||
ClearUri();
|
||||
ClearIv();
|
||||
ClearKeyFormat();
|
||||
ClearKeyFormatVersions();
|
||||
}
|
||||
|
||||
// Checks that the HLS key is well-formed based on the requirements
|
||||
// of an HLS key. Relies mainly on the requirements of METHOD.
|
||||
bool IsWellFormed() const;
|
||||
|
||||
// == Parsing / Serialization ==
|
||||
// Initializes the HLS key from a populated instance of
|
||||
// HlsAttributeList.
|
||||
//
|
||||
// Requirements:
|
||||
// - METHOD must be set, must be one of the well-known methods.
|
||||
// - URI is optional, must be quoted string if set.
|
||||
// - IV is optional, must be a 16-byte / 128-bit hex sequence if set.
|
||||
// - KEYFORMAT is optional, must be a quoted string if set, defaults
|
||||
// to "identify" is not set.
|
||||
// - KEYFORMATVERSIONS is optional, must be a quoted string containing
|
||||
// a valid sequence of '/' separated version if set, defaults to
|
||||
// "1" if not set.
|
||||
bool FromAttributeList(const HlsAttributeList& attr_list);
|
||||
// Initializes the HLS key from the HLS serialized HLS Attribute List.
|
||||
// Internally uses FromAttributeList(), and follows the same requirements.
|
||||
bool ParseAttributeList(const std::string& attr_list_rep);
|
||||
|
||||
// Packages the HLS key into the HlsAttributeList instance.
|
||||
// Clears existing data in |attr_list|.
|
||||
//
|
||||
// Serializing does not enforce any field requirements other than
|
||||
// types.
|
||||
//
|
||||
// Follows the following rules:
|
||||
// - METHOD packaged as enum string if set
|
||||
// - URI packaged as quoted string if set
|
||||
// - IV packaged as hex sequence if set
|
||||
// - KEYFORMAT packaged as quoted string if set
|
||||
// - KEYFORMATVERSIONS packaged as quoted string containing slash
|
||||
// separated version if any version is set.
|
||||
bool ToAttributeList(HlsAttributeList* attr_list) const;
|
||||
// Serializes the HLS key into an HLS attribute string format.
|
||||
// Internally uses ToAttributeList(), and follows the same packaging
|
||||
// rules.
|
||||
std::string Serialize() const;
|
||||
bool SerializeToStream(std::ostream* out) const;
|
||||
|
||||
private:
|
||||
// Values are either empty or set to valid values.
|
||||
std::string method_;
|
||||
std::string uri_;
|
||||
std::vector<uint8_t> iv_;
|
||||
std::string key_format_;
|
||||
std::set<uint64_t> key_format_versions_;
|
||||
}; // class HlsKey
|
||||
} // namespace wvutil
|
||||
#endif // WVCDM_UTIL_HLS_KEY_H_
|
||||
469
util/src/hls_key.cpp
Normal file
469
util/src/hls_key.cpp
Normal file
@@ -0,0 +1,469 @@
|
||||
// Copyright 2025 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
#include "hls_key.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "hls_attribute_list.h"
|
||||
#include "log.h"
|
||||
#include "string_conversions.h"
|
||||
#include "string_utils.h"
|
||||
|
||||
namespace wvutil {
|
||||
namespace {
|
||||
// If KEYFORMATVERSIONS specifies multiple versions, then each
|
||||
// version is separated by a '/' character.
|
||||
constexpr char kVersionSeparatorChar = '/';
|
||||
constexpr char kZeroChar = '0';
|
||||
|
||||
// RFC 8216 specifies that KEYFORMAT is optional, but when
|
||||
// METHOD is not NONE and KEYFORMAT absent, then KEYFORMAT is assumed
|
||||
// to be "identity".
|
||||
constexpr char kDefaultKeyFormat[] = "identity";
|
||||
// RFC 8216 specifies that KEYFORMATVERSIONS is optional, but when
|
||||
// METHOD is not NONE, and KEYFORMATVERSIONS absent, then
|
||||
// KEYFORMATVERSIONS is assumed to be "1".
|
||||
constexpr uint64_t kDefaultKeyFormatVersion = 1;
|
||||
|
||||
// Checks each version in the |versions| container are valid
|
||||
// values.
|
||||
template <class Container>
|
||||
bool IsValidKeyFormatVersionsInternal(const Container& versions) {
|
||||
// Container should be of uint64_t.
|
||||
static_assert(std::is_same_v<typename Container::value_type, uint64_t>,
|
||||
"Container must have values of uint64_t");
|
||||
if (versions.empty()) return false;
|
||||
// Note: Duplicate values are technically not invalid.
|
||||
return std::all_of(versions.begin(), versions.end(),
|
||||
HlsKey::IsValidKeyFormatVersion);
|
||||
}
|
||||
|
||||
bool IsValidKeyFormatVersionRep(const std::string& version_rep) {
|
||||
// Must be a valid HLS integer.
|
||||
if (!HlsAttributeList::IsValidIntegerRep(version_rep)) return false;
|
||||
// Version cannot be zero.
|
||||
// Note: HLS integer strings may contain leading zeros, so long
|
||||
// as not all the digits are zero, the |version_rep| is valid.
|
||||
const size_t zero_count =
|
||||
std::count(version_rep.begin(), version_rep.end(), kZeroChar);
|
||||
return zero_count < version_rep.size();
|
||||
}
|
||||
|
||||
bool ParseKeyFormatVersionList(const std::string& version_list_rep,
|
||||
std::set<uint64_t>* versions) {
|
||||
versions->clear();
|
||||
const std::vector<std::string> version_reps =
|
||||
StringSplit(version_list_rep, kVersionSeparatorChar);
|
||||
if (version_reps.empty()) {
|
||||
LOGV("Invalid key format version list rep");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& version_rep : version_reps) {
|
||||
uint64_t version = 0;
|
||||
if (!HlsAttributeList::ParseInteger(version_rep, &version)) {
|
||||
LOGV("Failed to parse key format version: %s", version_rep.c_str());
|
||||
versions->clear();
|
||||
return false;
|
||||
}
|
||||
if (!HlsKey::IsValidKeyFormatVersion(version)) {
|
||||
LOGV("Found invalid key format version: %" PRIu64, version);
|
||||
versions->clear();
|
||||
return false;
|
||||
}
|
||||
versions->insert(version);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string KeyFormatVersionsToString(const std::vector<uint64_t>& versions) {
|
||||
std::string result;
|
||||
for (const uint64_t& version : versions) {
|
||||
// Ensure each version is separated by a '/' character.
|
||||
if (!result.empty()) result.push_back(kVersionSeparatorChar);
|
||||
result.append(std::to_string(version));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string KeyFormatVersionsToString(const std::set<uint64_t>& versions) {
|
||||
// std::set are not necessarily sorted. Converting to a vector
|
||||
// to allow formatting in ascending order.
|
||||
std::vector<uint64_t> versions_vec(versions.begin(), versions.end());
|
||||
std::sort(versions_vec.begin(), versions_vec.end());
|
||||
return KeyFormatVersionsToString(versions_vec);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
bool HlsKey::IsKnownMethod(const std::string& method) {
|
||||
return method == kMethodNone || method == kMethodAes128 ||
|
||||
method == kMethodSampleAes;
|
||||
}
|
||||
|
||||
// static
|
||||
bool HlsKey::IsValidMethod(const std::string& method) {
|
||||
return !method.empty() && HlsAttributeList::IsValidEnumStringValue(method);
|
||||
}
|
||||
|
||||
// static
|
||||
bool HlsKey::IsValidUriValue(const std::string& uri) {
|
||||
return !uri.empty() && HlsAttributeList::IsValidQuotedStringValue(uri);
|
||||
}
|
||||
|
||||
// static
|
||||
bool HlsKey::IsValidKeyFormat(const std::string& key_format) {
|
||||
return !key_format.empty() &&
|
||||
HlsAttributeList::IsValidQuotedStringValue(key_format);
|
||||
}
|
||||
|
||||
// static
|
||||
bool HlsKey::IsValidKeyFormatVersions(const std::set<uint64_t>& versions) {
|
||||
return IsValidKeyFormatVersionsInternal(versions);
|
||||
}
|
||||
|
||||
// static
|
||||
bool HlsKey::IsValidKeyFormatVersionListRep(
|
||||
const std::string& version_list_rep) {
|
||||
const std::vector<std::string> version_reps =
|
||||
StringSplit(version_list_rep, kVersionSeparatorChar);
|
||||
if (version_reps.empty()) return false;
|
||||
return std::all_of(version_reps.begin(), version_reps.end(),
|
||||
IsValidKeyFormatVersionRep);
|
||||
}
|
||||
|
||||
bool HlsKey::SetMethod(const std::string& method) {
|
||||
if (!IsValidMethod(method)) {
|
||||
LOGV("Invalid method: %s", SafeByteIdToString(method).c_str());
|
||||
return false;
|
||||
}
|
||||
method_ = method;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HlsKey::SetUri(const std::string& uri) {
|
||||
if (!IsValidUriValue(uri)) {
|
||||
LOGV("Invalid URI: %s", SafeByteIdToString(uri).c_str());
|
||||
return false;
|
||||
}
|
||||
uri_ = uri;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HlsKey::SetIv(const std::vector<uint8_t>& iv) {
|
||||
if (!IsValidIv(iv)) {
|
||||
LOGV("Invalid IV: 0x%s (length = %zu)", b2a_hex(iv).c_str(), iv.size());
|
||||
return false;
|
||||
}
|
||||
iv_ = iv;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HlsKey::SetIv(const std::string& iv) {
|
||||
if (!IsValidIv(iv)) {
|
||||
LOGV("Invalid IV: 0x%s (length = %zu)", b2a_hex(iv).c_str(), iv.size());
|
||||
return false;
|
||||
}
|
||||
iv_.assign(iv.begin(), iv.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HlsKey::SetIvHex(const std::string& iv_hex) {
|
||||
std::vector<uint8_t> iv = a2b_hex(iv_hex);
|
||||
if (iv.empty() && !iv_hex.empty()) {
|
||||
LOGV("Invalid IV hex: %s", SafeByteIdToString(iv_hex).c_str());
|
||||
return false;
|
||||
}
|
||||
if (!IsValidIv(iv)) {
|
||||
LOGV("Invalid IV: 0x%s (length = %zu)", b2a_hex(iv).c_str(), iv.size());
|
||||
return false;
|
||||
}
|
||||
iv_ = std::move(iv);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HlsKey::SetKeyFormat(const std::string& key_format) {
|
||||
if (!IsValidKeyFormat(key_format)) {
|
||||
LOGV("Invalid key format: %s", SafeByteIdToString(key_format).c_str());
|
||||
return false;
|
||||
}
|
||||
key_format_ = key_format;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HlsKey::HasKeyFormatVersion(uint64_t version) const {
|
||||
return key_format_versions_.find(version) != key_format_versions_.end();
|
||||
}
|
||||
|
||||
bool HlsKey::SetKeyFormatVersions(const std::set<uint64_t>& versions) {
|
||||
if (!IsValidKeyFormatVersionsInternal(versions)) {
|
||||
LOGV("Invalid key format versions: %s",
|
||||
KeyFormatVersionsToString(versions).c_str());
|
||||
return false;
|
||||
}
|
||||
key_format_versions_ = versions;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HlsKey::SetKeyFormatVersions(const std::vector<uint64_t>& versions) {
|
||||
if (!IsValidKeyFormatVersionsInternal(versions)) {
|
||||
LOGV("Invalid key format versions: %s",
|
||||
KeyFormatVersionsToString(versions).c_str());
|
||||
return false;
|
||||
}
|
||||
key_format_versions_.clear();
|
||||
key_format_versions_.insert(versions.begin(), versions.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HlsKey::AddKeyFormatVersion(uint64_t version) {
|
||||
if (!IsValidKeyFormatVersion(version)) {
|
||||
LOGV("Invalid key format version: %" PRIu64, version);
|
||||
return false;
|
||||
}
|
||||
key_format_versions_.insert(version);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HlsKey::IsWellFormed() const {
|
||||
// METHOD is always required.
|
||||
if (!HasMethod()) {
|
||||
LOGV("Missing method");
|
||||
return false;
|
||||
}
|
||||
if (method() == kMethodNone) {
|
||||
// From RFC 8216, section 4.3.2.4:
|
||||
// If the encryption method is NONE, other attributes
|
||||
// MUST NOT be present.
|
||||
if (HasUri()) {
|
||||
LOGV("URI not allowed if method is NONE: uri = %s", uri_.c_str());
|
||||
return false;
|
||||
}
|
||||
if (HasIv()) {
|
||||
LOGV("IV not allowed if method is NONE: iv = 0x%s", b2a_hex(iv_).c_str());
|
||||
return false;
|
||||
}
|
||||
if (HasKeyFormat()) {
|
||||
LOGV("Key format not allowed if method is NONE: key_format = %s",
|
||||
key_format_.c_str());
|
||||
return false;
|
||||
}
|
||||
if (HasKeyFormatVersions()) {
|
||||
LOGV(
|
||||
"Key format versions are not allowed if method is NONE: "
|
||||
"key_format_versions = %s",
|
||||
KeyFormatVersionsToString(key_format_versions_).c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// METHOD != NONE
|
||||
|
||||
// URI is the only required field if METHOD is not NONE.
|
||||
if (!HasUri()) {
|
||||
LOGV("Missing URI");
|
||||
return false;
|
||||
}
|
||||
// IV, key format and key format versions are optional fields.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HlsKey::FromAttributeList(const HlsAttributeList& list) {
|
||||
if (list.IsEmpty()) {
|
||||
LOGV("HLS attribute list is empty");
|
||||
return false;
|
||||
}
|
||||
if (!list.IsType(kMethodName, HlsAttributeList::kEnumStringType)) {
|
||||
LOGV("HLS attribute list is missing METHOD");
|
||||
return false;
|
||||
}
|
||||
std::string method;
|
||||
if (!list.GetEnumString(kMethodName, &method)) {
|
||||
// Definitely an error as the check above should
|
||||
// ensure method is available.
|
||||
LOGE("Failed to get METHOD");
|
||||
return false;
|
||||
}
|
||||
if (!IsValidMethod(method)) {
|
||||
LOGV("Invalid method: %s", method.c_str());
|
||||
return false;
|
||||
}
|
||||
if (method == kMethodNone) {
|
||||
// Ignore all other fields.
|
||||
Clear();
|
||||
method_ = std::move(method);
|
||||
return true;
|
||||
}
|
||||
|
||||
// URI is the only required field.
|
||||
if (!list.IsType(kUriName, HlsAttributeList::kQuotedStringType)) {
|
||||
LOGV("HLS attribute list is missing URI");
|
||||
return false;
|
||||
}
|
||||
std::string uri;
|
||||
if (!list.GetQuotedString(kUriName, &uri)) {
|
||||
LOGE("Failed to get URI");
|
||||
return false;
|
||||
}
|
||||
if (!IsValidUriValue(uri)) {
|
||||
LOGV("Invalid URI: \"%s\"", uri.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> iv;
|
||||
if (list.IsType(kIvName, HlsAttributeList::kHexSequenceType)) {
|
||||
if (!list.GetHexSequence(kIvName, &iv)) {
|
||||
LOGE("Failed to get IV");
|
||||
return false;
|
||||
}
|
||||
if (!IsValidIv(iv)) {
|
||||
// Note: hex sequences are never empty.
|
||||
LOGV("Invalid IV: 0x%s", b2a_hex(iv).c_str());
|
||||
return false;
|
||||
}
|
||||
} else if (list.Contains(kIvName)) {
|
||||
LOGV("HLS attribute list contains an invalid IV");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string key_format = kDefaultKeyFormat;
|
||||
if (list.IsType(kKeyFormatName, HlsAttributeList::kQuotedStringType)) {
|
||||
if (!list.GetQuotedString(kKeyFormatName, &key_format)) {
|
||||
LOGE("Failed to get KEYFORMAT");
|
||||
return false;
|
||||
}
|
||||
if (!IsValidKeyFormat(key_format)) {
|
||||
LOGV("Invalid key format: \"%s\"", key_format.c_str());
|
||||
return false;
|
||||
}
|
||||
} else if (list.Contains(kKeyFormatName)) {
|
||||
LOGV("HLS attribute list contains an invalid KEYFORMAT");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<uint64_t> versions = {kDefaultKeyFormatVersion};
|
||||
if (list.IsType(kKeyFormatVersionsName,
|
||||
HlsAttributeList::kQuotedStringType)) {
|
||||
versions.clear();
|
||||
std::string version_list_rep;
|
||||
if (!list.GetQuotedString(kKeyFormatVersionsName, &version_list_rep)) {
|
||||
LOGE("Failed to get KEYFORMATVERSIONS");
|
||||
return false;
|
||||
}
|
||||
if (!IsValidKeyFormatVersionListRep(version_list_rep)) {
|
||||
LOGV("Invalid key format versions: \"%s\"", version_list_rep.c_str());
|
||||
return false;
|
||||
}
|
||||
if (!ParseKeyFormatVersionList(version_list_rep, &versions)) {
|
||||
LOGE("Failed to parse key format versions: \"%s\"",
|
||||
version_list_rep.c_str());
|
||||
return false;
|
||||
}
|
||||
} else if (list.Contains(kKeyFormatVersionsName)) {
|
||||
LOGV("HLS attribute list contains an invalid KEYFORMATVERSIONS");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore all other fields as they might be from a future HLS version.
|
||||
method_ = std::move(method);
|
||||
uri_ = std::move(uri);
|
||||
iv_ = std::move(iv);
|
||||
key_format_ = std::move(key_format);
|
||||
key_format_versions_ = std::move(versions);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HlsKey::ParseAttributeList(const std::string& list_rep) {
|
||||
if (list_rep.empty()) {
|
||||
LOGV("HLS attribute list rep is empty");
|
||||
return false;
|
||||
}
|
||||
HlsAttributeList list;
|
||||
if (!list.Parse(list_rep)) {
|
||||
LOGV("Failed to parse HLS attribute list");
|
||||
return false;
|
||||
}
|
||||
return FromAttributeList(list);
|
||||
}
|
||||
|
||||
// Note: Any value that is set is assumed to able to
|
||||
// produce a valid HLS attribute value, and therefore, setting
|
||||
// the attribute should be successful. Failure to do so is
|
||||
// considered an internal error.
|
||||
bool HlsKey::ToAttributeList(HlsAttributeList* list) const {
|
||||
if (list == nullptr) {
|
||||
LOGE("Output |list| is null");
|
||||
return false;
|
||||
}
|
||||
if (!IsWellFormed()) {
|
||||
// Serialize anyways.
|
||||
LOGW("Current HLS key is incomplete");
|
||||
}
|
||||
|
||||
list->Clear();
|
||||
if (HasMethod() && !list->SetEnumString(kMethodName, method_)) {
|
||||
LOGE("Failed to set method: %s=%s", kMethodName, method_.c_str());
|
||||
list->Clear();
|
||||
return false;
|
||||
}
|
||||
if (HasUri() && !list->SetQuotedString(kUriName, uri_)) {
|
||||
LOGE("Failed to set URI: %s=\"%s\"", kUriName, uri_.c_str());
|
||||
list->Clear();
|
||||
return false;
|
||||
}
|
||||
if (HasIv() && !list->SetHexSequence(kIvName, iv_)) {
|
||||
LOGE("Failed to set IV: %s=0x%s", kIvName, b2a_hex(iv_).c_str());
|
||||
list->Clear();
|
||||
return false;
|
||||
}
|
||||
if (HasKeyFormat() && !list->SetQuotedString(kKeyFormatName, key_format_)) {
|
||||
LOGE("Failed to set key format: %s=\"%s\"", kKeyFormatName,
|
||||
key_format_.c_str());
|
||||
list->Clear();
|
||||
return false;
|
||||
}
|
||||
if (HasKeyFormatVersions()) {
|
||||
const std::string formatted_versions =
|
||||
KeyFormatVersionsToString(key_format_versions_);
|
||||
if (!list->SetQuotedString(kKeyFormatVersionsName, formatted_versions)) {
|
||||
LOGE("Failed to set key format versions: %s=\"%s\"",
|
||||
kKeyFormatVersionsName, formatted_versions.c_str());
|
||||
list->Clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string HlsKey::Serialize() const {
|
||||
HlsAttributeList list;
|
||||
if (!ToAttributeList(&list)) {
|
||||
LOGV("Failed to convert HLS key to HLS attribute list");
|
||||
return std::string();
|
||||
}
|
||||
return list.Serialize();
|
||||
}
|
||||
|
||||
bool HlsKey::SerializeToStream(std::ostream* out) const {
|
||||
if (out == nullptr) {
|
||||
LOGE("Output stream is null");
|
||||
return false;
|
||||
}
|
||||
HlsAttributeList list;
|
||||
if (!ToAttributeList(&list)) {
|
||||
LOGV("Failed to convert HLS key to HLS attribute list");
|
||||
return false;
|
||||
}
|
||||
return list.SerializeToStream(out);
|
||||
}
|
||||
} // namespace wvutil
|
||||
866
util/test/hls_key_unittest.cpp
Normal file
866
util/test/hls_key_unittest.cpp
Normal file
@@ -0,0 +1,866 @@
|
||||
// Copyright 2025 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
#include "hls_key.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "hls_attribute_list.h"
|
||||
#include "string_conversions.h"
|
||||
|
||||
namespace wvutil {
|
||||
namespace test {
|
||||
TEST(HlsKeyTest, ClassConstants) {
|
||||
// Validity checks on the class constants.
|
||||
// Verify names.
|
||||
EXPECT_TRUE(HlsAttributeList::IsValidName(HlsKey::kMethodName))
|
||||
<< "METHOD key invalid: " << HlsKey::kMethodName;
|
||||
EXPECT_TRUE(HlsAttributeList::IsValidName(HlsKey::kUriName))
|
||||
<< "URI key invalid: " << HlsKey::kUriName;
|
||||
EXPECT_TRUE(HlsAttributeList::IsValidName(HlsKey::kIvName))
|
||||
<< "IV key invalid: " << HlsKey::kIvName;
|
||||
EXPECT_TRUE(HlsAttributeList::IsValidName(HlsKey::kKeyFormatName))
|
||||
<< "KEYFORMAT key invalid: " << HlsKey::kKeyFormatName;
|
||||
EXPECT_TRUE(HlsAttributeList::IsValidName(HlsKey::kKeyFormatVersionsName))
|
||||
<< "KEYFORMATVERSIONS key invalid: " << HlsKey::kKeyFormatVersionsName;
|
||||
|
||||
// Well-known methods.
|
||||
EXPECT_TRUE(HlsAttributeList::IsValidEnumStringValue(HlsKey::kMethodNone))
|
||||
<< "METHOD=NONE value invalid: " << HlsKey::kMethodNone;
|
||||
EXPECT_TRUE(HlsAttributeList::IsValidEnumStringValue(HlsKey::kMethodAes128))
|
||||
<< "METHOD=AES-128 value invalid: " << HlsKey::kMethodAes128;
|
||||
EXPECT_TRUE(
|
||||
HlsAttributeList::IsValidEnumStringValue(HlsKey::kMethodSampleAes))
|
||||
<< "METHOD=SAMPLE-AES value invalid: " << HlsKey::kMethodSampleAes;
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, IsValidKeyFormatVersion) {
|
||||
EXPECT_TRUE(HlsKey::IsValidKeyFormatVersion(1));
|
||||
EXPECT_TRUE(HlsKey::IsValidKeyFormatVersion(2));
|
||||
EXPECT_TRUE(HlsKey::IsValidKeyFormatVersion(1337));
|
||||
EXPECT_TRUE(
|
||||
HlsKey::IsValidKeyFormatVersion(std::numeric_limits<uint64_t>::max()));
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, IsValidKeyFormatVersion_Invalid) {
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersion(0));
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, IsValidKeyFormatVersions) {
|
||||
const std::set<uint64_t> kSingleVersion = {2};
|
||||
EXPECT_TRUE(HlsKey::IsValidKeyFormatVersions(kSingleVersion));
|
||||
|
||||
const std::set<uint64_t> kFewVersions = {1, 2, 5};
|
||||
EXPECT_TRUE(HlsKey::IsValidKeyFormatVersions(kFewVersions));
|
||||
|
||||
const std::set<uint64_t> kLargeVersion = {
|
||||
1, 2, std::numeric_limits<uint64_t>::max()};
|
||||
EXPECT_TRUE(HlsKey::IsValidKeyFormatVersions(kLargeVersion));
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, IsValidKeyFormatVersions_Invalid) {
|
||||
const std::set<uint64_t> kEmptySet;
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersions(kEmptySet));
|
||||
|
||||
const std::set<uint64_t> kZeroOnly = {0};
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersions(kZeroOnly));
|
||||
|
||||
const std::set<uint64_t> kWithZero = {0, 1, 2, 5};
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersions(kWithZero));
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, IsValidKeyFormatVersionListRep) {
|
||||
EXPECT_TRUE(HlsKey::IsValidKeyFormatVersionListRep("1"));
|
||||
EXPECT_TRUE(HlsKey::IsValidKeyFormatVersionListRep("1/2"));
|
||||
EXPECT_TRUE(HlsKey::IsValidKeyFormatVersionListRep("1/2/5"));
|
||||
EXPECT_TRUE(HlsKey::IsValidKeyFormatVersionListRep("1337"));
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, IsValidKeyFormatVersionListRep_Invalid) {
|
||||
// Empty not allowed.
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep(""));
|
||||
// Zero is not allowed.
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("0"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("0/2/5"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1/0/5"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1/2/0"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1/2/000000"));
|
||||
|
||||
// All must integers.
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("NONE"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1/NONE/4"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1/1.2/2"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1/0xDEADBEAF"));
|
||||
|
||||
// Cannot have empty values.
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("/2/5"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1//5"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1/2/"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("/"));
|
||||
|
||||
// Must be a slash separated list.
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1,0,5"));
|
||||
|
||||
// Cannot have spaces.
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep(" 1/2/5"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1 /2/5"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1/ 2/5"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1/2 /5"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1/2/ 5"));
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("1/2/5 "));
|
||||
|
||||
// Must fit in the 64-bit integer range.
|
||||
EXPECT_FALSE(HlsKey::IsValidKeyFormatVersionListRep("100000000000000000000"));
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, Empty) {
|
||||
const HlsKey key;
|
||||
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
EXPECT_FALSE(key.HasKeyFormat());
|
||||
EXPECT_FALSE(key.HasKeyFormatVersions());
|
||||
EXPECT_FALSE(key.HasKeyFormatVersion(1));
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetMethod) {
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.SetMethod("NONE"));
|
||||
EXPECT_TRUE(key.HasMethod());
|
||||
EXPECT_EQ(key.method(), "NONE");
|
||||
key.ClearMethod();
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetMethod_Invalid) {
|
||||
HlsKey key;
|
||||
// Check that an invalid cannot be set.
|
||||
EXPECT_FALSE(key.SetMethod("NOT VALID"));
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
|
||||
EXPECT_TRUE(key.SetMethod("SAMPLE-AES"));
|
||||
|
||||
// Check that setting an invalid method does not
|
||||
// overwrite the existing method.
|
||||
EXPECT_FALSE(key.SetMethod("NOT VALID"));
|
||||
EXPECT_EQ(key.method(), "SAMPLE-AES");
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetUri) {
|
||||
const std::string kSampleUri = "http://media.src/some-key";
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.SetUri(kSampleUri));
|
||||
EXPECT_TRUE(key.HasUri());
|
||||
EXPECT_EQ(key.uri(), kSampleUri);
|
||||
key.ClearUri();
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetUri_Invalid) {
|
||||
const std::string kBadUri = "No\"quotes";
|
||||
const std::string kGoodUri = "http://media.src/some-key";
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.SetUri(kBadUri));
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.SetUri(""));
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
|
||||
EXPECT_TRUE(key.SetUri(kGoodUri));
|
||||
|
||||
EXPECT_FALSE(key.SetUri(kBadUri));
|
||||
EXPECT_EQ(key.uri(), kGoodUri);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetIv_Vec) {
|
||||
const std::vector<uint8_t> kGoodIv(HlsKey::kIvLength, 42);
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.SetIv(kGoodIv));
|
||||
EXPECT_TRUE(key.HasIv());
|
||||
EXPECT_EQ(key.iv(), kGoodIv);
|
||||
key.ClearIv();
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetIv_Vec_Invalid) {
|
||||
const std::vector<uint8_t> kGoodIv(HlsKey::kIvLength, 42);
|
||||
const std::vector<uint8_t> kEmptyIv;
|
||||
const std::vector<uint8_t> kShortIv(HlsKey::kIvLength / 2, 22);
|
||||
const std::vector<uint8_t> kLargeIv(HlsKey::kIvLength * 2, 22);
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.SetIv(kEmptyIv));
|
||||
EXPECT_FALSE(key.SetIv(kShortIv));
|
||||
EXPECT_FALSE(key.SetIv(kLargeIv));
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
|
||||
EXPECT_TRUE(key.SetIv(kGoodIv));
|
||||
|
||||
EXPECT_FALSE(key.SetIv(kShortIv));
|
||||
EXPECT_EQ(key.iv(), kGoodIv);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetIv_String) {
|
||||
const std::string kGoodIv(HlsKey::kIvLength, 'x');
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.SetIv(kGoodIv));
|
||||
EXPECT_TRUE(key.HasIv());
|
||||
const std::vector<uint8_t> kGoodIvVec(kGoodIv.begin(), kGoodIv.end());
|
||||
EXPECT_EQ(key.iv(), kGoodIvVec);
|
||||
key.ClearIv();
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetIv_String_Invalid) {
|
||||
const std::vector<uint8_t> kGoodIv(HlsKey::kIvLength, 42);
|
||||
const std::string kEmptyIv;
|
||||
const std::string kShortIv(HlsKey::kIvLength / 2, 'y');
|
||||
const std::string kLargeIv(HlsKey::kIvLength * 2, 'z');
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.SetIv(kEmptyIv));
|
||||
EXPECT_FALSE(key.SetIv(kShortIv));
|
||||
EXPECT_FALSE(key.SetIv(kLargeIv));
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
|
||||
EXPECT_TRUE(key.SetIv(kGoodIv));
|
||||
|
||||
EXPECT_FALSE(key.SetIv(kShortIv));
|
||||
EXPECT_EQ(key.iv(), kGoodIv);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetIvHex) {
|
||||
const std::vector<uint8_t> kGoodIv(HlsKey::kIvLength, 42);
|
||||
const std::string kGoodIvHex = b2a_hex(kGoodIv);
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.SetIvHex(kGoodIvHex));
|
||||
EXPECT_TRUE(key.HasIv());
|
||||
EXPECT_EQ(key.iv(), kGoodIv);
|
||||
key.ClearIv();
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetIvHex_Invalid) {
|
||||
const std::vector<uint8_t> kGoodIv(HlsKey::kIvLength, 42);
|
||||
const std::string kEmptyIvHex;
|
||||
const std::string kShortIvHex(HlsKey::kIvLength, 'e');
|
||||
const std::string kLargeIvHex(HlsKey::kIvLength * 4, 'e');
|
||||
const std::string kNonHexIv(HlsKey::kIvLength * 2, 'x');
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.SetIvHex(kEmptyIvHex));
|
||||
EXPECT_FALSE(key.SetIvHex(kShortIvHex));
|
||||
EXPECT_FALSE(key.SetIvHex(kLargeIvHex));
|
||||
EXPECT_FALSE(key.SetIvHex(kNonHexIv));
|
||||
|
||||
EXPECT_TRUE(key.SetIv(kGoodIv));
|
||||
|
||||
EXPECT_FALSE(key.SetIvHex(kShortIvHex));
|
||||
EXPECT_EQ(key.iv(), kGoodIv);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetKeyFormat) {
|
||||
const std::string kGoodKeyFormat = "com.widevine";
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.SetKeyFormat(kGoodKeyFormat));
|
||||
EXPECT_TRUE(key.HasKeyFormat());
|
||||
EXPECT_EQ(key.key_format(), kGoodKeyFormat);
|
||||
key.ClearKeyFormat();
|
||||
EXPECT_FALSE(key.HasKeyFormat());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetKeyFormat_Invalid) {
|
||||
const std::string kGoodKeyFormat = "com.widevine";
|
||||
const std::string kEmptyKeyFormat;
|
||||
const std::string kInvalidKeyFormat = "com\"widevine";
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.SetKeyFormat(kEmptyKeyFormat));
|
||||
EXPECT_FALSE(key.SetKeyFormat(kInvalidKeyFormat));
|
||||
|
||||
EXPECT_TRUE(key.SetKeyFormat(kGoodKeyFormat));
|
||||
|
||||
EXPECT_FALSE(key.SetKeyFormat(kInvalidKeyFormat));
|
||||
EXPECT_EQ(key.key_format(), kGoodKeyFormat);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetKeyFormatVersions_Set) {
|
||||
const std::set<uint64_t> kSingleVersion = {3};
|
||||
const std::set<uint64_t> kFewVersions = {1, 2, 5};
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.SetKeyFormatVersions(kSingleVersion));
|
||||
EXPECT_TRUE(key.HasKeyFormatVersions());
|
||||
EXPECT_EQ(key.key_format_versions(), kSingleVersion);
|
||||
|
||||
key.ClearKeyFormatVersions();
|
||||
EXPECT_FALSE(key.HasKeyFormatVersions());
|
||||
|
||||
EXPECT_TRUE(key.SetKeyFormatVersions(kFewVersions));
|
||||
EXPECT_TRUE(key.HasKeyFormatVersions());
|
||||
EXPECT_EQ(key.key_format_versions(), kFewVersions);
|
||||
|
||||
// Ensure that set is not merging.
|
||||
EXPECT_TRUE(key.SetKeyFormatVersions(kSingleVersion));
|
||||
EXPECT_EQ(key.key_format_versions(), kSingleVersion);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetKeyFormatVersions_Set_Invalid) {
|
||||
const std::set<uint64_t> kSingleVersion = {3};
|
||||
const std::set<uint64_t> kBadVersions = {0, 2, 5};
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.SetKeyFormatVersions(kBadVersions));
|
||||
EXPECT_FALSE(key.HasKeyFormatVersions());
|
||||
|
||||
EXPECT_TRUE(key.SetKeyFormatVersions(kSingleVersion));
|
||||
|
||||
EXPECT_FALSE(key.SetKeyFormatVersions(kBadVersions));
|
||||
EXPECT_EQ(key.key_format_versions(), kSingleVersion);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetKeyFormatVersions_Vec) {
|
||||
const std::vector<uint64_t> kSingleVersionVec = {3};
|
||||
const std::vector<uint64_t> kFewVersionsVec = {1, 2, 5};
|
||||
const std::vector<uint64_t> kRepeatedVersionsVec = {1, 1, 2, 5, 5, 5, 5, 5};
|
||||
|
||||
const std::set<uint64_t> kSingleVersion = {3};
|
||||
const std::set<uint64_t> kFewVersions = {1, 2, 5};
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.SetKeyFormatVersions(kSingleVersionVec));
|
||||
EXPECT_TRUE(key.HasKeyFormatVersions());
|
||||
EXPECT_EQ(key.key_format_versions(), kSingleVersion);
|
||||
|
||||
key.ClearKeyFormatVersions();
|
||||
EXPECT_FALSE(key.HasKeyFormatVersions());
|
||||
|
||||
EXPECT_TRUE(key.SetKeyFormatVersions(kFewVersionsVec));
|
||||
EXPECT_TRUE(key.HasKeyFormatVersions());
|
||||
EXPECT_EQ(key.key_format_versions(), kFewVersions);
|
||||
|
||||
// Ensure that set is not merging.
|
||||
EXPECT_TRUE(key.SetKeyFormatVersions(kSingleVersionVec));
|
||||
EXPECT_EQ(key.key_format_versions(), kSingleVersion);
|
||||
|
||||
// Ensure that repeated values are not stored.
|
||||
EXPECT_TRUE(key.SetKeyFormatVersions(kRepeatedVersionsVec));
|
||||
EXPECT_EQ(key.key_format_versions(), kFewVersions);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, SetKeyFormatVersions_Vec_Invalid) {
|
||||
const std::set<uint64_t> kSingleVersion = {3};
|
||||
const std::vector<uint64_t> kBadVersionsVec = {1, 2, 0, 5};
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.SetKeyFormatVersions(kBadVersionsVec));
|
||||
EXPECT_FALSE(key.HasKeyFormatVersions());
|
||||
|
||||
EXPECT_TRUE(key.SetKeyFormatVersions(kSingleVersion));
|
||||
|
||||
EXPECT_FALSE(key.SetKeyFormatVersions(kBadVersionsVec));
|
||||
EXPECT_EQ(key.key_format_versions(), kSingleVersion);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, HasKeyFormatVersion) {
|
||||
const std::set<uint64_t> kFewVersions = {1, 2, 5};
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.HasKeyFormatVersion(1));
|
||||
EXPECT_FALSE(key.HasKeyFormatVersion(std::numeric_limits<uint64_t>::max()));
|
||||
|
||||
EXPECT_TRUE(key.SetKeyFormatVersions(kFewVersions));
|
||||
|
||||
EXPECT_FALSE(key.HasKeyFormatVersion(0));
|
||||
EXPECT_TRUE(key.HasKeyFormatVersion(1));
|
||||
EXPECT_TRUE(key.HasKeyFormatVersion(2));
|
||||
EXPECT_FALSE(key.HasKeyFormatVersion(3));
|
||||
EXPECT_FALSE(key.HasKeyFormatVersion(4));
|
||||
EXPECT_TRUE(key.HasKeyFormatVersion(5));
|
||||
EXPECT_FALSE(key.HasKeyFormatVersion(std::numeric_limits<uint64_t>::max()));
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, AddKeyFormatVersion) {
|
||||
const std::set<uint64_t> kFewVersions = {1, 2, 5};
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.AddKeyFormatVersion(1));
|
||||
EXPECT_TRUE(key.AddKeyFormatVersion(2));
|
||||
EXPECT_TRUE(key.AddKeyFormatVersion(5));
|
||||
|
||||
EXPECT_EQ(key.key_format_versions(), kFewVersions);
|
||||
|
||||
// Repeated adds doesn't count as error.
|
||||
EXPECT_TRUE(key.AddKeyFormatVersion(5));
|
||||
// Cannot add invalid.
|
||||
EXPECT_FALSE(key.AddKeyFormatVersion(0));
|
||||
|
||||
EXPECT_EQ(key.key_format_versions(), kFewVersions);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, IsWellFormed_Empty) {
|
||||
const HlsKey key;
|
||||
EXPECT_FALSE(key.IsWellFormed());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, IsWellFormed_MethodNone) {
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.SetMethod("NONE"));
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
}
|
||||
|
||||
// When method is none, all other fields must be empty.
|
||||
TEST(HlsKeyTest, IsWellFormed_MethodNone_Invalid) {
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.SetMethod("NONE"));
|
||||
|
||||
// With URI.
|
||||
EXPECT_TRUE(key.SetUri("http://domain.tld/key"));
|
||||
EXPECT_FALSE(key.IsWellFormed());
|
||||
key.ClearUri();
|
||||
|
||||
// With IV.
|
||||
EXPECT_TRUE(key.SetIv(std::vector<uint8_t>(HlsKey::kIvLength, 42)));
|
||||
EXPECT_FALSE(key.IsWellFormed());
|
||||
key.ClearIv();
|
||||
|
||||
// With key format.
|
||||
EXPECT_TRUE(key.SetKeyFormat("com.widevine"));
|
||||
EXPECT_FALSE(key.IsWellFormed());
|
||||
key.ClearKeyFormat();
|
||||
|
||||
// With key format versions.
|
||||
EXPECT_TRUE(key.AddKeyFormatVersion(1));
|
||||
EXPECT_FALSE(key.IsWellFormed());
|
||||
key.ClearKeyFormatVersions();
|
||||
|
||||
// Should be well-formed again.
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, IsWellFormed_MethodNonNone) {
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.SetMethod("AES-128"));
|
||||
// Required fields.
|
||||
EXPECT_TRUE(key.SetUri("http://domain.tld/key"));
|
||||
EXPECT_TRUE(key.SetIv(std::vector<uint8_t>(HlsKey::kIvLength, 42)));
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
|
||||
// Optional fields.
|
||||
EXPECT_TRUE(key.SetKeyFormat("com.widevine"));
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
|
||||
EXPECT_TRUE(key.AddKeyFormatVersion(1));
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, IsWellFormed_MethodNonNone_Invalid) {
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.SetMethod("AES-128"));
|
||||
// Missing required all fields.
|
||||
EXPECT_FALSE(key.IsWellFormed());
|
||||
|
||||
// URI is the only required field.
|
||||
EXPECT_TRUE(key.SetUri("http://domain.tld/key"));
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
|
||||
// Missing URI.
|
||||
key.ClearUri();
|
||||
EXPECT_FALSE(key.IsWellFormed());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_MethodNone) {
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "NONE"));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.FromAttributeList(list));
|
||||
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
EXPECT_EQ(key.method(), "NONE");
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
EXPECT_FALSE(key.HasKeyFormat());
|
||||
EXPECT_FALSE(key.HasKeyFormatVersions());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_MethodNone_IgnoreOtherFields) {
|
||||
// The HLS specification states that if METHOD is NONE, then
|
||||
// there should not be any other fields. However, this parser
|
||||
// is less strict, and will simply ignore the other fields
|
||||
// when reading from an attribute list.
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "NONE"));
|
||||
EXPECT_TRUE(
|
||||
list.SetHexSequence("IV", std::vector<uint8_t>(HlsKey::kIvLength, 42)));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", "http://example.com/key-data"));
|
||||
EXPECT_TRUE(list.SetQuotedString("KEYFORMAT", "com.example"));
|
||||
EXPECT_TRUE(list.SetQuotedString("KEYFORMATVERSIONS", "1337"));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.FromAttributeList(list));
|
||||
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
EXPECT_EQ(key.method(), "NONE");
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
EXPECT_FALSE(key.HasKeyFormat());
|
||||
EXPECT_FALSE(key.HasKeyFormatVersions());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_MethodNonNone_OnlyRequiredFields) {
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 42);
|
||||
const std::string kUri = "http://domain.tld/key";
|
||||
// HLS standard says to use the following defaults if not
|
||||
// present in the HLS list.
|
||||
const std::string kDefaultKeyFormat = "identity";
|
||||
const std::set<uint64_t> kDefaultKeyFormatVersions = {1};
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kIv));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", kUri));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.FromAttributeList(list));
|
||||
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
EXPECT_EQ(key.method(), "AES-128");
|
||||
EXPECT_EQ(key.uri(), kUri);
|
||||
EXPECT_EQ(key.iv(), kIv);
|
||||
EXPECT_EQ(key.key_format(), kDefaultKeyFormat);
|
||||
EXPECT_EQ(key.key_format_versions(), kDefaultKeyFormatVersions);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_MethodNonNone_AllFields) {
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 42);
|
||||
const std::string kUri = "http://domain.tld/key";
|
||||
const std::string kKeyFormat = "com.widevine";
|
||||
const std::set<uint64_t> kKeyFormatVersion = {1, 2, 5};
|
||||
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "SAMPLE-AES"));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kIv));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", kUri));
|
||||
EXPECT_TRUE(list.SetQuotedString("KEYFORMAT", kKeyFormat));
|
||||
EXPECT_TRUE(list.SetQuotedString("KEYFORMATVERSIONS", "1/2/5"));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.FromAttributeList(list));
|
||||
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
EXPECT_EQ(key.method(), "SAMPLE-AES");
|
||||
EXPECT_EQ(key.uri(), kUri);
|
||||
EXPECT_EQ(key.iv(), kIv);
|
||||
EXPECT_EQ(key.key_format(), kKeyFormat);
|
||||
EXPECT_EQ(key.key_format_versions(), kKeyFormatVersion);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_MissingFields_All) {
|
||||
HlsAttributeList list;
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_MissingFields_Method) {
|
||||
const std::string kUri = "http://domain.tld/key";
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 42);
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", kUri));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kIv));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
// Nothing should be set.
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_MissingFields_MissingUri) {
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 42);
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kIv));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
// Nothing should be set.
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidFields_BadMethodType) {
|
||||
HlsAttributeList list;
|
||||
// Must be enum string not quoted string.
|
||||
EXPECT_TRUE(list.SetQuotedString("METHOD", "NONE"));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidFields_EmptyUri) {
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 42);
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", ""));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kIv));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
// Nothing should be set.
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidFields_BadUriType) {
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 42);
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetEnumString("URI", "DATA"));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kIv));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
// Nothing should be set.
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidFields_ShortIv) {
|
||||
const std::vector<uint8_t> kShortIv(HlsKey::kIvLength / 2, 42);
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", "http://example.com/key-data"));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kShortIv));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidFields_LargeIv) {
|
||||
const std::vector<uint8_t> kLargeIv(HlsKey::kIvLength * 2, 42);
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", "http://example.com/key-data"));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kLargeIv));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidFields_BadIvType) {
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", "http://example.com/key-data"));
|
||||
EXPECT_TRUE(list.SetQuotedString("IV", "42 repeated 16 times"));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidFields_EmptyKeyFormat) {
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 42);
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", "http://example.com/key-data"));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kIv));
|
||||
EXPECT_TRUE(list.SetQuotedString("KEYFORMAT", ""));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
// Nothing should be set.
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidFields_BadKeyFormatType) {
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 42);
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", "http://example.com/key-data"));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kIv));
|
||||
EXPECT_TRUE(list.SetEnumString("KEYFORMAT", "COM-EXAMPLE"));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
// Nothing should be set.
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
EXPECT_FALSE(key.HasKeyFormat());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidFields_EmptyKeyFormatVersions) {
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 42);
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", "http://example.com/key-data"));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kIv));
|
||||
EXPECT_TRUE(list.SetQuotedString("KEYFORMAT", "com.example"));
|
||||
EXPECT_TRUE(list.SetQuotedString("KEYFORMATVERSIONS", ""));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
// Nothing should be set.
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
EXPECT_FALSE(key.HasKeyFormat());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidFields_ZeroKeyFormatVersions) {
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 42);
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", "http://example.com/key-data"));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kIv));
|
||||
EXPECT_TRUE(list.SetQuotedString("KEYFORMAT", "com.example"));
|
||||
EXPECT_TRUE(list.SetQuotedString("KEYFORMATVERSIONS", "0/1/5"));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
// Nothing should be set.
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
EXPECT_FALSE(key.HasKeyFormat());
|
||||
EXPECT_FALSE(key.HasKeyFormatVersions());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidFields_BadKeyFormatVersionsFormat) {
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 42);
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", "http://example.com/key-data"));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kIv));
|
||||
EXPECT_TRUE(list.SetQuotedString("KEYFORMAT", "com.example"));
|
||||
EXPECT_TRUE(list.SetQuotedString("KEYFORMATVERSIONS", "1,2,5"));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
// Nothing should be set.
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
EXPECT_FALSE(key.HasKeyFormat());
|
||||
EXPECT_FALSE(key.HasKeyFormatVersions());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidFields_BadKeyFormatVersionsType) {
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 42);
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("METHOD", "AES-128"));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", "http://example.com/key-data"));
|
||||
EXPECT_TRUE(list.SetHexSequence("IV", kIv));
|
||||
EXPECT_TRUE(list.SetQuotedString("KEYFORMAT", "com.example"));
|
||||
EXPECT_TRUE(list.SetInteger("KEYFORMATVERSIONS", 1));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
// Nothing should be set.
|
||||
EXPECT_FALSE(key.HasMethod());
|
||||
EXPECT_FALSE(key.HasUri());
|
||||
EXPECT_FALSE(key.HasIv());
|
||||
EXPECT_FALSE(key.HasKeyFormat());
|
||||
EXPECT_FALSE(key.HasKeyFormatVersions());
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, FromAttributeList_InvalidList) {
|
||||
// Populate HLS Attribute List as if it is a different message.
|
||||
// Using EXT-X-MEDIA.
|
||||
HlsAttributeList list;
|
||||
EXPECT_TRUE(list.SetEnumString("TYPE", "AUDIO"));
|
||||
EXPECT_TRUE(list.SetQuotedString("URI", "http://example.com/video-data"));
|
||||
EXPECT_TRUE(list.SetQuotedString("GROUP-ID", "Video Group"));
|
||||
EXPECT_TRUE(list.SetQuotedString("LANGUAGE", "en"));
|
||||
EXPECT_TRUE(list.SetQuotedString("NAME", "A nice video"));
|
||||
EXPECT_TRUE(list.SetEnumString("DEFAULT", "YES"));
|
||||
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.FromAttributeList(list));
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, ParseAttributeList_MethodNone) {
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.ParseAttributeList("METHOD=NONE"));
|
||||
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
EXPECT_EQ(key.method(), "NONE");
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, ParseAttributeList_MethodNonNone_OnlyRequiredFields) {
|
||||
const std::string kUri = "http://domain.tld/key";
|
||||
const std::vector<uint8_t> kEmptyIv;
|
||||
const std::string kDefaultKeyFormat = "identity";
|
||||
const std::set<uint64_t> kDefaultKeyFormatVersions = {1};
|
||||
|
||||
std::ostringstream hls_stream;
|
||||
hls_stream << "METHOD=AES-128,";
|
||||
hls_stream << "URI=\"" << kUri << "\"";
|
||||
|
||||
const std::string key_rep = hls_stream.str();
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.ParseAttributeList(key_rep));
|
||||
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
EXPECT_EQ(key.method(), "AES-128");
|
||||
EXPECT_EQ(key.uri(), kUri);
|
||||
EXPECT_EQ(key.iv(), kEmptyIv);
|
||||
EXPECT_EQ(key.key_format(), kDefaultKeyFormat);
|
||||
EXPECT_EQ(key.key_format_versions(), kDefaultKeyFormatVersions);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, ParseAttributeList_MethodNonNone_AllFields) {
|
||||
const std::string kIvHex(HlsKey::kIvLength * 2, 'A');
|
||||
const std::vector<uint8_t> kIv(HlsKey::kIvLength, 0xaa);
|
||||
const std::string kUri = "http://domain.tld/key";
|
||||
const std::string kKeyFormat = "com.widevine";
|
||||
const std::set<uint64_t> kKeyFormatVersion = {1, 2, 5};
|
||||
|
||||
std::ostringstream hls_stream;
|
||||
hls_stream << "METHOD=SAMPLE-AES,";
|
||||
hls_stream << "URI=\"" << kUri << "\",";
|
||||
hls_stream << "IV=0x" << kIvHex << ',';
|
||||
hls_stream << "KEYFORMAT=\"" << kKeyFormat << "\",";
|
||||
hls_stream << "KEYFORMATVERSIONS=\"1/2/5\"";
|
||||
|
||||
const std::string key_rep = hls_stream.str();
|
||||
HlsKey key;
|
||||
EXPECT_TRUE(key.ParseAttributeList(key_rep));
|
||||
|
||||
EXPECT_TRUE(key.IsWellFormed());
|
||||
EXPECT_EQ(key.method(), "SAMPLE-AES");
|
||||
EXPECT_EQ(key.uri(), kUri);
|
||||
EXPECT_EQ(key.iv(), kIv);
|
||||
EXPECT_EQ(key.key_format(), kKeyFormat);
|
||||
EXPECT_EQ(key.key_format_versions(), kKeyFormatVersion);
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, ParseAttributeList_Empty) {
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.ParseAttributeList(""));
|
||||
}
|
||||
|
||||
TEST(HlsKeyTest, ParseAttributeList_InvalidAttributeList) {
|
||||
HlsKey key;
|
||||
EXPECT_FALSE(key.ParseAttributeList("Not an Attribute List"));
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace wvutil
|
||||
Reference in New Issue
Block a user