Commit Graph

136 Commits

Author SHA1 Message Date
rlaphoenix
e4e109b9f3 RemoteCdm: Remove unnecessary parsing of license msg 2022-08-06 09:54:14 +01:00
rlaphoenix
1d606a9e54 Use Cdm.get_keys in license CLI command 2022-08-06 09:54:14 +01:00
rlaphoenix
f36977ef19 serve: Improve type hinting on Cdms gotten from app["cdms"]
For some reason on PyCharm typing doesnt work normally here even though the definition is provided in _startup().
2022-08-06 09:54:14 +01:00
rlaphoenix
dd1a355691 serve: Improve error handling on /parse_license 2022-08-06 09:54:14 +01:00
rlaphoenix
6eceaaf410 serve: Remote TODO that will not be done
We shouldn't really provide the derived context keys. There isn't any use to them outside of that specific license request and license response for which it was derived from. The only use to them would be to allow the client to decrypt the keys manually, which wont be necessary nor secure.
2022-08-06 09:54:14 +01:00
rlaphoenix
bd62b8d131 serve: Provide key_type to get_keys as-is
There's no need for serve code to handle parsing of it when the Cdm code will do so better.
2022-08-06 09:54:14 +01:00
rlaphoenix
11a2358002 serve: Improve error handling on /get_license_challenge 2022-08-06 09:54:14 +01:00
rlaphoenix
f2ed83205b serve: Provide license type to get_license_challenge as-is
There's no need for serve code to handle parsing of it when the Cdm code will do so better.
2022-08-06 09:54:14 +01:00
rlaphoenix
796cf7ffb0 serve: Improve error handling on /set_service_certificate 2022-08-06 09:54:14 +01:00
rlaphoenix
2c33af79df serve: Catch InvalidSession instead of manually ensuring session validity 2022-08-06 09:54:14 +01:00
rlaphoenix
93d9561fac serve: Use Cdm.get_keys() instead of accessing _sessions 2022-08-06 09:54:14 +01:00
rlaphoenix
c73078b7a9 serve: Add /get_keys endpoint 2022-08-06 09:54:14 +01:00
rlaphoenix
2445297ae8 serve: Match endpoints with Cdm class methods 2022-08-06 09:54:14 +01:00
rlaphoenix
01416f6513 Cdm: Add a method to get keys from loaded license 2022-08-06 09:54:14 +01:00
rlaphoenix
60e3ef0201 Remove unused Container import from Cdm and RemoteCdm 2022-08-06 08:27:19 +01:00
rlaphoenix
a1844fb195 gitignore: Exclude *.wvd for security 2022-08-06 08:21:30 +01:00
rlaphoenix
26d81a7bef PSSH: Allow crafting v0 boxes with just Key IDs
This is actually possible and in some cases necessary. While v0 boxes do not use key_IDs field of the PSSH Box, we can store the provided key_ids in the init data. E.g., Apple Music.
2022-08-05 08:31:14 +01:00
rlaphoenix
27a701aaea Cdm: Rework init_data param to expect PSSH object
A by product of this change is dropped support for providing a PSSH or init data directly in any form, that includes base64.

You must now provide it as a PSSH object, e.g., `cdm.get_license_challenge(session_id, PSSH("AAAAW3Bzc2...CSEQyAA=="))`

The idea behind this is to simplify the amount of places where parsing of PSSH and Init Data to a minimal amount. The codebase is getting quite annoying with the constant jumps and places where it needs to test for base64 strings, hex strings, bytes, and direct parsed PSSH boxes or WidevinePsshData. That's a ridiculous amount of code just to take in a pssh/init data, especially when the full pssh box will eventually be discarded/unused by the Cdm, as it just cares about the init data.

Client code should pass any PSSH value they get into a PSSH object appropriately, and then store it as such, instead of as a string or bytes. This makes it overall more powerful thanks to the ability to also access the underlying PSSH data more easily with this change.

