UNPKG

rx-player

Version:
356 lines (355 loc) 14.7 kB
"use strict"; /** * Copyright 2015 CANAL+ Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; Object.defineProperty(exports, "__esModule", { value: true }); var log_1 = require("../../../log"); var are_arrays_of_numbers_equal_1 = require("../../../utils/are_arrays_of_numbers_equal"); var assert_1 = require("../../../utils/assert"); var base64_1 = require("../../../utils/base64"); var hash_buffer_1 = require("../../../utils/hash_buffer"); var is_non_empty_string_1 = require("../../../utils/is_non_empty_string"); var is_null_or_undefined_1 = require("../../../utils/is_null_or_undefined"); var are_init_values_compatible_1 = require("./are_init_values_compatible"); var serializable_bytes_1 = require("./serializable_bytes"); /** * Throw if the given storage does not respect the right interface. * @param {Object} storage */ function checkStorage(storage) { (0, assert_1.assertInterface)(storage, { save: "function", load: "function" }, "persistentLicenseConfig"); } /** * Set representing persisted licenses. Depends on a simple * implementation with a `save`/`load` synchronous interface * to persist information on persisted sessions. * * This set is used only for a cdm/keysystem with license persistency * supported. * @class PersistentSessionsStore */ var PersistentSessionsStore = /** @class */ (function () { /** * Create a new PersistentSessionsStore. * @param {Object} storage */ function PersistentSessionsStore(storage) { checkStorage(storage); this._entries = []; this._storage = storage; try { var entries = this._storage.load(); if (!Array.isArray(entries)) { entries = []; } this._entries = entries; } catch (e) { log_1.default.warn("DRM-PSS: Could not get entries from license storage", e instanceof Error ? e : ""); this.dispose(); } } /** * Returns the number of stored values. * @returns {number} */ PersistentSessionsStore.prototype.getLength = function () { return this._entries.length; }; /** * Returns information about all stored MediaKeySession, in the order in which * the MediaKeySession have been created. * @returns {Array.<Object>} */ PersistentSessionsStore.prototype.getAll = function () { return this._entries; }; /** * Retrieve an entry based on its initialization data. * @param {Object} initData * @returns {Object|null} */ PersistentSessionsStore.prototype.get = function (initData) { var index = this._getIndex(initData); return index === -1 ? null : this._entries[index]; }; /** * Like `get`, but also move the corresponding value at the end of the store * (as returned by `getAll`) if found. * This can be used for example to tell when a previously-stored value is * re-used to then be able to implement a caching replacement algorithm based * on the least-recently-used values by just evicting the first values * returned by `getAll`. * @param {Object} initData * @returns {*} */ PersistentSessionsStore.prototype.getAndReuse = function (initData) { var index = this._getIndex(initData); if (index === -1) { return null; } var item = this._entries.splice(index, 1)[0]; this._entries.push(item); return item; }; /** * Add a new entry in the PersistentSessionsStore. * @param {Object} initData * @param {Array.<Uint8Array>|undefined} keyIds * @param {MediaKeySession} session */ PersistentSessionsStore.prototype.add = function (initData, keyIds, session) { var _a; if ((0, is_null_or_undefined_1.default)(session) || !(0, is_non_empty_string_1.default)(session.sessionId)) { log_1.default.warn("DRM-PSS: Invalid Persisten Session given."); return; } var sessionId = session.sessionId; var currentIndex = this._getIndex(initData); if (currentIndex >= 0) { var currVersion = keyIds === undefined ? 3 : 4; var currentEntry = this._entries[currentIndex]; var entryVersion = (_a = currentEntry.version) !== null && _a !== void 0 ? _a : -1; if (entryVersion >= currVersion && sessionId === currentEntry.sessionId) { return; } log_1.default.info("DRM-PSS: Updating session info.", sessionId); this._entries.splice(currentIndex, 1); } else { log_1.default.info("DRM-PSS: Add new session", sessionId); } var storedValues = prepareValuesForStore(initData.values.getFormattedValues()); if (keyIds === undefined) { this._entries.push({ version: 3, sessionId: sessionId, values: storedValues, initDataType: initData.type, }); } else { this._entries.push({ version: 4, sessionId: sessionId, keyIds: keyIds.map(function (k) { return new serializable_bytes_1.default(k); }), values: storedValues, initDataType: initData.type, }); } this._save(); }; /** * Delete stored MediaKeySession information based on its session id. * @param {string} sessionId */ PersistentSessionsStore.prototype.delete = function (sessionId) { var index = -1; for (var i = 0; i < this._entries.length; i++) { var entry_1 = this._entries[i]; if (entry_1.sessionId === sessionId) { index = i; break; } } if (index === -1) { log_1.default.warn("DRM-PSS: initData to delete not found."); return; } var entry = this._entries[index]; log_1.default.warn("DRM-PSS: Delete session from store", entry.sessionId); this._entries.splice(index, 1); this._save(); }; PersistentSessionsStore.prototype.deleteOldSessions = function (sessionsToDelete) { log_1.default.info("DRM-PSS: Deleting last ".concat(sessionsToDelete, " sessions.")); if (sessionsToDelete <= 0) { return; } if (sessionsToDelete <= this._entries.length) { this._entries.splice(0, sessionsToDelete); } else { log_1.default.warn("DRM-PSS: Asked to remove more information that it contains", sessionsToDelete, this._entries.length); this._entries = []; } this._save(); }; /** * Delete all saved entries. */ PersistentSessionsStore.prototype.dispose = function () { this._entries = []; this._save(); }; /** * Retrieve index of an entry. * Returns `-1` if not found. * @param {Object} initData * @returns {number} */ PersistentSessionsStore.prototype._getIndex = function (initData) { // Older versions of the format include a concatenation of all // initialization data and its hash. // This is only computed lazily, the first time it is needed. var lazyConcatenatedData = null; function getConcatenatedInitDataInfo() { if (lazyConcatenatedData === null) { var concatInitData = initData.values.constructRequestData(); lazyConcatenatedData = { initData: concatInitData, initDataHash: (0, hash_buffer_1.default)(concatInitData), }; } return lazyConcatenatedData; } var _loop_1 = function (i) { var entry = this_1._entries[i]; if (entry.initDataType === initData.type) { switch (entry.version) { case 4: if (initData.keyIds !== undefined) { var foundCompatible = initData.keyIds.every(function (keyId) { var e_1, _a; var keyIdB64 = (0, base64_1.bytesToBase64)(keyId); try { for (var _b = (e_1 = void 0, __values(entry.keyIds)), _c = _b.next(); !_c.done; _c = _b.next()) { var entryKid = _c.value; if (typeof entryKid === "string") { if (keyIdB64 === entryKid) { return true; } } else if ((0, are_arrays_of_numbers_equal_1.default)(entryKid.initData, keyId)) { return true; } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } return false; }); if (foundCompatible) { return { value: i }; } } else { var formatted = initData.values.getFormattedValues(); if ((0, are_init_values_compatible_1.default)(formatted, entry.values)) { return { value: i }; } } break; case 3: { var formatted = initData.values.getFormattedValues(); if ((0, are_init_values_compatible_1.default)(formatted, entry.values)) { return { value: i }; } break; } case 2: { var _a = getConcatenatedInitDataInfo(), concatInitData = _a.initData, concatHash = _a.initDataHash; if (entry.initDataHash === concatHash) { try { var decodedInitData = typeof entry.initData === "string" ? serializable_bytes_1.default.decode(entry.initData) : entry.initData.initData; if ((0, are_arrays_of_numbers_equal_1.default)(decodedInitData, concatInitData)) { return { value: i }; } } catch (e) { log_1.default.warn("DRM-PSS: Could not decode initialization data.", e instanceof Error ? e : ""); } } break; } case 1: { var _b = getConcatenatedInitDataInfo(), concatInitData = _b.initData, concatHash = _b.initDataHash; if (entry.initDataHash === concatHash) { if (typeof entry.initData.length === "undefined") { return { value: i }; } else if ((0, are_arrays_of_numbers_equal_1.default)(entry.initData, concatInitData)) { return { value: i }; } } break; } default: { var concatHash = getConcatenatedInitDataInfo().initDataHash; if (entry.initData === concatHash) { return { value: i }; } } } } }; var this_1 = this; for (var i = 0; i < this._entries.length; i++) { var state_1 = _loop_1(i); if (typeof state_1 === "object") return state_1.value; } return -1; }; /** * Use the given storage to store the current entries. */ PersistentSessionsStore.prototype._save = function () { try { this._storage.save(this._entries); } catch (e) { var err = e instanceof Error ? e : undefined; log_1.default.warn("DRM-PSS: Could not save MediaKeySession information", err); } }; return PersistentSessionsStore; }()); exports.default = PersistentSessionsStore; /** * Format given initializationData's values so they are ready to be stored: * - sort them by systemId, so they are faster to compare * - add hash for each initialization data encountered. * @param {Array.<Object>} initialValues * @returns {Array.<Object>} */ function prepareValuesForStore(initialValues) { return initialValues.map(function (_a) { var systemId = _a.systemId, data = _a.data, hash = _a.hash; return ({ systemId: systemId, hash: hash, data: new serializable_bytes_1.default(data), }); }); }