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
|
||||||
|
}
|
128
background.js
128
background.js
@ -1,84 +1,84 @@
|
|||||||
// Open popout window when the extension icon is clicked
|
// Open popout window when the extension icon is clicked
|
||||||
chrome.browserAction.onClicked.addListener(() => {
|
chrome.browserAction.onClicked.addListener(() => {
|
||||||
chrome.windows.create({
|
chrome.windows.create({
|
||||||
url: chrome.runtime.getURL("react/index.html"),
|
url: chrome.runtime.getURL("react/index.html"),
|
||||||
type: "popup", // opens as a floating window
|
type: "popup", // opens as a floating window
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600
|
height: 600,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for messages and store data in chrome.storage.local
|
// Listen for messages and store data in chrome.storage.local
|
||||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||||
const { type, data } = message;
|
const { type, data } = message;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "DRM_TYPE":
|
case "DRM_TYPE":
|
||||||
console.log("DRM Type:", data);
|
console.log("DRM Type:", data);
|
||||||
chrome.storage.local.set({ drmType: data });
|
chrome.storage.local.set({ drmType: data });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "PSSH_DATA":
|
case "PSSH_DATA":
|
||||||
console.log("Storing PSSH:", data);
|
console.log("Storing PSSH:", data);
|
||||||
chrome.storage.local.set({ latestPSSH: data });
|
chrome.storage.local.set({ latestPSSH: data });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "KEYS_DATA":
|
case "KEYS_DATA":
|
||||||
console.log("Storing Decryption Keys:", data);
|
console.log("Storing Decryption Keys:", data);
|
||||||
chrome.storage.local.set({ latestKeys: data });
|
chrome.storage.local.set({ latestKeys: data });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "LICENSE_URL":
|
case "LICENSE_URL":
|
||||||
console.log("Storling License URL " + data);
|
console.log("Storling License URL " + data);
|
||||||
chrome.storage.local.set({licenseURL: data});
|
chrome.storage.local.set({ licenseURL: data });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.warn("Unknown message type received:", type);
|
console.warn("Unknown message type received:", type);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set initial config and injection type on install
|
// Set initial config and injection type on install
|
||||||
chrome.runtime.onInstalled.addListener((details) => {
|
chrome.runtime.onInstalled.addListener((details) => {
|
||||||
if (details.reason === "install") {
|
if (details.reason === "install") {
|
||||||
chrome.storage.local.set({ valid_config: false }, () => {
|
chrome.storage.local.set({ valid_config: false }, () => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
console.error("Error setting valid_config:", chrome.runtime.lastError);
|
console.error("Error setting valid_config:", chrome.runtime.lastError);
|
||||||
} else {
|
} else {
|
||||||
console.log("valid_config set to false on first install.");
|
console.log("valid_config set to false on first install.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
chrome.storage.local.set({ injection_type: "LICENSE" }, () => {
|
chrome.storage.local.set({ injection_type: "LICENSE" }, () => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
console.error("Error setting Injection Type:", chrome.runtime.lastError);
|
console.error("Error setting Injection Type:", chrome.runtime.lastError);
|
||||||
} else {
|
} else {
|
||||||
console.log("Injection type set to LICENSE on first install.");
|
console.log("Injection type set to LICENSE on first install.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
chrome.storage.local.set({ drm_override: "DISABLED" }, () => {
|
chrome.storage.local.set({ drm_override: "DISABLED" }, () => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
console.error("Error setting DRM Override type:", chrome.runtime.lastError);
|
console.error("Error setting DRM Override type:", chrome.runtime.lastError);
|
||||||
} else {
|
} else {
|
||||||
console.log("DRM Override type set to DISABLED on first install.");
|
console.log("DRM Override type set to DISABLED on first install.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
chrome.storage.local.set({ cdrm_instance: null }, () => {
|
chrome.storage.local.set({ cdrm_instance: null }, () => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
console.error("Error setting CDRM instance:", chrome.runtime.lastError);
|
console.error("Error setting CDRM instance:", chrome.runtime.lastError);
|
||||||
} else {
|
} else {
|
||||||
console.log("CDRM instance set to null.");
|
console.log("CDRM instance set to null.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
chrome.storage.local.set({ cdrm_api_key: null }, () => {
|
chrome.storage.local.set({ cdrm_api_key: null }, () => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
console.error("Error setting CDRM API Key:", chrome.runtime.lastError);
|
console.error("Error setting CDRM API Key:", chrome.runtime.lastError);
|
||||||
} else {
|
} else {
|
||||||
console.log("CDRM API Key set.");
|
console.log("CDRM API Key set.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
115
content.js
115
content.js
@ -1,67 +1,96 @@
|
|||||||
// Inject `inject.js` into the page context
|
// Inject `inject.js` into the page context
|
||||||
(function injectScript() {
|
(function injectScript() {
|
||||||
const script = document.createElement('script');
|
const script = document.createElement("script");
|
||||||
script.src = chrome.runtime.getURL('inject.js');
|
script.src = chrome.runtime.getURL("inject.js");
|
||||||
script.type = 'text/javascript';
|
script.type = "text/javascript";
|
||||||
script.onload = () => script.remove(); // Clean up
|
script.onload = () => script.remove(); // Clean up
|
||||||
// Inject directly into <html> or <head>
|
// Inject directly into <html> or <head>
|
||||||
(document.documentElement || document.head || document.body).appendChild(script);
|
(document.documentElement || document.head || document.body).appendChild(script);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// Listen for messages from the injected script
|
// Listen for messages from the injected script
|
||||||
window.addEventListener("message", function(event) {
|
window.addEventListener("message", function (event) {
|
||||||
if (event.source !== window) return;
|
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({
|
chrome.runtime.sendMessage({
|
||||||
type: event.data.type.replace("__", "").replace("__", ""),
|
type: event.data.type.replace("__", "").replace("__", ""),
|
||||||
data: event.data.data
|
data: event.data.data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.data.type === "__GET_CDM_DEVICES__") {
|
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;
|
||||||
|
|
||||||
chrome.storage.local.get(["widevine_device", "playready_device"], (result) => {
|
window.postMessage(
|
||||||
const widevine_device = result.widevine_device || null;
|
{
|
||||||
const playready_device = result.playready_device || null;
|
type: "__CDM_DEVICES__",
|
||||||
|
widevine_device,
|
||||||
window.postMessage(
|
playready_device,
|
||||||
{
|
},
|
||||||
type: "__CDM_DEVICES__",
|
"*"
|
||||||
widevine_device,
|
);
|
||||||
playready_device
|
});
|
||||||
},
|
|
||||||
"*"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.data.type === "__GET_INJECTION_TYPE__") {
|
if (event.data.type === "__GET_INJECTION_TYPE__") {
|
||||||
|
chrome.storage.local.get("injection_type", (result) => {
|
||||||
|
const injectionType = result.injection_type || "LICENSE";
|
||||||
|
|
||||||
chrome.storage.local.get("injection_type", (result) => {
|
window.postMessage(
|
||||||
const injectionType = result.injection_type || "LICENSE";
|
{
|
||||||
|
type: "__INJECTION_TYPE__",
|
||||||
window.postMessage(
|
injectionType,
|
||||||
{
|
},
|
||||||
type: "__INJECTION_TYPE__",
|
"*"
|
||||||
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";
|
||||||
|
|
||||||
chrome.storage.local.get("drm_override", (result) => {
|
window.postMessage(
|
||||||
const drmOverride = result.drm_override || "DISABLED";
|
{
|
||||||
|
type: "__DRM_OVERRIDE__",
|
||||||
|
drmOverride,
|
||||||
|
},
|
||||||
|
"*"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
window.postMessage(
|
// Manifest header and URL
|
||||||
{
|
|
||||||
type: "__DRM_OVERRIDE__",
|
const seenManifestUrls = new Set();
|
||||||
drmOverride
|
|
||||||
},
|
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 js from "@eslint/js";
|
||||||
import globals from 'globals'
|
import globals from "globals";
|
||||||
import reactHooks from 'eslint-plugin-react-hooks'
|
import reactHooks from "eslint-plugin-react-hooks";
|
||||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
import reactRefresh from "eslint-plugin-react-refresh";
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{ ignores: ['dist'] },
|
{ ignores: ["dist"] },
|
||||||
{
|
{
|
||||||
files: ['**/*.{js,jsx}'],
|
files: ["**/*.{js,jsx}"],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
ecmaVersion: 2020,
|
ecmaVersion: 2020,
|
||||||
globals: globals.browser,
|
globals: globals.browser,
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: 'latest',
|
ecmaVersion: "latest",
|
||||||
ecmaFeatures: { jsx: true },
|
ecmaFeatures: { jsx: true },
|
||||||
sourceType: 'module',
|
sourceType: "module",
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
"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 }],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
plugins: {
|
];
|
||||||
'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 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>CDRM Decryption Extension</title>
|
<title>CDRM Decryption Extension</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="min-w-full min-h-full w-full h-full">
|
<body class="min-w-full min-h-full w-full h-full">
|
||||||
<div class="min-w-full min-h-full w-full h-full" id="root"></div>
|
<div class="min-w-full min-h-full w-full h-full" id="root"></div>
|
||||||
<script type="module" src="/src/main.jsx"></script>
|
<script type="module" src="/src/main.jsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
6810
frontend/package-lock.json
generated
6810
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,30 +1,30 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.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.7",
|
"@tailwindcss/vite": "^4.1.7",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-router-dom": "^7.6.1",
|
"react-router-dom": "^7.6.1",
|
||||||
"tailwindcss": "^4.1.7"
|
"tailwindcss": "^4.1.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.25.0",
|
"@eslint/js": "^9.25.0",
|
||||||
"@types/react": "^19.1.2",
|
"@types/react": "^19.1.2",
|
||||||
"@types/react-dom": "^19.1.2",
|
"@types/react-dom": "^19.1.2",
|
||||||
"@vitejs/plugin-react": "^4.4.1",
|
"@vitejs/plugin-react": "^4.4.1",
|
||||||
"eslint": "^9.25.0",
|
"eslint": "^9.25.0",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.19",
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
"vite": "^6.3.5"
|
"vite": "^6.3.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,77 +1,72 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import {
|
import { HashRouter as Router, Routes, Route, Navigate } from "react-router-dom";
|
||||||
HashRouter as Router,
|
|
||||||
Routes,
|
|
||||||
Route,
|
|
||||||
Navigate,
|
|
||||||
} from "react-router-dom";
|
|
||||||
import TopNav from "./components/topnav";
|
import TopNav from "./components/topnav";
|
||||||
import SideNav from "./components/sidenav";
|
import SideNav from "./components/sidenav";
|
||||||
import Results from "./components/results";
|
import Results from "./components/results";
|
||||||
import Settings from "./components/settings";
|
import Settings from "./components/settings";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [isSideNavOpen, setIsSideNavOpen] = useState(false);
|
const [isSideNavOpen, setIsSideNavOpen] = useState(false);
|
||||||
const [validConfig, setValidConfig] = useState(null); // null = loading
|
const [validConfig, setValidConfig] = useState(null); // null = loading
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
chrome.storage.local.get("valid_config", (result) => {
|
chrome.storage.local.get("valid_config", (result) => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
console.error("Error reading valid_config:", chrome.runtime.lastError);
|
console.error("Error reading valid_config:", chrome.runtime.lastError);
|
||||||
setValidConfig(false); // fallback
|
setValidConfig(false); // fallback
|
||||||
} else {
|
} else {
|
||||||
setValidConfig(result.valid_config === true);
|
setValidConfig(result.valid_config === true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
if (validConfig === null) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center h-screen bg-black text-white">
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (validConfig === null) {
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center h-screen bg-black text-white">
|
<Router>
|
||||||
Loading...
|
<div className="min-w-full min-h-full w-full h-full flex flex-grow bg-black/95 flex-col relative">
|
||||||
</div>
|
<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 overflow-x-hidden">
|
||||||
|
<TopNav onMenuClick={() => setIsSideNavOpen(true)} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="currentpagecontainer" className="w-full grow overflow-y-auto">
|
||||||
|
<Routes>
|
||||||
|
{!validConfig ? (
|
||||||
|
<>
|
||||||
|
<Route
|
||||||
|
path="/settings"
|
||||||
|
element={
|
||||||
|
<Settings onConfigSaved={() => setValidConfig(true)} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route path="*" element={<Navigate to="/settings" replace />} />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Route path="/" element={<Navigate to="/results" replace />} />
|
||||||
|
<Route path="/results" element={<Results />} />
|
||||||
|
<Route path="/settings" element={<Settings />} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Routes>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`fixed top-0 left-0 w-full h-full z-50 bg-black transform transition-transform duration-300 ease-in-out ${
|
||||||
|
isSideNavOpen ? "translate-x-0" : "-translate-x-full"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<SideNav onClose={() => setIsSideNavOpen(false)} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Router>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Router>
|
|
||||||
<div className="min-w-full min-h-full w-full h-full flex flex-grow bg-black/95 flex-col relative">
|
|
||||||
<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 overflow-x-hidden">
|
|
||||||
<TopNav onMenuClick={() => setIsSideNavOpen(true)} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="currentpagecontainer" className="w-full grow overflow-y-auto">
|
|
||||||
<Routes>
|
|
||||||
{!validConfig ? (
|
|
||||||
<>
|
|
||||||
<Route
|
|
||||||
path="/settings"
|
|
||||||
element={
|
|
||||||
<Settings onConfigSaved={() => setValidConfig(true)} />
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route path="*" element={<Navigate to="/settings" replace />} />
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Route path="/" element={<Navigate to="/results" replace />} />
|
|
||||||
<Route path="/results" element={<Results />} />
|
|
||||||
<Route path="/settings" element={<Settings />} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Routes>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className={`fixed top-0 left-0 w-full h-full z-50 bg-black transform transition-transform duration-300 ease-in-out ${
|
|
||||||
isSideNavOpen ? "translate-x-0" : "-translate-x-full"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<SideNav onClose={() => setIsSideNavOpen(false)} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Router>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
@ -1,149 +1,139 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
function Results() {
|
function Results() {
|
||||||
const [drmType, setDrmType] = useState("");
|
const [drmType, setDrmType] = useState("");
|
||||||
const [pssh, setPssh] = useState("");
|
const [pssh, setPssh] = useState("");
|
||||||
const [licenseUrl, setLicenseUrl] = useState("");
|
const [licenseUrl, setLicenseUrl] = useState("");
|
||||||
const [keys, setKeys] = useState([]);
|
const [keys, setKeys] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
chrome.storage.local.get(
|
chrome.storage.local.get(
|
||||||
[
|
["drmType", "latestPSSH", "latestLicenseRequest", "latestKeys", "licenseURL"],
|
||||||
"drmType",
|
(result) => {
|
||||||
"latestPSSH",
|
if (result.drmType) setDrmType(result.drmType);
|
||||||
"latestLicenseRequest",
|
if (result.latestPSSH) setPssh(result.latestPSSH);
|
||||||
"latestKeys",
|
if (result.licenseURL) setLicenseUrl(result.licenseURL);
|
||||||
"licenseURL",
|
if (result.latestKeys) {
|
||||||
],
|
try {
|
||||||
(result) => {
|
const parsed = Array.isArray(result.latestKeys)
|
||||||
if (result.drmType) setDrmType(result.drmType);
|
? result.latestKeys
|
||||||
if (result.latestPSSH) setPssh(result.latestPSSH);
|
: JSON.parse(result.latestKeys);
|
||||||
if (result.licenseURL) setLicenseUrl(result.licenseURL);
|
setKeys(parsed);
|
||||||
if (result.latestKeys) {
|
} catch (e) {
|
||||||
try {
|
console.error("Failed to parse keys:", e);
|
||||||
const parsed = Array.isArray(result.latestKeys)
|
setKeys([]);
|
||||||
? result.latestKeys
|
}
|
||||||
: JSON.parse(result.latestKeys);
|
}
|
||||||
setKeys(parsed);
|
}
|
||||||
} catch (e) {
|
|
||||||
console.error("Failed to parse keys:", e);
|
|
||||||
setKeys([]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleChange = (changes, area) => {
|
|
||||||
if (area === "local") {
|
|
||||||
if (changes.drmType) {
|
|
||||||
setDrmType(changes.drmType.newValue);
|
|
||||||
}
|
|
||||||
if (changes.latestPSSH) {
|
|
||||||
setPssh(changes.latestPSSH.newValue);
|
|
||||||
}
|
|
||||||
if (changes.licenseURL) {
|
|
||||||
setLicenseUrl(changes.licenseURL.newValue);
|
|
||||||
}
|
|
||||||
if (changes.latestKeys) {
|
|
||||||
setKeys(changes.latestKeys.newValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
chrome.storage.onChanged.addListener(handleChange);
|
|
||||||
return () => chrome.storage.onChanged.removeListener(handleChange);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleCapture = () => {
|
|
||||||
// Reset stored values
|
|
||||||
chrome.storage.local.set({
|
|
||||||
drmType: "None",
|
|
||||||
latestPSSH: "None",
|
|
||||||
licenseURL: "None",
|
|
||||||
latestKeys: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Get all normal windows to exclude your popup
|
|
||||||
chrome.windows.getAll(
|
|
||||||
{ populate: true, windowTypes: ["normal"] },
|
|
||||||
(windows) => {
|
|
||||||
if (!windows || windows.length === 0) {
|
|
||||||
console.warn("No normal Chrome windows found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the last focused normal window
|
|
||||||
const lastFocusedWindow = windows.find((w) => w.focused) || windows[0];
|
|
||||||
|
|
||||||
if (!lastFocusedWindow) {
|
|
||||||
console.warn("No focused normal window found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the active tab in that window (that is a regular webpage)
|
|
||||||
const activeTab = lastFocusedWindow.tabs.find(
|
|
||||||
(tab) => tab.active && tab.url && /^https?:\/\//.test(tab.url)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (activeTab?.id) {
|
const handleChange = (changes, area) => {
|
||||||
chrome.tabs.reload(activeTab.id, () => {
|
if (area === "local") {
|
||||||
if (chrome.runtime.lastError) {
|
if (changes.drmType) {
|
||||||
console.error("Failed to reload tab:", chrome.runtime.lastError);
|
setDrmType(changes.drmType.newValue);
|
||||||
|
}
|
||||||
|
if (changes.latestPSSH) {
|
||||||
|
setPssh(changes.latestPSSH.newValue);
|
||||||
|
}
|
||||||
|
if (changes.licenseURL) {
|
||||||
|
setLicenseUrl(changes.licenseURL.newValue);
|
||||||
|
}
|
||||||
|
if (changes.latestKeys) {
|
||||||
|
setKeys(changes.latestKeys.newValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
} else {
|
|
||||||
console.warn("No active tab found in the last focused normal window");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
chrome.storage.onChanged.addListener(handleChange);
|
||||||
<div className="w-full grow flex h-full overflow-y-auto overflow-x-auto flex-col text-white p-4">
|
return () => chrome.storage.onChanged.removeListener(handleChange);
|
||||||
<button
|
}, []);
|
||||||
onClick={handleCapture}
|
|
||||||
className="w-full h-10 bg-sky-500 rounded-md p-2 mt-2 text-white cursor-pointer hover:bg-sky-600"
|
const handleCapture = () => {
|
||||||
>
|
// Reset stored values
|
||||||
Capture current tab
|
chrome.storage.local.set({
|
||||||
</button>
|
drmType: "None",
|
||||||
<p className="text-2xl mt-5">DRM Type</p>
|
latestPSSH: "None",
|
||||||
<input
|
licenseURL: "None",
|
||||||
type="text"
|
latestKeys: [],
|
||||||
value={drmType}
|
});
|
||||||
className="w-full h-10 bg-slate-800/50 rounded-md p-2 mt-2 text-white"
|
|
||||||
placeholder="None"
|
// Get all normal windows to exclude your popup
|
||||||
disabled
|
chrome.windows.getAll({ populate: true, windowTypes: ["normal"] }, (windows) => {
|
||||||
/>
|
if (!windows || windows.length === 0) {
|
||||||
<p className="text-2xl mt-5">PSSH</p>
|
console.warn("No normal Chrome windows found");
|
||||||
<input
|
return;
|
||||||
type="text"
|
}
|
||||||
value={pssh}
|
|
||||||
className="w-full h-10 bg-slate-800/50 rounded-md p-2 mt-2 text-white"
|
// Find the last focused normal window
|
||||||
placeholder="None"
|
const lastFocusedWindow = windows.find((w) => w.focused) || windows[0];
|
||||||
disabled
|
|
||||||
/>
|
if (!lastFocusedWindow) {
|
||||||
<p className="text-2xl mt-5">License URL</p>
|
console.warn("No focused normal window found");
|
||||||
<input
|
return;
|
||||||
type="text"
|
}
|
||||||
value={licenseUrl}
|
|
||||||
className="w-full h-10 bg-slate-800/50 rounded-md p-2 mt-2 text-white"
|
// Find the active tab in that window (that is a regular webpage)
|
||||||
placeholder="None"
|
const activeTab = lastFocusedWindow.tabs.find(
|
||||||
disabled
|
(tab) => tab.active && tab.url && /^https?:\/\//.test(tab.url)
|
||||||
/>
|
);
|
||||||
<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">
|
if (activeTab?.id) {
|
||||||
{Array.isArray(keys) &&
|
chrome.tabs.reload(activeTab.id, () => {
|
||||||
keys.filter((k) => k.type !== "SIGNING").length > 0 ? (
|
if (chrome.runtime.lastError) {
|
||||||
keys
|
console.error("Failed to reload tab:", chrome.runtime.lastError);
|
||||||
.filter((k) => k.type !== "SIGNING")
|
}
|
||||||
.map((k) => `${k.key_id || k.keyId}:${k.key}`)
|
});
|
||||||
.join("\n")
|
} else {
|
||||||
) : (
|
console.warn("No active tab found in the last focused normal window");
|
||||||
<span className="text-gray-400">None</span>
|
}
|
||||||
)}
|
});
|
||||||
</div>
|
};
|
||||||
</div>
|
|
||||||
);
|
return (
|
||||||
|
<div className="w-full grow flex h-full overflow-y-auto overflow-x-auto flex-col text-white p-4">
|
||||||
|
<button
|
||||||
|
onClick={handleCapture}
|
||||||
|
className="w-full h-10 bg-sky-500 rounded-md p-2 mt-2 text-white cursor-pointer hover:bg-sky-600"
|
||||||
|
>
|
||||||
|
Capture current tab
|
||||||
|
</button>
|
||||||
|
<p className="text-2xl mt-5">DRM Type</p>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={drmType}
|
||||||
|
className="w-full h-10 bg-slate-800/50 rounded-md p-2 mt-2 text-white"
|
||||||
|
placeholder="None"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
<p className="text-2xl mt-5">PSSH</p>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={pssh}
|
||||||
|
className="w-full h-10 bg-slate-800/50 rounded-md p-2 mt-2 text-white"
|
||||||
|
placeholder="None"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
<p className="text-2xl mt-5">License URL</p>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={licenseUrl}
|
||||||
|
className="w-full h-10 bg-slate-800/50 rounded-md p-2 mt-2 text-white"
|
||||||
|
placeholder="None"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
<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 ? (
|
||||||
|
keys
|
||||||
|
.filter((k) => k.type !== "SIGNING")
|
||||||
|
.map((k) => `${k.key_id || k.keyId}:${k.key}`)
|
||||||
|
.join("\n")
|
||||||
|
) : (
|
||||||
|
<span className="text-gray-400">None</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Results;
|
export default Results;
|
||||||
|
@ -2,149 +2,140 @@ import { useState, useEffect } from "react";
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
function Settings({ onConfigSaved }) {
|
function Settings({ onConfigSaved }) {
|
||||||
const [instanceUrl, setInstanceUrl] = useState("");
|
const [instanceUrl, setInstanceUrl] = useState("");
|
||||||
const [storedUrl, setStoredUrl] = useState(null);
|
const [storedUrl, setStoredUrl] = useState(null);
|
||||||
const [message, setMessage] = useState(null);
|
const [message, setMessage] = useState(null);
|
||||||
const [messageType, setMessageType] = useState(null);
|
const [messageType, setMessageType] = useState(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
chrome.storage.local.get("cdrm_instance", (result) => {
|
chrome.storage.local.get("cdrm_instance", (result) => {
|
||||||
if (chrome.runtime.lastError) {
|
|
||||||
console.error(
|
|
||||||
"Error fetching CDRM instance:",
|
|
||||||
chrome.runtime.lastError
|
|
||||||
);
|
|
||||||
} else if (result.cdrm_instance) {
|
|
||||||
setStoredUrl(result.cdrm_instance);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleSave = async () => {
|
|
||||||
const trimmedUrl = instanceUrl.trim().replace(/\/+$/, "");
|
|
||||||
if (!trimmedUrl) {
|
|
||||||
setMessage("Please enter a valid URL.");
|
|
||||||
setMessageType("error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const endpoint = trimmedUrl + "/api/extension";
|
|
||||||
setLoading(true);
|
|
||||||
setMessage(null);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(endpoint, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (data.status === true) {
|
|
||||||
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 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 playreadyData = await playreadyRes.json();
|
|
||||||
|
|
||||||
chrome.storage.local.set(
|
|
||||||
{
|
|
||||||
valid_config: true,
|
|
||||||
cdrm_instance: trimmedUrl,
|
|
||||||
widevine_device: {
|
|
||||||
device_type: widevineData.device_type,
|
|
||||||
system_id: widevineData.system_id,
|
|
||||||
security_level: widevineData.security_level,
|
|
||||||
secret: widevineData.secret,
|
|
||||||
device_name: widevineData.device_name,
|
|
||||||
host: trimmedUrl,
|
|
||||||
},
|
|
||||||
playready_device: {
|
|
||||||
security_level: playreadyData.security_level,
|
|
||||||
secret: playreadyData.secret,
|
|
||||||
device_name: playreadyData.device_name,
|
|
||||||
host: trimmedUrl,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
console.error(
|
console.error("Error fetching CDRM instance:", chrome.runtime.lastError);
|
||||||
"Error saving to chrome.storage:",
|
} else if (result.cdrm_instance) {
|
||||||
chrome.runtime.lastError
|
setStoredUrl(result.cdrm_instance);
|
||||||
);
|
|
||||||
setMessage("Error saving configuration.");
|
|
||||||
setMessageType("error");
|
|
||||||
} else {
|
|
||||||
console.log("Configuration saved.");
|
|
||||||
setStoredUrl(trimmedUrl);
|
|
||||||
setInstanceUrl("");
|
|
||||||
if (onConfigSaved) onConfigSaved();
|
|
||||||
navigate("/results"); // Automatically redirect after success
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
}, []);
|
||||||
} else {
|
|
||||||
throw new Error("Invalid response from endpoint.");
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Connection error:", err);
|
|
||||||
setMessage("Invalid endpoint or device info could not be retrieved.");
|
|
||||||
setMessageType("error");
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
const handleSave = async () => {
|
||||||
<div className="w-full h-full overflow-y-auto overflow-x-auto flex flex-col p-4">
|
const trimmedUrl = instanceUrl.trim().replace(/\/+$/, "");
|
||||||
<input
|
if (!trimmedUrl) {
|
||||||
type="text"
|
setMessage("Please enter a valid URL.");
|
||||||
value={instanceUrl}
|
setMessageType("error");
|
||||||
onChange={(e) => setInstanceUrl(e.target.value)}
|
return;
|
||||||
placeholder={
|
|
||||||
storedUrl
|
|
||||||
? `Current CDRM Instance: ${storedUrl}`
|
|
||||||
: "CDRM Instance URL (e.g., https://cdrm-project.com/, http://127.0.0.1:5000/)"
|
|
||||||
}
|
}
|
||||||
className="w-full p-4 text-lg bg-gray-800 text-white border border-gray-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 mt-4"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
onClick={handleSave}
|
|
||||||
disabled={loading}
|
|
||||||
className={`mt-4 p-2 ${
|
|
||||||
loading ? "bg-blue-400" : "bg-blue-600 hover:bg-blue-700"
|
|
||||||
} text-white rounded-md transition duration-300`}
|
|
||||||
>
|
|
||||||
{loading ? "Connecting..." : "Save Settings"}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{message && (
|
const endpoint = trimmedUrl + "/api/extension";
|
||||||
<p
|
setLoading(true);
|
||||||
className={`mt-2 text-sm text-center ${
|
setMessage(null);
|
||||||
messageType === "success" ? "text-green-400" : "text-red-400"
|
|
||||||
}`}
|
try {
|
||||||
>
|
const response = await fetch(endpoint, {
|
||||||
{message}
|
method: "POST",
|
||||||
</p>
|
headers: {
|
||||||
)}
|
"Content-Type": "application/json",
|
||||||
</div>
|
},
|
||||||
);
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.status === true) {
|
||||||
|
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 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 playreadyData = await playreadyRes.json();
|
||||||
|
|
||||||
|
chrome.storage.local.set(
|
||||||
|
{
|
||||||
|
valid_config: true,
|
||||||
|
cdrm_instance: trimmedUrl,
|
||||||
|
widevine_device: {
|
||||||
|
device_type: widevineData.device_type,
|
||||||
|
system_id: widevineData.system_id,
|
||||||
|
security_level: widevineData.security_level,
|
||||||
|
secret: widevineData.secret,
|
||||||
|
device_name: widevineData.device_name,
|
||||||
|
host: trimmedUrl,
|
||||||
|
},
|
||||||
|
playready_device: {
|
||||||
|
security_level: playreadyData.security_level,
|
||||||
|
secret: playreadyData.secret,
|
||||||
|
device_name: playreadyData.device_name,
|
||||||
|
host: trimmedUrl,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
console.error(
|
||||||
|
"Error saving to chrome.storage:",
|
||||||
|
chrome.runtime.lastError
|
||||||
|
);
|
||||||
|
setMessage("Error saving configuration.");
|
||||||
|
setMessageType("error");
|
||||||
|
} else {
|
||||||
|
console.log("Configuration saved.");
|
||||||
|
setStoredUrl(trimmedUrl);
|
||||||
|
setInstanceUrl("");
|
||||||
|
if (onConfigSaved) onConfigSaved();
|
||||||
|
navigate("/results"); // Automatically redirect after success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw new Error("Invalid response from endpoint.");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Connection error:", err);
|
||||||
|
setMessage("Invalid endpoint or device info could not be retrieved.");
|
||||||
|
setMessageType("error");
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full h-full overflow-y-auto overflow-x-auto flex flex-col p-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={instanceUrl}
|
||||||
|
onChange={(e) => setInstanceUrl(e.target.value)}
|
||||||
|
placeholder={
|
||||||
|
storedUrl
|
||||||
|
? `Current CDRM Instance: ${storedUrl}`
|
||||||
|
: "CDRM Instance URL (e.g., https://cdrm-project.com/, http://127.0.0.1:5000/)"
|
||||||
|
}
|
||||||
|
className="w-full p-4 text-lg bg-gray-800 text-white border border-gray-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 mt-4"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={handleSave}
|
||||||
|
disabled={loading}
|
||||||
|
className={`mt-4 p-2 ${
|
||||||
|
loading ? "bg-blue-400" : "bg-blue-600 hover:bg-blue-700"
|
||||||
|
} text-white rounded-md transition duration-300`}
|
||||||
|
>
|
||||||
|
{loading ? "Connecting..." : "Save Settings"}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{message && (
|
||||||
|
<p
|
||||||
|
className={`mt-2 text-sm text-center ${
|
||||||
|
messageType === "success" ? "text-green-400" : "text-red-400"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Settings;
|
export default Settings;
|
||||||
|
@ -4,48 +4,45 @@ import settingsIcon from "../assets/settings.svg";
|
|||||||
import closeIcon from "../assets/close.svg";
|
import closeIcon from "../assets/close.svg";
|
||||||
|
|
||||||
function SideNav({ onClose }) {
|
function SideNav({ onClose }) {
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full overflow-y-auto overflow-x-auto flex flex-col bg-black">
|
<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">
|
<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
|
<button onClick={onClose} className="h-full ml-auto p-3 hover:cursor-pointer">
|
||||||
onClick={onClose}
|
<img src={closeIcon} alt="Close" className="h-full" />
|
||||||
className="h-full ml-auto p-3 hover:cursor-pointer"
|
</button>
|
||||||
>
|
</div>
|
||||||
<img src={closeIcon} alt="Close" className="h-full" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-full h-16 flex items-center justify-center mt-2">
|
<div className="w-full h-16 flex items-center justify-center mt-2">
|
||||||
<NavLink
|
<NavLink
|
||||||
to="/results"
|
to="/results"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="text-white text-2xl font-bold flex flex-row items-center border-l-white hover:border-l-1 w-full hover:bg-black/50 transition duration-300 ease-in-out p-2"
|
className="text-white text-2xl font-bold flex flex-row items-center border-l-white hover:border-l-1 w-full hover:bg-black/50 transition duration-300 ease-in-out p-2"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={homeIcon}
|
src={homeIcon}
|
||||||
alt="Home"
|
alt="Home"
|
||||||
className="h-full w-16 p-2 flex items-center cursor-pointer"
|
className="h-full w-16 p-2 flex items-center cursor-pointer"
|
||||||
/>
|
/>
|
||||||
Home
|
Home
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full h-16 flex items-center justify-center mt-2">
|
<div className="w-full h-16 flex items-center justify-center mt-2">
|
||||||
<NavLink
|
<NavLink
|
||||||
to="/settings"
|
to="/settings"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="text-white text-2xl font-bold flex flex-row items-center hover:border-l-1 border-l-white w-full hover:bg-black/50 transition duration-300 ease-in-out p-2"
|
className="text-white text-2xl font-bold flex flex-row items-center hover:border-l-1 border-l-white w-full hover:bg-black/50 transition duration-300 ease-in-out p-2"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={settingsIcon}
|
src={settingsIcon}
|
||||||
alt="Settings"
|
alt="Settings"
|
||||||
className="h-full w-16 p-2 flex items-center cursor-pointer"
|
className="h-full w-16 p-2 flex items-center cursor-pointer"
|
||||||
/>
|
/>
|
||||||
Settings
|
Settings
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SideNav;
|
export default SideNav;
|
||||||
|
@ -2,84 +2,81 @@ import { useEffect, useState } from "react";
|
|||||||
import hamburgerIcon from "../assets/hamburger.svg";
|
import hamburgerIcon from "../assets/hamburger.svg";
|
||||||
|
|
||||||
function TopNav({ onMenuClick }) {
|
function TopNav({ onMenuClick }) {
|
||||||
const [injectionType, setInjectionType] = useState("LICENSE");
|
const [injectionType, setInjectionType] = useState("LICENSE");
|
||||||
const [drmOverride, setDrmOverride] = useState("DISABLED");
|
const [drmOverride, setDrmOverride] = useState("DISABLED");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
chrome.storage.local.get(["injection_type", "drm_override"], (result) => {
|
chrome.storage.local.get(["injection_type", "drm_override"], (result) => {
|
||||||
if (result.injection_type !== undefined) {
|
if (result.injection_type !== undefined) {
|
||||||
setInjectionType(result.injection_type);
|
setInjectionType(result.injection_type);
|
||||||
}
|
}
|
||||||
if (result.drm_override !== undefined) {
|
if (result.drm_override !== undefined) {
|
||||||
setDrmOverride(result.drm_override);
|
setDrmOverride(result.drm_override);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleInjectionTypeChange = (type) => {
|
const handleInjectionTypeChange = (type) => {
|
||||||
chrome.storage.local.set({ injection_type: type }, () => {
|
chrome.storage.local.set({ injection_type: type }, () => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
console.error(
|
console.error("Error updating injection_type:", chrome.runtime.lastError);
|
||||||
"Error updating injection_type:",
|
} else {
|
||||||
chrome.runtime.lastError
|
setInjectionType(type);
|
||||||
);
|
console.log(`Injection type updated to ${type}`);
|
||||||
} else {
|
}
|
||||||
setInjectionType(type);
|
});
|
||||||
console.log(`Injection type updated to ${type}`);
|
};
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDrmOverrideChange = (type) => {
|
const handleDrmOverrideChange = (type) => {
|
||||||
chrome.storage.local.set({ drm_override: type }, () => {
|
chrome.storage.local.set({ drm_override: type }, () => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
console.error("Error updating drm_override:", chrome.runtime.lastError);
|
console.error("Error updating drm_override:", chrome.runtime.lastError);
|
||||||
} else {
|
} else {
|
||||||
setDrmOverride(type);
|
setDrmOverride(type);
|
||||||
console.log(`DRM Override updated to ${type}`);
|
console.log(`DRM Override updated to ${type}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full flex flex-row overflow-x-hidden">
|
<div className="w-full h-full flex flex-row overflow-x-hidden">
|
||||||
<img
|
<img
|
||||||
src={hamburgerIcon}
|
src={hamburgerIcon}
|
||||||
alt="Menu"
|
alt="Menu"
|
||||||
className="h-full w-16 p-2 flex items-center cursor-pointer"
|
className="h-full w-16 p-2 flex items-center cursor-pointer"
|
||||||
onClick={onMenuClick}
|
onClick={onMenuClick}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-row h-full justify-center items-center ml-auto mr-2">
|
<div className="flex flex-row h-full justify-center items-center ml-auto mr-2">
|
||||||
<p className="text-white text-lg p-2 mr-2 border-r-2 border-r-white text-nowrap">
|
<p className="text-white text-lg p-2 mr-2 border-r-2 border-r-white text-nowrap">
|
||||||
Injection Type:
|
Injection Type:
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleInjectionTypeChange("LICENSE")}
|
onClick={() => handleInjectionTypeChange("LICENSE")}
|
||||||
className={`text-white text-lg p-2 rounded-md m-1 cursor-pointer ${
|
className={`text-white text-lg p-2 rounded-md m-1 cursor-pointer ${
|
||||||
injectionType === "LICENSE" ? "bg-sky-500/70" : "bg-black"
|
injectionType === "LICENSE" ? "bg-sky-500/70" : "bg-black"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
License
|
License
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleInjectionTypeChange("EME")}
|
onClick={() => handleInjectionTypeChange("EME")}
|
||||||
className={`text-white text-lg p-2 rounded-md m-1 cursor-pointer ${
|
className={`text-white text-lg p-2 rounded-md m-1 cursor-pointer ${
|
||||||
injectionType === "EME" ? "bg-green-500/70" : "bg-black"
|
injectionType === "EME" ? "bg-green-500/70" : "bg-black"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
EME
|
EME
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleInjectionTypeChange("DISABLED")}
|
onClick={() => handleInjectionTypeChange("DISABLED")}
|
||||||
className={`text-white text-lg p-2 rounded-md m-1 cursor-pointer ${
|
className={`text-white text-lg p-2 rounded-md m-1 cursor-pointer ${
|
||||||
injectionType === "DISABLED" ? "bg-red-500/70" : "bg-black"
|
injectionType === "DISABLED" ? "bg-red-500/70" : "bg-black"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Disabled
|
Disabled
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TopNav;
|
export default TopNav;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
|
||||||
html, body, #root {
|
html,
|
||||||
height: 100%;
|
body,
|
||||||
width: 100%;
|
#root {
|
||||||
margin: 0;
|
height: 100%;
|
||||||
padding: 0;
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
@ -1,10 +1,10 @@
|
|||||||
import { StrictMode } from 'react'
|
import { StrictMode } from "react";
|
||||||
import { createRoot } from 'react-dom/client'
|
import { createRoot } from "react-dom/client";
|
||||||
import './index.css'
|
import "./index.css";
|
||||||
import App from './App.jsx'
|
import App from "./App.jsx";
|
||||||
|
|
||||||
createRoot(document.getElementById('root')).render(
|
createRoot(document.getElementById("root")).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<App />
|
<App />
|
||||||
</StrictMode>,
|
</StrictMode>
|
||||||
)
|
);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from "vite";
|
||||||
import react from '@vitejs/plugin-react'
|
import react from "@vitejs/plugin-react";
|
||||||
import tailwindcss from '@tailwindcss/vite'
|
import tailwindcss from "@tailwindcss/vite";
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
base: './',
|
base: "./",
|
||||||
plugins: [react(), tailwindcss()],
|
plugins: [react(), tailwindcss()],
|
||||||
})
|
});
|
||||||
|
@ -1,41 +1,41 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "CDRM Extension 2.0",
|
"name": "CDRM Extension 2.0",
|
||||||
"version": "2.0",
|
"version": "2.0",
|
||||||
"description": "Decrypt DRM Protected content",
|
"description": "Decrypt DRM Protected content",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"webRequest",
|
"webRequest",
|
||||||
"webRequestBlocking",
|
"webRequestBlocking",
|
||||||
"<all_urls>",
|
"<all_urls>",
|
||||||
"activeTab",
|
"activeTab",
|
||||||
"storage",
|
"storage",
|
||||||
"tabs",
|
"tabs",
|
||||||
"contextMenus"
|
"contextMenus"
|
||||||
],
|
],
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": ["background.js"],
|
"scripts": ["background.js"],
|
||||||
"persistent": true
|
"persistent": true
|
||||||
},
|
},
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
"matches": ["<all_urls>"],
|
"matches": ["<all_urls>"],
|
||||||
"js": ["content.js"],
|
"js": ["content.js"],
|
||||||
"run_at": "document_start",
|
"run_at": "document_start",
|
||||||
"all_frames": true
|
"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"
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user