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.2.0 to 0.3.0

282

dist/bundle.js

@@ -15,4 +15,3 @@ (function (global, factory) {

methods: {},
properties: {},
events: {} // TODO
properties: {}
},

@@ -22,4 +21,3 @@ SourceBuffer: {

methods: {},
properties: {},
events: {} // TODO
properties: {}
}

@@ -47,3 +45,3 @@ };

/**
* Define the logger for startMSESpy.
* Define the logger for the MSE-spy.
* Allows to re-define a specific logger on runtime / before applying this

@@ -53,45 +51,93 @@ * script.

*/
var Logger = window.Logger || {
var Logger = window.MSESpyLogger || {
/* eslint-disable no-console */
log: function log() {
var _console;
(_console = console).log.apply(_console, arguments);
/**
* Triggered each time a property is accessed.
* @param {string} pathString - human-readable path to the property.
* @param {*} value - the value it currently has.
*/
onPropertyAccess: function onPropertyAccess(pathString, value) {
console.debug(">>> Getting ${pathString}:", value);
},
debug: function debug() {
var _console2;
(_console2 = console).debug.apply(_console2, arguments);
/**
* Triggered each time a property is set.
* @param {string} pathString - human-readable path to the property.
* @param {*} value - the value it is set to.
*/
onSettingProperty: function onSettingProperty(pathString, value) {
console.debug(">> Setting " + pathString + ":", value);
},
info: function info() {
var _console3;
(_console3 = console).info.apply(_console3, arguments);
/**
* Triggered when some object is instanciated (just before).
* @param {string} objectName - human-readable name for the concerned object.
* @param {Array.<*>} args - Arguments given to the constructor
*/
onObjectInstanciation: function onObjectInstanciation(objectName, args) {
if (args.length) {
console.debug(">>> Creating ${objectName} with arguments:", args);
} else {
console.debug(">>> Creating ${objectName}");
}
},
error: function error() {
var _console4;
(_console4 = console).error.apply(_console4, arguments);
/**
* Triggered when an Object instanciation failed.
* @param {string} objectName - human-readable name for the concerned object.
* @param {Error} error - Error thrown by the constructor
*/
onObjectInstanciationError: function onObjectInstanciationError(objectName, error) {
console.error(">> ${objectName} creation failed:", error);
},
warning: function warning() {
var _console5;
(_console5 = console).warning.apply(_console5, arguments);
/**
* Triggered when an Object instanciation succeeded.
* @param {string} objectName - human-readable name for the concerned object.
* @param {*} value - The corresponding object instanciated.
*/
onObjectInstanciationSuccess: function onObjectInstanciationSuccess(objectName, value) {
console.debug(">>> ${objectName} created:", value);
},
/**
* Triggered when some method/function is called.
* @param {string} pathName - human-readable path for the concerned function.
* @param {Array.<*>} args - Arguments given to this function.
*/
onFunctionCall: function onFunctionCall(pathName, args) {
if (args.length) {
console.debug(">>> " + pathName + " called with arguments:", args);
} else {
console.debug(">>> " + pathName + " called");
}
},
/**
* Triggered when a function call fails.
* @param {string} pathName - human-readable path for the concerned function.
* @param {Error} error - Error thrown by the call
*/
onFunctionCallError: function onFunctionCallError(pathName, error) {
console.error(">> " + pathName + " failed:", error);
},
/**
* Triggered when a function call succeeded.
* @param {string} pathName - human-readable path for the concerned function.
* @param {*} value - The result of the function
*/
onFunctionCallSuccess: function onFunctionCallSuccess(pathName, value) {
console.info(">>> ${pathName} succeeded:", value);
}
/* eslint-enable no-console */
};
/**
* Log when a function is called with its arguments.
* @param {string} fnName
* @param {Array.<*>} args
*/
function onAPICall(fnName, args) {
if (args.length) {
Logger.debug(">>> " + fnName + " called with arguments:", args);
} else {
Logger.debug(">>> " + fnName + " called");
}
}
function stubRegularMethods(obj, methods, path, logObj) {

@@ -112,3 +158,3 @@ var _loop = function _loop(i) {

onAPICall(completePath, args);
Logger.onFunctionCall(completePath, args);
var myObj = {

@@ -129,3 +175,3 @@ self: obj,

} catch (e) {
Logger.error(">> " + completePath + " failed:", e);
Logger.onFunctionCallError(completePath, e);
myObj.error = e;

@@ -135,3 +181,3 @@ myObj.errorDate = Date.now();

}
Logger.debug(">> " + completePath + " succeeded:", res);
Logger.onFunctionCallSuccess(completePath, res);
myObj.response = res;

@@ -160,4 +206,4 @@ myObj.responseDate = Date.now();

get: function get() {
Logger.onPropertyAccess(completePath, value);
var value = oldDescriptor.get.bind(this)();
var myObj = {

@@ -168,3 +214,2 @@ self: this,

};
if (!logObj[propertyName]) {

@@ -176,4 +221,2 @@ logObj[propertyName] = {

logObj[propertyName].get.push(myObj);
Logger.debug(">> Getting " + completePath + ":", value);
return value;

@@ -201,4 +244,4 @@ }

get: function get() {
Logger.onPropertyAccess(completePath, value);
var value = oldDescriptor.get.bind(this)();
var myObj = {

@@ -218,8 +261,6 @@ self: this,

Logger.debug(">> Getting " + completePath + ":", value);
return value;
},
set: function set(value) {
Logger.debug(">> Setting " + completePath + ":", value);
Logger.onSettingProperty(completePath, value);
var myObj = {

@@ -248,5 +289,19 @@ self: this,

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 NativeMediaSourceProtoDescriptors = Object.getOwnPropertyDescriptors(NativeMediaSource.prototype);
var NativeMediaSourceIsTypeSupported = NativeMediaSource.isTypeSupported;
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;
}, {});

@@ -258,13 +313,21 @@ function StubbedMediaSource() {

if (args.length) {
Logger.debug(">>> Creating MediaSource with arguments:", args);
} else {
Logger.debug(">>> Creating MediaSource");
Logger.onObjectInstanciation("MediaSource", args);
var now = Date.now();
var spyObj = {
date: now,
args: args
};
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;
}
var nativeMediaSource = new (Function.prototype.bind.apply(NativeMediaSource, [null].concat(args)))();
Logger.debug(">>> MediaSource created:", nativeMediaSource);
stubReadOnlyProperties(nativeMediaSource, NativeMediaSourceProtoDescriptors, ["sourceBuffers", "activeSourceBuffers", "readyState"], "MediaSource.prototype", MSE_CALLS.MediaSource.properties);
stubProperties(nativeMediaSource, NativeMediaSourceProtoDescriptors, ["duration", "onsourceopen", "onsourceended", "onsourceclose"], "MediaSource.prototype", MSE_CALLS.MediaSource.properties);
stubRegularMethods(nativeMediaSource, ["addEventListener", "removeEventListener", "dispatchEvent", "addSourceBuffer", "removeSourceBuffer", "endOfStream", "setLiveSeekableRange", "clearLiveSeekableRange"], "MediaSource.prototype", MSE_CALLS.MediaSource.methods);
Logger.onObjectInstanciationSuccess("MediaSource", nativeMediaSource);
spyObj.response = nativeMediaSource;
spyObj.responseDate = Date.now();
return nativeMediaSource;

@@ -274,3 +337,6 @@ }

function spyOnMediaSource() {
stubRegularMethods(NativeMediaSource, ["isTypeSupported"], "MediaSource.isTypeSupported", MSE_CALLS.MediaSource.methods);
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);
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;

@@ -280,41 +346,77 @@ }

function stopSpyingOnMediaSource() {
Object.defineProperties(NativeMediaSource.prototype, MEDIASOURCE_SPY_OBJECT.properties.concat(MEDIASOURCE_SPY_OBJECT.readOnlyProperties).reduce(function (acc, propertyName) {
acc[propertyName] = NativeMediaSourceProtoDescriptors[propertyName];
}, {}));
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;
window.MediaSource.isTypeSupported = NativeMediaSourceIsTypeSupported;
}
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"]
};
var NativeSourceBufferProtoDescriptors = Object.getOwnPropertyDescriptors(NativeSourceBuffer.prototype);
var NativeSourceBufferAddEventListener = NativeSourceBuffer.prototype.addEventListener;
var NativeSourceBufferRemoveEventListener = NativeSourceBuffer.prototype.removeEventListener;
var NativeSourceBufferDispatchEvent = NativeSourceBuffer.prototype.dispatchEvent;
var NativeSourceBufferAppendBuffer = NativeSourceBuffer.prototype.appendBuffer;
var NativeSourceBufferAbort = NativeSourceBuffer.prototype.abort;
var NativeSourceBufferRemove = NativeSourceBuffer.prototype.remove;
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;
}, {});
function StubbedSourceBuffer() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
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;
}
function spyOnSourceBuffer() {
stubReadOnlyProperties(NativeSourceBuffer.prototype, NativeSourceBufferProtoDescriptors, ["updating", "buffered"], "SourceBuffer.prototype", MSE_CALLS.SourceBuffer.properties);
stubProperties(NativeSourceBuffer.prototype, NativeSourceBufferProtoDescriptors, ["mode", "timestampOffset", "appendWindowStart", "appendWindowEnd", "onupdate", "onupdatestart", "onupdateend", "onerror", "onabort"], "SourceBuffer.prototype", MSE_CALLS.SourceBuffer.properties);
stubRegularMethods(NativeSourceBuffer.prototype, ["addEventListener", "removeEventListener", "dispatchEvent", "appendBuffer", "abort", "remove"], "SourceBuffer.prototype", MSE_CALLS.SourceBuffer.methods);
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 stopSpyingOnSourceBuffer() {
Object.defineProperties(NativeSourceBuffer.prototype, {
updating: NativeSourceBufferProtoDescriptors.updating,
buffered: NativeSourceBufferProtoDescriptors.buffered,
mode: NativeSourceBufferProtoDescriptors.mode,
timestampOffset: NativeSourceBufferProtoDescriptors.timestampOffset,
appendWindowStart: NativeSourceBufferProtoDescriptors.appendWindowStart,
appendWindowEnd: NativeSourceBufferProtoDescriptors.appendWindowEnd,
onupdate: NativeSourceBufferProtoDescriptors.onupdate,
onupdatestart: NativeSourceBufferProtoDescriptors.onupdatestart,
onupdateend: NativeSourceBufferProtoDescriptors.onupdateend,
onerror: NativeSourceBufferProtoDescriptors.onerror,
onabort: NativeSourceBufferProtoDescriptors.onabort
Object.defineProperties(NativeSourceBuffer.prototype, SOURCEBUFFER_SPY_OBJECT.properties.concat(SOURCEBUFFER_SPY_OBJECT.readOnlyProperties).reduce(function (acc, propertyName) {
acc[propertyName] = NativeSourceBufferProtoDescriptors[propertyName];
}, {}));
SOURCEBUFFER_SPY_OBJECT.staticMethods.forEach(function (methodName) {
NativeSourceBuffer[methodName] = NativeSourceBufferStaticMethods[methodName];
});
NativeSourceBuffer.prototype.addEventListener = NativeSourceBufferAddEventListener;
NativeSourceBuffer.prototype.removeEventListener = NativeSourceBufferRemoveEventListener;
NativeSourceBuffer.prototype.dispatchEvent = NativeSourceBufferDispatchEvent;
NativeSourceBuffer.prototype.appendBuffer = NativeSourceBufferAppendBuffer;
NativeSourceBuffer.prototype.abort = NativeSourceBufferAbort;
NativeSourceBuffer.prototype.remove = NativeSourceBufferRemove;
SOURCEBUFFER_SPY_OBJECT.methods.forEach(function (methodName) {
NativeSourceBuffer.prototype[methodName] = NativeSourceBufferMethods[methodName];
});
window.SourceBuffer = NativeSourceBuffer;
}

@@ -325,3 +427,3 @@

*/
function activateMSESpy() {
function start() {
spyOnMediaSource();

@@ -331,3 +433,3 @@ spyOnSourceBuffer();

function deactivateMSESpy() {
function stop() {
stopSpyingOnMediaSource();

@@ -340,4 +442,4 @@ stopSpyingOnSourceBuffer();

exports.Logger = Logger;
exports.activateMSESpy = activateMSESpy;
exports.deactivateMSESpy = deactivateMSESpy;
exports.start = start;
exports.stop = stop;

@@ -344,0 +446,0 @@ Object.defineProperty(exports, '__esModule', { value: true });

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

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

@@ -6,7 +6,11 @@ # MSESpy.js ####################################################################

This is a tool to spy on most MSE-related browser API calls.
This is a tool to spy on most MSE-related browser API calls. It mainly has been
used for debugging and reverse-engineering purposes on media-oriented
web-applications.
It logs and registers when any of the following actions take place:
1. the following MediaSource methods are called:
1. A MediaSource object is instanciated
2. the following MediaSource methods are called:
- ``MediaSource.prototype.addSourceBuffer``

@@ -22,3 +26,3 @@ - ``MediaSource.prototype.removeSourceBuffer``

2. Those MediaSource properties are get/set:
3. Those MediaSource properties are get/set:
- ``MediaSource.prototype.duration``

@@ -32,3 +36,3 @@ - ``MediaSource.prototype.onsourceopen``

3. Those SourceBuffer methods are called:
4. Those SourceBuffer methods are called:
- ``SourceBuffer.prototype.appendBuffer``

@@ -42,3 +46,3 @@ - ``SourceBuffer.prototype.abort``

4. Those SourceBuffer properties are get/set:
5. Those SourceBuffer properties are get/set:
- ``SourceBuffer.prototype.mode``

@@ -72,3 +76,3 @@ - ``SourceBuffer.prototype.timestampOffset``

It can then be used to produced useful reports on how those APIs are exploited
by the application.
by any application.

@@ -91,5 +95,6 @@

// Start the spy
MSESpy.activateMSESpy();
MSESpy.start();
// Get the global MSECalls object registering every calls
// (More informations on it in the concerned chapter)
const MSECalls = MSESpy.getMSECalls();

@@ -114,3 +119,3 @@ ```

// - will add entries to the global MSECalls object.
MSESpy.activateMSESpy();
MSESpy.start();

@@ -121,2 +126,3 @@ // Get the global MSECalls object.

// errors...) when the spy has been active.
// (More informations on it in the concerned chapter)
console.log(MSESpy.getMSECalls());

@@ -132,19 +138,182 @@

// - clean up the resources taken
MSESpy.deactivateMSESpy();
MSESpy.stop();
// Spy again (after deactivating it)
MSESpy.activateMSESpy();
MSESpy.start();
// You can also declare custom log functions
// (More informations on it in the concerned chapter)
MSESpy.Logger.debug = CustomLogger;
```
// For debug calls (when a MSE API is called and was resolved/returned
// sucessfully - depending on the type of API and when a property is accesed)
MSESpy.Logger.debug = function(...args) {
myPersonalLogger.debug(...args);
}
// For errors and rejected promises from MSE APIs
MSESpy.Logger.error = function(...args) {
myPersonalLogger.error(...args);
### MSECalls object ############################################################
The MSECalls object contains information about every call performed while the
spy was active.
It can be obtained by calling the ``MSESpy.getMSECalls()`` API.
Here is its basic structure:
```js
// MSE Calls object
{
MediaSource: { // Data about the MediaSource native object
new: [ // An entry is added each time a MediaSource is created.
// Empty array by default.
{
date: 1533722155401, // {number} timestamp at which the call was made
args: [], // {Array} Eventual arguments the constructor has been called
// with
// If the call succeeded:
response: mediaSource, // {MediaSource|undefined} MediaSource created
responseDate: 1533722155401, // {number|undefined} timestamp at which
// the response was received
// If the call has trown
error: someError, // {Error|undefined} If an error was thrown while
// creating a new MediaSource.
// If this property is set, we won't have `response`
// nor `responseDate` set
errorDate: 1533722155401 // {number|undefined} timestamp at which
// the error was received
}
],
methods: {
addSourceBuffer: [ // Name of the method concerned
{
self: mediaSource, // {Object} The value of `this` at the time of the
// call (usually the MediaSource)
date: 1533722155401, // {number} timestamp at which the call was made
args: [], // {Array} Eventual arguments this method has been called
// with
// If the call succeeded:
response: sourceBuffer, // {*} What has been returned by the call
responseDate: 1533722155401, // {number|undefined} timestamp at which
// the response was received
// If the call has trown
error: someError, // {Error|undefined} If an error was thrown while
// calling the method.
// If this property is set, we won't have `response`
// nor `responseDate` set
errorDate: 1533722155401 // {number|undefined} timestamp at which
// the error was received
}
]
},
properties: {
duration: { // name of the property
get: [ // A new entry is added each time the property is accessed
{
self: mediaSource, // {MediaSource} The instance of the concerned
// mediaSource
date: 1533722155401, // {number} timestamp at which the property
// was accessed
value: 10 // {*} Content of the property as it was accessed
}
],
set: [ // A new entry is added each time the property is set
{
self: mediaSource, // {MediaSource} The instance of the concerned
// mediaSource
date: 1533722155401, // {number} timestamp at which the property
// was set
value: 15 // {*} Content the property was set to
}
]
}
}
},
SourceBuffer: { // SourceBuffer follows the same structure
new: [], // Note: SourceBuffer are usually created through
// MediaSource.prototype.addSourceBuffer and not threw the `new`
// keyword. As such, this array might always stay empty.
methods: {},
properties: {},
},
}
```
### Custom Logger ##############################################################
If you don't like the default logging strategy or find it too verbose, a custom
Logger can be defined.
It is accessible through the ``MSESpy.Logger`` object. All it contains are
several functions automatically called at various key points:
```js
Logger = {
/**
* Triggered each time a property is accessed.
* @param {string} pathString - human-readable path to the property.
* @param {*} value - the value it currently has.
*/
onPropertyAccess(pathString, value) {},
/**
* Triggered each time a property is set.
* @param {string} pathString - human-readable path to the property.
* @param {*} value - the value it is set to.
*/
onSettingProperty(pathString, value) {},
/**
* Triggered when some object is instanciated (just before).
* @param {string} objectName - human-readable name for the concerned object.
* @param {Array.<*>} args - Arguments given to the constructor
*/
onObjectInstanciation(objectName, args) {},
/**
* Triggered when an Object instanciation failed.
* @param {string} objectName - human-readable name for the concerned object.
* @param {Error} error - Error thrown by the constructor
*/
onObjectInstanciationError(objectName, error) {},
/**
* Triggered when an Object instanciation succeeded.
* @param {string} objectName - human-readable name for the concerned object.
* @param {*} value - The corresponding object instanciated.
*/
onObjectInstanciationSuccess(objectName, value) {},
/**
* Triggered when some method/function is called.
* @param {string} pathName - human-readable path for the concerned function.
* @param {Array.<*>} args - Arguments given to this function.
*/
onFunctionCall(pathName, args) {},
/**
* Triggered when a function call fails.
* @param {string} pathName - human-readable path for the concerned function.
* @param {Error} error - Error thrown by the call
*/
onFunctionCallError(pathName, error) {},
/**
* Triggered when a function call succeeded.
* @param {string} pathName - human-readable path for the concerned function.
* @param {*} value - The result of the function
*/
onFunctionCallSuccess(pathName, value) {},
};
```
Note: if the code above were to be implemented, you wouldn't have any logs
displaying in the console, as all functions declared here are empty.
You can look at ``src/utils/logger.js`` for default implementations.

@@ -10,3 +10,2 @@ /**

properties: {},
events: {}, // TODO
},

@@ -17,3 +16,2 @@ SourceBuffer: {

properties: {},
events: {}, // TODO
},

@@ -20,0 +18,0 @@ };

@@ -16,3 +16,3 @@ import {

*/
function activateMSESpy() {
function start() {
spyOnMediaSource();

@@ -22,3 +22,3 @@ spyOnSourceBuffer();

function deactivateMSESpy() {
function stop() {
stopSpyingOnMediaSource();

@@ -32,4 +32,4 @@ stopSpyingOnSourceBuffer();

Logger,
activateMSESpy,
deactivateMSESpy,
start,
stop,
};

@@ -10,35 +10,84 @@ import Logger from "./utils/logger.js";

const MEDIASOURCE_SPY_OBJECT = {
readOnlyProperties: [
"sourceBuffers",
"activeSourceBuffers",
"readyState",
],
properties: [
"duration",
"onsourceopen",
"onsourceended",
"onsourceclose",
],
staticMethods: [
"isTypeSupported",
],
methods: [
"addEventListener",
"removeEventListener",
"dispatchEvent",
"addSourceBuffer",
"removeSourceBuffer",
"endOfStream",
"setLiveSeekableRange",
"clearLiveSeekableRange",
],
};
const NativeMediaSourceProtoDescriptors =
Object.getOwnPropertyDescriptors(NativeMediaSource.prototype);
const NativeMediaSourceIsTypeSupported = NativeMediaSource.isTypeSupported;
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;
}, {});
function StubbedMediaSource(...args) {
if (args.length) {
Logger.debug(">>> Creating MediaSource with arguments:", args);
} else {
Logger.debug(">>> Creating MediaSource");
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;
}
const nativeMediaSource = new NativeMediaSource(...args);
Logger.debug(">>> MediaSource created:", nativeMediaSource);
Logger.onObjectInstanciationSuccess("MediaSource", nativeMediaSource);
spyObj.response = nativeMediaSource;
spyObj.responseDate = Date.now();
return nativeMediaSource;
}
export default function spyOnMediaSource() {
stubReadOnlyProperties(
nativeMediaSource,
NativeMediaSource.prototype,
NativeMediaSourceProtoDescriptors,
[
"sourceBuffers",
"activeSourceBuffers",
"readyState",
],
MEDIASOURCE_SPY_OBJECT.readOnlyProperties,
"MediaSource.prototype",
MSE_CALLS.MediaSource.properties,
);
stubRegularMethods(
NativeMediaSource,
MEDIASOURCE_SPY_OBJECT.staticMethods,
"MediaSource",
MSE_CALLS.MediaSource.methods,
);
stubProperties(
nativeMediaSource,
NativeMediaSource.prototype,
NativeMediaSourceProtoDescriptors,
[
"duration",
"onsourceopen",
"onsourceended",
"onsourceclose",
],
MEDIASOURCE_SPY_OBJECT.properties,
"MediaSource.prototype",

@@ -48,27 +97,7 @@ MSE_CALLS.MediaSource.properties,

stubRegularMethods(
nativeMediaSource,
[
"addEventListener",
"removeEventListener",
"dispatchEvent",
"addSourceBuffer",
"removeSourceBuffer",
"endOfStream",
"setLiveSeekableRange",
"clearLiveSeekableRange",
],
NativeMediaSource.prototype,
MEDIASOURCE_SPY_OBJECT.methods,
"MediaSource.prototype",
MSE_CALLS.MediaSource.methods,
);
return nativeMediaSource;
}
export default function spyOnMediaSource() {
stubRegularMethods(
NativeMediaSource,
["isTypeSupported"],
"MediaSource.isTypeSupported",
MSE_CALLS.MediaSource.methods,
);
window.MediaSource = StubbedMediaSource;

@@ -78,4 +107,16 @@ }

export function stopSpyingOnMediaSource() {
Object.defineProperties(NativeMediaSource.prototype,
MEDIASOURCE_SPY_OBJECT.properties
.concat(MEDIASOURCE_SPY_OBJECT.readOnlyProperties)
.reduce((acc, propertyName) => {
acc[propertyName] = NativeMediaSourceProtoDescriptors[propertyName];
}, {})
);
MEDIASOURCE_SPY_OBJECT.staticMethods.forEach((methodName) => {
NativeMediaSource[methodName] = NativeMediaSourceStaticMethods[methodName];
});
MEDIASOURCE_SPY_OBJECT.methods.forEach((methodName) => {
NativeMediaSource.prototype[methodName] = NativeMediaSourceMethods[methodName];
});
window.MediaSource = NativeMediaSource;
window.MediaSource.isTypeSupported = NativeMediaSourceIsTypeSupported;
}

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

import Logger from "./utils/logger.js";
import stubRegularMethods from "./utils/stubRegularMethods.js";

@@ -9,18 +10,69 @@ import stubReadOnlyProperties from "./utils/stubReadOnlyProperties.js";

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",
],
};
const NativeSourceBufferProtoDescriptors =
Object.getOwnPropertyDescriptors(NativeSourceBuffer.prototype);
const NativeSourceBufferAddEventListener =
NativeSourceBuffer.prototype.addEventListener;
const NativeSourceBufferRemoveEventListener =
NativeSourceBuffer.prototype.removeEventListener;
const NativeSourceBufferDispatchEvent =
NativeSourceBuffer.prototype.dispatchEvent;
const NativeSourceBufferAppendBuffer =
NativeSourceBuffer.prototype.appendBuffer;
const NativeSourceBufferAbort =
NativeSourceBuffer.prototype.abort;
const NativeSourceBufferRemove =
NativeSourceBuffer.prototype.remove;
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;
}, {});
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;
}
export default function spyOnSourceBuffer() {

@@ -30,9 +82,3 @@ stubReadOnlyProperties(

NativeSourceBufferProtoDescriptors,
[
"updating",
"buffered",
// "audioTracks",
// "videoTracks",
// "textTracks",
],
SOURCEBUFFER_SPY_OBJECT.readOnlyProperties,
"SourceBuffer.prototype",

@@ -44,13 +90,3 @@ MSE_CALLS.SourceBuffer.properties,

NativeSourceBufferProtoDescriptors,
[
"mode",
"timestampOffset",
"appendWindowStart",
"appendWindowEnd",
"onupdate",
"onupdatestart",
"onupdateend",
"onerror",
"onabort",
],
SOURCEBUFFER_SPY_OBJECT.properties,
"SourceBuffer.prototype",

@@ -61,41 +97,24 @@ MSE_CALLS.SourceBuffer.properties,

NativeSourceBuffer.prototype,
[
"addEventListener",
"removeEventListener",
"dispatchEvent",
"appendBuffer",
"abort",
"remove",
],
SOURCEBUFFER_SPY_OBJECT.methods,
"SourceBuffer.prototype",
MSE_CALLS.SourceBuffer.methods,
);
window.SourceBuffer = StubbedSourceBuffer;
}
export function stopSpyingOnSourceBuffer() {
Object.defineProperties(NativeSourceBuffer.prototype, {
updating: NativeSourceBufferProtoDescriptors.updating,
buffered: NativeSourceBufferProtoDescriptors.buffered,
mode: NativeSourceBufferProtoDescriptors.mode,
timestampOffset: NativeSourceBufferProtoDescriptors.timestampOffset,
appendWindowStart: NativeSourceBufferProtoDescriptors.appendWindowStart,
appendWindowEnd: NativeSourceBufferProtoDescriptors.appendWindowEnd,
onupdate: NativeSourceBufferProtoDescriptors.onupdate,
onupdatestart: NativeSourceBufferProtoDescriptors.onupdatestart,
onupdateend: NativeSourceBufferProtoDescriptors.onupdateend,
onerror: NativeSourceBufferProtoDescriptors.onerror,
onabort: NativeSourceBufferProtoDescriptors.onabort,
Object.defineProperties(NativeSourceBuffer.prototype,
SOURCEBUFFER_SPY_OBJECT.properties
.concat(SOURCEBUFFER_SPY_OBJECT.readOnlyProperties)
.reduce((acc, propertyName) => {
acc[propertyName] = NativeSourceBufferProtoDescriptors[propertyName];
}, {})
);
SOURCEBUFFER_SPY_OBJECT.staticMethods.forEach((methodName) => {
NativeSourceBuffer[methodName] = NativeSourceBufferStaticMethods[methodName];
});
NativeSourceBuffer.prototype.addEventListener =
NativeSourceBufferAddEventListener;
NativeSourceBuffer.prototype.removeEventListener =
NativeSourceBufferRemoveEventListener;
NativeSourceBuffer.prototype.dispatchEvent =
NativeSourceBufferDispatchEvent;
NativeSourceBuffer.prototype.appendBuffer =
NativeSourceBufferAppendBuffer;
NativeSourceBuffer.prototype.abort =
NativeSourceBufferAbort;
NativeSourceBuffer.prototype.remove =
NativeSourceBufferRemove;
SOURCEBUFFER_SPY_OBJECT.methods.forEach((methodName) => {
NativeSourceBuffer.prototype[methodName] = NativeSourceBufferMethods[methodName];
});
window.SourceBuffer = NativeSourceBuffer;
}
/**
* Define the logger for startMSESpy.
* Define the logger for the MSE-spy.
* Allows to re-define a specific logger on runtime / before applying this

@@ -7,19 +7,84 @@ * script.

*/
const Logger = window.Logger || {
const Logger = window.MSESpyLogger || {
/* eslint-disable no-console */
log: function(...args) {
console.log(...args);
/**
* Triggered each time a property is accessed.
* @param {string} pathString - human-readable path to the property.
* @param {*} value - the value it currently has.
*/
onPropertyAccess(pathString, value) {
console.debug(">>> Getting ${pathString}:", value);
},
debug: function(...args) {
console.debug(...args);
/**
* Triggered each time a property is set.
* @param {string} pathString - human-readable path to the property.
* @param {*} value - the value it is set to.
*/
onSettingProperty(pathString, value) {
console.debug(`>> Setting ${pathString}:`, value);
},
info: function(...args) {
console.info(...args);
/**
* Triggered when some object is instanciated (just before).
* @param {string} objectName - human-readable name for the concerned object.
* @param {Array.<*>} args - Arguments given to the constructor
*/
onObjectInstanciation(objectName, args) {
if (args.length) {
console.debug(">>> Creating ${objectName} with arguments:", args);
} else {
console.debug(">>> Creating ${objectName}");
}
},
error: function(...args) {
console.error(...args);
/**
* Triggered when an Object instanciation failed.
* @param {string} objectName - human-readable name for the concerned object.
* @param {Error} error - Error thrown by the constructor
*/
onObjectInstanciationError(objectName, error) {
console.error(">> ${objectName} creation failed:", error);
},
warning: function(...args) {
console.warning(...args);
/**
* Triggered when an Object instanciation succeeded.
* @param {string} objectName - human-readable name for the concerned object.
* @param {*} value - The corresponding object instanciated.
*/
onObjectInstanciationSuccess(objectName, value) {
console.debug(">>> ${objectName} created:", value);
},
/**
* Triggered when some method/function is called.
* @param {string} pathName - human-readable path for the concerned function.
* @param {Array.<*>} args - Arguments given to this function.
*/
onFunctionCall(pathName, args) {
if (args.length) {
console.debug(`>>> ${pathName} called with arguments:`, args);
} else {
console.debug(`>>> ${pathName} called`);
}
},
/**
* Triggered when a function call fails.
* @param {string} pathName - human-readable path for the concerned function.
* @param {Error} error - Error thrown by the call
*/
onFunctionCallError(pathName, error) {
console.error(`>> ${pathName} failed:`, error);
},
/**
* Triggered when a function call succeeded.
* @param {string} pathName - human-readable path for the concerned function.
* @param {*} value - The result of the function
*/
onFunctionCallSuccess(pathName, value) {
console.info(">>> ${pathName} succeeded:", value);
},
/* eslint-enable no-console */

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

@@ -22,4 +22,4 @@ import Logger from "./logger.js";

get() {
Logger.onPropertyAccess(completePath, value);
const value = oldDescriptor.get.bind(this)();
const myObj = {

@@ -39,8 +39,6 @@ self: this,

Logger.debug(`>> Getting ${completePath}:`, value);
return value;
},
set(value) {
Logger.debug(`>> Setting ${completePath}:`, value);
Logger.onSettingProperty(completePath, value);
const myObj = {

@@ -47,0 +45,0 @@ self: this,

@@ -22,4 +22,4 @@ import Logger from "./logger.js";

get() {
Logger.onPropertyAccess(completePath, value);
const value = oldDescriptor.get.bind(this)();
const myObj = {

@@ -30,3 +30,2 @@ self: this,

};
if (!logObj[propertyName]) {

@@ -38,4 +37,2 @@ logObj[propertyName] = {

logObj[propertyName].get.push(myObj);
Logger.debug(`>> Getting ${completePath}:`, value);
return value;

@@ -42,0 +39,0 @@ },

import Logger from "./logger.js";
import onAPICall from "./onAPICall.js";

@@ -20,3 +19,3 @@ export default function stubRegularMethods(

obj[methodName] = function (...args) {
onAPICall(completePath, args);
Logger.onFunctionCall(completePath, args);
const myObj = {

@@ -37,3 +36,3 @@ self: obj,

} catch (e) {
Logger.error(`>> ${completePath} failed:`, e);
Logger.onFunctionCallError(completePath, e);
myObj.error = e;

@@ -43,3 +42,3 @@ myObj.errorDate = Date.now();

}
Logger.debug(`>> ${completePath} succeeded:`, res);
Logger.onFunctionCallSuccess(completePath, res);
myObj.response = res;

@@ -46,0 +45,0 @@ myObj.responseDate = Date.now();

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