Unverified Commit a2939a55 authored by Florian Klink's avatar Florian Klink Committed by GitHub
Browse files

widevine-cdm: refactor x86_64-linux to use official sources, add update script (#438810)

parents 011f7759 ecec1b74
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
}:

let
  # TODO: update aarch64 to use crx3
  targets = lib.genAttrs [
    "aarch64-linux"
    "x86_64-linux"
+107 −0
Original line number Diff line number Diff line
#! /usr/bin/env nix-shell
#! nix-shell -i python3 -p python3

from __future__ import annotations
import sys, os, json, base64, re, argparse, urllib.request, time
from typing import Dict, Optional, Tuple
from pathlib import Path

DEFAULT_JSON = "https://raw.githubusercontent.com/mozilla/gecko-dev/master/toolkit/content/gmp-sources/widevinecdm.json"
ARCH_PATTERNS = {
    "linux_x86_64": ["Linux_x86_64-gcc3"],
    "linux_aarch64": ["Linux_aarch64-gcc3"]
}

def fetch_json(url: str) -> dict:
    with urllib.request.urlopen(url) as r:
        return json.load(r)

def hex_to_sri(hexstr: str) -> str:
    b = bytes.fromhex(hexstr)
    return "sha512-" + base64.b64encode(b).decode()

def find_widevine_vendor(data: dict) -> dict:
    vendors = data.get("vendors") or {}
    for key, value in vendors.items():
        if "gmp-widevinecdm" in key.lower():
            return value

    raise SystemExit("ERR: couldn't find a widevine vendor entry in JSON !")

def judge_platforms(platforms: dict, patterns) -> Optional[Tuple[str, dict]]:
    for plkey, plvalue in platforms.items():
        if plvalue.get("alias"):
            continue

        low = plkey.lower()
        for pat in patterns:
            if pat.lower() in low:
                return plkey, plvalue

    return None

def normalize_fileurl(entry: dict) -> Optional[str]:
    if entry.get("fileUrl"):
        return entry["fileUrl"]

    m = entry.get("mirrorUrls")
    if isinstance(m, list) and m:
        return m[0]

    return None

def extract_ver_from_url(url: str) -> Optional[str]:
    m = re.search(r'[_-](\d+\.\d+\.\d+\.\d+)[_-]', url)
    if m:
        return m.group(1)
    m = re.search(r'(\d+\.\d+\.\d+\.\d+)', url)
    return m.group(1) if m else None

def build_entry(pkey: str, pentry: dict) -> dict:
    url = normalize_fileurl(pentry)
    hv = pentry.get("hashValue")

    if not url or not hv:
        raise SystemExit(f"ERR: platform {pkey} is missing a file URL or hash !")

    sri = hex_to_sri(hv)
    version = extract_ver_from_url(url)
    return {"platform_key": pkey, "url": url, "sri": sri, "version": version}

def main():
    WIDEVINE_DIR = Path(__file__).resolve().parent
    DEFAULT_FILE = WIDEVINE_DIR / "x86_64-manifest.json"

    ap = argparse.ArgumentParser()
    ap.add_argument("file", type=Path, nargs="?", default=DEFAULT_FILE)
    ap.add_argument("--json-url", default=DEFAULT_JSON)
    args = ap.parse_args()

    print(f"# fetching {args.json_url} !", file=sys.stderr)
    data = fetch_json(args.json_url)
    vendor = find_widevine_vendor(data)
    platforms = vendor.get("platforms") or {} # should never be null but moz could forseeably delete it
    if not platforms:
        raise SystemExit("ERR: no widevine platforms !")

    results = {}
    for arch, patterns in ARCH_PATTERNS.items():
        found = judge_platforms(platforms, patterns)
        if not found:
            print(f"# WARN: no platform for {arch}. skipping !", file=sys.stderr)
            continue
        pkey, pentry = found
        print(f"# found {arch} --> {pkey}", file=sys.stderr)
        entry = build_entry(pkey, pentry)
        results[arch] = entry

    if not results:
        raise SystemExit("ERR: no linux platform entries !")

    linux_x64 = results["linux_x86_64"]

    args.file.write_text(json.dumps(linux_x64, indent=2) + "\n", encoding="utf-8")
    print("# updated", file=sys.stderr)

if __name__ == "__main__":
    main()
+24 −9
Original line number Diff line number Diff line
{
  lib,
  stdenv,
  fetchzip,
  fetchurl,
  go-crx3,
}:

let
  manifest = builtins.fromJSON (builtins.readFile ./x86_64-manifest.json);
in

stdenv.mkDerivation (finalAttrs: {
  pname = "widevine-cdm";
  version = "4.10.2891.0";
  version = manifest.version;

  src = fetchzip {
    # The download 404s
    url = "https://web.archive.org/web/20250725071306/https://dl.google.com/widevine-cdm/4.10.2891.0-linux-x64.zip";
    hash = "sha256-ZO6FmqJUnB9VEJ7caJt58ym8eB3/fDATri3iOWCULRI=";
    stripRoot = false;
  src = fetchurl {
    url = manifest.url;
    hash = manifest.sri;
  };

  nativeBuildInputs = [ go-crx3 ];

  unpackPhase = ''
    unpackDir="src"
    cp "$src" "$unpackDir".crx # go-crx3 doesn't like .crx3 extensions
    crx3 unpack "$unpackDir".crx

    cd "$unpackDir"
  '';

  installPhase = ''
    runHook preInstall

    install -vD manifest.json $out/share/google/chrome/WidevineCdm/manifest.json
    install -vD LICENSE.txt $out/share/google/chrome/WidevineCdm/LICENSE.txt
    install -vD libwidevinecdm.so $out/share/google/chrome/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so
    install -vD LICENSE $out/share/google/chrome/WidevineCdm/LICENSE.txt
    install -vD _platform_specific/linux_x64/libwidevinecdm.so $out/share/google/chrome/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so

    runHook postInstall
  '';

  passthru.updateScript = ./update-x86_64.py;

  meta = import ./meta.nix lib;
})
+6 −0
Original line number Diff line number Diff line
{
  "platform_key": "Linux_x86_64-gcc3",
  "url": "https://edgedl.me.gvt1.com/edgedl/release2/chrome_component/aclxnidwwkj5di3vduduj2gqpgpq_4.10.2891.0/oimompecagnajdejgnnjijobebaeigek_4.10.2891.0_linux_b4hin3q5s66ws2322cyyfp35lu.crx3",
  "sri": "sha512-8S/4FRQQmQAO9wJ7QGJg8KUVxUQgm5/oEl6l9N2/WGAdMCIqxBoBPrCkPadrpwQUpK0WYX2fIZ8Zzfx3lNm8lA==",
  "version": "4.10.2891.0"
}