Skip to content

Commit

Permalink
Add Youtube / Update Amazon, C+, Polsat / Update UI (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
TPD94 authored Sep 28, 2024
1 parent 384fa9f commit 03366c6
Show file tree
Hide file tree
Showing 17 changed files with 323 additions and 184 deletions.
6 changes: 2 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
device.wvd

device_client_id_blob
device_private_key

client_id.bin
private_key.pem

remote.json
.idea
remote.json
4 changes: 2 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"manifest_version": 2,
"name": "Widevine L3 Guessor 2024",
"name": "Widevine L3 Decrypter",
"version": "240731.1",
"version_name": "a1297aa",
"icons": {
Expand Down Expand Up @@ -28,7 +28,7 @@
}
],
"browser_action": {
"default_title": "Widevine Guessor"
"default_title": "Widevine Decrypter"
},
"web_accessible_resources": ["inject.js"],
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
Expand Down
156 changes: 100 additions & 56 deletions popup.html
Original file line number Diff line number Diff line change
@@ -1,85 +1,129 @@
<html>
<!-- HTML -->
<html lang="en">

<!-- Heading -->
<head>
<meta charset="UTF-8">
<title>Widevine L3 Guessor 2024</title>
<title>Widevine L3 Decrypter</title>
<link rel="stylesheet" href="style.css">
<script src="pyodide/pyodide.js"></script>
</head>

<!-- Body -->
<body>
<div id="toggleHistory">
<button id="historyButton">Show History</button><br><br>
</div>



<!-- noEME -->
<div id="noEME">
Widevine content hasn't detected in this page.<br>
Open widevine-protected website and try again!
Widevine content hasn't detected in this page.
<br>
Open Widevine protected website and try again!
</div>
<div id="home" class="hidden">

<!-- Main -->
<div id="wvHome" >

<!-- Decryption forms -->
<form id="wvForm">
<label for="pssh">PSSH</label>
<input type="text" id="pssh" disabled/>
<input type="hidden" id="psshIndex" />
<input type="button" id="psshButton" value="Select" /><br>

<label for="license">License URL</label>
<input type="text" id="license" disabled/>
<input type="hidden" id="licenseIndex" />
<input type="button" id="licenseButton" value="Select" /><br>

<label for="scheme">Challenge scheme</label>
<select id="scheme">
<option value="CommonWV">CommonWV</option>
<option value="Amazon">Amazon</option>
<option value="CanalPlus">Canal+</option>
<option value="CanalPlus2">Canal+(Alt)</option>
<option value="Comcast">Comcast Xfinity</option>
<option value="DRMToday">DRMToday</option>
<option value="GlobalTV">GlobalTV</option>
<option value="moTV">moTV</option>
<option value="NosTV">NosTV</option>
<option value="oqee">Oqee</option>
<option value="Polsat">Polsat</option>
<option value="RedBee">Red Bee Media</option>
<option value="thePlatform">thePlatform</option>
<option value="VdoCipher">VdoCipher</option>
<option value="VUDRM">VUDRM</option>
<option value="Vodafone">Vodafone</option>
<option value="Youku">Youku</option>
</select>

<input type="button" id="guess" value="Guess!"><br>

<label for="result">Result:</label><br>
<textarea id="result" rows="10" cols="50"></textarea>

<!-- PSSH line -->
<div id="wvHomePSSHLines">
<label for="pssh">PSSH</label>
<input type="text" id="pssh" disabled/>
<input type="hidden" id="psshIndex" />
<input type="button" id="psshButton" value="Select" />
<br>
</div>

<!-- License URL line -->
<div id="wvHomeLicenseLine">
<label for="license">License URL</label>
<input type="text" id="license" disabled/>
<input type="hidden" id="licenseIndex" />
<input type="button" id="licenseButton" value="Select" />
<br>
</div>

<!-- Scheme line -->
<div id="wvHomeSchemeLine">
<label for="scheme">Challenge scheme</label>
<select id="scheme">
<option value="CommonWV">CommonWV</option>
<option value="Amazon">Amazon</option>
<option value="CanalPlusPL">CanalPlusPL</option>
<option value="Comcast">Comcast Xfinity</option>
<option value="DRMToday">DRMToday</option>
<option value="GlobalTV">GlobalTV</option>
<option value="moTV">moTV</option>
<option value="NosTV">NosTV</option>
<option value="oqee">Oqee</option>
<option value="PolSatBoxGo">PolSatBoxGo</option>
<option value="RedBee">Red Bee Media</option>
<option value="thePlatform">thePlatform</option>
<option value="VdoCipher">VdoCipher</option>
<option value="VUDRM">VUDRM</option>
<option value="Vodafone">Vodafone</option>
<option value="Youku">Youku</option>
<option value="YouTube">YouTube</option>
</select>
<input type="button" id="guess" value="Decrypt">
<br>
</div>

<!-- Result line -->
<div id="wvHomeResultLine">
<label for="result">Result:</label><br>
<textarea id="result" rows="10" cols="50" readonly></textarea>
</div>

