mirror of
https://github.com/Ingan121/Vineless.git
synced 2026-04-02 18:48:40 +00:00
* Add proper support for server certificates (only for local WV devices)
* Fix issues with some services that append extra data, which is not a PR WRM initData, to the WV PSSH
This commit is contained in:
@@ -80,7 +80,7 @@ async function parseClearKey(body, sendResponse, tab_url) {
|
||||
sendResponse(JSON.stringify({pssh: pssh_data, keys : formatted_keys}));
|
||||
}
|
||||
|
||||
async function generateChallenge(body, sendResponse) {
|
||||
async function generateChallenge(body, sendResponse, serverCert) {
|
||||
const pssh_data = getWvPsshFromConcatPssh(body);
|
||||
|
||||
if (!pssh_data) {
|
||||
@@ -107,6 +107,10 @@ async function generateChallenge(body, sendResponse) {
|
||||
pssh_data
|
||||
);
|
||||
|
||||
if (serverCert) {
|
||||
session.setServiceCertificate(base64toUint8Array(serverCert));
|
||||
}
|
||||
|
||||
const [challenge, request_id] = session.createLicenseRequest(LicenseType.STREAMING, widevine_device.type === 2);
|
||||
sessions.set(uint8ArrayToBase64(request_id), session);
|
||||
|
||||
@@ -355,11 +359,12 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
return;
|
||||
} catch {
|
||||
if (message.body) {
|
||||
const split = message.body.split(":");
|
||||
if (message.body.startsWith("lookup:")) {
|
||||
const split = message.body.split(":");
|
||||
const [ _, sessionId, kidHex, serverCert ] = split;
|
||||
// Find first log that contains the requested KID
|
||||
const log = logs.find(log =>
|
||||
log.keys.some(k => k.kid.toLowerCase() === split[2].toLowerCase())
|
||||
log.keys.some(k => k.kid.toLowerCase() === kidHex.toLowerCase())
|
||||
);
|
||||
if (!log) {
|
||||
console.warn("[Vineless] Lookup failed: no log found for KID", kidHex);
|
||||
@@ -378,7 +383,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
const device_type = await SettingsManager.getSelectedDeviceType();
|
||||
switch (device_type) {
|
||||
case "WVD":
|
||||
await generateChallenge(log.pssh_data, sendResponse);
|
||||
await generateChallenge(log.pssh_data, sendResponse, serverCert);
|
||||
break;
|
||||
case "REMOTE":
|
||||
await generateChallengeRemote(log.pssh_data, sendResponse);
|
||||
@@ -386,7 +391,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
}
|
||||
break;
|
||||
case "PLAYREADY": // UNTESTED
|
||||
await generatePRChallenge(log.pssh_data, sendResponse, split[1]);
|
||||
await generatePRChallenge(log.pssh_data, sendResponse, sessionId);
|
||||
break;
|
||||
}
|
||||
} else if (message.body.startsWith("pr:")) {
|
||||
@@ -395,21 +400,22 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
manifests.clear();
|
||||
return;
|
||||
}
|
||||
const split = message.body.split(':');
|
||||
await generatePRChallenge(split[2], sendResponse, split[1]);
|
||||
const [ _, sessionId, wrmHeader ] = split;
|
||||
await generatePRChallenge(wrmHeader, sendResponse, sessionId);
|
||||
} else {
|
||||
if (!await SettingsManager.getWVEnabled()) {
|
||||
sendResponse();
|
||||
manifests.clear();
|
||||
return;
|
||||
}
|
||||
const [ pssh, serverCert ] = split;
|
||||
const device_type = await SettingsManager.getSelectedDeviceType();
|
||||
switch (device_type) {
|
||||
case "WVD":
|
||||
await generateChallenge(message.body, sendResponse);
|
||||
await generateChallenge(pssh, sendResponse, serverCert);
|
||||
break;
|
||||
case "REMOTE":
|
||||
await generateChallengeRemote(message.body, sendResponse);
|
||||
await generateChallengeRemote(pssh, sendResponse); // No serverCert support for remote yet
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,10 +535,11 @@
|
||||
if (!await getEnabledForKeySystem(keySystem) || _this._ck) {
|
||||
return await _target.apply(_this, _args);
|
||||
}
|
||||
// Server certificates are not supported yet
|
||||
// Chrome returns false when this is called on a CK MediaKeys, while Firefox raises an exception when done so
|
||||
// Let's just return false for now to prevent some sites from entirely breaking
|
||||
// Server certificate support is planned for the future, for services that truly need it for playback/higher quality content
|
||||
if (keySystem.startsWith("com.widevine.alpha")) {
|
||||
_this._emeShim.serverCert = uint8ArrayToBase64(new Uint8Array(_args[0]));
|
||||
return true;
|
||||
}
|
||||
// Server certificates are not supported on ClearKey or PlayReady
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -561,7 +562,16 @@
|
||||
|
||||
if (_args[0].toLowerCase() === "webm") {
|
||||
const kid = uint8ArrayToHex(_args[1]);
|
||||
const base64Pssh = await emitAndWaitForResponse("REQUEST", `lookup:${_this.sessionId}:${kid}`);
|
||||
let data = `lookup:${_this.sessionId}:${kid}`;
|
||||
if (_this._mediaKeys._emeShim.serverCert) {
|
||||
data += `:${_this._mediaKeys._emeShim.serverCert}`;
|
||||
}
|
||||
const base64Pssh = await emitAndWaitForResponse("REQUEST", data);
|
||||
if (!base64Pssh) {
|
||||
const error = new Error("[Vineless] No PSSH received for WebM request");
|
||||
console.error(error);
|
||||
throw error;
|
||||
}
|
||||
const evt = new MediaKeyMessageEvent("message", {
|
||||
message: base64toUint8Array(base64Pssh).buffer,
|
||||
messageType: "license-request"
|
||||
@@ -571,7 +581,10 @@
|
||||
}
|
||||
|
||||
const base64Pssh = uint8ArrayToBase64(new Uint8Array(_args[1]));
|
||||
const data = keySystem.startsWith("com.microsoft.playready") ? `pr:${_this.sessionId}:${base64Pssh}` : base64Pssh;
|
||||
let data = keySystem.startsWith("com.microsoft.playready") ? `pr:${_this.sessionId}:${base64Pssh}` : base64Pssh;
|
||||
if (_this._mediaKeys._emeShim.serverCert) {
|
||||
data += `:${_this._mediaKeys._emeShim.serverCert}`;
|
||||
}
|
||||
const challenge = await emitAndWaitForResponse("REQUEST", data);
|
||||
const challengeBytes = base64toUint8Array(challenge);
|
||||
|
||||
|
||||
6
util.js
6
util.js
@@ -507,12 +507,6 @@ export function stringToHex(string){
|
||||
export function getWvPsshFromConcatPssh(psshBase64) {
|
||||
const raw = base64toUint8Array(psshBase64);
|
||||
|
||||
// Detect PlayReady PSSH by presence of "WRMHEADER" in UTF-16LE
|
||||
const text = new TextDecoder('utf-16le').decode(raw);
|
||||
if (!text.includes('WRMHEADER')) {
|
||||
return psshBase64; // Keep as-is if PlayReady not mixed in
|
||||
}
|
||||
|
||||
let offset = 0;
|
||||
while (offset + 8 <= raw.length) {
|
||||
const size = new DataView(raw.buffer, raw.byteOffset + offset).getUint32(0);
|
||||
|
||||
Reference in New Issue
Block a user