80 lines
2.9 KiB
Python
80 lines
2.9 KiB
Python
|
#!/usr/bin/env python3
|
||
|
|
||
|
import argparse
|
||
|
import base64
|
||
|
|
||
|
import yaml
|
||
|
|
||
|
from vinetrimmer.utils.widevine.protos.widevine_pb2 import ClientIdentificationRaw
|
||
|
|
||
|
parser = argparse.ArgumentParser("Widevine Client ID building tool.")
|
||
|
parser.add_argument("-q", "--quiet",
|
||
|
help="do not print the generated client id",
|
||
|
action="store_true")
|
||
|
parser.add_argument("-c", "--config",
|
||
|
help="configuration yaml file",
|
||
|
default="config.yml")
|
||
|
parser.add_argument("-o", "--output",
|
||
|
default="device_client_id_blob",
|
||
|
help="output filename")
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
with open(args.config) as fd:
|
||
|
config = yaml.safe_load(fd)
|
||
|
|
||
|
with open(config["token"], "rb") as fd:
|
||
|
token = fd.read()
|
||
|
|
||
|
ci = ClientIdentificationRaw()
|
||
|
ci.Type = ClientIdentificationRaw.DEVICE_CERTIFICATE
|
||
|
ci.Token = token
|
||
|
|
||
|
for name, value in config["client_info"].items():
|
||
|
nv = ci.ClientInfo.add()
|
||
|
nv.Name = name
|
||
|
if name == "device_id":
|
||
|
value = base64.b64decode(value)
|
||
|
nv.Value = value
|
||
|
|
||
|
capabilities = ClientIdentificationRaw.ClientCapabilities()
|
||
|
caps = config["capabilities"]
|
||
|
if "client_token" in caps:
|
||
|
capabilities.ClientToken = caps["client_token"]
|
||
|
if "session_token" in caps:
|
||
|
capabilities.SessionToken = caps["session_token"]
|
||
|
if "video_resolution_constraints" in caps:
|
||
|
capabilities.VideoResolutionConstraints = caps["video_resolution_constraints"]
|
||
|
if "max_hdcp_version" in caps:
|
||
|
max_hdcp_version = caps["max_hdcp_version"]
|
||
|
if str(max_hdcp_version).isdigit():
|
||
|
max_hdcp_version = int(max_hdcp_version)
|
||
|
else:
|
||
|
max_hdcp_version = ClientIdentificationRaw.ClientCapabilities.HdcpVersion.Value(max_hdcp_version)
|
||
|
capabilities.MaxHdcpVersion = max_hdcp_version
|
||
|
if "oem_crypto_api_version" in caps:
|
||
|
capabilities.OemCryptoApiVersion = int(caps["oem_crypto_api_version"])
|
||
|
# I have not seen any of the following in use:
|
||
|
if "anti_rollback_usage_table" in caps:
|
||
|
capabilities.AntiRollbackUsageTable = caps["anti_rollback_usage_table"]
|
||
|
if "srm_version" in caps:
|
||
|
capabilities.SrmVersion = int(caps["srm_version"])
|
||
|
if "can_update_srm" in caps:
|
||
|
capabilities.ClientToken = caps["can_update_srm"]
|
||
|
# is it possible to refactor this?
|
||
|
if "supported_certificate_key_type" in caps:
|
||
|
supported_certificate_key_type = caps["supported_certificate_key_type"]
|
||
|
if str(supported_certificate_key_type).isdigit():
|
||
|
supported_certificate_key_type = int(supported_certificate_key_type)
|
||
|
else:
|
||
|
supported_certificate_key_type = ClientIdentificationRaw.ClientCapabilities.CertificateKeyType.Value(
|
||
|
supported_certificate_key_type
|
||
|
)
|
||
|
capabilities.SupportedCertificateKeyType.append(supported_certificate_key_type)
|
||
|
ci._ClientCapabilities.CopyFrom(capabilities)
|
||
|
|
||
|
if not args.quiet:
|
||
|
print(ci)
|
||
|
|
||
|
with open(args.output, "wb") as fd:
|
||
|
fd.write(ci.SerializeToString())
|