forked from tpd94/CDRM-Extension
prettier formatting, add manifest url in console.log
This commit is contained in:
parent
bafe525510
commit
c9ff17558d
3
.prettierignore
Normal file
3
.prettierignore
Normal file
@ -0,0 +1,3 @@
|
||||
react/
|
||||
frontend/dist/
|
||||
frontend/src/assets/
|
8
.prettierrc.json
Normal file
8
.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"useTabs": false,
|
||||
"printWidth": 100
|
||||
}
|
@ -4,7 +4,7 @@ chrome.browserAction.onClicked.addListener(() => {
|
||||
url: chrome.runtime.getURL("react/index.html"),
|
||||
type: "popup", // opens as a floating window
|
||||
width: 800,
|
||||
height: 600
|
||||
height: 600,
|
||||
});
|
||||
});
|
||||
|
||||
@ -30,7 +30,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
|
||||
case "LICENSE_URL":
|
||||
console.log("Storling License URL " + data);
|
||||
chrome.storage.local.set({licenseURL: data});
|
||||
chrome.storage.local.set({ licenseURL: data });
|
||||
break;
|
||||
|
||||
default:
|
||||
|
53
content.js
53
content.js
@ -1,26 +1,29 @@
|
||||
// Inject `inject.js` into the page context
|
||||
(function injectScript() {
|
||||
const script = document.createElement('script');
|
||||
script.src = chrome.runtime.getURL('inject.js');
|
||||
script.type = 'text/javascript';
|
||||
const script = document.createElement("script");
|
||||
script.src = chrome.runtime.getURL("inject.js");
|
||||
script.type = "text/javascript";
|
||||
script.onload = () => script.remove(); // Clean up
|
||||
// Inject directly into <html> or <head>
|
||||
(document.documentElement || document.head || document.body).appendChild(script);
|
||||
})();
|
||||
|
||||
// Listen for messages from the injected script
|
||||
window.addEventListener("message", function(event) {
|
||||
window.addEventListener("message", function (event) {
|
||||
if (event.source !== window) return;
|
||||
|
||||
if (["__DRM_TYPE__", "__PSSH_DATA__", "__KEYS_DATA__", "__LICENSE_URL__"].includes(event.data?.type)) {
|
||||
if (
|
||||
["__DRM_TYPE__", "__PSSH_DATA__", "__KEYS_DATA__", "__LICENSE_URL__"].includes(
|
||||
event.data?.type
|
||||
)
|
||||
) {
|
||||
chrome.runtime.sendMessage({
|
||||
type: event.data.type.replace("__", "").replace("__", ""),
|
||||
data: event.data.data
|
||||
data: event.data.data,
|
||||
});
|
||||
}
|
||||
|
||||
if (event.data.type === "__GET_CDM_DEVICES__") {
|
||||
|
||||
chrome.storage.local.get(["widevine_device", "playready_device"], (result) => {
|
||||
const widevine_device = result.widevine_device || null;
|
||||
const playready_device = result.playready_device || null;
|
||||
@ -29,7 +32,7 @@ window.addEventListener("message", function(event) {
|
||||
{
|
||||
type: "__CDM_DEVICES__",
|
||||
widevine_device,
|
||||
playready_device
|
||||
playready_device,
|
||||
},
|
||||
"*"
|
||||
);
|
||||
@ -37,31 +40,57 @@ window.addEventListener("message", function(event) {
|
||||
}
|
||||
|
||||
if (event.data.type === "__GET_INJECTION_TYPE__") {
|
||||
|
||||
chrome.storage.local.get("injection_type", (result) => {
|
||||
const injectionType = result.injection_type || "LICENSE";
|
||||
|
||||
window.postMessage(
|
||||
{
|
||||
type: "__INJECTION_TYPE__",
|
||||
injectionType
|
||||
injectionType,
|
||||
},
|
||||
"*"
|
||||
);
|
||||
});
|
||||
}
|
||||
if (event.data.type === "__GET_DRM_OVERRIDE__") {
|
||||
|
||||
if (event.data.type === "__GET_DRM_OVERRIDE__") {
|
||||
chrome.storage.local.get("drm_override", (result) => {
|
||||
const drmOverride = result.drm_override || "DISABLED";
|
||||
|
||||
window.postMessage(
|
||||
{
|
||||
type: "__DRM_OVERRIDE__",
|
||||
drmOverride
|
||||
drmOverride,
|
||||
},
|
||||
"*"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Manifest header and URL
|
||||
|
||||
const seenManifestUrls = new Set();
|
||||
|
||||
if (event.data?.type === "__MANIFEST_URL__") {
|
||||
const url = event.data.data;
|
||||
if (seenManifestUrls.has(url)) return;
|
||||
seenManifestUrls.add(url);
|
||||
console.log("✅ [Content] Unique manifest URL:", url);
|
||||
|
||||
chrome.runtime.sendMessage({
|
||||
type: "MANIFEST_URL_FOUND",
|
||||
data: url,
|
||||
});
|
||||
}
|
||||
|
||||
if (event.data?.type === "__MANIFEST_HEADERS__") {
|
||||
const { url, headers } = event.data;
|
||||
console.log("[Content.js] Manifest Headers:", url, headers);
|
||||
|
||||
chrome.runtime.sendMessage({
|
||||
type: "MANIFEST_HEADERS",
|
||||
url,
|
||||
headers,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -1,33 +1,30 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import js from "@eslint/js";
|
||||
import globals from "globals";
|
||||
import reactHooks from "eslint-plugin-react-hooks";
|
||||
import reactRefresh from "eslint-plugin-react-refresh";
|
||||
|
||||
export default [
|
||||
{ ignores: ['dist'] },
|
||||
{ ignores: ["dist"] },
|
||||
{
|
||||
files: ['**/*.{js,jsx}'],
|
||||
files: ["**/*.{js,jsx}"],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
ecmaVersion: "latest",
|
||||
ecmaFeatures: { jsx: true },
|
||||
sourceType: 'module',
|
||||
sourceType: "module",
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
"react-hooks": reactHooks,
|
||||
"react-refresh": reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...js.configs.recommended.rules,
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
"no-unused-vars": ["error", { varsIgnorePattern: "^[A-Z_]" }],
|
||||
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
|
||||
},
|
||||
},
|
||||
]
|
||||
];
|
||||
|
@ -1,10 +1,5 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import {
|
||||
HashRouter as Router,
|
||||
Routes,
|
||||
Route,
|
||||
Navigate,
|
||||
} from "react-router-dom";
|
||||
import { HashRouter as Router, Routes, Route, Navigate } from "react-router-dom";
|
||||
import TopNav from "./components/topnav";
|
||||
import SideNav from "./components/sidenav";
|
||||
import Results from "./components/results";
|
||||
|
@ -8,13 +8,7 @@ function Results() {
|
||||
|
||||
useEffect(() => {
|
||||
chrome.storage.local.get(
|
||||
[
|
||||
"drmType",
|
||||
"latestPSSH",
|
||||
"latestLicenseRequest",
|
||||
"latestKeys",
|
||||
"licenseURL",
|
||||
],
|
||||
["drmType", "latestPSSH", "latestLicenseRequest", "latestKeys", "licenseURL"],
|
||||
(result) => {
|
||||
if (result.drmType) setDrmType(result.drmType);
|
||||
if (result.latestPSSH) setPssh(result.latestPSSH);
|
||||
@ -64,9 +58,7 @@ function Results() {
|
||||
});
|
||||
|
||||
// Get all normal windows to exclude your popup
|
||||
chrome.windows.getAll(
|
||||
{ populate: true, windowTypes: ["normal"] },
|
||||
(windows) => {
|
||||
chrome.windows.getAll({ populate: true, windowTypes: ["normal"] }, (windows) => {
|
||||
if (!windows || windows.length === 0) {
|
||||
console.warn("No normal Chrome windows found");
|
||||
return;
|
||||
@ -94,8 +86,7 @@ function Results() {
|
||||
} else {
|
||||
console.warn("No active tab found in the last focused normal window");
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@ -132,8 +123,7 @@ function Results() {
|
||||
/>
|
||||
<p className="text-2xl mt-5">Keys</p>
|
||||
<div className="w-full min-h-64 h-64 flex items-center justify-center text-center overflow-y-auto bg-slate-800/50 rounded-md p-2 mt-2 text-white whitespace-pre-line">
|
||||
{Array.isArray(keys) &&
|
||||
keys.filter((k) => k.type !== "SIGNING").length > 0 ? (
|
||||
{Array.isArray(keys) && keys.filter((k) => k.type !== "SIGNING").length > 0 ? (
|
||||
keys
|
||||
.filter((k) => k.type !== "SIGNING")
|
||||
.map((k) => `${k.key_id || k.keyId}:${k.key}`)
|
||||
|
@ -13,10 +13,7 @@ function Settings({ onConfigSaved }) {
|
||||
useEffect(() => {
|
||||
chrome.storage.local.get("cdrm_instance", (result) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.error(
|
||||
"Error fetching CDRM instance:",
|
||||
chrome.runtime.lastError
|
||||
);
|
||||
console.error("Error fetching CDRM instance:", chrome.runtime.lastError);
|
||||
} else if (result.cdrm_instance) {
|
||||
setStoredUrl(result.cdrm_instance);
|
||||
}
|
||||
@ -49,18 +46,12 @@ function Settings({ onConfigSaved }) {
|
||||
setMessage("Successfully connected to CDRM Instance.");
|
||||
setMessageType("success");
|
||||
|
||||
const widevineRes = await fetch(
|
||||
`${trimmedUrl}/remotecdm/widevine/deviceinfo`
|
||||
);
|
||||
if (!widevineRes.ok)
|
||||
throw new Error("Failed to fetch Widevine device info");
|
||||
const widevineRes = await fetch(`${trimmedUrl}/remotecdm/widevine/deviceinfo`);
|
||||
if (!widevineRes.ok) throw new Error("Failed to fetch Widevine device info");
|
||||
const widevineData = await widevineRes.json();
|
||||
|
||||
const playreadyRes = await fetch(
|
||||
`${trimmedUrl}/remotecdm/playready/deviceinfo`
|
||||
);
|
||||
if (!playreadyRes.ok)
|
||||
throw new Error("Failed to fetch PlayReady device info");
|
||||
const playreadyRes = await fetch(`${trimmedUrl}/remotecdm/playready/deviceinfo`);
|
||||
if (!playreadyRes.ok) throw new Error("Failed to fetch PlayReady device info");
|
||||
const playreadyData = await playreadyRes.json();
|
||||
|
||||
chrome.storage.local.set(
|
||||
|
@ -7,10 +7,7 @@ function SideNav({ onClose }) {
|
||||
return (
|
||||
<div className="w-full h-full overflow-y-auto overflow-x-auto flex flex-col bg-black">
|
||||
<div className="w-full min-h-16 max-h-16 h-16 shrink-0 flex sticky top-0 z-20 border-b border-b-white bg-black">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="h-full ml-auto p-3 hover:cursor-pointer"
|
||||
>
|
||||
<button onClick={onClose} className="h-full ml-auto p-3 hover:cursor-pointer">
|
||||
<img src={closeIcon} alt="Close" className="h-full" />
|
||||
</button>
|
||||
</div>
|
||||
|
@ -19,10 +19,7 @@ function TopNav({ onMenuClick }) {
|
||||
const handleInjectionTypeChange = (type) => {
|
||||
chrome.storage.local.set({ injection_type: type }, () => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.error(
|
||||
"Error updating injection_type:",
|
||||
chrome.runtime.lastError
|
||||
);
|
||||
console.error("Error updating injection_type:", chrome.runtime.lastError);
|
||||
} else {
|
||||
setInjectionType(type);
|
||||
console.log(`Injection type updated to ${type}`);
|
||||
|
@ -1,6 +1,8 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
html, body, #root {
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import App from './App.jsx'
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import "./index.css";
|
||||
import App from "./App.jsx";
|
||||
|
||||
createRoot(document.getElementById('root')).render(
|
||||
createRoot(document.getElementById("root")).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
</StrictMode>
|
||||
);
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
base: './',
|
||||
base: "./",
|
||||
plugins: [react(), tailwindcss()],
|
||||
})
|
||||
});
|
||||
|
593
inject.js
593
inject.js
@ -1,6 +1,6 @@
|
||||
let widevineDeviceInfo = null;
|
||||
let playreadyDeviceInfo = null;
|
||||
let originalChallenge = null
|
||||
let originalChallenge = null;
|
||||
let serviceCertFound = false;
|
||||
let drmType = "NONE";
|
||||
let psshFound = false;
|
||||
@ -21,7 +21,7 @@ let keysRetrieved = false;
|
||||
window.postMessage({ type: "__GET_DRM_OVERRIDE__" }, "*");
|
||||
|
||||
// Add listener for DRM override messages
|
||||
window.addEventListener("message", function(event) {
|
||||
window.addEventListener("message", function (event) {
|
||||
if (event.source !== window) return;
|
||||
if (event.data.type === "__DRM_OVERRIDE__") {
|
||||
drmOverride = event.data.drmOverride || "DISABLED";
|
||||
@ -33,7 +33,7 @@ window.addEventListener("message", function(event) {
|
||||
window.postMessage({ type: "__GET_INJECTION_TYPE__" }, "*");
|
||||
|
||||
// Add listener for injection type messages
|
||||
window.addEventListener("message", function(event) {
|
||||
window.addEventListener("message", function (event) {
|
||||
if (event.source !== window) return;
|
||||
|
||||
if (event.data.type === "__INJECTION_TYPE__") {
|
||||
@ -46,7 +46,7 @@ window.addEventListener("message", function(event) {
|
||||
window.postMessage({ type: "__GET_CDM_DEVICES__" }, "*");
|
||||
|
||||
// Add listener for CDM device messages
|
||||
window.addEventListener("message", function(event) {
|
||||
window.addEventListener("message", function (event) {
|
||||
if (event.source !== window) return;
|
||||
|
||||
if (event.data.type === "__CDM_DEVICES__") {
|
||||
@ -59,6 +59,122 @@ window.addEventListener("message", function(event) {
|
||||
}
|
||||
});
|
||||
|
||||
function safeHeaderShellEscape(str) {
|
||||
return str
|
||||
.replace(/\\/g, "\\\\")
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/\$/g, "\\$") // escape shell expansion
|
||||
.replace(/`/g, "\\`")
|
||||
.replace(/\n/g, ""); // strip newlines
|
||||
}
|
||||
|
||||
// Intercep network to find manifest
|
||||
function injectManifestInterceptor() {
|
||||
const script = document.createElement("script");
|
||||
script.textContent = `
|
||||
(function() {
|
||||
function isProbablyManifest(text = "", contentType = "") {
|
||||
const lowerCT = contentType?.toLowerCase() ?? "";
|
||||
const sample = text.slice(0, 2000);
|
||||
|
||||
const isHLSMime = lowerCT.includes("mpegurl");
|
||||
const isDASHMime = lowerCT.includes("dash+xml");
|
||||
const isSmoothMime = lowerCT.includes("sstr+xml");
|
||||
|
||||
const isHLSKeyword = sample.includes("#EXTM3U") || sample.includes("#EXT-X-STREAM-INF");
|
||||
const isDASHKeyword = sample.includes("<MPD") || sample.includes("<AdaptationSet");
|
||||
const isSmoothKeyword = sample.includes("<SmoothStreamingMedia");
|
||||
const isJsonManifest = sample.includes('"playlist"') && sample.includes('"segments"');
|
||||
|
||||
return (
|
||||
isHLSMime || isDASHMime || isSmoothMime ||
|
||||
isHLSKeyword || isDASHKeyword || isSmoothKeyword || isJsonManifest
|
||||
);
|
||||
}
|
||||
|
||||
const originalFetch = window.fetch;
|
||||
window.fetch = async function(input, init) {
|
||||
const response = await originalFetch.apply(this, arguments);
|
||||
|
||||
try {
|
||||
const clone = response.clone();
|
||||
const contentType = clone.headers.get("content-type") || "";
|
||||
const text = await clone.text();
|
||||
|
||||
const url = typeof input === "string" ? input : input.url;
|
||||
|
||||
if (isProbablyManifest(text, contentType)) {
|
||||
window.postMessage({ type: "__MANIFEST_URL__", data: url }, "*");
|
||||
console.log("[Manifest][fetch]", url, contentType);
|
||||
|
||||
const headersObj = {};
|
||||
clone.headers.forEach((value, key) => {
|
||||
headersObj[key] = value;
|
||||
});
|
||||
|
||||
const headerFlags = Object.entries(headersObj)
|
||||
.map(([key, val]) => '--add-headers "' + safeHeaderShellEscape(key) + ': ' + safeHeaderShellEscape(val) + '"')
|
||||
.join(" ");
|
||||
|
||||
window.postMessage({
|
||||
type: "__MANIFEST_HEADERS__",
|
||||
url,
|
||||
headers: headerFlags
|
||||
}, "*");
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
const originalXHROpen = XMLHttpRequest.prototype.open;
|
||||
const originalXHRSend = XMLHttpRequest.prototype.send;
|
||||
|
||||
XMLHttpRequest.prototype.open = function(method, url) {
|
||||
this.__url = url;
|
||||
return originalXHROpen.apply(this, arguments);
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype.send = function(body) {
|
||||
this.addEventListener("load", function () {
|
||||
try {
|
||||
const contentType = this.getResponseHeader("content-type") || "";
|
||||
const text = this.responseText;
|
||||
|
||||
if (isProbablyManifest(text, contentType)) {
|
||||
window.postMessage({ type: "__MANIFEST_URL__", data: this.__url }, "*");
|
||||
console.log("[Manifest][xhr]", this.__url, contentType);
|
||||
|
||||
const xhrHeaders = {};
|
||||
const rawHeaders = this.getAllResponseHeaders().trim().split(/\\r?\\n/);
|
||||
rawHeaders.forEach(line => {
|
||||
const parts = line.split(": ");
|
||||
if (parts.length === 2) {
|
||||
xhrHeaders[parts[0]] = parts[1];
|
||||
}
|
||||
});
|
||||
|
||||
const headerFlags = Object.entries(xhrHeaders)
|
||||
.map(([key, val]) => '--add-headers "' + safeHeaderShellEscape(key) + ': ' + safeHeaderShellEscape(val) + '"')
|
||||
.join(" ");
|
||||
|
||||
window.postMessage({
|
||||
type: "__MANIFEST_HEADERS__",
|
||||
url: this.__url,
|
||||
headers: headerFlags
|
||||
}, "*");
|
||||
}
|
||||
} catch (e) {}
|
||||
});
|
||||
return originalXHRSend.apply(this, arguments);
|
||||
};
|
||||
})();
|
||||
`;
|
||||
document.documentElement.appendChild(script);
|
||||
script.remove();
|
||||
}
|
||||
|
||||
injectManifestInterceptor();
|
||||
|
||||
// PlayReady Remote CDM Class
|
||||
class remotePlayReadyCDM {
|
||||
@ -76,8 +192,8 @@ class remotePlayReadyCDM {
|
||||
openSession() {
|
||||
const url = `${this.host}/remotecdm/playready/${this.device_name}/open`;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, false);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.open("GET", url, false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.send();
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData.data?.session_id) {
|
||||
@ -93,11 +209,11 @@ class remotePlayReadyCDM {
|
||||
getChallenge(init_data) {
|
||||
const url = `${this.host}/remotecdm/playready/${this.device_name}/get_license_challenge`;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url, false);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.open("POST", url, false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
const body = {
|
||||
session_id: this.session_id,
|
||||
init_data: init_data
|
||||
init_data: init_data,
|
||||
};
|
||||
xhr.send(JSON.stringify(body));
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
@ -114,16 +230,17 @@ class remotePlayReadyCDM {
|
||||
parseLicense(license_message) {
|
||||
const url = `${this.host}/remotecdm/playready/${this.device_name}/parse_license`;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url, false);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.open("POST", url, false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
const body = {
|
||||
session_id: this.session_id,
|
||||
license_message: license_message
|
||||
}
|
||||
license_message: license_message,
|
||||
};
|
||||
xhr.send(JSON.stringify(body));
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData.message === "Successfully parsed and loaded the Keys from the License message")
|
||||
{
|
||||
if (
|
||||
jsonData.message === "Successfully parsed and loaded the Keys from the License message"
|
||||
) {
|
||||
console.log("PlayReady license response parsed successfully");
|
||||
return true;
|
||||
} else {
|
||||
@ -136,11 +253,11 @@ class remotePlayReadyCDM {
|
||||
getKeys() {
|
||||
const url = `${this.host}/remotecdm/playready/${this.device_name}/get_keys`;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url, false);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.open("POST", url, false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
const body = {
|
||||
session_id: this.session_id
|
||||
}
|
||||
session_id: this.session_id,
|
||||
};
|
||||
xhr.send(JSON.stringify(body));
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData.data?.keys) {
|
||||
@ -153,11 +270,11 @@ class remotePlayReadyCDM {
|
||||
}
|
||||
|
||||
// Close PlayReady session
|
||||
closeSession () {
|
||||
closeSession() {
|
||||
const url = `${this.host}/remotecdm/playready/${this.device_name}/close/${this.session_id}`;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, false);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.open("GET", url, false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.send();
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData) {
|
||||
@ -184,11 +301,11 @@ class remoteWidevineCDM {
|
||||
}
|
||||
|
||||
// Open Widevine session
|
||||
openSession () {
|
||||
openSession() {
|
||||
const url = `${this.host}/remotecdm/widevine/${this.device_name}/open`;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, false);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.open("GET", url, false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.send();
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData.data?.session_id) {
|
||||
@ -204,12 +321,12 @@ class remoteWidevineCDM {
|
||||
setServiceCertificate(certificate) {
|
||||
const url = `${this.host}/remotecdm/widevine/${this.device_name}/set_service_certificate`;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url, false);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.open("POST", url, false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
const body = {
|
||||
session_id: this.session_id,
|
||||
certificate: certificate ?? null
|
||||
}
|
||||
certificate: certificate ?? null,
|
||||
};
|
||||
xhr.send(JSON.stringify(body));
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData.status === 200) {
|
||||
@ -221,15 +338,15 @@ class remoteWidevineCDM {
|
||||
}
|
||||
|
||||
// Get Widevine challenge
|
||||
getChallenge(init_data, license_type = 'STREAMING') {
|
||||
getChallenge(init_data, license_type = "STREAMING") {
|
||||
const url = `${this.host}/remotecdm/widevine/${this.device_name}/get_license_challenge/${license_type}`;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url, false);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.open("POST", url, false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
const body = {
|
||||
session_id: this.session_id,
|
||||
init_data: init_data,
|
||||
privacy_mode: serviceCertFound
|
||||
privacy_mode: serviceCertFound,
|
||||
};
|
||||
xhr.send(JSON.stringify(body));
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
@ -246,11 +363,11 @@ class remoteWidevineCDM {
|
||||
parseLicense(license_message) {
|
||||
const url = `${this.host}/remotecdm/widevine/${this.device_name}/parse_license`;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url, false);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.open("POST", url, false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
const body = {
|
||||
session_id: this.session_id,
|
||||
license_message: license_message
|
||||
license_message: license_message,
|
||||
};
|
||||
xhr.send(JSON.stringify(body));
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
@ -267,10 +384,10 @@ class remoteWidevineCDM {
|
||||
getKeys() {
|
||||
const url = `${this.host}/remotecdm/widevine/${this.device_name}/get_keys/ALL`;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url, false);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.open("POST", url, false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
const body = {
|
||||
session_id: this.session_id
|
||||
session_id: this.session_id,
|
||||
};
|
||||
xhr.send(JSON.stringify(body));
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
@ -287,8 +404,8 @@ class remoteWidevineCDM {
|
||||
closeSession() {
|
||||
const url = `${this.host}/remotecdm/widevine/${this.device_name}/close/${this.session_id}`;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, false);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.open("GET", url, false);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.send();
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData) {
|
||||
@ -302,22 +419,22 @@ class remoteWidevineCDM {
|
||||
|
||||
// Utility functions
|
||||
function hexStrToU8(hexString) {
|
||||
return Uint8Array.from(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
|
||||
return Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
|
||||
}
|
||||
|
||||
function u8ToHexStr(bytes) {
|
||||
return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
|
||||
return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
|
||||
}
|
||||
|
||||
function b64ToHexStr(b64) {
|
||||
return [...atob(b64)].map(c => c.charCodeAt(0).toString(16).padStart(2, '0')).join``;
|
||||
return [...atob(b64)].map((c) => c.charCodeAt(0).toString(16).padStart(2, "0")).join``;
|
||||
}
|
||||
|
||||
function jsonContainsValue(obj, prefix = "CAES") {
|
||||
if (typeof obj === "string") return obj.startsWith(prefix);
|
||||
if (Array.isArray(obj)) return obj.some(val => jsonContainsValue(val, prefix));
|
||||
if (Array.isArray(obj)) return obj.some((val) => jsonContainsValue(val, prefix));
|
||||
if (typeof obj === "object" && obj !== null) {
|
||||
return Object.values(obj).some(val => jsonContainsValue(val, prefix));
|
||||
return Object.values(obj).some((val) => jsonContainsValue(val, prefix));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -328,7 +445,7 @@ function jsonReplaceValue(obj, newValue) {
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(item => jsonReplaceValue(item, newValue));
|
||||
return obj.map((item) => jsonReplaceValue(item, newValue));
|
||||
}
|
||||
|
||||
if (typeof obj === "object" && obj !== null) {
|
||||
@ -379,10 +496,10 @@ function getPlayReadyPssh(buffer) {
|
||||
}
|
||||
|
||||
function getClearkey(response) {
|
||||
let obj = JSON.parse((new TextDecoder("utf-8")).decode(response));
|
||||
return obj["keys"].map(o => ({
|
||||
key_id: b64ToHexStr(o["kid"].replace(/-/g, '+').replace(/_/g, '/')),
|
||||
key: b64ToHexStr(o["k"].replace(/-/g, '+').replace(/_/g, '/')),
|
||||
let obj = JSON.parse(new TextDecoder("utf-8").decode(response));
|
||||
return obj["keys"].map((o) => ({
|
||||
key_id: b64ToHexStr(o["kid"].replace(/-/g, "+").replace(/_/g, "/")),
|
||||
key: b64ToHexStr(o["k"].replace(/-/g, "+").replace(/_/g, "/")),
|
||||
}));
|
||||
}
|
||||
|
||||
@ -397,7 +514,7 @@ function base64ToUint8Array(base64) {
|
||||
}
|
||||
|
||||
function arrayBufferToBase64(uint8array) {
|
||||
let binary = '';
|
||||
let binary = "";
|
||||
const len = uint8array.length;
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
@ -409,20 +526,20 @@ function arrayBufferToBase64(uint8array) {
|
||||
|
||||
// Challenge generator interceptor
|
||||
const originalGenerateRequest = MediaKeySession.prototype.generateRequest;
|
||||
MediaKeySession.prototype.generateRequest = function(initDataType, initData) {
|
||||
MediaKeySession.prototype.generateRequest = function (initDataType, initData) {
|
||||
const session = this;
|
||||
let playReadyPssh = getPlayReadyPssh(initData);
|
||||
if (playReadyPssh) {
|
||||
console.log("[DRM Detected] PlayReady");
|
||||
foundPlayreadyPssh = playReadyPssh;
|
||||
console.log("[PlayReady PSSH found] " + playReadyPssh)
|
||||
console.log("[PlayReady PSSH found] " + playReadyPssh);
|
||||
}
|
||||
let wideVinePssh = getWidevinePssh(initData)
|
||||
let wideVinePssh = getWidevinePssh(initData);
|
||||
if (wideVinePssh) {
|
||||
// Widevine code
|
||||
console.log("[DRM Detected] Widevine");
|
||||
foundWidevinePssh = wideVinePssh;
|
||||
console.log("[Widevine PSSH found] " + wideVinePssh)
|
||||
console.log("[Widevine PSSH found] " + wideVinePssh);
|
||||
}
|
||||
// Challenge message interceptor
|
||||
if (!remoteListenerMounted) {
|
||||
@ -432,10 +549,16 @@ MediaKeySession.prototype.generateRequest = function(initDataType, initData) {
|
||||
const uint8Array = new Uint8Array(event.message);
|
||||
const base64challenge = arrayBufferToBase64(uint8Array);
|
||||
if (base64challenge === "CAQ=" && interceptType !== "DISABLED" && !serviceCertFound) {
|
||||
const {
|
||||
device_type, system_id, security_level, host, secret, device_name
|
||||
} = widevineDeviceInfo;
|
||||
remoteCDM = new remoteWidevineCDM(device_type, system_id, security_level, host, secret, device_name);
|
||||
const { device_type, system_id, security_level, host, secret, device_name } =
|
||||
widevineDeviceInfo;
|
||||
remoteCDM = new remoteWidevineCDM(
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
}
|
||||
if (!injectionSuccess && base64challenge !== "CAQ=" && interceptType !== "DISABLED") {
|
||||
@ -450,30 +573,53 @@ MediaKeySession.prototype.generateRequest = function(initDataType, initData) {
|
||||
window.postMessage({ type: "__PSSH_DATA__", data: foundWidevinePssh }, "*");
|
||||
if (interceptType === "EME" && !remoteCDM) {
|
||||
const {
|
||||
device_type, system_id, security_level, host, secret, device_name
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name,
|
||||
} = widevineDeviceInfo;
|
||||
remoteCDM = new remoteWidevineCDM(device_type, system_id, security_level, host, secret, device_name);
|
||||
remoteCDM = new remoteWidevineCDM(
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundWidevinePssh);
|
||||
}}
|
||||
}
|
||||
}
|
||||
if (!originalChallenge.startsWith("CAES")) {
|
||||
const buffer = event.message;
|
||||
const decoder = new TextDecoder('utf-16');
|
||||
const decoder = new TextDecoder("utf-16");
|
||||
const decodedText = decoder.decode(buffer);
|
||||
const match = decodedText.match(/<Challenge encoding="base64encoded">([^<]+)<\/Challenge>/);
|
||||
const match = decodedText.match(
|
||||
/<Challenge encoding="base64encoded">([^<]+)<\/Challenge>/
|
||||
);
|
||||
if (match) {
|
||||
window.postMessage({ type: "__DRM_TYPE__", data: "PlayReady" }, "*");
|
||||
window.postMessage({ type: "__PSSH_DATA__", data: foundPlayreadyPssh }, "*");
|
||||
window.postMessage(
|
||||
{ type: "__PSSH_DATA__", data: foundPlayreadyPssh },
|
||||
"*"
|
||||
);
|
||||
originalChallenge = match[1];
|
||||
if (interceptType === "EME" && !remoteCDM) {
|
||||
const {
|
||||
security_level, host, secret, device_name
|
||||
} = playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(security_level, host, secret, device_name)
|
||||
const { security_level, host, secret, device_name } =
|
||||
playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundPlayreadyPssh);
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
if (interceptType === "EME" && remoteCDM) {
|
||||
const uint8challenge = base64ToUint8Array(remoteCDM.challenge);
|
||||
const challengeBuffer = uint8challenge.buffer;
|
||||
@ -482,24 +628,24 @@ MediaKeySession.prototype.generateRequest = function(initDataType, initData) {
|
||||
origin: event.origin,
|
||||
lastEventId: event.lastEventId,
|
||||
source: event.source,
|
||||
ports: event.ports
|
||||
ports: event.ports,
|
||||
});
|
||||
Object.defineProperty(syntheticEvent, "message", {
|
||||
get: () => challengeBuffer
|
||||
get: () => challengeBuffer,
|
||||
});
|
||||
console.log("Intercepted EME Challenge and injected custom one.")
|
||||
console.log("Intercepted EME Challenge and injected custom one.");
|
||||
session.dispatchEvent(syntheticEvent);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
console.log("Message interceptor mounted.");
|
||||
}
|
||||
return originalGenerateRequest.call(session, initDataType, initData);
|
||||
return originalGenerateRequest.call(session, initDataType, initData);
|
||||
};
|
||||
|
||||
// Message update interceptors
|
||||
const originalUpdate = MediaKeySession.prototype.update;
|
||||
MediaKeySession.prototype.update = function(response) {
|
||||
MediaKeySession.prototype.update = function (response) {
|
||||
const uint8 = response instanceof Uint8Array ? response : new Uint8Array(response);
|
||||
const base64Response = window.btoa(String.fromCharCode(...uint8));
|
||||
if (base64Response.startsWith("CAUS") && foundWidevinePssh && remoteCDM && !serviceCertFound) {
|
||||
@ -511,7 +657,11 @@ MediaKeySession.prototype.update = function(response) {
|
||||
window.postMessage({ type: "__PSSH_DATA__", data: foundWidevinePssh }, "*");
|
||||
serviceCertFound = true;
|
||||
}
|
||||
if (!base64Response.startsWith("CAUS") && (foundWidevinePssh || foundPlayreadyPssh) && !keysRetrieved) {
|
||||
if (
|
||||
!base64Response.startsWith("CAUS") &&
|
||||
(foundWidevinePssh || foundPlayreadyPssh) &&
|
||||
!keysRetrieved
|
||||
) {
|
||||
if (licenseResponseCounter === 1 || foundChallengeInBody) {
|
||||
remoteCDM.parseLicense(base64Response);
|
||||
remoteCDM.getKeys();
|
||||
@ -530,17 +680,17 @@ MediaKeySession.prototype.update = function(response) {
|
||||
console.log("[CLEARKEY] ", clearKeys);
|
||||
const drmType = {
|
||||
type: "__DRM_TYPE__",
|
||||
data: 'ClearKey'
|
||||
data: "ClearKey",
|
||||
};
|
||||
window.postMessage(drmType, "*");
|
||||
const keysData = {
|
||||
type: "__KEYS_DATA__",
|
||||
data: clearKeys
|
||||
data: clearKeys,
|
||||
};
|
||||
window.postMessage(keysData, "*");
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
.catch((e) => {
|
||||
console.log("[CLEARKEY] Not found");
|
||||
});
|
||||
}
|
||||
@ -549,41 +699,67 @@ MediaKeySession.prototype.update = function(response) {
|
||||
};
|
||||
|
||||
// fetch POST interceptor
|
||||
(function() {
|
||||
(function () {
|
||||
const originalFetch = window.fetch;
|
||||
|
||||
window.fetch = async function(resource, config = {}) {
|
||||
const method = (config.method || 'GET').toUpperCase();
|
||||
window.fetch = async function (resource, config = {}) {
|
||||
const method = (config.method || "GET").toUpperCase();
|
||||
|
||||
if (method === 'POST') {
|
||||
if (method === "POST") {
|
||||
let body = config.body;
|
||||
if (body) {
|
||||
if (body instanceof ArrayBuffer || body instanceof Uint8Array) {
|
||||
const buffer = body instanceof Uint8Array ? body : new Uint8Array(body);
|
||||
const base64Body = window.btoa(String.fromCharCode(...buffer));
|
||||
if ((base64Body.startsWith("CAES") || base64Body.startsWith("PD94")) && (!remoteCDM || remoteCDM.challenge === null || base64Body !== remoteCDM.challenge) && interceptType === "EME") {
|
||||
if (
|
||||
(base64Body.startsWith("CAES") || base64Body.startsWith("PD94")) &&
|
||||
(!remoteCDM ||
|
||||
remoteCDM.challenge === null ||
|
||||
base64Body !== remoteCDM.challenge) &&
|
||||
interceptType === "EME"
|
||||
) {
|
||||
foundChallengeInBody = true;
|
||||
window.postMessage({ type: "__LICENSE_URL__", data: resource }, "*");
|
||||
// Block the request
|
||||
return;
|
||||
}
|
||||
if ((base64Body.startsWith("CAES") || base64Body.startsWith("PD94")) && interceptType == "LICENSE" &&!foundChallengeInBody) {
|
||||
if (
|
||||
(base64Body.startsWith("CAES") || base64Body.startsWith("PD94")) &&
|
||||
interceptType == "LICENSE" &&
|
||||
!foundChallengeInBody
|
||||
) {
|
||||
foundChallengeInBody = true;
|
||||
window.postMessage({ type: "__LICENSE_URL__", data: resource }, "*");
|
||||
if (!remoteCDM) {
|
||||
if (base64Body.startsWith("CAES")) {
|
||||
const {
|
||||
device_type, system_id, security_level, host, secret, device_name
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name,
|
||||
} = widevineDeviceInfo;
|
||||
remoteCDM = new remoteWidevineCDM(device_type, system_id, security_level, host, secret, device_name);
|
||||
remoteCDM = new remoteWidevineCDM(
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundWidevinePssh);
|
||||
}
|
||||
if (base64Body.startsWith("PD94")) {
|
||||
const {
|
||||
security_level, host, secret, device_name
|
||||
} = playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(security_level, host, secret, device_name);
|
||||
const { security_level, host, secret, device_name } =
|
||||
playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundPlayreadyPssh);
|
||||
}
|
||||
@ -596,31 +772,59 @@ MediaKeySession.prototype.update = function(response) {
|
||||
return originalFetch(resource, config);
|
||||
}
|
||||
}
|
||||
if (typeof body === 'string' && !isJson(body)) {
|
||||
if (typeof body === "string" && !isJson(body)) {
|
||||
const base64EncodedBody = btoa(body);
|
||||
if ((base64EncodedBody.startsWith("CAES") || base64EncodedBody.startsWith("PD94")) && (!remoteCDM || remoteCDM.challenge === null || base64EncodedBody !== remoteCDM.challenge) && interceptType === "EME") {
|
||||
if (
|
||||
(base64EncodedBody.startsWith("CAES") ||
|
||||
base64EncodedBody.startsWith("PD94")) &&
|
||||
(!remoteCDM ||
|
||||
remoteCDM.challenge === null ||
|
||||
base64EncodedBody !== remoteCDM.challenge) &&
|
||||
interceptType === "EME"
|
||||
) {
|
||||
foundChallengeInBody = true;
|
||||
window.postMessage({ type: "__LICENSE_URL__", data: resource }, "*");
|
||||
// Block the request
|
||||
return;
|
||||
}
|
||||
if ((base64EncodedBody.startsWith("CAES") || base64EncodedBody.startsWith("PD94")) && interceptType == "LICENSE" && !foundChallengeInBody) {
|
||||
if (
|
||||
(base64EncodedBody.startsWith("CAES") ||
|
||||
base64EncodedBody.startsWith("PD94")) &&
|
||||
interceptType == "LICENSE" &&
|
||||
!foundChallengeInBody
|
||||
) {
|
||||
foundChallengeInBody = true;
|
||||
window.postMessage({ type: "__LICENSE_URL__", data: resource }, "*");
|
||||
if (!remoteCDM) {
|
||||
if (base64EncodedBody.startsWith("CAES")) {
|
||||
const {
|
||||
device_type, system_id, security_level, host, secret, device_name
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name,
|
||||
} = widevineDeviceInfo;
|
||||
remoteCDM = new remoteWidevineCDM(device_type, system_id, security_level, host, secret, device_name);
|
||||
remoteCDM = new remoteWidevineCDM(
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundWidevinePssh);
|
||||
}
|
||||
if (base64EncodedBody.startsWith("PD94")) {
|
||||
const {
|
||||
security_level, host, secret, device_name
|
||||
} = playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(security_level, host, secret, device_name);
|
||||
const { security_level, host, secret, device_name } =
|
||||
playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundPlayreadyPssh);
|
||||
}
|
||||
@ -633,33 +837,59 @@ MediaKeySession.prototype.update = function(response) {
|
||||
return originalFetch(resource, config);
|
||||
}
|
||||
}
|
||||
if (typeof body === 'string' && isJson(body)) {
|
||||
if (typeof body === "string" && isJson(body)) {
|
||||
const jsonBody = JSON.parse(body);
|
||||
|
||||
if ((jsonContainsValue(jsonBody, "CAES") || jsonContainsValue(jsonBody, "PD94")) && (!remoteCDM || remoteCDM.challenge === null) && interceptType === "EME") {
|
||||
if (
|
||||
(jsonContainsValue(jsonBody, "CAES") ||
|
||||
jsonContainsValue(jsonBody, "PD94")) &&
|
||||
(!remoteCDM || remoteCDM.challenge === null) &&
|
||||
interceptType === "EME"
|
||||
) {
|
||||
foundChallengeInBody = true;
|
||||
window.postMessage({ type: "__LICENSE_URL__", data: resource }, "*");
|
||||
// Block the request
|
||||
return;
|
||||
}
|
||||
|
||||
if ((jsonContainsValue(jsonBody, "CAES") || jsonContainsValue(jsonBody, "PD94")) && interceptType === "LICENSE" && !foundChallengeInBody) {
|
||||
if (
|
||||
(jsonContainsValue(jsonBody, "CAES") ||
|
||||
jsonContainsValue(jsonBody, "PD94")) &&
|
||||
interceptType === "LICENSE" &&
|
||||
!foundChallengeInBody
|
||||
) {
|
||||
foundChallengeInBody = true;
|
||||
window.postMessage({ type: "__LICENSE_URL__", data: resource }, "*");
|
||||
if (!remoteCDM) {
|
||||
if (jsonContainsValue(jsonBody, "CAES")) {
|
||||
const {
|
||||
device_type, system_id, security_level, host, secret, device_name
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name,
|
||||
} = widevineDeviceInfo;
|
||||
remoteCDM = new remoteWidevineCDM(device_type, system_id, security_level, host, secret, device_name);
|
||||
remoteCDM = new remoteWidevineCDM(
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundWidevinePssh);
|
||||
}
|
||||
if (jsonContainsValue(jsonBody, "PD94")) {
|
||||
const {
|
||||
security_level, host, secret, device_name
|
||||
} = playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(security_level, host, secret, device_name);
|
||||
const { security_level, host, secret, device_name } =
|
||||
playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundPlayreadyPssh);
|
||||
}
|
||||
@ -679,46 +909,71 @@ MediaKeySession.prototype.update = function(response) {
|
||||
})();
|
||||
|
||||
// XHR POST interceptor
|
||||
(function() {
|
||||
(function () {
|
||||
const originalOpen = XMLHttpRequest.prototype.open;
|
||||
const originalSend = XMLHttpRequest.prototype.send;
|
||||
|
||||
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
|
||||
XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
|
||||
this._method = method;
|
||||
this._url = url;
|
||||
return originalOpen.apply(this, arguments);
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype.send = function(body) {
|
||||
if (this._method && this._method.toUpperCase() === 'POST') {
|
||||
XMLHttpRequest.prototype.send = function (body) {
|
||||
if (this._method && this._method.toUpperCase() === "POST") {
|
||||
if (body) {
|
||||
|
||||
if (body instanceof ArrayBuffer || body instanceof Uint8Array) {
|
||||
const buffer = body instanceof Uint8Array ? body : new Uint8Array(body);
|
||||
const base64Body = window.btoa(String.fromCharCode(...buffer));
|
||||
if ((base64Body.startsWith("CAES") || base64Body.startsWith("PD94")) && (!remoteCDM || remoteCDM.challenge === null || base64Body !== remoteCDM.challenge) && interceptType === "EME") {
|
||||
if (
|
||||
(base64Body.startsWith("CAES") || base64Body.startsWith("PD94")) &&
|
||||
(!remoteCDM ||
|
||||
remoteCDM.challenge === null ||
|
||||
base64Body !== remoteCDM.challenge) &&
|
||||
interceptType === "EME"
|
||||
) {
|
||||
foundChallengeInBody = true;
|
||||
window.postMessage({ type: "__LICENSE_URL__", data: this._url }, "*");
|
||||
// Block the request
|
||||
return;
|
||||
}
|
||||
if ((base64Body.startsWith("CAES") || base64Body.startsWith("PD94")) && interceptType == "LICENSE" &&!foundChallengeInBody) {
|
||||
if (
|
||||
(base64Body.startsWith("CAES") || base64Body.startsWith("PD94")) &&
|
||||
interceptType == "LICENSE" &&
|
||||
!foundChallengeInBody
|
||||
) {
|
||||
foundChallengeInBody = true;
|
||||
window.postMessage({ type: "__LICENSE_URL__", data: this._url }, "*");
|
||||
if (!remoteCDM) {
|
||||
if (base64Body.startsWith("CAES")) {
|
||||
const {
|
||||
device_type, system_id, security_level, host, secret, device_name
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name,
|
||||
} = widevineDeviceInfo;
|
||||
remoteCDM = new remoteWidevineCDM(device_type, system_id, security_level, host, secret, device_name);
|
||||
remoteCDM = new remoteWidevineCDM(
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundWidevinePssh);
|
||||
}
|
||||
if (base64Body.startsWith("PD94")) {
|
||||
const {
|
||||
security_level, host, secret, device_name
|
||||
} = playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(security_level, host, secret, device_name);
|
||||
const { security_level, host, secret, device_name } =
|
||||
playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundPlayreadyPssh);
|
||||
}
|
||||
@ -731,31 +986,59 @@ MediaKeySession.prototype.update = function(response) {
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof body === 'string' && !isJson(body)) {
|
||||
if (typeof body === "string" && !isJson(body)) {
|
||||
const base64EncodedBody = btoa(body);
|
||||
if ((base64EncodedBody.startsWith("CAES") || base64EncodedBody.startsWith("PD94")) && (!remoteCDM || remoteCDM.challenge === null || base64EncodedBody !== remoteCDM.challenge) && interceptType === "EME") {
|
||||
if (
|
||||
(base64EncodedBody.startsWith("CAES") ||
|
||||
base64EncodedBody.startsWith("PD94")) &&
|
||||
(!remoteCDM ||
|
||||
remoteCDM.challenge === null ||
|
||||
base64EncodedBody !== remoteCDM.challenge) &&
|
||||
interceptType === "EME"
|
||||
) {
|
||||
foundChallengeInBody = true;
|
||||
window.postMessage({ type: "__LICENSE_URL__", data: this._url }, "*");
|
||||
// Block the request
|
||||
return;
|
||||
}
|
||||
if ((base64EncodedBody.startsWith("CAES") || base64EncodedBody.startsWith("PD94")) && interceptType == "LICENSE" && !foundChallengeInBody) {
|
||||
if (
|
||||
(base64EncodedBody.startsWith("CAES") ||
|
||||
base64EncodedBody.startsWith("PD94")) &&
|
||||
interceptType == "LICENSE" &&
|
||||
!foundChallengeInBody
|
||||
) {
|
||||
foundChallengeInBody = true;
|
||||
window.postMessage({ type: "__LICENSE_URL__", data: this._url }, "*");
|
||||
if (!remoteCDM) {
|
||||
if (base64EncodedBody.startsWith("CAES")) {
|
||||
const {
|
||||
device_type, system_id, security_level, host, secret, device_name
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name,
|
||||
} = widevineDeviceInfo;
|
||||
remoteCDM = new remoteWidevineCDM(device_type, system_id, security_level, host, secret, device_name);
|
||||
remoteCDM = new remoteWidevineCDM(
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundWidevinePssh);
|
||||
}
|
||||
if (base64EncodedBody.startsWith("PD94")) {
|
||||
const {
|
||||
security_level, host, secret, device_name
|
||||
} = playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(security_level, host, secret, device_name);
|
||||
const { security_level, host, secret, device_name } =
|
||||
playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundPlayreadyPssh);
|
||||
}
|
||||
@ -768,33 +1051,59 @@ MediaKeySession.prototype.update = function(response) {
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof body === 'string' && isJson(body)) {
|
||||
if (typeof body === "string" && isJson(body)) {
|
||||
const jsonBody = JSON.parse(body);
|
||||
|
||||
if ((jsonContainsValue(jsonBody, "CAES") || jsonContainsValue(jsonBody, "PD94")) && (!remoteCDM || remoteCDM.challenge === null) && interceptType === "EME") {
|
||||
if (
|
||||
(jsonContainsValue(jsonBody, "CAES") ||
|
||||
jsonContainsValue(jsonBody, "PD94")) &&
|
||||
(!remoteCDM || remoteCDM.challenge === null) &&
|
||||
interceptType === "EME"
|
||||
) {
|
||||
foundChallengeInBody = true;
|
||||
window.postMessage({ type: "__LICENSE_URL__", data: this._url }, "*");
|
||||
// Block the request
|
||||
return;
|
||||
}
|
||||
|
||||
if ((jsonContainsValue(jsonBody, "CAES") || jsonContainsValue(jsonBody, "PD94")) && interceptType === "LICENSE" && !foundChallengeInBody) {
|
||||
if (
|
||||
(jsonContainsValue(jsonBody, "CAES") ||
|
||||
jsonContainsValue(jsonBody, "PD94")) &&
|
||||
interceptType === "LICENSE" &&
|
||||
!foundChallengeInBody
|
||||
) {
|
||||
foundChallengeInBody = true;
|
||||
window.postMessage({ type: "__LICENSE_URL__", data: this._url }, "*");
|
||||
if (!remoteCDM) {
|
||||
if (jsonContainsValue(jsonBody, "CAES")) {
|
||||
const {
|
||||
device_type, system_id, security_level, host, secret, device_name
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name,
|
||||
} = widevineDeviceInfo;
|
||||
remoteCDM = new remoteWidevineCDM(device_type, system_id, security_level, host, secret, device_name);
|
||||
remoteCDM = new remoteWidevineCDM(
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundWidevinePssh);
|
||||
}
|
||||
if (jsonContainsValue(jsonBody, "PD94")) {
|
||||
const {
|
||||
security_level, host, secret, device_name
|
||||
} = playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(security_level, host, secret, device_name);
|
||||
const { security_level, host, secret, device_name } =
|
||||
playreadyDeviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundPlayreadyPssh);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user