</form>
<button id="historyButton">Show History</button>
</div>
<div id="ckHome" class="hidden">

<!-- Clearkey -->
<div id="ckHome">
<h3>Clearkey detected</h3>
<label for="ckResult">Result:</label><br>
<textarea id="ckResult" rows="10" cols="50"></textarea>
<label for="ckResult">Result:</label>
<textarea id="ckResult" rows="10" cols="50" readonly></textarea>
</div>
<div id="selectPssh" class="hidden">
<input type="text" id="psshSearch" placeholder="Search">

<!-- PSSH Selection -->
<div id="selectPssh">
<label for="psshSearch"></label>
<input type="text" id="psshSearch" placeholder="Search for PSSH">
<ul id="psshList"></ul>
</div>
<div id="selectRequest" class="hidden">
<input type="text" id="requestSearch" placeholder="Search">

<!-- License URL Selection -->
<div id="selectRequest">
<label for="requestSearch"></label>
<input type="text" id="requestSearch" placeholder="Search for License request">
<ul id="requestList"></ul>
</div>
<div id="history" class="hidden">
<button id="backHistory">🔙 Back</button>
<button id="saveHistory">💾 Save History</button>
<button id="clearHistory">❌ Clear History</button>

<!-- History -->
<div id="history">
<div id="histDisp"></div>
<div id="histButtons">
<button class="text-red-600" id="backHistory">🔙 Back</button>
<button id="saveHistory">💾 Save History</button>
<button id="clearHistory">❌ Clear History</button>
</div>
</div>
<div id="updateNotice" class="hidden">

<!-- Update notice -->
<div id="updateNoticeExtension">
Version =VER= update available!
<a href="https://github.com/FoxRefire/wvg/archive/=HASH=.zip">Download</a>
<a href="https://github.com/FoxRefire/wvg/archive/=HASH=.zip"> Download</a>
</div>
</body>

<!-- Scripts -->
<script src="popup.js" type="module"></script>
<script src="popup_drawList.js"></script>
<script src="jsonview.js"></script>
<script src="popup_showHistory.js"></script>
<script src="popup_updateNotice.js"></script>

