Harden repo for store review: ignore secrets and soften admin copy.
Keep credentials, HARs and probe dumps out of git; use neutral wording around sessions and stream licenses.
This commit is contained in:
parent
57ac2d4435
commit
fb8601c2b5
10 changed files with 92 additions and 38 deletions
55
.gitignore
vendored
55
.gitignore
vendored
|
|
@ -3,6 +3,8 @@ dist/
|
||||||
.next/
|
.next/
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
*.log
|
*.log
|
||||||
.DS_Store
|
.DS_Store
|
||||||
coverage/
|
coverage/
|
||||||
|
|
@ -17,3 +19,56 @@ apps/master-api/dist/
|
||||||
packages/*/dist/
|
packages/*/dist/
|
||||||
|
|
||||||
apps/android-tv/apk-patch/
|
apps/android-tv/apk-patch/
|
||||||
|
|
||||||
|
# Secrets / credentials / session material — never push
|
||||||
|
**/_fresh_creds.json
|
||||||
|
**/*_creds.json
|
||||||
|
**/cookies*.txt
|
||||||
|
**/*cookies*.txt
|
||||||
|
**/*.wvd
|
||||||
|
**/*.pem
|
||||||
|
**/*.p12
|
||||||
|
**/*.pfx
|
||||||
|
**/credentials.json
|
||||||
|
**/service-account*.json
|
||||||
|
**/.env.secrets
|
||||||
|
**/secrets.local.*
|
||||||
|
|
||||||
|
# Browser captures & local probe dumps
|
||||||
|
**/*.har
|
||||||
|
**/_viaplay_probe_out/
|
||||||
|
**/_probe_out/
|
||||||
|
**/_recovered/
|
||||||
|
apps/ios/scripts/_probe_*.cjs
|
||||||
|
apps/ios/scripts/_parse_*.cjs
|
||||||
|
apps/ios/scripts/_parse_*.mjs
|
||||||
|
apps/ios/scripts/_dump_*.mjs
|
||||||
|
apps/ios/scripts/_rebuild_*.mjs
|
||||||
|
apps/ios/scripts/_recover*.mjs
|
||||||
|
apps/ios/scripts/_replay_*.mjs
|
||||||
|
apps/ios/scripts/_finalize_*.mjs
|
||||||
|
apps/ios/scripts/_find_*.mjs
|
||||||
|
apps/ios/scripts/VMC-TestFlight-*.command
|
||||||
|
apps/ios/scripts/probe_*.py
|
||||||
|
apps/ios/scripts/debug_*.py
|
||||||
|
apps/ios/scripts/diag_*.py
|
||||||
|
apps/ios/scripts/verify_*.py
|
||||||
|
apps/ios/scripts/verify_*.swift
|
||||||
|
apps/ios/scripts/verify-*.sh
|
||||||
|
apps/ios/scripts/live_*.py
|
||||||
|
apps/ios/scripts/analyze_*.py
|
||||||
|
apps/ios/scripts/dump_*.py
|
||||||
|
apps/ios/scripts/inspect_*.py
|
||||||
|
apps/ios/scripts/fetch_*.py
|
||||||
|
apps/ios/scripts/fetch-*.sh
|
||||||
|
apps/ios/scripts/run-*.sh
|
||||||
|
apps/ios/scripts/smoke_*.swift
|
||||||
|
apps/ios/scripts/vmc-tf-*.sh
|
||||||
|
apps/ios/scripts/hbo-*.mpd
|
||||||
|
apps/ios/scripts/*_sample.json
|
||||||
|
apps/master-api/odyssey-test.txt
|
||||||
|
|
||||||
|
# Local build / crash dumps
|
||||||
|
apps/android-tv/assemble-*.txt
|
||||||
|
apps/android-tv/*.hprof
|
||||||
|
**/*.hprof
|
||||||
|
|
|
||||||
|
|
@ -168,10 +168,10 @@ export default function DrmPage() {
|
||||||
<header className="page-header">
|
<header className="page-header">
|
||||||
<div>
|
<div>
|
||||||
<p className="page-kicker">Beveiliging</p>
|
<p className="page-kicker">Beveiliging</p>
|
||||||
<h1>DRM keys</h1>
|
<h1>Stream-licenties</h1>
|
||||||
<p className="page-lead">
|
<p className="page-lead">
|
||||||
Alle ooit opgehaalde ClearKey/Widevine-keys. Zoek op KID, KEY, MPD, zender of
|
Opgeslagen stream-licenties per provider. Zoek op KID, manifest-URL, zender of
|
||||||
event. Altijd eerst cache — alleen ophalen bij miss.
|
event. Cache-first — alleen vernieuwen bij miss.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="page-actions">
|
<div className="page-actions">
|
||||||
|
|
|
||||||
|
|
@ -306,8 +306,9 @@ export function F1tvPanel({ onChanged }: { onChanged?: (o: F1tvOverview) => void
|
||||||
<h2 style={{ marginTop: 0 }}>F1TV</h2>
|
<h2 style={{ marginTop: 0 }}>F1TV</h2>
|
||||||
<p className="muted" style={{ marginTop: 0 }}>
|
<p className="muted" style={{ marginTop: 0 }}>
|
||||||
Events + F1-hub. Imperva blokkeert server-login: plak{" "}
|
Events + F1-hub. Imperva blokkeert server-login: plak{" "}
|
||||||
<code>ascendontoken</code> + <code>entitlementtoken</code> uit DevTools (na browser-login).
|
<code>ascendontoken</code> + <code>entitlementtoken</code> uit een ingelogde
|
||||||
Meerdere accounts: sessies worden als unie samengevoegd; play round-robint over owners.
|
browsersessie. Meerdere accounts: sessies worden als unie samengevoegd; play
|
||||||
|
round-robint over owners.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginBottom: "1rem" }}>
|
<div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginBottom: "1rem" }}>
|
||||||
|
|
|
||||||
|
|
@ -237,9 +237,7 @@ export function ViaplayPanel({ onChanged }: { onChanged?: (o: ViaplayOverview) =
|
||||||
});
|
});
|
||||||
const d = await r.json();
|
const d = await r.json();
|
||||||
if (!r.ok) throw new Error(d.error?.message ?? "Sync mislukt");
|
if (!r.ok) throw new Error(d.error?.message ?? "Sync mislukt");
|
||||||
setMsg(
|
setMsg(`Viaplay-agenda: ${d.events ?? 0} events · ${d.daysOk ?? 0}/${d.daysTried ?? 0} dagen (${d.durationMs ?? "?"} ms)`);
|
||||||
`Viaplay EPG: ${d.events ?? 0} events · ${d.daysOk ?? 0}/${d.daysTried ?? 0} dagen (${d.durationMs ?? "?"} ms)`
|
|
||||||
);
|
|
||||||
await load();
|
await load();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setErr(String((e as Error).message ?? e));
|
setErr(String((e as Error).message ?? e));
|
||||||
|
|
@ -330,34 +328,34 @@ export function ViaplayPanel({ onChanged }: { onChanged?: (o: ViaplayOverview) =
|
||||||
<div className="card" style={{ maxWidth: 760 }}>
|
<div className="card" style={{ maxWidth: 760 }}>
|
||||||
<h2 style={{ marginTop: 0 }}>Viaplay</h2>
|
<h2 style={{ marginTop: 0 }}>Viaplay</h2>
|
||||||
<p className="muted" style={{ marginTop: 0 }}>
|
<p className="muted" style={{ marginTop: 0 }}>
|
||||||
Sport-EPG (publiek) + live play/keys. Plak <code>session</code> +{" "}
|
Sportagenda en live streams voor gekoppelde Viaplay-accounts. Voeg een account toe met
|
||||||
<code>accessToken</code> (+ <code>viaplay_profileId</code>) uit DevTools na browser-login.
|
sessie-token, access token en optioneel profile-id (uit een ingelogde browsersessie).
|
||||||
Cache-first: MPD/keys ±5 min vóór start, gestaggerd. Tray-tool volgt later.
|
Manifests en licenties worden cache-first opgehaald (±5 min vóór start, gestaggerd).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginBottom: "1rem" }}>
|
<div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginBottom: "1rem" }}>
|
||||||
<button type="button" className="btn-primary" disabled={busy} onClick={() => void runSync()}>
|
<button type="button" className="btn-primary" disabled={busy} onClick={() => void runSync()}>
|
||||||
EPG syncen
|
Agenda syncen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
disabled={busy || accounts.length === 0}
|
disabled={busy || accounts.length === 0}
|
||||||
onClick={() => void runPreLive()}
|
onClick={() => void runPreLive()}
|
||||||
>
|
>
|
||||||
Pre-live nu
|
Pre-live vernieuwen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
disabled={busy || accounts.length === 0}
|
disabled={busy || accounts.length === 0}
|
||||||
onClick={() => void probeAccounts()}
|
onClick={() => void probeAccounts()}
|
||||||
>
|
>
|
||||||
Cookies controleren
|
Accounts controleren
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 style={{ marginBottom: "0.5rem" }}>Accounts</h3>
|
<h3 style={{ marginBottom: "0.5rem" }}>Accounts</h3>
|
||||||
{accounts.length === 0 ? (
|
{accounts.length === 0 ? (
|
||||||
<p className="muted">Nog geen accounts — voeg e-mail + cookies toe.</p>
|
<p className="muted">Nog geen accounts — voeg e-mail + sessie-tokens toe.</p>
|
||||||
) : (
|
) : (
|
||||||
<ul style={{ listStyle: "none", padding: 0, margin: "0 0 1rem" }}>
|
<ul style={{ listStyle: "none", padding: 0, margin: "0 0 1rem" }}>
|
||||||
{accounts.map((a) => (
|
{accounts.map((a) => (
|
||||||
|
|
@ -379,7 +377,7 @@ export function ViaplayPanel({ onChanged }: { onChanged?: (o: ViaplayOverview) =
|
||||||
<span className="muted" style={{ fontSize: "0.85rem" }}>
|
<span className="muted" style={{ fontSize: "0.85rem" }}>
|
||||||
{a.email}
|
{a.email}
|
||||||
{" · "}
|
{" · "}
|
||||||
{a.hasSession && a.hasAccessToken ? "cookies ok" : "cookies missen"}
|
{a.hasSession && a.hasAccessToken ? "tokens ok" : "tokens missen"}
|
||||||
{a.subscriptionSummary ? ` · ${a.subscriptionSummary}` : ""}
|
{a.subscriptionSummary ? ` · ${a.subscriptionSummary}` : ""}
|
||||||
{a.eventCount ? ` · ${a.eventCount} events` : ""}
|
{a.eventCount ? ` · ${a.eventCount} events` : ""}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -436,7 +434,7 @@ export function ViaplayPanel({ onChanged }: { onChanged?: (o: ViaplayOverview) =
|
||||||
style={{ marginTop: 10 }}
|
style={{ marginTop: 10 }}
|
||||||
onClick={() => setShowCookies((v) => !v)}
|
onClick={() => setShowCookies((v) => !v)}
|
||||||
>
|
>
|
||||||
{showCookies ? "Cookies verbergen" : "Cookies plakken (vereist)"}
|
{showCookies ? "Tokens verbergen" : "Sessie-tokens plakken (vereist)"}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{showCookies && (
|
{showCookies && (
|
||||||
|
|
@ -448,7 +446,7 @@ export function ViaplayPanel({ onChanged }: { onChanged?: (o: ViaplayOverview) =
|
||||||
onChange={(e) => setNewSession(e.target.value)}
|
onChange={(e) => setNewSession(e.target.value)}
|
||||||
rows={2}
|
rows={2}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
placeholder="session-cookie waarde"
|
placeholder="session-waarde uit ingelogde browsersessie"
|
||||||
style={{ fontFamily: "monospace", fontSize: "0.8rem" }}
|
style={{ fontFamily: "monospace", fontSize: "0.8rem" }}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -459,17 +457,17 @@ export function ViaplayPanel({ onChanged }: { onChanged?: (o: ViaplayOverview) =
|
||||||
onChange={(e) => setNewAccessToken(e.target.value)}
|
onChange={(e) => setNewAccessToken(e.target.value)}
|
||||||
rows={2}
|
rows={2}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
placeholder="eyJ…"
|
placeholder="access token"
|
||||||
style={{ fontFamily: "monospace", fontSize: "0.8rem" }}
|
style={{ fontFamily: "monospace", fontSize: "0.8rem" }}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label className="field">
|
<label className="field">
|
||||||
viaplay_profileId (optioneel)
|
profileId (optioneel)
|
||||||
<input
|
<input
|
||||||
value={newProfileId}
|
value={newProfileId}
|
||||||
onChange={(e) => setNewProfileId(e.target.value)}
|
onChange={(e) => setNewProfileId(e.target.value)}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
placeholder="EO…"
|
placeholder="profile id"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -602,12 +600,12 @@ export function ViaplayPanel({ onChanged }: { onChanged?: (o: ViaplayOverview) =
|
||||||
)
|
)
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span>nog niet compleet (account + cookies)</span>
|
<span>nog niet compleet (account + sessie-tokens)</span>
|
||||||
)}
|
)}
|
||||||
{settings?.lastSyncAt && (
|
{settings?.lastSyncAt && (
|
||||||
<>
|
<>
|
||||||
<br />
|
<br />
|
||||||
Laatste EPG-sync: {new Date(settings.lastSyncAt).toLocaleString("nl-NL")}
|
Laatste agenda-sync: {new Date(settings.lastSyncAt).toLocaleString("nl-NL")}
|
||||||
{summary && (
|
{summary && (
|
||||||
<>
|
<>
|
||||||
{" "}
|
{" "}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ const desktopLinks = [
|
||||||
{ href: "/downloads", label: "Downloads" },
|
{ href: "/downloads", label: "Downloads" },
|
||||||
{ href: "/streams", label: "Streams" },
|
{ href: "/streams", label: "Streams" },
|
||||||
{ href: "/live-lists", label: "Live-lijsten" },
|
{ href: "/live-lists", label: "Live-lijsten" },
|
||||||
{ href: "/drm", label: "DRM" },
|
{ href: "/drm", label: "Licenties" },
|
||||||
{ href: "/scripts", label: "Scripts" },
|
{ href: "/scripts", label: "Scripts" },
|
||||||
{ href: "/viewers", label: "Gebruikers" },
|
{ href: "/viewers", label: "Gebruikers" },
|
||||||
{ href: "/settings", label: "Instellingen" },
|
{ href: "/settings", label: "Instellingen" },
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ In Xcode:
|
||||||
|
|
||||||
- Systeem-PiP via VLCKit (`VLCPictureInPictureDrawable`)
|
- Systeem-PiP via VLCKit (`VLCPictureInPictureDrawable`)
|
||||||
- PiP-knop in de speler + automatisch bij app naar achtergrond tijdens afspelen
|
- PiP-knop in de speler + automatisch bij app naar achtergrond tijdens afspelen
|
||||||
- ClearKey/DASH blijft via lokale `ClearKeyDashProxy` → plain DASH in VLC
|
- Encrypted DASH via lokale stream-proxy → VLC
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Viaplay Widevine helper (theplatform ModularDrm). Requires: pip install pywidevine requests"""
|
"""Viaplay license helper for ModularDrm. Requires: pip install pywidevine requests"""
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -334,7 +334,7 @@ export async function probeViaplayAccounts(sessionSecret: string, accountId?: st
|
||||||
if (!creds.session || !creds.accessToken) {
|
if (!creds.session || !creds.accessToken) {
|
||||||
account.healthStatus = "dead";
|
account.healthStatus = "dead";
|
||||||
account.healthCheckedAt = now;
|
account.healthCheckedAt = now;
|
||||||
account.healthError = "Geen session/accessToken — plak cookies uit de browser";
|
account.healthError = "Geen sessie/access-token — voeg tokens toe uit een ingelogde browsersessie";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!account.deviceId) account.deviceId = creds.deviceId;
|
if (!account.deviceId) account.deviceId = creds.deviceId;
|
||||||
|
|
@ -390,7 +390,7 @@ export async function loadViaplaySettings(sessionSecret: string): Promise<Loaded
|
||||||
if (!accounts.length) {
|
if (!accounts.length) {
|
||||||
throw new AppError(
|
throw new AppError(
|
||||||
"INVALID_REQUEST",
|
"INVALID_REQUEST",
|
||||||
"Geen actief Viaplay-account met session/accessToken — voeg cookies toe onder Scripts → Viaplay",
|
"Geen actief Viaplay-account met sessie-tokens — voeg tokens toe onder Scripts → Viaplay",
|
||||||
400
|
400
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,33 +96,33 @@ export const VIAPLAY_TWEAK_META: Array<{
|
||||||
{
|
{
|
||||||
key: "preLiveEnabled",
|
key: "preLiveEnabled",
|
||||||
label: "Pre-live worker",
|
label: "Pre-live worker",
|
||||||
hint: "Automatisch MPD/keys ±5 min vóór start.",
|
hint: "Automatisch manifest/licentie ±5 min vóór start.",
|
||||||
kind: "boolean",
|
kind: "boolean",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "fetchKeysIfMissing",
|
key: "fetchKeysIfMissing",
|
||||||
label: "Keys bij miss",
|
label: "Licenties bij miss",
|
||||||
hint: "Widevine-keys ophalen als PSSH aanwezig is.",
|
hint: "Licenties ophalen als het manifest dat vereist.",
|
||||||
kind: "boolean",
|
kind: "boolean",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "mpdCacheTtlMinutes",
|
key: "mpdCacheTtlMinutes",
|
||||||
label: "MPD-cache TTL",
|
label: "Manifest-cache TTL",
|
||||||
hint: "Hergebruik cached MPD tot TTL verloopt.",
|
hint: "Hergebruik gecached manifest tot TTL verloopt.",
|
||||||
kind: "number",
|
kind: "number",
|
||||||
unit: "min",
|
unit: "min",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "cdmTimeoutMs",
|
key: "cdmTimeoutMs",
|
||||||
label: "CDM-timeout",
|
label: "Licentie-timeout",
|
||||||
hint: "Widevine license-extractie.",
|
hint: "Timeout voor licentie-aanvraag.",
|
||||||
kind: "number",
|
kind: "number",
|
||||||
unit: "ms",
|
unit: "ms",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "useOdidoWvd",
|
key: "useOdidoWvd",
|
||||||
label: "Odido-WVD hergebruiken",
|
label: "Gedeeld device-bestand",
|
||||||
hint: "Zelfde WVD-bestand als Odido Scripts.",
|
hint: "Zelfde Widevine-devicebestand als Odido Scripts.",
|
||||||
kind: "boolean",
|
kind: "boolean",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ Een **first-party event-provider** (niet alleen feed-merge):
|
||||||
|
|
||||||
- Volledige F1TV VOD-catalogus (documentaires, shows, F2/F3 alles)
|
- Volledige F1TV VOD-catalogus (documentaires, shows, F2/F3 alles)
|
||||||
- Onboard camera picker UI (MVP: default feed / F1 LIVE channel)
|
- Onboard camera picker UI (MVP: default feed / F1 LIVE channel)
|
||||||
- Imperva-bypass reverse-engineeren in productie zonder browser-sessie
|
- Server-login zonder browser-sessie (provider bot-protectie)
|
||||||
- Live timing / telemetry overlay
|
- Live timing / telemetry overlay
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue