From 379fbdab6de27b433c6ca40a17ba30458af10688 Mon Sep 17 00:00:00 2001 From: Jos Vooges | STH Date: Mon, 28 Sep 2026 04:40:17 +0200 Subject: [PATCH] Send Viaplay session cookies encoded and reject Don't go without a license. --- apps/master-api/src/viaplay/client.ts | 51 +++++++++++++++------------ 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/apps/master-api/src/viaplay/client.ts b/apps/master-api/src/viaplay/client.ts index 72c4c9e..4c37ff5 100644 --- a/apps/master-api/src/viaplay/client.ts +++ b/apps/master-api/src/viaplay/client.ts @@ -21,12 +21,23 @@ function asRecord(v: unknown): Record | null { : null; } +/** Netscape/browser-cookies blijven encoded; decoded JSON in Cookie-header = Don't go. */ +function cookieValue(raw: string): string { + const v = raw.trim(); + if (!v) return v; + if (/%[0-9A-Fa-f]{2}/.test(v)) return v; + if (/[{}"\s]/.test(v)) return encodeURIComponent(v); + return v; +} + function cookieHeader(creds: ViaplayAccountCreds): string { const parts: string[] = []; - if (creds.session) parts.push(`session=${creds.session}`); - if (creds.accessToken) parts.push(`accessToken=${creds.accessToken}`); - if (creds.profileId) parts.push(`viaplay_profileId=${creds.profileId}`); - if (creds.persistentLogin) parts.push(`persistentLogin=${creds.persistentLogin}`); + if (creds.session) parts.push(`session=${cookieValue(creds.session)}`); + if (creds.accessToken) parts.push(`accessToken=${creds.accessToken.trim()}`); + if (creds.profileId) parts.push(`viaplay_profileId=${creds.profileId.trim()}`); + if (creds.persistentLogin) { + parts.push(`persistentLogin=${cookieValue(creds.persistentLogin)}`); + } return parts.join("; "); } @@ -127,22 +138,9 @@ export async function refreshViaplaySession( : ""); if (!sessionRaw || !accessRaw) return null; - let session = sessionRaw; - try { - session = decodeURIComponent(sessionRaw); - } catch { - /* keep raw */ - } + const session = sessionRaw; const accessToken = normalizeAccessToken(accessRaw) || accessRaw.trim(); - const nextPl = jar.persistentLogin - ? (() => { - try { - return decodeURIComponent(jar.persistentLogin); - } catch { - return jar.persistentLogin; - } - })() - : pl; + const nextPl = jar.persistentLogin || pl; return { ...creds, @@ -818,6 +816,12 @@ function assertPlayNotSoftFail( if (isDontGoPlaceholder(played.mpdUrl)) { throw new Error("Viaplay gaf Don't go-placeholder i.p.v. de wedstrijdstream"); } + if (/vod-dash/i.test(played.mpdUrl) && !played.licenseUrl) { + throw new Error("Viaplay gaf Don't go-VOD zonder licentie"); + } + if (!played.licenseUrl) { + throw new Error("Viaplay play-response mist Widevine-licentie (Don't go-fallback)"); + } if (opts?.requireLiveDash && !isLiveDashMpd(played.mpdUrl)) { throw new Error( "Viaplay gaf geen live-dash stream (Don't go/VOD-fallback — sessie of rechten)" @@ -903,12 +907,12 @@ export async function playByMediaGuid( const urls = [ buildPlayLiveUrl(creds, mediaGuid, { deviceKey: opts.deviceKey, - pageUrl: opts.pageUrl, - harStyle: true, + harStyle: false, }), buildPlayLiveUrl(creds, mediaGuid, { deviceKey: opts.deviceKey, - harStyle: false, + pageUrl: opts.pageUrl, + harStyle: true, }), ]; @@ -1076,6 +1080,9 @@ function assertVodPlayMatchesGuid( "Viaplay gaf Don't go-placeholder i.p.v. de gevraagde stream" ); } + if (/vod-dash/i.test(played.mpdUrl) && !played.licenseUrl) { + throw new Error("Viaplay gaf Don't go-VOD zonder licentie"); + } const links = asRecord(body._links); const productHref = asRecord(links?.["viaplay:product"])?.href;