</html>
18 changes: 16 additions & 2 deletions popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,30 @@ async function autoSelect(){

if (clearkey) {
document.getElementById('noEME').style.display = 'none';
document.getElementById('ckHome').style.display = 'grid';
document.getElementById('wvHome').style.display = 'none';
document.getElementById('ckHome').style.display = 'flex';
document.getElementById('history').style.display = 'none'
document.getElementById('selectPssh').style.display = 'none';
document.getElementById('selectRequest').style.display = 'none';
document.getElementById('ckResult').value = clearkey;
document.getElementById('ckResult').addEventListener("click", copyResult);
document.getElementById('toggleHistory').style.display = 'none'
} else if (psshs.length) {
document.getElementById('wvHome').style.display = 'flex';
document.getElementById('noEME').style.display = 'none';
document.getElementById('home').style.display = 'grid';
document.getElementById('ckHome').style.display = 'none';
document.getElementById('history').style.display = 'none';
document.getElementById('guess').addEventListener("click", guess);
document.getElementById('result').addEventListener("click", copyResult);
drawList(psshs, 'psshSearch', 'psshList', 'pssh');
drawList(requests.map(r => r['url']), 'requestSearch', 'requestList', 'license');
autoSelect();
}
else {
document.getElementById('noEME').style.display = 'flex';
document.getElementById('wvHome').style.display = 'none';
document.getElementById('ckHome').style.display = 'none';
document.getElementById('selectPssh').style.display = 'none';
document.getElementById('selectRequest').style.display = 'none';
document.getElementById('history').style.display = 'none';
}
28 changes: 12 additions & 16 deletions popup_drawList.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
function selectPssh(){
document.getElementById('home').style.display='none';
document.getElementById('selectPssh').style.display='grid';
document.getElementById('psshList').style.display='grid';
document.getElementById('toggleHistory').style.display='none';
document.getElementById('wvHome').style.display='none';
document.getElementById('selectPssh').style.display='flex';
}

function selectRequest(){
document.getElementById('home').style.display='none';
document.getElementById('selectRequest').style.display='grid';
document.getElementById('requestList').style.display='grid';
document.getElementById('toggleHistory').style.display='none';
document.getElementById('wvHome').style.display='none';
document.getElementById('selectRequest').style.display='flex';
}

document.getElementById('psshButton').addEventListener("click", selectPssh);
Expand All @@ -18,17 +14,17 @@ document.getElementById('licenseButton').addEventListener("click", selectRequest
function writeListElement(arrElements, list, outputVar, search) {
list.innerHTML = '';
arrElements.forEach((element, index) => {
if (!search || element.includes(searchValue)) {
// Check if search is defined and if the element includes the search value
if (!search || element.toLowerCase().includes(search)) {
const li = document.createElement('li');
li.textContent = element;
li.addEventListener('click', () => {
userInputs[outputVar]=index;
document.getElementById(outputVar).value=element;
document.getElementById(outputVar+'Index').value=index;
document.getElementById('selectPssh').style.display='none';
document.getElementById('selectRequest').style.display='none';
document.getElementById('home').style.display='grid';
document.getElementById('toggleHistory').style.display='grid';
userInputs[outputVar] = index;
document.getElementById(outputVar).value = element;
document.getElementById(outputVar + 'Index').value = index;
document.getElementById('selectPssh').style.display = 'none';
document.getElementById('selectRequest').style.display = 'none';
document.getElementById('wvHome').style.display = 'flex';
});
list.appendChild(li);
}
Expand Down
10 changes: 4 additions & 6 deletions popup_showHistory.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,18 @@ function showHistory(){
let tree=jsonview.renderJSON(JSON.stringify(data), document.getElementById('histDisp'));
jsonview.toggleNode(tree);
}));
document.getElementById('home').style.display='none';
document.getElementById('wvHome').style.display='none';
document.getElementById('noEME').style.display='none';
document.getElementById('history').style.display='grid';
document.getElementById('toggleHistory').style.display='none';
document.getElementById('history').style.display='flex';
}

function backHistory(){
document.getElementById('histDisp').innerHTML="";
document.getElementById('history').style.display='none';
document.getElementById('toggleHistory').style.display='grid';
if(psshs.length){
document.getElementById('home').style.display='grid';
document.getElementById('wvHome').style.display='flex';
} else {
document.getElementById('noEME').style.display='grid';
document.getElementById('noEME').style.display='none';
}
}

Expand Down
4 changes: 2 additions & 2 deletions popup_updateNotice.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ document.addEventListener('DOMContentLoaded', async function() {
cManifest=await fetch("manifest.json").then(r=>r.json());
rManifest=await fetch("https://raw.githubusercontent.com/FoxRefire/wvg/next/manifest.json").then(r=>r.json());
if(cManifest.version < rManifest.version){
let notice = document.getElementById("updateNotice");
notice.style.display='block';
let notice = document.getElementById("updateNoticeExtension");
notice.style.display='flex';
notice.innerHTML = notice.innerHTML.replace("=VER=", rManifest.version);
notice.innerHTML = notice.innerHTML.replace("=HASH=", rManifest.version_name);
}
Expand Down
16 changes: 16 additions & 0 deletions python/pre.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,22 @@ def loadBody(loadAs: str):

return licBody

# Define a function to get challenge if needed to set a service cert
def getChallenge(getAs, *cert):
global session_id
global pssh

if bool(cert):
cdm.set_service_certificate(session_id, cert[0])

challenge = cdm.get_license_challenge(session_id, pssh)

match getAs:
case "blob": pass
case "b64": challenge = base64.b64encode(challenge).decode()
case "list": challenge = list(challenge)
return challenge

# prepare pssh
pssh = PSSH(pssh)

Expand Down
14 changes: 7 additions & 7 deletions python/schemes/Amazon.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import urllib.parse
payload = f"widevine2Challenge={urllib.parse.quote(base64.b64encode(challenge).decode())}&includeHdcpTestKeyInLicense=true"

licHeaders['User-Agent'] = "Mozilla/5.0 (X11; Linux x86_64; rv:126.0) Gecko/20100101 Firefox/126.0"

res = await corsFetch(licUrl, "POST", licHeaders, payload, "json")
licence = res['widevine2License']['license']

payload = f'widevine2Challenge={urllib.parse.quote(base64.b64encode(cdm.service_certificate_challenge).decode())}&includeHdcpTestKeyInLicense=true'
service_cert = await corsFetch(licUrl, "POST", licHeaders, payload, "json")
service_cert = service_cert['widevine2License']['license']
getChallenge('b64', service_cert)
payload = f'widevine2Challenge={urllib.parse.quote(getChallenge("b64", service_cert))}&includeHdcpTestKeyInLicense=true'
licence = await corsFetch(licUrl, "POST", licHeaders, payload, "json")
licence = licence['widevine2License']['license']
7 changes: 0 additions & 7 deletions python/schemes/CanalPlus.py

This file was deleted.

5 changes: 0 additions & 5 deletions python/schemes/CanalPlus2.py

This file was deleted.

4 changes: 4 additions & 0 deletions python/schemes/CanalPlusPL.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import xml.etree.ElementTree as ET
challenge_with_cert = getChallenge('b64', Cdm.common_privacy_cert)
licence = await corsFetch(licUrl, "POST", licHeaders, challenge_with_cert, "blob")
licence = ET.fromstring(licence).find('.//{http://www.canal-plus.com/DRM/V1}license').text
4 changes: 4 additions & 0 deletions python/schemes/PolSatBoxGo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
body = loadBody('json')
body['params']['object'] = getChallenge('b64', Cdm.common_privacy_cert)
licence = await corsFetch(licUrl, "POST", licHeaders, body, "json")
licence = licence['result']['object']['license']
Loading

0 comments on commit 03366c6

Please sign in to comment.