forked from tpd94/CDRM-Extension
add extension prefix and color for ease of debugging and filtering
This commit is contained in:
parent
30e797bc09
commit
89f66b25be
@ -13,27 +13,27 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
|
||||
switch (type) {
|
||||
case "DRM_TYPE":
|
||||
console.log("DRM Type:", data);
|
||||
logWithPrefix("DRM Type:", data);
|
||||
chrome.storage.local.set({ drmType: data });
|
||||
break;
|
||||
|
||||
case "PSSH_DATA":
|
||||
console.log("Storing PSSH:", data);
|
||||
logWithPrefix("Storing PSSH:", data);
|
||||
chrome.storage.local.set({ latestPSSH: data });
|
||||
break;
|
||||
|
||||
case "KEYS_DATA":
|
||||
console.log("Storing Decryption Keys:", data);
|
||||
logWithPrefix("Storing Decryption Keys:", data);
|
||||
chrome.storage.local.set({ latestKeys: data });
|
||||
break;
|
||||
|
||||
case "LICENSE_URL":
|
||||
console.log("Storling License URL " + data);
|
||||
logWithPrefix("Storling License URL " + data);
|
||||
chrome.storage.local.set({ licenseURL: data });
|
||||
break;
|
||||
|
||||
case "MANIFEST_URL":
|
||||
console.log("Storing Manifest URL:", data);
|
||||
logWithPrefix("Storing Manifest URL:", data);
|
||||
chrome.storage.local.set({ manifestURL: data });
|
||||
break;
|
||||
|
||||
@ -44,12 +44,27 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
|
||||
// Set initial config and injection type on install
|
||||
chrome.runtime.onInstalled.addListener((details) => {
|
||||
const EXTENSION_PREFIX = "[CDRM EXTENSION]";
|
||||
const PREFIX_COLOR = "black";
|
||||
const PREFIX_BACKGROUND_COLOR = "yellow";
|
||||
|
||||
const logWithPrefix = (...args) => {
|
||||
const style = `color: ${PREFIX_COLOR}; background: ${PREFIX_BACKGROUND_COLOR}; font-weight: bold; padding: 2px 4px; border-radius: 2px;`;
|
||||
if (typeof args[0] === "string") {
|
||||
// If the first arg is a string, prepend the prefix
|
||||
console.log(`%c${EXTENSION_PREFIX}%c ${args[0]}`, style, "", ...args.slice(1));
|
||||
} else {
|
||||
// If not, just log the prefix and the rest
|
||||
console.log(`%c${EXTENSION_PREFIX}`, style, ...args);
|
||||
}
|
||||
};
|
||||
|
||||
if (details.reason === "install") {
|
||||
chrome.storage.local.set({ valid_config: false }, () => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.error("Error setting valid_config:", chrome.runtime.lastError);
|
||||
} else {
|
||||
console.log("valid_config set to false on first install.");
|
||||
logWithPrefix("valid_config set to false on first install.");
|
||||
}
|
||||
});
|
||||
|
||||
@ -57,7 +72,7 @@ chrome.runtime.onInstalled.addListener((details) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.error("Error setting Injection Type:", chrome.runtime.lastError);
|
||||
} else {
|
||||
console.log("Injection type set to LICENSE on first install.");
|
||||
logWithPrefix("Injection type set to LICENSE on first install.");
|
||||
}
|
||||
});
|
||||
|
||||
@ -65,7 +80,7 @@ chrome.runtime.onInstalled.addListener((details) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.error("Error setting DRM Override type:", chrome.runtime.lastError);
|
||||
} else {
|
||||
console.log("DRM Override type set to DISABLED on first install.");
|
||||
logWithPrefix("DRM Override type set to DISABLED on first install.");
|
||||
}
|
||||
});
|
||||
|
||||
@ -73,7 +88,7 @@ chrome.runtime.onInstalled.addListener((details) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.error("Error setting CDRM instance:", chrome.runtime.lastError);
|
||||
} else {
|
||||
console.log("CDRM instance set to null.");
|
||||
logWithPrefix("CDRM instance set to null.");
|
||||
}
|
||||
});
|
||||
|
||||
@ -81,7 +96,7 @@ chrome.runtime.onInstalled.addListener((details) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.error("Error setting CDRM API Key:", chrome.runtime.lastError);
|
||||
} else {
|
||||
console.log("CDRM API Key set.");
|
||||
logWithPrefix("CDRM API Key set.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -68,6 +68,19 @@ window.addEventListener("message", function (event) {
|
||||
}
|
||||
|
||||
// Manifest header and URL
|
||||
const EXTENSION_PREFIX = "[CDRM EXTENSION]";
|
||||
const PREFIX_COLOR = "black";
|
||||
const PREFIX_BACKGROUND_COLOR = "yellow";
|
||||
const logWithPrefix = (...args) => {
|
||||
const style = `color: ${PREFIX_COLOR}; background: ${PREFIX_BACKGROUND_COLOR}; font-weight: bold; padding: 2px 4px; border-radius: 2px;`;
|
||||
if (typeof args[0] === "string") {
|
||||
// If the first arg is a string, prepend the prefix
|
||||
console.log(`%c${EXTENSION_PREFIX}%c ${args[0]}`, style, "", ...args.slice(1));
|
||||
} else {
|
||||
// If not, just log the prefix and the rest
|
||||
console.log(`%c${EXTENSION_PREFIX}`, style, ...args);
|
||||
}
|
||||
};
|
||||
|
||||
const seenManifestUrls = new Set();
|
||||
|
||||
@ -75,7 +88,7 @@ window.addEventListener("message", function (event) {
|
||||
const url = event.data.data;
|
||||
if (seenManifestUrls.has(url)) return;
|
||||
seenManifestUrls.add(url);
|
||||
console.log("✅ [Content] Unique manifest URL:", url);
|
||||
logWithPrefix("✅ [Content] Unique manifest URL:", url);
|
||||
|
||||
chrome.runtime.sendMessage({
|
||||
type: "MANIFEST_URL",
|
||||
@ -85,7 +98,7 @@ window.addEventListener("message", function (event) {
|
||||
|
||||
if (event.data?.type === "__MANIFEST_HEADERS__") {
|
||||
const { url, headers } = event.data;
|
||||
console.log("[Content.js] Manifest Headers:", url, headers);
|
||||
logWithPrefix("[Content.js] Manifest Headers:", url, headers);
|
||||
|
||||
chrome.runtime.sendMessage({
|
||||
type: "MANIFEST_HEADERS",
|
||||
|
149
src/inject.js
149
src/inject.js
@ -24,6 +24,21 @@ const DRM_SIGNATURES = {
|
||||
WIDEVINE_INIT: "CAQ=",
|
||||
};
|
||||
|
||||
const EXTENSION_PREFIX = "[CDRM EXTENSION]";
|
||||
const PREFIX_COLOR = "black";
|
||||
const PREFIX_BACKGROUND_COLOR = "yellow";
|
||||
|
||||
const logWithPrefix = (...args) => {
|
||||
const style = `color: ${PREFIX_COLOR}; background: ${PREFIX_BACKGROUND_COLOR}; font-weight: bold; padding: 2px 4px; border-radius: 2px;`;
|
||||
if (typeof args[0] === "string") {
|
||||
// If the first arg is a string, prepend the prefix
|
||||
console.log(`%c${EXTENSION_PREFIX}%c ${args[0]}`, style, "", ...args.slice(1));
|
||||
} else {
|
||||
// If not, just log the prefix and the rest
|
||||
console.log(`%c${EXTENSION_PREFIX}`, style, ...args);
|
||||
}
|
||||
};
|
||||
|
||||
// Post message to content.js to get DRM override
|
||||
window.postMessage({ type: "__GET_DRM_OVERRIDE__" }, "*");
|
||||
|
||||
@ -32,7 +47,7 @@ window.addEventListener("message", function (event) {
|
||||
if (event.source !== window) return;
|
||||
if (event.data.type === "__DRM_OVERRIDE__") {
|
||||
drmOverride = event.data.drmOverride || "DISABLED";
|
||||
console.log("DRM Override set to:", drmOverride);
|
||||
logWithPrefix("DRM Override set to:", drmOverride);
|
||||
}
|
||||
});
|
||||
|
||||
@ -45,7 +60,7 @@ window.addEventListener("message", function (event) {
|
||||
|
||||
if (event.data.type === "__INJECTION_TYPE__") {
|
||||
interceptType = event.data.injectionType || "DISABLED";
|
||||
console.log("Injection type set to:", interceptType);
|
||||
logWithPrefix("Injection type set to:", interceptType);
|
||||
}
|
||||
});
|
||||
|
||||
@ -59,7 +74,7 @@ window.addEventListener("message", function (event) {
|
||||
if (event.data.type === "__CDM_DEVICES__") {
|
||||
const { widevine_device, playready_device } = event.data;
|
||||
|
||||
console.log("Received device info:", widevine_device, playready_device);
|
||||
logWithPrefix("Received device info:", widevine_device, playready_device);
|
||||
|
||||
widevineDeviceInfo = widevine_device;
|
||||
playreadyDeviceInfo = playready_device;
|
||||
@ -90,7 +105,7 @@ function headersToFlags(headersObj) {
|
||||
|
||||
function handleManifestDetection(url, headersObj, contentType, source) {
|
||||
window.postMessage({ type: "__MANIFEST_URL__", data: url }, "*");
|
||||
console.log(`[Manifest][${source}]`, url, contentType);
|
||||
logWithPrefix(`[Manifest][${source}]`, url, contentType);
|
||||
|
||||
const headerFlags = headersToFlags(headersObj);
|
||||
|
||||
@ -209,7 +224,7 @@ class RemoteCDMBase {
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData.data?.session_id) {
|
||||
this.session_id = jsonData.data.session_id;
|
||||
console.log("Session opened:", this.session_id);
|
||||
logWithPrefix("Session opened:", this.session_id);
|
||||
} else {
|
||||
console.error("Failed to open session:", jsonData.message);
|
||||
throw new Error("Failed to open session");
|
||||
@ -225,10 +240,10 @@ class RemoteCDMBase {
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData.data?.challenge) {
|
||||
this.challenge = btoa(jsonData.data.challenge);
|
||||
console.log("Challenge received:", this.challenge);
|
||||
logWithPrefix("Challenge received:", this.challenge);
|
||||
} else if (jsonData.data?.challenge_b64) {
|
||||
this.challenge = jsonData.data.challenge_b64;
|
||||
console.log("Challenge received:", this.challenge);
|
||||
logWithPrefix("Challenge received:", this.challenge);
|
||||
} else {
|
||||
console.error("Failed to get challenge:", jsonData.message);
|
||||
throw new Error("Failed to get challenge");
|
||||
@ -243,7 +258,7 @@ class RemoteCDMBase {
|
||||
xhr.send(JSON.stringify(body));
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData.status === 200 || jsonData.message?.includes("parsed and loaded")) {
|
||||
console.log("License response parsed successfully");
|
||||
logWithPrefix("License response parsed successfully");
|
||||
return true;
|
||||
} else {
|
||||
console.error("Failed to parse license response:", jsonData.message);
|
||||
@ -260,7 +275,7 @@ class RemoteCDMBase {
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData.data?.keys) {
|
||||
this.keys = jsonData.data.keys;
|
||||
console.log("Keys received:", this.keys);
|
||||
logWithPrefix("Keys received:", this.keys);
|
||||
} else {
|
||||
console.error("Failed to get keys:", jsonData.message);
|
||||
throw new Error("Failed to get keys");
|
||||
@ -275,7 +290,7 @@ class RemoteCDMBase {
|
||||
xhr.send();
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData) {
|
||||
console.log("Session closed successfully");
|
||||
logWithPrefix("Session closed successfully");
|
||||
} else {
|
||||
console.error("Failed to close session:", jsonData.message);
|
||||
throw new Error("Failed to close session");
|
||||
@ -342,7 +357,7 @@ class remoteWidevineCDM extends RemoteCDMBase {
|
||||
xhr.send(JSON.stringify(body));
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData.status === 200) {
|
||||
console.log("Service certificate set successfully");
|
||||
logWithPrefix("Service certificate set successfully");
|
||||
} else {
|
||||
console.error("Failed to set service certificate:", jsonData.message);
|
||||
throw new Error("Failed to set service certificate");
|
||||
@ -363,7 +378,7 @@ class remoteWidevineCDM extends RemoteCDMBase {
|
||||
const jsonData = JSON.parse(xhr.responseText);
|
||||
if (jsonData.data?.challenge_b64) {
|
||||
this.challenge = jsonData.data.challenge_b64;
|
||||
console.log("Widevine challenge received:", this.challenge);
|
||||
logWithPrefix("Widevine challenge received:", this.challenge);
|
||||
} else {
|
||||
console.error("Failed to get Widevine challenge:", jsonData.message);
|
||||
throw new Error("Failed to get Widevine challenge");
|
||||
@ -501,30 +516,74 @@ function arrayBufferToBase64(uint8array) {
|
||||
return window.btoa(binary);
|
||||
}
|
||||
|
||||
function bufferToBase64(buffer) {
|
||||
const uint8 = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
||||
return window.btoa(String.fromCharCode(...uint8));
|
||||
}
|
||||
|
||||
// DRM type detection
|
||||
function isWidevine(base64str) {
|
||||
return base64str.startsWith(DRM_SIGNATURES.WIDEVINE);
|
||||
}
|
||||
function isPlayReady(base64str) {
|
||||
return base64str.startsWith(DRM_SIGNATURES.PLAYREADY);
|
||||
}
|
||||
function isServiceCertificate(base64str) {
|
||||
return base64str.startsWith(DRM_SIGNATURES.SERVICE_CERT);
|
||||
}
|
||||
|
||||
function postDRMTypeAndPssh(type, pssh) {
|
||||
window.postMessage({ type: "__DRM_TYPE__", data: type }, "*");
|
||||
window.postMessage({ type: "__PSSH_DATA__", data: pssh }, "*");
|
||||
}
|
||||
|
||||
function ensureRemoteCDM(type, deviceInfo, pssh) {
|
||||
if (!remoteCDM) {
|
||||
if (type === "Widevine") {
|
||||
const { device_type, system_id, security_level, host, secret, device_name } =
|
||||
deviceInfo;
|
||||
remoteCDM = new remoteWidevineCDM(
|
||||
device_type,
|
||||
system_id,
|
||||
security_level,
|
||||
host,
|
||||
secret,
|
||||
device_name
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(pssh);
|
||||
} else if (type === "PlayReady") {
|
||||
const { security_level, host, secret, device_name } = deviceInfo;
|
||||
remoteCDM = new remotePlayReadyCDM(security_level, host, secret, device_name);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(pssh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Challenge generator interceptor
|
||||
const originalGenerateRequest = MediaKeySession.prototype.generateRequest;
|
||||
MediaKeySession.prototype.generateRequest = function (initDataType, initData) {
|
||||
const session = this;
|
||||
let playReadyPssh = getPlayReadyPssh(initData);
|
||||
if (playReadyPssh) {
|
||||
console.log("[DRM Detected] PlayReady");
|
||||
logWithPrefix("[DRM Detected] PlayReady");
|
||||
foundPlayreadyPssh = playReadyPssh;
|
||||
console.log("[PlayReady PSSH found] " + playReadyPssh);
|
||||
logWithPrefix("[PlayReady PSSH found] " + playReadyPssh);
|
||||
}
|
||||
let wideVinePssh = getWidevinePssh(initData);
|
||||
if (wideVinePssh) {
|
||||
// Widevine code
|
||||
console.log("[DRM Detected] Widevine");
|
||||
logWithPrefix("[DRM Detected] Widevine");
|
||||
foundWidevinePssh = wideVinePssh;
|
||||
console.log("[Widevine PSSH found] " + wideVinePssh);
|
||||
logWithPrefix("[Widevine PSSH found] " + wideVinePssh);
|
||||
}
|
||||
// Challenge message interceptor
|
||||
if (!remoteListenerMounted) {
|
||||
remoteListenerMounted = true;
|
||||
session.addEventListener("message", function messageInterceptor(event) {
|
||||
event.stopImmediatePropagation();
|
||||
const uint8Array = new Uint8Array(event.message);
|
||||
const base64challenge = arrayBufferToBase64(uint8Array);
|
||||
const base64challenge = bufferToBase64(event.message);
|
||||
if (
|
||||
base64challenge === DRM_SIGNATURES.WIDEVINE_INIT &&
|
||||
interceptType !== "DISABLED" &&
|
||||
@ -554,27 +613,9 @@ MediaKeySession.prototype.generateRequest = function (initDataType, initData) {
|
||||
originalChallenge = base64challenge;
|
||||
}
|
||||
if (originalChallenge.startsWith(DRM_SIGNATURES.WIDEVINE)) {
|
||||
window.postMessage({ type: "__DRM_TYPE__", data: "Widevine" }, "*");
|
||||
window.postMessage({ type: "__PSSH_DATA__", data: foundWidevinePssh }, "*");
|
||||
if (interceptType === "EME" && !remoteCDM) {
|
||||
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();
|
||||
remoteCDM.getChallenge(foundWidevinePssh);
|
||||
postDRMTypeAndPssh("Widevine", foundWidevinePssh);
|
||||
if (interceptType === "EME") {
|
||||
ensureRemoteCDM("Widevine", widevineDeviceInfo, foundWidevinePssh);
|
||||
}
|
||||
}
|
||||
if (!originalChallenge.startsWith(DRM_SIGNATURES.WIDEVINE)) {
|
||||
@ -585,23 +626,10 @@ MediaKeySession.prototype.generateRequest = function (initDataType, initData) {
|
||||
/<Challenge encoding="base64encoded">([^<]+)<\/Challenge>/
|
||||
);
|
||||
if (match) {
|
||||
window.postMessage({ type: "__DRM_TYPE__", data: "PlayReady" }, "*");
|
||||
window.postMessage(
|
||||
{ type: "__PSSH_DATA__", data: foundPlayreadyPssh },
|
||||
"*"
|
||||
);
|
||||
postDRMTypeAndPssh("PlayReady", 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
|
||||
);
|
||||
remoteCDM.openSession();
|
||||
remoteCDM.getChallenge(foundPlayreadyPssh);
|
||||
if (interceptType === "EME") {
|
||||
ensureRemoteCDM("PlayReady", playreadyDeviceInfo, foundPlayreadyPssh);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -618,12 +646,12 @@ MediaKeySession.prototype.generateRequest = function (initDataType, initData) {
|
||||
Object.defineProperty(syntheticEvent, "message", {
|
||||
get: () => challengeBuffer,
|
||||
});
|
||||
console.log("Intercepted EME Challenge and injected custom one.");
|
||||
logWithPrefix("Intercepted EME Challenge and injected custom one.");
|
||||
session.dispatchEvent(syntheticEvent);
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log("Message interceptor mounted.");
|
||||
logWithPrefix("Message interceptor mounted.");
|
||||
}
|
||||
return originalGenerateRequest.call(session, initDataType, initData);
|
||||
};
|
||||
@ -631,8 +659,7 @@ MediaKeySession.prototype.generateRequest = function (initDataType, initData) {
|
||||
// Message update interceptors
|
||||
const originalUpdate = MediaKeySession.prototype.update;
|
||||
MediaKeySession.prototype.update = function (response) {
|
||||
const uint8 = response instanceof Uint8Array ? response : new Uint8Array(response);
|
||||
const base64Response = window.btoa(String.fromCharCode(...uint8));
|
||||
const base64Response = bufferToBase64(response);
|
||||
if (
|
||||
base64Response.startsWith(DRM_SIGNATURES.SERVICE_CERT) &&
|
||||
foundWidevinePssh &&
|
||||
@ -667,7 +694,7 @@ MediaKeySession.prototype.update = function (response) {
|
||||
.then(() => {
|
||||
let clearKeys = getClearkey(response);
|
||||
if (clearKeys && clearKeys.length > 0) {
|
||||
console.log("[CLEARKEY] ", clearKeys);
|
||||
logWithPrefix("[CLEARKEY] ", clearKeys);
|
||||
const drmType = {
|
||||
type: "__DRM_TYPE__",
|
||||
data: "ClearKey",
|
||||
@ -681,7 +708,7 @@ MediaKeySession.prototype.update = function (response) {
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("[CLEARKEY] Not found");
|
||||
logWithPrefix("[CLEARKEY] Not found");
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user