diff --git a/.gitignore b/.gitignore index 414ff3d..851d9fc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ device_private_key client_id.bin private_key.pem .idea -remote.json \ No newline at end of file +remote.json diff --git a/background.js b/background.js index ed91225..56346f3 100644 --- a/background.js +++ b/background.js @@ -4,7 +4,9 @@ window.requests=[]; window.bodys=[]; window.targetIds=[]; window.pageURL=""; +window.title = ""; window.clearkey=""; +window.manifests = []; chrome.storage.local.get("isBlock", (value) => { window.isBlock = value.isBlock; @@ -62,11 +64,16 @@ chrome.runtime.onMessage.addListener( case "PSSH": window.psshs.push(request.text) window.pageURL=sender.tab.url + window.title = sender.tab.title window.targetIds=[sender.tab.id, sender.frameId] break; case "CLEARKEY": window.clearkey=request.text break; + case "MANIFEST": + window.manifests.push(JSON.parse(request.text)) + break; + } } ); diff --git a/content.js b/content.js index 5dcc6f7..9232d07 100644 --- a/content.js +++ b/content.js @@ -26,6 +26,13 @@ document.addEventListener('clearkey', (e) => { },null); }); +document.addEventListener('manifest', (e) => { + chrome.runtime.sendMessage({ + type: "MANIFEST", + text: e.detail + },null); +}); + //Fetch from original origin chrome.runtime.onMessage.addListener( function (request, sender, sendResponse) { diff --git a/inject.js b/inject.js index 4b6956e..08ab782 100644 --- a/inject.js +++ b/inject.js @@ -48,3 +48,132 @@ MediaKeySession.prototype.update = function(response) { return result; } }; + + + +function uint8ArrayToString(uint8array) { + return String.fromCharCode.apply(null, uint8array) +} + +class Evaluator { + static isDASH(text) { + return text.includes(''); + } + + static isHLS(text) { + return text.includes('#extm3u'); + } + + static isHLSMaster(text) { + return text.includes('#ext-x-stream-inf'); + } + + static isMSS(text) { + return text.includes(''); + } + + static getManifestType(text) { + const lower = text.toLowerCase(); + if (this.isDASH(lower)) { + return "DASH"; + } else if (this.isHLS(lower)) { + if (this.isHLSMaster(lower)) { + return "HLS_MASTER"; + } else { + return "HLS_PLAYLIST"; + } + } else if (this.isMSS(lower)) { + return "MSS"; + } + } +} + +const originalFetch = window.fetch; +window.fetch = function() { + return new Promise(async (resolve, reject) => { + originalFetch.apply(this, arguments).then((response) => { + if (response) { + response.clone().text().then((text) => { + const manifest_type = Evaluator.getManifestType(text); + if (manifest_type) { + if (arguments.length === 1) { + console.log('fetch1 manifest', arguments[0].url, manifest_type); + document.dispatchEvent(new CustomEvent('manifest', { + detail: JSON.stringify({ + "url": arguments[0].url, + "type": manifest_type, + }) + })); + } else if (arguments.length === 2) { + console.log('fetch2 manifest', arguments[0], manifest_type); + document.dispatchEvent(new CustomEvent('manifest', { + detail: JSON.stringify({ + "url": arguments[0], + "type": manifest_type, + }) + })); + } + } + resolve(response); + }).catch(() => { + resolve(response); + }) + } else { + resolve(response); + } + }).catch(() => { + resolve(); + }) + }) +} + +const open = XMLHttpRequest.prototype.open; +XMLHttpRequest.prototype.open = function(method, url) { + this._method = method; + return open.apply(this, arguments); +}; + +const send = XMLHttpRequest.prototype.send; +XMLHttpRequest.prototype.send = function(postData) { + this.addEventListener('load', async function() { + if (this._method === "GET") { + let body = void 0; + switch (this.responseType) { + case "": + case "text": + body = this.responseText ?? this.response; + break; + case "json": + // TODO: untested + body = JSON.stringify(this.response); + break; + case "arraybuffer": + // TODO: untested + if (this.response.byteLength) { + const response = new Uint8Array(this.response); + body = uint8ArrayToString(new Uint8Array([...response.slice(0, 2000), ...response.slice(-2000)])); + } + break; + case "document": + // todo + break; + case "blob": + body = await this.response.text(); + break; + } + if (body) { + const manifest_type = Evaluator.getManifestType(body); + if (manifest_type) { + console.log('send manifest', this.responseURL, manifest_type); + document.dispatchEvent(new CustomEvent('manifest', { + detail: JSON.stringify({ + "url": this.responseURL, + "type": manifest_type, + }) + })); + } + } + } + }); + return send.apply(this, arguments); +}; diff --git a/manifest.json b/manifest.json index 2cdd168..610a141 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Widevine L3 Decrypter", - "version": "241029.1", + "version": "250709.2", "version_name": "4316530", "icons": { "128": "icon.png" diff --git a/popup/main.html b/popup/main.html index d8a5173..2afe65d 100644 --- a/popup/main.html +++ b/popup/main.html @@ -24,6 +24,13 @@
+ +
+ +
+ +
+ +
+ Settings + +
+ +
+ + +
+ + + +