serve: add /{device} prefix to all endpoints
This is necessary to support different Cdm devices per-user. E.g., without this change if you do /open/a_device, you will only ever be able to use `a_device` until the next server restart. Even if you do /open/b_device, it will still use `a_device`, without error or warning. This is because it stores the device with the Cdm in the previous change from storing the session ids to storing the Cdms instead. With this change we can now have the user specify which device they are using, which allows us to map that to a Cdm that was initialized with the respective device. Arguably we could remove the /{device} prefix and instead do a brute check on the app["cdms"] until we find a Cdm with a matching session, but this seems like a more semantic less hacky method to the madness. (especially since /open already used {device}, but as a postfix)
This commit is contained in:
parent
9501c34f60
commit
a4d8be683b
|
@ -23,7 +23,7 @@ routes = web.RouteTableDef()
|
|||
|
||||
|
||||
async def _startup(app: web.Application):
|
||||
app["cdms"]: dict[str, Cdm] = {}
|
||||
app["cdms"]: dict[tuple[str, str], Cdm] = {}
|
||||
app["config"]["devices"] = {
|
||||
path.stem: path
|
||||
for x in app["config"]["devices"]
|
||||
|
@ -46,24 +46,24 @@ async def ping(_) -> web.Response:
|
|||
})
|
||||
|
||||
|
||||
@routes.get("/open/{device}")
|
||||
@routes.get("/{device}/open")
|
||||
async def open(request: web.Request) -> web.Response:
|
||||
secret_key = request.headers["X-Secret-Key"]
|
||||
device_name = request.match_info["device"]
|
||||
user = request.app["config"]["users"][secret_key]
|
||||
device = request.match_info["device"]
|
||||
|
||||
if device not in user["devices"] or device not in request.app["config"]["devices"]:
|
||||
if device_name not in user["devices"] or device_name not in request.app["config"]["devices"]:
|
||||
# we don't want to be verbose with the error as to not reveal device names
|
||||
# by trial and error to users that are not authorized to use them
|
||||
return web.json_response({
|
||||
"status": 403,
|
||||
"message": f"Device '{device}' is not found or you are not authorized to use it."
|
||||
"message": f"Device '{device_name}' is not found or you are not authorized to use it."
|
||||
}, status=403)
|
||||
|
||||
cdm = request.app["cdms"].get(secret_key)
|
||||
cdm = request.app["cdms"].get((secret_key, device_name))
|
||||
if not cdm:
|
||||
device = Device.load(request.app["config"]["devices"][device])
|
||||
cdm = request.app["cdms"][secret_key] = Cdm(device)
|
||||
device = Device.load(request.app["config"]["devices"][device_name])
|
||||
cdm = request.app["cdms"][(secret_key, device_name)] = Cdm(device)
|
||||
|
||||
try:
|
||||
session_id = cdm.open()
|
||||
|
@ -86,9 +86,10 @@ async def open(request: web.Request) -> web.Response:
|
|||
})
|
||||
|
||||
|
||||
@routes.post("/challenge/{license_type}")
|
||||
@routes.post("/{device}/challenge/{license_type}")
|
||||
async def challenge(request: web.Request) -> web.Response:
|
||||
secret_key = request.headers["X-Secret-Key"]
|
||||
device_name = request.match_info["device"]
|
||||
|
||||
body = await request.json()
|
||||
for required_field in ("session_id", "init_data"):
|
||||
|
@ -102,8 +103,14 @@ async def challenge(request: web.Request) -> web.Response:
|
|||
session_id = bytes.fromhex(body["session_id"])
|
||||
|
||||
# get cdm
|
||||
cdm = request.app["cdms"].get(secret_key)
|
||||
if not cdm or session_id not in cdm._sessions:
|
||||
cdm = request.app["cdms"].get((secret_key, device_name))
|
||||
if not cdm:
|
||||
return web.json_response({
|
||||
"status": 400,
|
||||
"message": f"No Cdm session for {device_name} has been opened yet. No session to use."
|
||||
}, status=400)
|
||||
|
||||
if session_id not in cdm._sessions:
|
||||
# This can happen if:
|
||||
# - API server gets shutdown/restarted,
|
||||
# - The user calls /challenge before /open,
|
||||
|
@ -141,9 +148,10 @@ async def challenge(request: web.Request) -> web.Response:
|
|||
}, status=200)
|
||||
|
||||
|
||||
@routes.post("/keys/{key_type}")
|
||||
@routes.post("/{device}/keys/{key_type}")
|
||||
async def keys(request: web.Request) -> web.Response:
|
||||
secret_key = request.headers["X-Secret-Key"]
|
||||
device_name = request.match_info["device"]
|
||||
|
||||
body = await request.json()
|
||||
for required_field in ("session_id", "license_message"):
|
||||
|
@ -173,8 +181,14 @@ async def keys(request: web.Request) -> web.Response:
|
|||
}, status=400)
|
||||
|
||||
# get cdm
|
||||
cdm = request.app["cdms"].get(secret_key)
|
||||
if not cdm or session_id not in cdm._sessions:
|
||||
cdm = request.app["cdms"].get((secret_key, device_name))
|
||||
if not cdm:
|
||||
return web.json_response({
|
||||
"status": 400,
|
||||
"message": f"No Cdm session for {device_name} has been opened yet. No session to use."
|
||||
}, status=400)
|
||||
|
||||
if session_id not in cdm._sessions:
|
||||
# This can happen if:
|
||||
# - API server gets shutdown/restarted,
|
||||
# - The user calls /challenge before /open,
|
||||
|
|
Loading…
Reference in New Issue