It also helps to increase contrast between a compliant Widevine Cenc Header or PSSH Box, and arbitrary data (e.g., Netflix WidevineExchange's init data) because of how you initialize the PSSH.

It also allows the user to more accurately trace the underlying final parse of the PSSH value, instead of looking at it being pinged between multiple functions.

RemoteCdm now also sends the PSSH/init_data in full box form now, the serve API will be able to handle both scenarios but in edge cases providing the full box may be the difference between a working License Request and not.
2022-08-05 08:26:03 +01:00
rlaphoenix
2a87d55e20 PSSH: Add dump and dumps methods 2022-08-05 08:26:03 +01:00
rlaphoenix
76c7a402eb PSSH: Optimize how overwrite_key_ids works with the repeated field
We can clear a repeated field with `del field[:]` and overwrite an entire field with `field[:] = [b"123", b"456"]`. So we can reduce this down to a single call operation.
2022-08-05 08:26:03 +01:00
rlaphoenix
10fb954097 PSSH: Remove from_key_ids, use new() instead 2022-08-05 08:26:03 +01:00
rlaphoenix
9d7eaf4949 PSSH: Rework from_playready_pssh as a class method 2022-08-05 08:26:03 +01:00
rlaphoenix
0537c9666c PSSH: Add new() class method to craft boxes manually 2022-08-05 08:26:03 +01:00
rlaphoenix
fc47bbb436 PSSH: Merge get_as_box into the Constructor
Also improves the code of it overall including documentation.

The _box class instance variable has been removed and the raw box is no longer kept.
2022-08-05 05:33:13 +01:00
rlaphoenix
1ea57865ad PSSH: Fix usage of WidevinePsshData's key_ids field 2022-08-04 09:46:30 +01:00
rlaphoenix
f09a06857a Update Changelog for v1.3.1 2022-08-04 08:39:50 +01:00
rlaphoenix
e4f6a23725 Bump to v1.3.1 2022-08-04 08:39:42 +01:00
rlaphoenix
f21a21712b RemoteCdm: Improve Server Version testing
Some systems like Caddy or Nginx will prefix their own word to the Server header, e.g., `Caddy, pywidevine server v1.2.3` so I had to change a fair bit of the code to have wider compatibility across some unknowns that may occur with the Serve header.
2022-08-04 08:33:33 +01:00
rlaphoenix
a1494a3742 Allow specification of Cdm device_type as string 2022-08-04 08:26:41 +01:00
rlaphoenix
5b13e1a689 serve: Don't require force_privacy_mode to be defined on config 2022-08-04 08:22:06 +01:00
rlaphoenix
c9288dc391 Update Changelog for v1.3.0 2022-08-04 05:56:47 +01:00
rlaphoenix
7640d6fcab Bump to v1.3.0 2022-08-04 05:56:38 +01:00
rlaphoenix
3d794ad659 RemoteCdm: Implement /set_service_certificate 2022-08-04 05:54:15 +01:00
rlaphoenix
5788dde7b1 serve: Implement /set_service_certificate
Removed service certificate setting related code from /challenge.
2022-08-04 05:54:15 +01:00
rlaphoenix
ddf755f82f Cdm: Add ability to unset certificate via set_service_certificate()
To unset, just provide `None` as the certificate param.
2022-08-04 05:43:10 +01:00
rlaphoenix
e8785fcd84 Create RemoteCdm class as Client code for the serve feature
This can be considered the Client-side code for the `serve` feature.

The RemoteCdm object can be used with the same underlying interface as the normal `Cdm` object. Including stuff like .open(), .get_license_challenge(), .decrypt(), even same access to data like `cdm.system_id`, or even `cdm._sessions` just like normal.

However, since we don't have any private key and client ID, we spoof the super construction with dummy data. You wont have access to any data that uses the underlying Client ID and Private Key like the signer or decrypter. Any Cdm code trying to access them on RemoteCdm will fail.
2022-08-04 05:43:10 +01:00
rlaphoenix
c969d80931 Cdm: Change construction interface to allow manual creation
This is so you can construct a Cdm object without using `.wvd` files (nor the Device class). It also improves enforcement of some required data from the Device. The underlying Device object is discarded for it's data as it won't be required.

Note that the Client ID and Private Key related variables are now stored as private `__var` variables to further amplify their private nature and to really discourage manual read write. This is not impossible to workaround in Python but further discourages manual read/writes to the variable that could cause serious issues.

The RSA Key is also no longer stored as-is. It is now stored as PSS and PKCS1_OAEP objects, as they will be used like so. This makes it even more annoying to directly read/write the RSA key (but not impossible).
2022-08-04 04:52:26 +01:00
rlaphoenix
f1a38d1966 Update Changelog for v1.2.1 2022-08-02 01:53:44 +01:00
rlaphoenix
3fe87f2917 Bump to v1.2.1 2022-08-02 01:53:38 +01:00
rlaphoenix
dc48c11e1a Add Changelog to PyPI Project URLs 2022-08-02 01:53:29 +01:00
rlaphoenix
97126391c4 PSSH: Fix get_as_box parsing on arbitrary init data
An IOError can occur if the mp4 box parsing fails because it could not read enough bytes.
2022-08-02 01:48:49 +01:00
rlaphoenix
6a286a4c23 Remove second serve dependencies check
The second one isnt needed so long as the YAML import is 2nd. Once it tries to import serve it will fail and it's ImportError will get handled.
2022-08-02 01:48:48 +01:00
rlaphoenix
4bc0edcca9 serve: Set Server response header with pywidevine version
This allows clients to test with a HEAD request to / to see what version the API is running and test if it's actually a pywidevine serve API.
2022-08-02 01:48:48 +01:00
rlaphoenix
4f96ee402b serve: Add check that all devices in config exist 2022-08-02 01:48:48 +01:00
rlaphoenix
2ba13f5e07 serve: Add /close endpoint
All client's should implement this and handle the 400 response safely. Under normal circumstances, with good client code, the 400 responses should not happen.
2022-08-02 01:48:48 +01:00
rlaphoenix
a4d8be683b 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)
2022-08-02 01:48:48 +01:00
rlaphoenix
9501c34f60 serve: Store Cdm per-secret, ensure session more efficiently
The Cdm is now stored per-secret due to the Cdm object's session limit. This is so one user (by secret key) cannot overload the server with too many sessions.

But this also fixes it so that the serve API will work for more than just 50 sessions for all users. Otherwise the user pool will eventually overload the Cdm with 50 sessions, even if they close it, it will eventually happen. Think of it like the server being overloaded prematurely.
2022-08-02 01:48:48 +01:00
rlaphoenix
290da707ea serve: Add ability to get all types of keys in /keys 2022-08-02 01:48:48 +01:00
rlaphoenix
64ae5709d3 serve: Handle TooManySessions on /open 2022-08-02 01:48:48 +01:00
rlaphoenix
5c1b0e89ef Cdm: Support multiple forms of Service Certs in encrypt_client_id 2022-08-02 01:48:48 +01:00