Initial upload
This commit is contained in:
TPD94
2024-04-24 14:23:32 -04:00
parent ab15abe804
commit c681cd80df
6 changed files with 164 additions and 3 deletions

View File

@@ -1,3 +0,0 @@
# CDRM-Extension-API
Open source API back end for the popular Google Chrome extension written by Zane.

12
cache_keys.py Normal file
View File

@@ -0,0 +1,12 @@
# Import dependencies
import sqlite3
import os
# Define cache function
def cache_keys(pssh: str, keys: str, mpd: str):
dbconnection = sqlite3.connect(f"{os.getcwd()}/keys/database.db")
dbcursor = dbconnection.cursor()
dbcursor.execute("INSERT or REPLACE INTO database VALUES (?, ?, ?)", (pssh, keys, mpd))
dbconnection.commit()
dbconnection.close()

17
database_check.py Normal file
View File

@@ -0,0 +1,17 @@
# Import dependencies
import os
import sqlite3
# Check to see if the database already exists, if not create a keys folder, and create the database.
def database_check():
# Check to see if the "keys" directory exists, if not creates it
if "keys" not in os.listdir(os.getcwd()):
os.makedirs('keys')
# Check to see if a database exists in keys directory, if not create it
if not os.path.isfile(f"{os.getcwd()}/keys/database.db"):
dbconnection = sqlite3.connect(f"{os.getcwd()}/keys/database.db")
dbcursor = dbconnection.cursor()
dbcursor.execute('CREATE TABLE IF NOT EXISTS "DATABASE" ( "pssh" TEXT, "keys" TEXT, "mpd" TEXT, PRIMARY KEY("pssh") )')
dbconnection.close()

79
decrypt.py Normal file
View File

@@ -0,0 +1,79 @@
# import dependencies
import os
from pywidevine import PSSH
from pywidevine import Cdm
from pywidevine import Device
import requests
import glob
from cache_keys import cache_keys
# Get the current working directory
main_directory = os.getcwd()
# Making sure a .wvd file exists and using that as the extracted device
try:
extracted_device = glob.glob(f'{main_directory}/*.wvd')[0]
except:
extracted_cdm = None
print(f"Please place a WVD in {main_directory}/")
# Defining decrypt function
def decrypt_content(in_pssh: str = None, license_url: str = None, headers: dict = None, mpd: str = None) -> list:
# prepare pssh
pssh = PSSH(in_pssh)
# load device
device = Device.load(extracted_device)
# load CDM from device
cdm = Cdm.from_device(device)
# open CDM session
session_id = cdm.open()
# Generate the challenge
challenge = cdm.get_license_challenge(session_id, pssh)
# send license challenge
license = requests.post(
url=license_url,
headers=headers,
data=challenge
)
# Parse the license if it comes back in plain bytes
try:
cdm.parse_license(session_id, license.content)
except:
# Exception, try to find by regex via json
try:
cdm.parse_license(session_id, license.json()['license'])
except:
try:
cdm.parse_license(session_id, license.json()['licenseData'])
except Exception as error:
return [error]
# Assign variable for caching keys
cached_keys = ""
# assign variable for returned keys
returned_keys = []
for key in cdm.get_keys(session_id):
if key.type != "SIGNING":
returned_keys.append(f"--key {key.kid.hex}:{key.key.hex()}")
cached_keys += f"{key.kid.hex}:{key.key.hex()}\n"
# Cache the keys
cache_keys(pssh=in_pssh, keys=cached_keys, mpd=mpd)
# close session, disposes of session data
cdm.close(session_id)
# Return the keys
return returned_keys

53
main.py Normal file
View File

@@ -0,0 +1,53 @@
from decrypt import decrypt_content
import json
from flask import Flask, request
from database_check import database_check
app = Flask(__name__)
database_check()
@app.route('/', methods=['POST'])
def post_endpoint():
# Get the JSON data from the request
data = json.loads(request.data.decode())
print(json.dumps(data, indent=4))
# Get the PSSH
pssh = data['pssh']
# Get the license URL
lic_url = data['license_url']
# Get the headers
headers = data['headers']
# Get the MPD url
mpd = data['manifest_url']
# Format the headers
# Split the string into lines
lines = headers.strip().split('\n')
# Create an empty dictionary to store the key-value pairs
headers_dict = {}
# Iterate through each line and split it into key-value pairs
for line in lines:
key, value = line.split(': ', 1) # Split only at the first occurrence of ': ' to handle values containing ': '
headers_dict[key] = value
print(json.dumps(headers_dict, indent=4))
try:
keys = decrypt_content(in_pssh=pssh, license_url=lic_url, headers=headers_dict, mpd=mpd)
return {"keys": keys}
except Exception as error:
return {"keys": [f'{error}']}
if __name__ == '__main__':
app.run(debug=True)

3
requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
flask>=3.0.3
requests>=2.31.0
pywidevine>=1.8.0