+ serve.py raw PSSH support
This commit is contained in:
parent
b2e9725b3a
commit
9b25aafe07
|
@ -10,4 +10,4 @@ from .session import *
|
||||||
from .xml_key import *
|
from .xml_key import *
|
||||||
from .xmrlicense import *
|
from .xmrlicense import *
|
||||||
|
|
||||||
__version__ = "0.3.8"
|
__version__ = "0.3.9"
|
||||||
|
|
|
@ -265,7 +265,7 @@ class Cdm:
|
||||||
raise InvalidLicense("Public encryption key does not match")
|
raise InvalidLicense("Public encryption key does not match")
|
||||||
|
|
||||||
for key in parsed_licence.get_content_keys():
|
for key in parsed_licence.get_content_keys():
|
||||||
if Key.CipherType(key.cipher_type) == Key.CipherType.ECC256:
|
if Key.CipherType(key.cipher_type) == Key.CipherType.ECC_256:
|
||||||
session.keys.append(Key(
|
session.keys.append(Key(
|
||||||
key_id=UUID(bytes_le=key.key_id),
|
key_id=UUID(bytes_le=key.key_id),
|
||||||
key_type=key.key_type,
|
key_type=key.key_type,
|
||||||
|
|
|
@ -6,12 +6,12 @@ from typing import Union
|
||||||
|
|
||||||
class Key:
|
class Key:
|
||||||
class KeyType(Enum):
|
class KeyType(Enum):
|
||||||
Invalid = 0x0000
|
INVALID = 0x0000
|
||||||
AES128CTR = 0x0001
|
AES_128_CTR = 0x0001
|
||||||
RC4 = 0x0002
|
RC4_CIPHER = 0x0002
|
||||||
AES128ECB = 0x0003
|
AES_128_ECB = 0x0003
|
||||||
Cocktail = 0x0004
|
COCKTAIL = 0x0004
|
||||||
AES128CBC = 0x0005
|
AES_128_CBC = 0x0005
|
||||||
UNKNOWN = 0xffff
|
UNKNOWN = 0xffff
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -19,12 +19,12 @@ class Key:
|
||||||
return cls.UNKNOWN
|
return cls.UNKNOWN
|
||||||
|
|
||||||
class CipherType(Enum):
|
class CipherType(Enum):
|
||||||
Invalid = 0x0000
|
INVALID = 0x0000
|
||||||
RSA128 = 0x0001
|
RSA_1024 = 0x0001
|
||||||
ChainedLicense = 0x0002
|
CHAINED_LICENSE = 0x0002
|
||||||
ECC256 = 0x0003
|
ECC_256 = 0x0003
|
||||||
ECCforScalableLicenses = 0x0004
|
ECC_256_WITH_KZ = 0x0004
|
||||||
Scalable = 0x0005
|
SCALABLE = 0x0005
|
||||||
UNKNOWN = 0xffff
|
UNKNOWN = 0xffff
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -5,11 +5,11 @@ from typing import Any, Optional, Union
|
||||||
from aiohttp.typedefs import Handler
|
from aiohttp.typedefs import Handler
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
|
||||||
from pyplayready import __version__
|
from pyplayready import __version__, PSSH
|
||||||
from pyplayready.cdm import Cdm
|
from pyplayready.cdm import Cdm
|
||||||
from pyplayready.device import Device
|
from pyplayready.device import Device
|
||||||
|
|
||||||
from pyplayready.exceptions import (InvalidSession, TooManySessions, InvalidLicense)
|
from pyplayready.exceptions import (InvalidSession, TooManySessions, InvalidLicense, InvalidPssh)
|
||||||
|
|
||||||
routes = web.RouteTableDef()
|
routes = web.RouteTableDef()
|
||||||
|
|
||||||
|
@ -134,6 +134,18 @@ async def get_license_challenge(request: web.Request) -> web.Response:
|
||||||
# get init data
|
# get init data
|
||||||
init_data = body["init_data"]
|
init_data = body["init_data"]
|
||||||
|
|
||||||
|
if not init_data.startswith("<WRMHEADER"):
|
||||||
|
try:
|
||||||
|
pssh = PSSH(init_data)
|
||||||
|
wrm_headers = pssh.get_wrm_headers(downgrade_to_v4=True)
|
||||||
|
if wrm_headers:
|
||||||
|
init_data = wrm_headers[0]
|
||||||
|
except InvalidPssh as e:
|
||||||
|
return web.json_response({
|
||||||
|
"status": 500,
|
||||||
|
"message": f"Unable to parse base64 PSSH, {e}"
|
||||||
|
}, status=500)
|
||||||
|
|
||||||
# get challenge
|
# get challenge
|
||||||
try:
|
try:
|
||||||
license_request = cdm.get_license_challenge(
|
license_request = cdm.get_license_challenge(
|
||||||
|
@ -147,9 +159,9 @@ async def get_license_challenge(request: web.Request) -> web.Response:
|
||||||
}, status=400)
|
}, status=400)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return web.json_response({
|
return web.json_response({
|
||||||
"status": 400,
|
"status": 500,
|
||||||
"message": f"Error, {e}"
|
"message": f"Error, {e}"
|
||||||
}, status=400)
|
}, status=500)
|
||||||
|
|
||||||
return web.json_response({
|
return web.json_response({
|
||||||
"status": 200,
|
"status": 200,
|
||||||
|
@ -199,9 +211,9 @@ async def parse_license(request: web.Request) -> web.Response:
|
||||||
}, status=400)
|
}, status=400)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return web.json_response({
|
return web.json_response({
|
||||||
"status": 400,
|
"status": 500,
|
||||||
"message": f"Error, {e}"
|
"message": f"Error, {e}"
|
||||||
}, status=400)
|
}, status=500)
|
||||||
|
|
||||||
return web.json_response({
|
return web.json_response({
|
||||||
"status": 200,
|
"status": 200,
|
||||||
|
@ -243,9 +255,9 @@ async def get_keys(request: web.Request) -> web.Response:
|
||||||
}, status=400)
|
}, status=400)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return web.json_response({
|
return web.json_response({
|
||||||
"status": 400,
|
"status": 500,
|
||||||
"message": f"Error, {e}"
|
"message": f"Error, {e}"
|
||||||
}, status=400)
|
}, status=500)
|
||||||
|
|
||||||
# get the keys in json form
|
# get the keys in json form
|
||||||
keys_json = [
|
keys_json = [
|
||||||
|
|
|
@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "pyplayready"
|
name = "pyplayready"
|
||||||
version = "0.3.8"
|
version = "0.3.9"
|
||||||
description = "pyplayready CDM (Content Decryption Module) implementation in Python."
|
description = "pyplayready CDM (Content Decryption Module) implementation in Python."
|
||||||
license = "CC BY-NC-ND 4.0"
|
license = "CC BY-NC-ND 4.0"
|
||||||
authors = ["DevLARLEY, Erevoc", "DevataDev"]
|
authors = ["DevLARLEY, Erevoc", "DevataDev"]
|
||||||
|
|
Loading…
Reference in New Issue