update to manifest v3

This commit is contained in:
voldemort 2025-07-20 16:27:13 +07:00
parent 5678c9b5da
commit 5949228d4f
8 changed files with 1415 additions and 78 deletions

View File

@ -11,6 +11,8 @@ Keep these extension core files inside `src`:
- `inject.js` - `inject.js`
- `manifest.json` - `manifest.json`
The `mv2` folder is for Manifest v2 backup for legacy reasons.
Frontend React source stays in `frontend`. Frontend React source stays in `frontend`.
The build process will take care of everything into `extension-release`. The build process will take care of everything into `extension-release`.

View File

@ -1,30 +1,30 @@
{ {
"name": "frontend", "name": "frontend",
"private": true, "private": true,
"version": "2.1.0", "version": "2.1.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"lint": "eslint .", "lint": "eslint .",
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@tailwindcss/vite": "^4.1.11", "@tailwindcss/vite": "^4.1.11",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-router-dom": "^7.7.0", "react-router-dom": "^7.7.0",
"tailwindcss": "^4.1.11" "tailwindcss": "^4.1.11"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.31.0", "@eslint/js": "^9.31.0",
"@types/react": "^19.1.8", "@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6", "@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^4.7.0", "@vitejs/plugin-react": "^4.7.0",
"eslint": "^9.31.0", "eslint": "^9.31.0",
"eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20", "eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.3.0", "globals": "^16.3.0",
"vite": "^7.0.5" "vite": "^7.0.5"
} }
} }

89
mv2/background.js Normal file
View File

@ -0,0 +1,89 @@
// Open popout window when the extension icon is clicked
chrome.browserAction.onClicked.addListener(() => {
chrome.windows.create({
url: chrome.runtime.getURL("index.html"),
type: "popup", // opens as a floating window
width: 800,
height: 600,
});
});
// Listen for messages and store data in chrome.storage.local
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
const { type, data } = message;
switch (type) {
case "DRM_TYPE":
console.log("DRM Type:", data);
chrome.storage.local.set({ drmType: data });
break;
case "PSSH_DATA":
console.log("Storing PSSH:", data);
chrome.storage.local.set({ latestPSSH: data });
break;
case "KEYS_DATA":
console.log("Storing Decryption Keys:", data);
chrome.storage.local.set({ latestKeys: data });
break;
case "LICENSE_URL":
console.log("Storling License URL " + data);
chrome.storage.local.set({ licenseURL: data });
break;
case "MANIFEST_URL_FOUND":
console.log("Storing Manifest URL:", data);
chrome.storage.local.set({ manifestURL: data });
break;
default:
console.warn("Unknown message type received:", type);
}
});
// Set initial config and injection type on install
chrome.runtime.onInstalled.addListener((details) => {
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.");
}
});
chrome.storage.local.set({ injection_type: "LICENSE" }, () => {
if (chrome.runtime.lastError) {
console.error("Error setting Injection Type:", chrome.runtime.lastError);
} else {
console.log("Injection type set to LICENSE on first install.");
}
});
chrome.storage.local.set({ drm_override: "DISABLED" }, () => {
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.");
}
});
chrome.storage.local.set({ cdrm_instance: null }, () => {
if (chrome.runtime.lastError) {
console.error("Error setting CDRM instance:", chrome.runtime.lastError);
} else {
console.log("CDRM instance set to null.");
}
});
chrome.storage.local.set({ cdrm_api_key: null }, () => {
if (chrome.runtime.lastError) {
console.error("Error setting CDRM API Key:", chrome.runtime.lastError);
} else {
console.log("CDRM API Key set.");
}
});
}
});

96
mv2/content.js Normal file
View File

@ -0,0 +1,96 @@
// 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";
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) {
if (event.source !== window) return;
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,
});
}
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;
window.postMessage(
{
type: "__CDM_DEVICES__",
widevine_device,
playready_device,
},
"*"
);
});
}
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,
},
"*"
);
});
}
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,
},
"*"
);
});
}
// 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,
});
}
});

1122
mv2/inject.js Normal file

File diff suppressed because it is too large Load Diff

41
mv2/manifest.json Normal file
View File

@ -0,0 +1,41 @@
{
"manifest_version": 2,
"name": "CDRM Extension",
"version": "2.1.0",
"description": "Decrypt DRM protected content",
"permissions": [
"webRequest",
"webRequestBlocking",
"<all_urls>",
"activeTab",
"storage",
"tabs",
"contextMenus"
],
"background": {
"scripts": ["background.js"],
"persistent": true
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_start",
"all_frames": true
}
],
"web_accessible_resources": ["inject.js"],
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"browser_action": {
"default_icon": {
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"128": "icons/icon128.png"
}
},
"icons": {
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"128": "icons/icon128.png"
}
}

View File

@ -1,8 +1,7 @@
// Open popout window when the extension icon is clicked chrome.action.onClicked.addListener(() => {
chrome.browserAction.onClicked.addListener(() => {
chrome.windows.create({ chrome.windows.create({
url: chrome.runtime.getURL("index.html"), url: chrome.runtime.getURL("index.html"),
type: "popup", // opens as a floating window type: "popup",
width: 800, width: 800,
height: 600, height: 600,
}); });

View File

@ -1,49 +1,37 @@
{ {
"manifest_version": 2, "manifest_version": 3,
"name": "CDRM Extension", "name": "CDRM Extension",
"version": "2.1.0", "version": "2.1.0",
"description": "Decrypt DRM protected content", "description": "Decrypt DRM protected content",
"permissions": [ "permissions": ["storage", "activeTab", "contextMenus"],
"webRequest", "host_permissions": ["<all_urls>"],
"webRequestBlocking", "background": {
"<all_urls>", "service_worker": "background.js"
"activeTab", },
"storage", "content_scripts": [
"tabs", {
"contextMenus" "matches": ["<all_urls>"],
], "js": ["content.js"],
"background": { "run_at": "document_start",
"scripts": [ "all_frames": true
"background.js" }
], ],
"persistent": true "web_accessible_resources": [
}, {
"content_scripts": [ "resources": ["inject.js"],
{ "matches": ["<all_urls>"]
"matches": [ }
"<all_urls>" ],
], "action": {
"js": [ "default_icon": {
"content.js" "16": "icons/icon16.png",
], "32": "icons/icon32.png",
"run_at": "document_start", "128": "icons/icon128.png"
"all_frames": true }
},
"icons": {
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"128": "icons/icon128.png"
} }
], }
"web_accessible_resources": [
"inject.js"
],
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"browser_action": {
"default_icon": {
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"128": "icons/icon128.png"
}
},
"icons": {
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"128": "icons/icon128.png"
}
}