Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mse-spy

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mse-spy - npm Package Compare versions

Comparing version 0.3.1 to 0.4.0

src/utils/generate_id.js

544

dist/bundle.js

@@ -11,16 +11,3 @@ (function (global, factory) {

*/
var MSE_CALLS = {
MediaSource: {
new: [],
methods: {},
properties: {},
eventListeners: {} // TODO
},
SourceBuffer: {
new: [],
methods: {},
properties: {},
eventListeners: {} // TODO
}
};
var MSE_CALLS = {};

@@ -32,11 +19,5 @@ function getMSECalls() {

function resetMSECalls() {
MSE_CALLS.MediaSource.new = [];
MSE_CALLS.MediaSource.methods = [];
MSE_CALLS.MediaSource.properties = [];
MSE_CALLS.MediaSource.events = [];
MSE_CALLS.SourceBuffer.new = [];
MSE_CALLS.SourceBuffer.methods = [];
MSE_CALLS.SourceBuffer.properties = [];
MSE_CALLS.SourceBuffer.events = [];
Object.key(MSE_CALLS).forEach(function (key) {
delete MSE_CALLS[key];
});
}

@@ -140,10 +121,98 @@ var NativeMediaSource = window.MediaSource;

console.info(">>> " + pathName + " succeeded:", value);
},
/**
* Triggered when a function returned a Promise and that promise resolved.
* @param {string} pathName - human-readable path for the concerned function.
* @param {*} value - The value when the function resolved.
*/
onFunctionPromiseResolve: function onFunctionPromiseResolve(pathName, value) {
console.info(">>> " + pathName + " resolved:", value);
},
/**
* Triggered when a function returned a Promise and that promise rejected.
* @param {string} pathName - human-readable path for the concerned function.
* @param {*} value - The error when the function's promise rejected.
*/
onFunctionPromiseReject: function onFunctionPromiseReject(pathName, value) {
console.error(">>> " + pathName + " rejected:", value);
}
};
function stubRegularMethods(obj, methods, path, logObj) {
var id = 0;
/**
* Generate a new number each time it is called.
* /!\ Never check for an upper-bound. Please do not use if you can reach
* `Number.MAX_VALUE`
* @returns {number}
*/
function generateId() {
return id++;
}
/**
* Log multiple method calls for an object.
* Also populates an object with multiple data at the time of the call.
*
* @param {Object} baseObject - Object in which the method/function is.
* For example to spy on the Date method `toLocaleDateString`, you will have to
* set here `Date.prototype`.
* @param {Array.<string>} methodNames - Every methods you want to spy on
* @param {string} humanReadablePath - Path to the method. Used for logging
* purposes.
* For example `"Date.prototype"`, for spies of Date's methods.
* @param {Object} logObject - Object where infos about the method calls will be
* added.
* The methods' name will be the key of the object.
*
* The values will be an array of object with the following properties:
*
* - self {Object}: Reference to the baseObject argument.
*
* - id {number}: a uniquely generated ascending ID for any stubbed
* property/methods with this library.
*
* - date {number}: Timestamp at the time of the call.
*
* - args {Array}: Array of arguments given to the function
*
* - response {*}: Response of the function.
* The property is not defined if the function did not respond yet or was on
* error.
*
* - responseDate {number}: Timestamp at the time of the response.
* The property is not defined if the function did not respond yet or was on
* error.
*
* - error {*}: Error thrown by the function, if one.
* The property is not defined if the function did not throw.
*
* - errorDate {number} Timestamp at the time of the error.
* The property is not defined if the function did not throw.
*
* - responseResolved {*}: When the returned value (the response) is a promise
* and that promise resolved, this property contains the value emitted by
* the resolve. Else, that property is not set.
*
* - responseResolvedDate {number}: When the returned value (the response) is
* a promise and that promise resolved, this property contains the date at
* which the promise resolved. Else, that property is not set.
*
* - responseRejected {*}: When the returned value (the response) is a promise
* and that promise rejected, this property contains the error emitted by
* the reject. Else, that property is not set.
*
* - responseRejectedDate {number}: When the returned value (the response) is
* a promise and that promise rejected, this property contains the date at
* which the promise rejected. Else, that property is not set.
*/
function spyOnMethods(baseObject, methodNames, humanReadablePath, logObject) {
var _loop = function _loop(i) {
var methodName = methods[i];
var completePath = path + "." + methodName;
var oldMethod = obj[methodName];
var methodName = methodNames[i];
var completePath = humanReadablePath + "." + methodName;
var oldMethod = baseObject[methodName];

@@ -154,3 +223,3 @@ if (!oldMethod) {

obj[methodName] = function () {
baseObject[methodName] = function () {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {

@@ -161,4 +230,5 @@ args[_key] = arguments[_key];

Logger.onFunctionCall(completePath, args);
var myObj = {
self: obj,
var currentLogObject = {
self: baseObject,
id: generateId(),
date: Date.now(),

@@ -168,6 +238,6 @@ args: args

if (!logObj[methodName]) {
logObj[methodName] = [];
if (!logObject[methodName]) {
logObject[methodName] = [];
}
logObj[methodName].push(myObj);
logObject[methodName].push(currentLogObject);

@@ -179,9 +249,26 @@ var res = void 0;

Logger.onFunctionCallError(completePath, e);
myObj.error = e;
myObj.errorDate = Date.now();
currentLogObject.error = e;
currentLogObject.errorDate = Date.now();
throw e;
}
Logger.onFunctionCallSuccess(completePath, res);
myObj.response = res;
myObj.responseDate = Date.now();
currentLogObject.response = res;
currentLogObject.responseDate = Date.now();
if (res instanceof Promise) {
res.then(
// on success
function (value) {
Logger.onFunctionPromiseResolve(completePath, value);
currentLogObject.responseResolved = value;
currentLogObject.responseResolvedDate = Date.now();
},
// on error
function (err) {
Logger.onFunctionPromiseReject(completePath, err);
currentLogObject.responseRejected = err;
currentLogObject.responseRejectedDate = Date.now();
});
}
return res;

@@ -191,3 +278,3 @@ };

for (var i = 0; i < methods.length; i++) {
for (var i = 0; i < methodNames.length; i++) {
_loop(i);

@@ -197,27 +284,62 @@ }

function stubReadOnlyProperties(obj, oldDescriptors, properties, path, logObj) {
/**
* Spy access and updates of an Object's read-only properties:
* - log every access/updates
* - add entries in a logging object
*
* @param {Object} baseObject - Object in which the property is.
* For example to spy on the HTMLMediaElement property `currentTime`, you will
* have to set here `HTMLMediaElement.prototype`.
* @param {Object} baseDescriptors - Descriptors for the spied properties.
* The keys are the properties' names, the values are the properties'
* descriptors.
* @param {Array.<string>} propertyNames - Every properties you want to spy on.
* @param {string} humanReadablePath - Path to the property. Used for logging
* purposes.
* For example `"HTMLMediaElement.prototype"`, for spies of HTMLMediaElement's
* class properties.
* @param {Object} logObject - Object where infos about the properties access
* will be added.
* The methods' name will be the key of the object.
*
* The values will be an object with a single key ``get``, corresponding to
* property accesses
*
* This key will then have as value an array of object.
*
* - self {Object}: Reference to the baseObject argument.
*
* - id {number}: a uniquely generated ID for any stubbed property/methods with
* this library.
*
* - date {number}: Timestamp at the time of the property access.
*
* - value {*}: value of the property at the time of access.
*/
function spyOnReadOnlyProperties(baseObject, baseDescriptors, propertyNames, humanReadablePath, logObject) {
var _loop = function _loop(i) {
var propertyName = properties[i];
var oldDescriptor = oldDescriptors[propertyName];
var completePath = path + "." + propertyName;
var propertyName = propertyNames[i];
var baseDescriptor = baseDescriptors[propertyName];
var completePath = humanReadablePath + "." + propertyName;
if (!oldDescriptor) {
if (!baseDescriptor) {
throw new Error("No descriptor for property " + completePath);
}
Object.defineProperty(obj, propertyName, {
Object.defineProperty(baseObject, propertyName, {
get: function get() {
var value = oldDescriptor.get.bind(this)();
var value = baseDescriptor.get.bind(this)();
Logger.onPropertyAccess(completePath, value);
var myObj = {
var currentLogObject = {
self: this,
id: generateId(),
date: Date.now(),
value: value
};
if (!logObj[propertyName]) {
logObj[propertyName] = {
if (!logObject[propertyName]) {
logObject[propertyName] = {
get: []
};
}
logObj[propertyName].get.push(myObj);
logObject[propertyName].get.push(currentLogObject);
return value;

@@ -228,3 +350,3 @@ }

for (var i = 0; i < properties.length; i++) {
for (var i = 0; i < propertyNames.length; i++) {
_loop(i);

@@ -234,18 +356,68 @@ }

function stubProperties(obj, oldDescriptors, properties, path, logObj) {
/**
* Spy access and updates of an Object's read & write properties:
* - log every access/updates
* - add entries in a logging object
*
* @param {Object} baseObject - Object in which the property is.
* For example to spy on the HTMLMediaElement property `currentTime`, you will
* have to set here `HTMLMediaElement.prototype`.
* @param {Object} baseDescriptors - Descriptors for the spied properties.
* The keys are the properties' names, the values are the properties'
* descriptors.
* @param {Array.<string>} propertyNames - Every properties you want to spy on.
* @param {string} humanReadablePath - Path to the property. Used for logging
* purposes.
* For example `"HTMLMediaElement.prototype"`, for spies of HTMLMediaElement's
* class properties.
* @param {Object} logObject - Object where infos about the properties access
* will be added.
* The methods' name will be the key of the object.
*
* The values will be an object with two keys ``get`` and ``set``, respectively
* for property accesses and property updates.
*
* Each one of those properties will then have as values an array of object.
* Those objects are under the following form:
*
* 1. for `get` (property access):
*
* - self {Object}: Reference to the baseObject argument.
*
* - id {number}: a uniquely generated ascending ID for any stubbed
* property/methods with this library.
*
* - date {number}: Timestamp at the time of the property access.
*
* - value {*}: value of the property at the time of access.
*
*
* 2. for `set` (property updates):
*
* - self {Object}: Reference to the baseObject argument.
*
* - id {number}: a uniquely generated ascending ID for any stubbed
* property/methods with this library.
*
* - date {number}: Timestamp at the time of the property update.
*
* - value {*}: new value the property is set to
*/
function spyOnProperties(baseObject, baseDescriptors, propertyNames, humanReadablePath, logObject) {
var _loop = function _loop(i) {
var propertyName = properties[i];
var oldDescriptor = oldDescriptors[propertyName];
var completePath = path + "." + propertyName;
var propertyName = propertyNames[i];
var baseDescriptor = baseDescriptors[propertyName];
var completePath = humanReadablePath + "." + propertyName;
if (!oldDescriptor) {
if (!baseDescriptor) {
throw new Error("No descriptor for property " + completePath);
}
Object.defineProperty(obj, propertyName, {
Object.defineProperty(baseObject, propertyName, {
get: function get() {
var value = oldDescriptor.get.bind(this)();
var value = baseDescriptor.get.bind(this)();
Logger.onPropertyAccess(completePath, value);
var myObj = {
var currentLogObject = {
self: this,
id: generateId(),
date: Date.now(),

@@ -255,4 +427,4 @@ value: value

if (!logObj[propertyName]) {
logObj[propertyName] = {
if (!logObject[propertyName]) {
logObject[propertyName] = {
set: [],

@@ -262,3 +434,3 @@ get: []

}
logObj[propertyName].get.push(myObj);
logObject[propertyName].get.push(currentLogObject);

@@ -269,4 +441,5 @@ return value;

Logger.onSettingProperty(completePath, value);
var myObj = {
var currentLogObject = {
self: this,
id: generateId(),
date: Date.now(),

@@ -276,4 +449,4 @@ value: value

if (!logObj[propertyName]) {
logObj[propertyName] = {
if (!logObject[propertyName]) {
logObject[propertyName] = {
set: [],

@@ -283,4 +456,4 @@ get: []

}
logObj[propertyName].set.push(myObj);
oldDescriptor.set.bind(this)(value);
logObject[propertyName].set.push(currentLogObject);
baseDescriptor.set.bind(this)(value);
}

@@ -290,3 +463,3 @@ });

for (var i = 0; i < properties.length; i++) {
for (var i = 0; i < propertyNames.length; i++) {
_loop(i);

@@ -296,138 +469,133 @@ }

var MEDIASOURCE_SPY_OBJECT = {
readOnlyProperties: ["sourceBuffers", "activeSourceBuffers", "readyState"],
properties: ["duration", "onsourceopen", "onsourceended", "onsourceclose"],
staticMethods: ["isTypeSupported"],
methods: ["addEventListener", "removeEventListener", "dispatchEvent", "addSourceBuffer", "removeSourceBuffer", "endOfStream", "setLiveSeekableRange", "clearLiveSeekableRange"]
};
var stubbedObjects = [];
function spyOnWholeObject(BaseObject, objectName, readOnlyPropertyNames, propertyNames, staticMethodNames, methodNames, loggingObject) {
if (BaseObject == null || !BaseObject.prototype) {
throw new Error("Invalid object");
}
if (stubbedObjects.includes(BaseObject)) {
return;
}
var NativeMediaSourceProtoDescriptors = Object.getOwnPropertyDescriptors(NativeMediaSource.prototype);
var BaseObjectProtoDescriptors = Object.getOwnPropertyDescriptors(BaseObject.prototype);
var BaseObjectStaticMethods = staticMethodNames.reduce(function (acc, methodName) {
acc[methodName] = BaseObject[methodName];
return acc;
}, {});
var BaseObjectMethods = methodNames.reduce(function (acc, methodName) {
acc[methodName] = BaseObject.prototype[methodName];
return acc;
}, {});
var NativeMediaSourceStaticMethods = MEDIASOURCE_SPY_OBJECT.staticMethods.reduce(function (acc, methodName) {
acc[methodName] = NativeMediaSource[methodName];
return acc;
}, {});
var NativeMediaSourceMethods = MEDIASOURCE_SPY_OBJECT.methods.reduce(function (acc, methodName) {
acc[methodName] = NativeMediaSource.prototype[methodName];
return acc;
}, {});
if (loggingObject[objectName] == null) {
loggingObject[objectName] = {
new: [],
methods: {},
staticMethods: {},
properties: {},
eventListeners: {} // TODO
};
}
function StubbedMediaSource() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
function StubbedObject() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
Logger.onObjectInstanciation(objectName, args);
var now = Date.now();
var spyObj = {
date: now,
args: args
};
loggingObject[objectName].new.push(spyObj);
var baseObject = void 0;
try {
baseObject = new (Function.prototype.bind.apply(BaseObject, [null].concat(args)))();
} catch (e) {
Logger.onObjectInstanciationError(objectName, e);
spyObj.error = e;
spyObj.errorDate = Date.now();
throw e;
}
Logger.onObjectInstanciationSuccess(objectName, baseObject);
spyObj.response = baseObject;
spyObj.responseDate = Date.now();
return baseObject;
}
Logger.onObjectInstanciation("MediaSource", args);
var now = Date.now();
var spyObj = {
date: now,
args: args
spyOnMethods(BaseObject, staticMethodNames, objectName, loggingObject[objectName].staticMethods);
staticMethodNames.forEach(function (method) {
StubbedObject[method] = BaseObject[method].bind(BaseObject);
});
spyOnReadOnlyProperties(BaseObject.prototype, BaseObjectProtoDescriptors, readOnlyPropertyNames, objectName + ".prototype", loggingObject[objectName].properties);
spyOnProperties(BaseObject.prototype, BaseObjectProtoDescriptors, propertyNames, objectName + ".prototype", loggingObject[objectName].properties);
spyOnMethods(BaseObject.prototype, methodNames, objectName + ".prototype", loggingObject[objectName].methods);
window[objectName] = StubbedObject;
stubbedObjects.push(BaseObject);
return function stopSpying() {
Object.defineProperties(BaseObject.prototype, propertyNames.concat(readOnlyPropertyNames).reduce(function (acc, propertyName) {
acc[propertyName] = BaseObjectProtoDescriptors[propertyName];
return acc;
}, {}));
staticMethodNames.forEach(function (methodName) {
BaseObject[methodName] = BaseObjectStaticMethods[methodName];
});
methodNames.forEach(function (methodName) {
BaseObject.prototype[methodName] = BaseObjectMethods[methodName];
});
window[objectName] = BaseObject;
};
MSE_CALLS.MediaSource.new.push(spyObj);
var nativeMediaSource = void 0;
try {
nativeMediaSource = new (Function.prototype.bind.apply(NativeMediaSource, [null].concat(args)))();
} catch (e) {
Logger.onObjectInstanciationError("MediaSource", e);
spyObj.error = e;
spyObj.errorDate = Date.now();
throw e;
}
Logger.onObjectInstanciationSuccess("MediaSource", nativeMediaSource);
spyObj.response = nativeMediaSource;
spyObj.responseDate = Date.now();
return nativeMediaSource;
}
function spyOnMediaSource() {
stubReadOnlyProperties(NativeMediaSource.prototype, NativeMediaSourceProtoDescriptors, MEDIASOURCE_SPY_OBJECT.readOnlyProperties, "MediaSource.prototype", MSE_CALLS.MediaSource.properties);
stubRegularMethods(NativeMediaSource, MEDIASOURCE_SPY_OBJECT.staticMethods, "MediaSource", MSE_CALLS.MediaSource.methods);
MEDIASOURCE_SPY_OBJECT.staticMethods.forEach(function (method) {
StubbedMediaSource[method] = NativeMediaSource[method].bind(NativeMediaSource);
});
stubProperties(NativeMediaSource.prototype, NativeMediaSourceProtoDescriptors, MEDIASOURCE_SPY_OBJECT.properties, "MediaSource.prototype", MSE_CALLS.MediaSource.properties);
stubRegularMethods(NativeMediaSource.prototype, MEDIASOURCE_SPY_OBJECT.methods, "MediaSource.prototype", MSE_CALLS.MediaSource.methods);
window.MediaSource = StubbedMediaSource;
}
return spyOnWholeObject(
// Object to spy on
NativeMediaSource,
function stopSpyingOnMediaSource() {
Object.defineProperties(NativeMediaSource.prototype, MEDIASOURCE_SPY_OBJECT.properties.concat(MEDIASOURCE_SPY_OBJECT.readOnlyProperties).reduce(function (acc, propertyName) {
acc[propertyName] = NativeMediaSourceProtoDescriptors[propertyName];
return acc;
}, {}));
MEDIASOURCE_SPY_OBJECT.staticMethods.forEach(function (methodName) {
NativeMediaSource[methodName] = NativeMediaSourceStaticMethods[methodName];
});
MEDIASOURCE_SPY_OBJECT.methods.forEach(function (methodName) {
NativeMediaSource.prototype[methodName] = NativeMediaSourceMethods[methodName];
});
window.MediaSource = NativeMediaSource;
}
// name in window
"MediaSource",
var SOURCEBUFFER_SPY_OBJECT = {
readOnlyProperties: ["updating", "buffered"],
properties: ["mode", "timestampOffset", "appendWindowStart", "appendWindowEnd", "onupdate", "onupdatestart", "onupdateend", "onerror", "onabort"],
staticMethods: [],
methods: ["addEventListener", "removeEventListener", "dispatchEvent", "appendBuffer", "abort", "remove"]
};
// read-only properties
["sourceBuffers", "activeSourceBuffers", "readyState"],
var NativeSourceBufferProtoDescriptors = Object.getOwnPropertyDescriptors(NativeSourceBuffer.prototype);
// regular properties
["duration", "onsourceopen", "onsourceended", "onsourceclose"],
var NativeSourceBufferStaticMethods = SOURCEBUFFER_SPY_OBJECT.staticMethods.reduce(function (acc, methodName) {
acc[methodName] = NativeSourceBuffer[methodName];
return acc;
}, {});
var NativeSourceBufferMethods = SOURCEBUFFER_SPY_OBJECT.methods.reduce(function (acc, methodName) {
acc[methodName] = NativeSourceBuffer.prototype[methodName];
return acc;
}, {});
// static methods
["isTypeSupported"],
function StubbedSourceBuffer() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
// methods
["addEventListener", "removeEventListener", "dispatchEvent", "addSourceBuffer", "removeSourceBuffer", "endOfStream", "setLiveSeekableRange", "clearLiveSeekableRange"],
Logger.onObjectInstanciation("SourceBuffer", args);
var now = Date.now();
var spyObj = {
date: now,
args: args
};
MSE_CALLS.SourceBuffer.new.push(spyObj);
var nativeSourceBuffer = void 0;
try {
nativeSourceBuffer = new (Function.prototype.bind.apply(NativeSourceBuffer, [null].concat(args)))();
} catch (e) {
Logger.onObjectInstanciationError("SourceBuffer", e);
spyObj.error = e;
spyObj.errorDate = Date.now();
throw e;
}
Logger.onObjectInstanciationSuccess("SourceBuffer", nativeSourceBuffer);
spyObj.response = nativeSourceBuffer;
spyObj.responseDate = Date.now();
return nativeSourceBuffer;
// global logging object
MSE_CALLS);
}
function spyOnSourceBuffer() {
stubReadOnlyProperties(NativeSourceBuffer.prototype, NativeSourceBufferProtoDescriptors, SOURCEBUFFER_SPY_OBJECT.readOnlyProperties, "SourceBuffer.prototype", MSE_CALLS.SourceBuffer.properties);
stubProperties(NativeSourceBuffer.prototype, NativeSourceBufferProtoDescriptors, SOURCEBUFFER_SPY_OBJECT.properties, "SourceBuffer.prototype", MSE_CALLS.SourceBuffer.properties);
stubRegularMethods(NativeSourceBuffer.prototype, SOURCEBUFFER_SPY_OBJECT.methods, "SourceBuffer.prototype", MSE_CALLS.SourceBuffer.methods);
window.SourceBuffer = StubbedSourceBuffer;
}
function spyOnMediaSource$1() {
return spyOnWholeObject(
// Object to spy on
NativeSourceBuffer,
function stopSpyingOnSourceBuffer() {
Object.defineProperties(NativeSourceBuffer.prototype, SOURCEBUFFER_SPY_OBJECT.properties.concat(SOURCEBUFFER_SPY_OBJECT.readOnlyProperties).reduce(function (acc, propertyName) {
acc[propertyName] = NativeSourceBufferProtoDescriptors[propertyName];
return acc;
}, {}));
SOURCEBUFFER_SPY_OBJECT.staticMethods.forEach(function (methodName) {
NativeSourceBuffer[methodName] = NativeSourceBufferStaticMethods[methodName];
});
SOURCEBUFFER_SPY_OBJECT.methods.forEach(function (methodName) {
NativeSourceBuffer.prototype[methodName] = NativeSourceBufferMethods[methodName];
});
window.SourceBuffer = NativeSourceBuffer;
// name in window
"SourceBuffer",
// read-only properties
["updating", "buffered"],
// regular properties
["mode", "timestampOffset", "appendWindowStart", "appendWindowEnd", "onupdate", "onupdatestart", "onupdateend", "onerror", "onabort"],
// static methods
[],
// methods
["addEventListener", "removeEventListener", "dispatchEvent", "appendBuffer", "abort", "remove"],
// global logging object
MSE_CALLS);
}
var resetSpyFunctions = [];
/**

@@ -437,9 +605,11 @@ * Start spying on MSE API calls.

function start() {
spyOnMediaSource();
spyOnSourceBuffer();
resetSpyFunctions.push(spyOnMediaSource());
resetSpyFunctions.push(spyOnMediaSource$1());
}
function stop() {
stopSpyingOnMediaSource();
stopSpyingOnSourceBuffer();
resetSpyFunctions.forEach(function (fn) {
fn();
});
resetSpyFunctions.length = 0;
}

@@ -446,0 +616,0 @@

{
"name": "mse-spy",
"version": "0.3.1",
"version": "0.4.0",
"description": "Report every MSE API a webpage calls",

@@ -5,0 +5,0 @@ "main": "dist/bundle.js",

@@ -157,2 +157,5 @@ # MSESpy.js ####################################################################

{
id: 1, // {number} unique id, generated in ascending order for any
// entry.
// Generated here at the time of MediaSource creation.
date: 1533722155401, // {number} timestamp at which the call was made

@@ -182,2 +185,5 @@ args: [], // {Array} Eventual arguments the constructor has been called

// call (usually the MediaSource)
id: 4, // {number} unique id, generated in ascending order for any
// entry.
// Generated here at the time of the call.
date: 1533722155401, // {number} timestamp at which the call was made

@@ -210,2 +216,5 @@ args: [], // {Array} Eventual arguments this method has been called

// mediaSource
id: 3, // {number} unique id, generated in ascending order for any
// entry.
// Generated here at the time of the access.
date: 1533722155401, // {number} timestamp at which the property

@@ -220,2 +229,5 @@ // was accessed

// mediaSource
id: 2, // {number} unique id, generated in ascending order for any
// entry.
// Generated here at the time of the update.
date: 1533722155401, // {number} timestamp at which the property

@@ -316,4 +328,6 @@ // was set

## Left to do
## Left to do ##################################################################
The next steps would be to:

@@ -324,5 +338,2 @@

- use performance.now and/or an incrementing ID to better pinpoint when the
calls or property access are made relatively to each other
- simplify the MSECalls object exploitation

@@ -5,16 +5,3 @@ /**

*/
const MSE_CALLS = {
MediaSource: {
new: [],
methods: {},
properties: {},
eventListeners: {}, // TODO
},
SourceBuffer: {
new: [],
methods: {},
properties: {},
eventListeners: {}, // TODO
},
};
const MSE_CALLS = {};

@@ -26,11 +13,5 @@ function getMSECalls() {

function resetMSECalls() {
MSE_CALLS.MediaSource.new = [];
MSE_CALLS.MediaSource.methods = [];
MSE_CALLS.MediaSource.properties = [];
MSE_CALLS.MediaSource.events = [];
MSE_CALLS.SourceBuffer.new = [];
MSE_CALLS.SourceBuffer.methods = [];
MSE_CALLS.SourceBuffer.properties = [];
MSE_CALLS.SourceBuffer.events = [];
Object.key(MSE_CALLS).forEach(key => {
delete MSE_CALLS[key];
});
}

@@ -37,0 +18,0 @@ const NativeMediaSource = window.MediaSource;

@@ -6,9 +6,7 @@ import {

import Logger from "./utils/logger.js";
import spyOnMediaSource, {
stopSpyingOnMediaSource,
} from "./spyOnMediaSource.js";
import spyOnSourceBuffer, {
stopSpyingOnSourceBuffer,
} from "./spyOnSourceBuffer.js";
import spyOnMediaSource from "./spyOnMediaSource.js";
import spyOnSourceBuffer from "./spyOnSourceBuffer.js";
const resetSpyFunctions = [];
/**

@@ -18,9 +16,9 @@ * Start spying on MSE API calls.

function start() {
spyOnMediaSource();
spyOnSourceBuffer();
resetSpyFunctions.push(spyOnMediaSource());
resetSpyFunctions.push(spyOnSourceBuffer());
}
function stop() {
stopSpyingOnMediaSource();
stopSpyingOnSourceBuffer();
resetSpyFunctions.forEach(fn => { fn(); });
resetSpyFunctions.length = 0;
}

@@ -27,0 +25,0 @@

@@ -1,5 +0,2 @@

import Logger from "./utils/logger.js";
import stubRegularMethods from "./utils/stubRegularMethods.js";
import stubReadOnlyProperties from "./utils/stubReadOnlyProperties.js";
import stubProperties from "./utils/stubProperties.js";
import spyOnWholeObject from "./utils/spyOnWholeObject.js";
import {

@@ -10,115 +7,34 @@ MSE_CALLS,

const MEDIASOURCE_SPY_OBJECT = {
readOnlyProperties: [
"sourceBuffers",
"activeSourceBuffers",
"readyState",
],
properties: [
"duration",
"onsourceopen",
"onsourceended",
"onsourceclose",
],
staticMethods: [
"isTypeSupported",
],
methods: [
"addEventListener",
"removeEventListener",
"dispatchEvent",
"addSourceBuffer",
"removeSourceBuffer",
"endOfStream",
"setLiveSeekableRange",
"clearLiveSeekableRange",
],
};
export default function spyOnMediaSource() {
return spyOnWholeObject(
// Object to spy on
NativeMediaSource,
const NativeMediaSourceProtoDescriptors =
Object.getOwnPropertyDescriptors(NativeMediaSource.prototype);
// name in window
"MediaSource",
const NativeMediaSourceStaticMethods = MEDIASOURCE_SPY_OBJECT.staticMethods
.reduce((acc, methodName) => {
acc[methodName] = NativeMediaSource[methodName];
return acc;
}, {});
const NativeMediaSourceMethods = MEDIASOURCE_SPY_OBJECT.methods
.reduce((acc, methodName) => {
acc[methodName] = NativeMediaSource.prototype[methodName];
return acc;
}, {});
// read-only properties
["sourceBuffers", "activeSourceBuffers", "readyState"],
function StubbedMediaSource(...args) {
Logger.onObjectInstanciation("MediaSource", args);
const now = Date.now();
const spyObj = {
date: now,
args,
};
MSE_CALLS.MediaSource.new.push(spyObj);
let nativeMediaSource;
try {
nativeMediaSource = new NativeMediaSource(...args);
} catch (e) {
Logger.onObjectInstanciationError("MediaSource", e);
spyObj.error = e;
spyObj.errorDate = Date.now();
throw e;
}
Logger.onObjectInstanciationSuccess("MediaSource", nativeMediaSource);
spyObj.response = nativeMediaSource;
spyObj.responseDate = Date.now();
return nativeMediaSource;
}
// regular properties
["duration", "onsourceopen", "onsourceended", "onsourceclose"],
export default function spyOnMediaSource() {
stubReadOnlyProperties(
NativeMediaSource.prototype,
NativeMediaSourceProtoDescriptors,
MEDIASOURCE_SPY_OBJECT.readOnlyProperties,
"MediaSource.prototype",
MSE_CALLS.MediaSource.properties,
);
stubRegularMethods(
NativeMediaSource,
MEDIASOURCE_SPY_OBJECT.staticMethods,
"MediaSource",
MSE_CALLS.MediaSource.methods,
);
MEDIASOURCE_SPY_OBJECT.staticMethods.forEach((method) => {
StubbedMediaSource[method] = NativeMediaSource[method].bind(NativeMediaSource);
});
stubProperties(
NativeMediaSource.prototype,
NativeMediaSourceProtoDescriptors,
MEDIASOURCE_SPY_OBJECT.properties,
"MediaSource.prototype",
MSE_CALLS.MediaSource.properties,
);
stubRegularMethods(
NativeMediaSource.prototype,
MEDIASOURCE_SPY_OBJECT.methods,
"MediaSource.prototype",
MSE_CALLS.MediaSource.methods,
);
window.MediaSource = StubbedMediaSource;
}
// static methods
["isTypeSupported"],
// methods
[
"addEventListener",
"removeEventListener",
"dispatchEvent",
"addSourceBuffer",
"removeSourceBuffer",
"endOfStream",
"setLiveSeekableRange",
"clearLiveSeekableRange",
],
export function stopSpyingOnMediaSource() {
Object.defineProperties(NativeMediaSource.prototype,
MEDIASOURCE_SPY_OBJECT.properties
.concat(MEDIASOURCE_SPY_OBJECT.readOnlyProperties)
.reduce((acc, propertyName) => {
acc[propertyName] = NativeMediaSourceProtoDescriptors[propertyName];
return acc;
}, {})
// global logging object
MSE_CALLS
);
MEDIASOURCE_SPY_OBJECT.staticMethods.forEach((methodName) => {
NativeMediaSource[methodName] = NativeMediaSourceStaticMethods[methodName];
});
MEDIASOURCE_SPY_OBJECT.methods.forEach((methodName) => {
NativeMediaSource.prototype[methodName] = NativeMediaSourceMethods[methodName];
});
window.MediaSource = NativeMediaSource;
}

@@ -1,5 +0,2 @@

import Logger from "./utils/logger.js";
import stubRegularMethods from "./utils/stubRegularMethods.js";
import stubReadOnlyProperties from "./utils/stubReadOnlyProperties.js";
import stubProperties from "./utils/stubProperties.js";
import spyOnWholeObject from "./utils/spyOnWholeObject.js";
import {

@@ -10,109 +7,42 @@ MSE_CALLS,

const SOURCEBUFFER_SPY_OBJECT = {
readOnlyProperties: [
"updating",
"buffered",
// "audioTracks",
// "videoTracks",
// "textTracks",
],
properties: [
"mode",
"timestampOffset",
"appendWindowStart",
"appendWindowEnd",
"onupdate",
"onupdatestart",
"onupdateend",
"onerror",
"onabort",
],
staticMethods: [],
methods: [
"addEventListener",
"removeEventListener",
"dispatchEvent",
"appendBuffer",
"abort",
"remove",
],
};
export default function spyOnMediaSource() {
return spyOnWholeObject(
// Object to spy on
NativeSourceBuffer,
const NativeSourceBufferProtoDescriptors =
Object.getOwnPropertyDescriptors(NativeSourceBuffer.prototype);
// name in window
"SourceBuffer",
const NativeSourceBufferStaticMethods = SOURCEBUFFER_SPY_OBJECT.staticMethods
.reduce((acc, methodName) => {
acc[methodName] = NativeSourceBuffer[methodName];
return acc;
}, {});
const NativeSourceBufferMethods = SOURCEBUFFER_SPY_OBJECT.methods
.reduce((acc, methodName) => {
acc[methodName] = NativeSourceBuffer.prototype[methodName];
return acc;
}, {});
// read-only properties
["updating", "buffered"],
function StubbedSourceBuffer(...args) {
Logger.onObjectInstanciation("SourceBuffer", args);
const now = Date.now();
const spyObj = {
date: now,
args,
};
MSE_CALLS.SourceBuffer.new.push(spyObj);
let nativeSourceBuffer;
try {
nativeSourceBuffer = new NativeSourceBuffer(...args);
} catch (e) {
Logger.onObjectInstanciationError("SourceBuffer", e);
spyObj.error = e;
spyObj.errorDate = Date.now();
throw e;
}
Logger.onObjectInstanciationSuccess("SourceBuffer", nativeSourceBuffer);
spyObj.response = nativeSourceBuffer;
spyObj.responseDate = Date.now();
return nativeSourceBuffer;
}
// regular properties
[
"mode",
"timestampOffset",
"appendWindowStart",
"appendWindowEnd",
"onupdate",
"onupdatestart",
"onupdateend",
"onerror",
"onabort",
],
export default function spyOnSourceBuffer() {
stubReadOnlyProperties(
NativeSourceBuffer.prototype,
NativeSourceBufferProtoDescriptors,
SOURCEBUFFER_SPY_OBJECT.readOnlyProperties,
"SourceBuffer.prototype",
MSE_CALLS.SourceBuffer.properties,
);
stubProperties(
NativeSourceBuffer.prototype,
NativeSourceBufferProtoDescriptors,
SOURCEBUFFER_SPY_OBJECT.properties,
"SourceBuffer.prototype",
MSE_CALLS.SourceBuffer.properties,
);
stubRegularMethods(
NativeSourceBuffer.prototype,
SOURCEBUFFER_SPY_OBJECT.methods,
"SourceBuffer.prototype",
MSE_CALLS.SourceBuffer.methods,
);
window.SourceBuffer = StubbedSourceBuffer;
}
// static methods
[],
// methods
[
"addEventListener",
"removeEventListener",
"dispatchEvent",
"appendBuffer",
"abort",
"remove",
],
export function stopSpyingOnSourceBuffer() {
Object.defineProperties(NativeSourceBuffer.prototype,
SOURCEBUFFER_SPY_OBJECT.properties
.concat(SOURCEBUFFER_SPY_OBJECT.readOnlyProperties)
.reduce((acc, propertyName) => {
acc[propertyName] = NativeSourceBufferProtoDescriptors[propertyName];
return acc;
}, {})
// global logging object
MSE_CALLS
);
SOURCEBUFFER_SPY_OBJECT.staticMethods.forEach((methodName) => {
NativeSourceBuffer[methodName] = NativeSourceBufferStaticMethods[methodName];
});
SOURCEBUFFER_SPY_OBJECT.methods.forEach((methodName) => {
NativeSourceBuffer.prototype[methodName] = NativeSourceBufferMethods[methodName];
});
window.SourceBuffer = NativeSourceBuffer;
}

@@ -89,2 +89,20 @@ /**

},
/**
* Triggered when a function returned a Promise and that promise resolved.
* @param {string} pathName - human-readable path for the concerned function.
* @param {*} value - The value when the function resolved.
*/
onFunctionPromiseResolve(pathName, value) {
console.info(`>>> ${pathName} resolved:`, value);
},
/**
* Triggered when a function returned a Promise and that promise rejected.
* @param {string} pathName - human-readable path for the concerned function.
* @param {*} value - The error when the function's promise rejected.
*/
onFunctionPromiseReject(pathName, value) {
console.error(`>>> ${pathName} rejected:`, value);
},
/* eslint-enable no-console */

@@ -91,0 +109,0 @@ };

import Logger from "./logger.js";
import generateId from "./generate_id.js";
export default function stubReadOnlyProperties(
obj,
oldDescriptors,
properties,
path,
logObj,
/**
* Spy access and updates of an Object's read-only properties:
* - log every access/updates
* - add entries in a logging object
*
* @param {Object} baseObject - Object in which the property is.
* For example to spy on the HTMLMediaElement property `currentTime`, you will
* have to set here `HTMLMediaElement.prototype`.
* @param {Object} baseDescriptors - Descriptors for the spied properties.
* The keys are the properties' names, the values are the properties'
* descriptors.
* @param {Array.<string>} propertyNames - Every properties you want to spy on.
* @param {string} humanReadablePath - Path to the property. Used for logging
* purposes.
* For example `"HTMLMediaElement.prototype"`, for spies of HTMLMediaElement's
* class properties.
* @param {Object} logObject - Object where infos about the properties access
* will be added.
* The methods' name will be the key of the object.
*
* The values will be an object with a single key ``get``, corresponding to
* property accesses
*
* This key will then have as value an array of object.
*
* - self {Object}: Reference to the baseObject argument.
*
* - id {number}: a uniquely generated ascending ID for any stubbed
* property/methods with this library.
*
* - date {number}: Timestamp at the time of the property access.
*
* - value {*}: value of the property at the time of access.
*/
export default function spyOnReadOnlyProperties(
baseObject,
baseDescriptors,
propertyNames,
humanReadablePath,
logObject,
) {
for (let i = 0; i < properties.length; i++) {
const propertyName = properties[i];
const oldDescriptor = oldDescriptors[propertyName];
const completePath = path + "." + propertyName;
for (let i = 0; i < propertyNames.length; i++) {
const propertyName = propertyNames[i];
const baseDescriptor = baseDescriptors[propertyName];
const completePath = humanReadablePath + "." + propertyName;
if (!oldDescriptor) {
if (!baseDescriptor) {
throw new Error("No descriptor for property " +

@@ -20,17 +55,18 @@ completePath);

Object.defineProperty(obj, propertyName, {
Object.defineProperty(baseObject, propertyName, {
get() {
const value = oldDescriptor.get.bind(this)();
const value = baseDescriptor.get.bind(this)();
Logger.onPropertyAccess(completePath, value);
const myObj = {
const currentLogObject = {
self: this,
id: generateId(),
date: Date.now(),
value: value,
};
if (!logObj[propertyName]) {
logObj[propertyName] = {
if (!logObject[propertyName]) {
logObject[propertyName] = {
get: [],
};
}
logObj[propertyName].get.push(myObj);
logObject[propertyName].get.push(currentLogObject);
return value;

@@ -37,0 +73,0 @@ },

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc