No soy experto en DRM, es por eso que me parece interesante el problema con el que me topé mientras intentaba ver un video protegido con el cual contaba permiso, pero no tenía idea de como obtener la licencia del servidor para que el reproductor desencriptara el video y poderlo reproducir en el navegador.
Para mis pruebas, utilicé Video.js
con el plugin videojs-contrib-eme
para poder interactuar con servidores DRM.
En un mundo ideal, el código necesario sería el siguiente:
const keySystems = {
"com.apple.fps.1_0": {
certificateUri: "<CERTIFICATE_URL>",
licenseUri: "<LICENSE_URL>",
},
};
Pero en este caso, el servidor necesita que el Server Playback Context (SPC) sea enviado como un parámetro y codificado en base64. Por lo cual es necesario utilizar la opción getLicense
que permite una función para personalizar la forma en que se conecta con el servidor y los parámetros que son enviados. En este ejemplo también se añade el encabezado Authorization
.
En el siguiente código, dejo algunos comentarios de las partes clave de esta transacción del reproductor con el servidor:
player.eme();
const keySystems = {
"com.widevine.alpha": {
url: "https://<DRM_SERVER>/WideVine/",
licenseHeaders: {
Authorization: `Bearer ${token}`,
},
},
"com.microsoft.playready": {
url: "https://<DRM_SERVER>/PlayReady/",
licenseHeaders: {
Authorization: `Bearer ${token}`,
},
},
"com.apple.fps.1_0": {
certificateUri: "https://<CERTIFICATE_SERVER>/fairplay.der",
getLicense: (emeOptions, contentId, keyMessage, callback) => {
// Convert payload to base64
const spc = encodeURI(btoa(String.fromCharCode(...keyMessage)));
fetch("skd://<DRM_SERVER>".replace("skd://", "https://"), {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/x-www-form-urlencoded",
},
body: `spc=${spc}`,
})
.then((res) => res.text())
.then((body) => {
// Remove the <ckc> and </ckc> tags
const b64key = body.trim().slice(5, -6);
// Decode the base64 encoded data
const key = new Uint8Array(
atob(b64key)
.split("")
.map((c) => c.charCodeAt(0))
);
// Send the key to the player
callback(null, key);
})
.catch((err) => callback(err));
},
},
};
player.src([
{ src: "https://<SERVER>/dash.url", type: "application/dash+xml", keySystems },
{ src: "https://<SERVER>/hls.m3u8", type: "application/x-mpegUrl", keySystems },
]);
Fuentes:
Relacionados: