devine-dl / pywidevine

Python implementation of Google's Widevine DRM CDM (Content Decryption Module)
GNU General Public License v3.0
535 stars 118 forks source link

Add support for a Remote-Accessible Cdm #3

Closed rlaphoenix closed 2 years ago

rlaphoenix commented 2 years ago

Is your feature request related to a problem? Please describe. You may want to set up your environment for the Python Cdm to be usable by another user, but have the sensitive provision RSA key and Client ID blob kept out of reach.

Currently, there is no option for this sort of scenario without manually altering the Cdm code entirely, or wrapping it in an API (e.g., fastapi or flask).

Describe the solution you'd like There are a few ways I can do this and I cannot decide between them for the best way.

The first would be to implement an abstracted RemoteCdm class in which developers can implement the different methods get_license_challenge and so on, linking them to their own different API schemas or remote connection methods. This would likely be the easiest on my part, but provide almost no benefit to the actual ender user using this package as they could pretty much already do this if they implement exactly this themselves and ignore type-hint errors.

The second method would be to implement RemoteCdm in full, as a specific API schema. I would have to also add code to serve one of these Remote CDM APIs, perhaps through aiohttp, flask, or such, so that the user can actually create and use a RemoteCdm without doing the guesswork themselves on serving the API. This would all result in almost no work for the user other than needing to deal with using pywidevine to run the API server, and to manage authentication/API tokens.

Describe alternatives you've considered An alternative method would be to look at making Abstract Device classes rather than Cdm classes. Since the Device class is semantic to the root device keys/access, it would be more ideal. The problem is if it is remote, we shouldn't be providing the Private Keys and such as plain text, but we need to as the Cdm class expects there to be a private_key class instance attribute.

We could move the code that deals with the generation and parsing of license acquisition to the Device class, and therefore abstract it for Local/Remote Device classes, but that reduces the actual workload of the Cdm class to almost nothing. It would end up being more of a proxy to the Device classes' methods, and make using the Cdm class almost pointless. Dealing with storage and fetching of session related data would also be complicated under such a scenario.

Additional context

rlaphoenix commented 2 years ago

Support for serving a Cdm remotely was added in v1.2.0 with pywidevine serve --help command. You can serve a session-based Cdm loaded with a device chosen by the caller. However, There's currently no code within pywidevine to take advantage of these served API instances.

rlaphoenix commented 2 years ago

Client-side code has been added in v1.3.0 https://github.com/rlaphoenix/pywidevine/commit/e8785fcd8414d66ebb1d47eaf86c19c4b8615caa