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

cross-domain-events

Package Overview
Dependencies
Maintainers
4
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cross-domain-events - npm Package Compare versions

Comparing version 0.0.3 to 0.0.4

.jshintrc

66

karma.conf.js

@@ -1,20 +0,62 @@

module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['mocha', 'sinon', 'referee'],
module.exports = function(config) {
var settings = {
basePath: '',
frameworks: ['mocha', 'es5-shim', 'sinon', 'referee'],
plugins: ['karma-*'],
files: [
files: [{
pattern: 'test/fixtures/childIframe.html',
included: false,
served: true
},
'node_modules/eventlistener/eventlistener.js',
'lib/**/*.js',
'test/**/*.js',
'test/helpers/helpers.js',
'lib/xde.js',
'test/*.test.js'
],
reporters: ['progress'],
browsers: ['PhantomJS'],
singleRun: false,
autoWatch: true,
colors: true,
logLevel: config.LOG_INFO,
client: {
mocha: {
ui: 'tdd'
}
captureConsole: true
}
});
};
};
if (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY) {
// keep
} else {
settings.browserDisconnectTimeout = 60000 * 2;
settings.browserNoActivityTimeout = 60000 * 2;
//settings.browserDisconnectTolerance = 1;
settings.captureTimeout = 60000 * 3;
settings.sauceLabs = {
testName: 'XDE',
tags: ['xde']
};
settings.reporters = ['dots', 'saucelabs'];
settings.customLaunchers = {};
// only 3 vmms / browsers per run because of
// https://github.com/karma-runner/karma-sauce-launcher/issues/40
// should either add better setup for running max currently or
var key = process.env.BROWSER_TYPE;
var target = require('./ci-browsers.js')[key];
if (!target) {
console.error('Missing / Unknown BROWSER_TYPE ' + process.env.BROWSER_TYPE);
process.exit(1);
}
Object.keys(target).forEach(function(key){
settings.customLaunchers[key] = target[key];
});
console.log('Running CI tests on', Object.keys(settings.customLaunchers).join(', '));
settings.browsers = Object.keys(settings.customLaunchers);
}
return config.set(settings);
};

67

lib/xde.js

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

(function (win, events) {
(function(win, events) {
var xde;
var DEFAULT_ORIGIN = '*';
var xde, eventListeners;
var onlyStrings;
var eventListeners = {};

@@ -14,3 +14,3 @@ function onMessage(evt) {

parsedData = evt.data;
if (typeof evt.data == 'string') {
if (typeof evt.data == 'string' && evt.data[0] === '{') {
try {

@@ -30,3 +30,3 @@ parsedData = JSON.parse(evt.data);

if (listeners && listeners.length > 0) {
listeners.forEach(function(fn){
listeners.forEach(function(fn) {
fn(parsedData);

@@ -37,13 +37,17 @@ });

function validateName (name) {
if (!name || typeof name != 'string') { throw new Error('Event name has to be a string'); };
function validateName(name) {
if (!name || typeof name != 'string') {
throw new Error('Event name has to be a string');
}
}
function validateNameAndFn (name, fn) {
function validateNameAndFn(name, fn) {
validateName(name);
if (typeof fn != "function" ) { throw new Error('Callback function has to be given'); }
if (typeof fn != 'function') {
throw new Error('Callback function has to be given');
}
}
xde = {
on: function (name, fn) {
on: function(name, fn) {
validateNameAndFn(name, fn);

@@ -57,3 +61,3 @@

off: function (name, fn) {
off: function(name, fn) {
validateNameAndFn(name, fn);

@@ -64,3 +68,3 @@ var listeners = eventListeners[name];

}
eventListeners[name] = listeners.filter(function (listener) {
eventListeners[name] = listeners.filter(function(listener) {
return listener !== fn;

@@ -70,3 +74,3 @@ });

sendTo: function (otherWindow, name, data) {
sendTo: function(otherWindow, name, data) {
validateName(name);

@@ -77,4 +81,4 @@ try {

}
} catch(e) {}
if ( !otherWindow || !otherWindow.postMessage ) {
} catch (e) {}
if (!otherWindow || !otherWindow.postMessage) {
throw new TypeError('otherWindow does not support postMessage');

@@ -84,10 +88,10 @@ }

var msg = {
name : name,
data : data,
__xde : true
name: name,
data: data,
__xde: true
};
if (onlyStrings) {
if (xde.onlyStringSupport) {
msg = JSON.stringify(msg);
}
otherWindow.postMessage(msg, this.targetOrigin); // TODO fix security issue
otherWindow.postMessage(msg, xde.targetOrigin); // TODO fix security issue
},

@@ -97,14 +101,25 @@

_reset: function (forceStringify) {
onlyStringSupport: false,
_reset: function() {
eventListeners = {};
this.targetOrigin = DEFAULT_ORIGIN;
onlyStrings = forceStringify || false;
try{win.postMessage({toString:function(){onlyStrings=true;}},"*");}catch(e){}
}
};
xde._reset();
function featureTestObjectTransportSupport() {
try {
win.postMessage({
toString: function() {
xde.onlyStringSupport = true;
}
}, DEFAULT_ORIGIN);
} catch (e) {}
}
featureTestObjectTransportSupport();
events.add(win, 'message', onMessage, false);
if(typeof exports === 'object') {
if (typeof exports === 'object') {
module.exports = xde;

@@ -114,2 +129,2 @@ } else {

}
})(this.window || (typeof global !== "undefined" ? global : this), this.eventListener || require('eventlistener'));
})(this.window || (typeof global !== 'undefined' ? global : this), this.eventListener || require('eventlistener'));
{
"name": "cross-domain-events",
"version": "0.0.3",
"version": "0.0.4",
"description": "Event-like api for postMessage to send objects between cross-domain frames",

@@ -27,20 +27,22 @@ "license": "MIT",

"scripts": {
"test": "./node_modules/karma/bin/karma start --single-run"
"test": "./node_modules/karma/bin/karma start --single-run",
"test-ci": "BROWSER_TYPE=android npm test && BROWSER_TYPE=ios npm test && BROWSER_TYPE=ienew npm test && BROWSER_TYPE=ie npm test && BROWSER_TYPE=firefox npm test && BROWSER_TYPE=chrome npm test",
"validate": "finn-js-code-style lib && jscs -c node_modules/finn-js-code-style/.jscsrc lib"
},
"main": "lib/xde.js",
"devDependencies": {
"karma-script-launcher": "~0.1.0",
"karma-chrome-launcher": "~0.1.1",
"karma-html2js-preprocessor": "~0.1.0",
"karma-firefox-launcher": "~0.1.2",
"requirejs": "~2.1.9",
"karma-requirejs": "~0.2.0",
"karma-phantomjs-launcher": "~0.1.1",
"karma": "0.12.21",
"mocha": "~1.15.1",
"karma-mocha": "~0.1.1",
"karma-commonjs": "0.0.3",
"finn-js-code-style": "^4.3.0",
"jscs": "^1.12.0",
"karma": "^0.12.31",
"karma-es5-shim": "0.0.4",
"karma-mocha": "^0.1.10",
"karma-phantomjs-launcher": "^0.1.4",
"karma-referee": "^0.4.2",
"karma-sauce-launcher": "^0.2.10",
"karma-sinon": "~1.0.0",
"karma-referee": "~0.2.0"
"mocha": "^2.2.4",
"referee": "^1.1.1",
"referee-sinon": "^1.0.2",
"sinon": "^1.14.1"
}
}

@@ -8,2 +8,5 @@ cross-domain-events

[![Sauce Test Status](https://saucelabs.com/browser-matrix/cross-domain-events.svg)](https://saucelabs.com/u/cross-domain-events)
postMessage was implemented in Internet Explorer 8, but only supports sending text strings. Modern browsers can send objects, but if you want to listen for different kind of objects you have to implement your own delegation.

@@ -10,0 +13,0 @@

@@ -1,6 +0,12 @@

suite('xde', function () {
var iframe, childXde, postMessage;
var miniEvtListener = function (el, n, m, u) {el.addEventListener(n, m, u);};
var iframeContent = '<!DOCTYPE html><html><head><script>var eventListener={add:'+miniEvtListener.toString()+'};</script><script src=\'/base/lib/xde.js?'+new Date().getTime()+'\'></script><script>parent.setChildXde(xde);</script></head><body>test</body></html>';
function cleanupSpy(){
if (this.spy) {
this.spy.restore();
this.spy = null;
}
}
describe('xde', function () {
var iframeElem;
var iframeWindow;
function async(fn, done) {

@@ -12,2 +18,3 @@ return function () {

} catch (e) {
console.error(e);
done(e);

@@ -18,42 +25,52 @@ }

function dispatchMessageEvt (msg, origin, source) {
var evt;
try {
evt = new MessageEvent('message', {data: msg, origin: origin, source: source});
} catch (e) {
evt = document.createEvent('MessageEvent');
evt.initMessageEvent('message', true, true, msg, origin, 1, source);
function asyncAssert(fn, done) {
return setTimeout(async(fn, done), 50);
}
function sendPostMessage(data, cb) {
var name = data.name || 'test';
if (cb) {
window.xde.on(name, cb);
}
window.dispatchEvent(evt);
iframeWindow.xde.sendTo(window, name, data);
}
setup(function (done) {
window.setChildXde = function (xde) {
window.setChildXde = null;
childXde = xde;
beforeEach(function (done) {
this.timeout(20000); // saucelabs may need more time to load the iframe
// var time = 0;
// var timer = setInterval(function(){
// time += 1;
// console.log('time:', time);
// }, 1000);
window.initXde = function (_win) {
// clearTimeout(timer);
iframeWindow = _win.window; //accessing window.window for IE8
done();
};
iframe = document.createElement('iframe');
document.body.appendChild(iframe);
var doc = iframe.contentWindow.document;
doc.open('text/html', 'replace');
doc.write(iframeContent);
doc.close();
postMessage = sinon.spy(iframe.contentWindow, 'postMessage');
iframeElem = document.createElement('iframe');
iframeElem.width = '300px';
iframeElem.height = '100px';
iframeElem.style.width = '300px';
iframeElem.style.height = '100px';
iframeElem.style.backgroundColor = 'red';
setTimeout(function(){
// we get more stable tests on saucelabs if we wait some
document.body.appendChild(iframeElem);
iframeElem.src = '/base/test/fixtures/childIframe.html?' + (+new Date());
}, 100);
});
teardown(function teardown () {
document.body.removeChild(iframe);
childXde = undefined;
postMessage.restore();
xde._reset();
afterEach(function teardown () {
iframeWindow = null;
window.xde._reset();
document.body.removeChild(iframeElem);
cleanupSpy.call(this);
});
suite('on', function() {
test('should be defined', function () {
describe('on', function() {
it('should be defined', function () {
assert.defined(xde.on);
});
test('should throw if event name is not given', function () {
it('should throw if event name is not given', function () {
assert.exception(function () {

@@ -64,3 +81,3 @@ xde.on();

test('should throw if event name is empty string', function () {
it('should throw if event name is empty string', function () {
assert.exception(function () {

@@ -71,3 +88,3 @@ xde.on('');

test('should throw if callback is not a function', function () {
it('should throw if callback is not a function', function () {
assert.exception(function () {

@@ -78,3 +95,3 @@ xde.on('test');

test('should not throw when calling with right arguments', function () {
it('should not throw when calling with right arguments', function () {
refute.exception(function () {

@@ -85,6 +102,6 @@ xde.on('test', function () {});

test('should not trigger listener sync', function () {
var eventName = 'foo',
eventData = 'bar',
spy = sinon.spy();
it('should not trigger listener sync', function () {
var eventName = 'foo';
var eventData = 'bar';
var spy = sinon.spy();

@@ -95,34 +112,49 @@ xde.on(eventName, spy);

test('should not use JSON.parse when message data is an object', function () {
var spy = sinon.spy(JSON, "parse");
dispatchMessageEvt({foo: 'bar'});
sinon.assert.notCalled(spy);
spy.restore();
// add if
// cleanup somewhere missing
it('should not use JSON.parse when message data is an object', function (done) {
var spy = wrapAndSpy(JSON, "parse");
sendPostMessage({foo: 'bar'}, function() {
if (xde.onlyStringSupport === false) {
assert.equals(spy.callCount, 0, 'JSON parse should NOT be called');
} else {
assert.equals(spy.callCount, 1, 'JSON parse should be called when string');
}
spy.restore();
done();
});
});
test('should try JSON.parse when message data is a string', function () {
var spy = sinon.spy(JSON, "parse");
dispatchMessageEvt('{"foo":"bar"}');
sinon.assert.calledOnce(spy);
spy.restore();
it('should try JSON.parse when message data is a string', function (done) {
var spy = wrapAndSpy(JSON, "parse");
var orig = iframeWindow.xde.onlyStringSupport;
iframeWindow.xde.onlyStringSupport = true;
sendPostMessage({"foo":"bar"}, function() {
iframeWindow.xde.onlyStringSupport = orig;
assert.equals(spy.callCount, 1, 'JSON parse should be called');
spy.restore();
done();
});
});
test('should pass source and origin to the event object', function (done) {
var source = window;
var origin = location.href;
it('should pass source and origin to the event object', function (done) {
var origin = 'http://'+iframeWindow.location.host;
xde.on('test', function (evt) {
assert.equals(source, evt.source);
assert.equals(origin, evt.origin);
assert.equals(evt.origin, origin);
assert.equals(evt.source, iframeWindow);
done();
});
dispatchMessageEvt({
__xde: true,
name: 'test'
}, origin, source);
sendPostMessage({});
});
});
suite('sendTo', function() {
test('should throw if otherWindow is not valid postMessage target', function () {
describe('sendTo', function() {
it('should throw if otherWindow is not valid postMessage target', function () {
assert.exception(function () {

@@ -133,34 +165,46 @@ xde.sendTo('test', 'name');

test('should not throw when calling with iframe as otherWindow', function () {
it('should not throw when calling with iframeElem as otherWindow', function () {
refute.exception(function () {
xde.sendTo(iframe, 'test');
xde.sendTo(iframeWindow, 'test');
});
});
test('should not throw when calling with window.top as otherWindow', function () {
it('should not throw when calling with window.top as otherWindow', function () {
refute.exception(function () {
childXde.sendTo(window, 'test');
iframeWindow.xde.sendTo(window, 'test');
});
});
test('should throw if event name is not given', function () {
it('should throw if event name is not given', function () {
assert.exception(function(){
xde.sendTo(iframe);
xde.sendTo(iframeWindow);
});
});
test('should throw if event name is empty string', function () {
it('should throw if event name is empty string', function () {
assert.exception(function () {
xde.sendTo(iframe, '');
xde.sendTo(iframeWindow, '');
});
});
test('should call postMessage only once', function () {
xde.sendTo(iframe, 'test');
assert(postMessage.calledOnce);
it('should call postMessage only once', function (done) {
var spy = wrapAndSpy(window, 'postMessage');
assert.equals(iframeWindow.spy.callCount, 0);
window.xde.on('test321', function() {
spy.restore();
assert.equals(iframeWindow.spy.callCount, 0, 'iframeSpy should not be called');
assert.equals(spy.callCount, 1);
done();
});
iframeWindow.xde.sendTo(window, 'test321', {payload: 'asd'});
});
test('should trigger listener on the other side', function (done) {
it('should trigger listener on the other side', function (done) {
var eventName = 'foo';
childXde.on(eventName, async(function (evt) {
iframeWindow.xde.on(eventName, async(function (evt) {
assert.defined(evt);

@@ -170,6 +214,6 @@ assert.equals(evt.name, eventName);

xde.sendTo(iframe, eventName);
xde.sendTo(iframeWindow, eventName);
});
test('should send event data to the listener', function (done) {
it('should send event data to the listener', function (done) {
var eventName = 'foo',

@@ -180,86 +224,91 @@ eventData = {

};
childXde.on(eventName, async(function (evt) {
iframeWindow.xde.on(eventName, async(function (evt) {
assert.equals(evt.data, eventData);
}, done));
xde.sendTo(iframe, eventName, eventData);
xde.sendTo(iframeWindow, eventName, eventData);
});
test('should not throw exception on non-JSON message events', function (done) {
it('should not throw exception on non-JSON message events', function (done) {
var spy = sinon.spy();
iframe.contentWindow.onerror = spy;
iframe.contentWindow.postMessage('not serialized JSON', '*');
iframeWindow.onerror = spy;
iframeWindow.postMessage('not serialized JSON', '*');
setTimeout(async(function () {
asyncAssert(function () {
sinon.assert.notCalled(spy);
}, done), 50);
}, done);
});
test('should ignore json messages not sent by xde', function (done) {
it('should ignore json messages not sent by xde', function (done) {
var spy = sinon.spy();
var data = {data : 'foo', name : 'bar'};
childXde.on(data.name, spy);
iframe.contentWindow.postMessage(JSON.stringify(data), '*');
iframeWindow.xde.on(data.name, spy);
iframeWindow.postMessage(JSON.stringify(data), '*');
setTimeout(async(function () {
asyncAssert(function () {
sinon.assert.notCalled(spy);
}, done), 50);
}, done);
});
test('should allow multiple listeners for same event name', function (done) {
it('should allow multiple listeners for same event name', function (done) {
var spy1 = sinon.spy(), spy2 = sinon.spy();
var evtName = 'multiple';
childXde.on(evtName, spy1);
childXde.on(evtName, spy2);
xde.sendTo(iframe, evtName);
setTimeout(async(function () {
iframeWindow.xde.on(evtName, spy1);
iframeWindow.xde.on(evtName, spy2);
xde.sendTo(iframeWindow, evtName);
asyncAssert(function () {
sinon.assert.calledOnce(spy1);
sinon.assert.calledOnce(spy2);
}, done), 50);
}, done);
});
test('should only trigger listeners for the sent event name', function (done) {
it('should only trigger listeners for the sent event name', function (done) {
var spy1 = sinon.spy(), spy2 = sinon.spy();
var evtName1 = 'foo';
var evtName2 = 'bar';
childXde.on(evtName1, spy1);
childXde.on(evtName2, spy2);
xde.sendTo(iframe, evtName1);
setTimeout(async(function () {
iframeWindow.xde.on(evtName1, spy1);
iframeWindow.xde.on(evtName2, spy2);
xde.sendTo(iframeWindow, evtName1);
asyncAssert(function () {
sinon.assert.calledOnce(spy1);
sinon.assert.notCalled(spy2);
}, done), 50);
}, done);
});
test('should not throw error or call any callbacks if no listners for an event name', function (done) {
it('should not throw error or call any callbacks if no listners for an event name', function (done) {
var spy = sinon.spy();
iframe.contentWindow.onerror = spy;
childXde.on('foo', spy);
xde.sendTo(iframe, 'bar');
setTimeout(async(function () {
iframeWindow.onerror = spy;
iframeWindow.xde.on('foo', spy);
xde.sendTo(iframeWindow, 'bar');
asyncAssert(function () {
sinon.assert.notCalled(spy);
}, done), 50);
}, done);
});
test('should not stringify to JSON when browser supports postMessage with objects', function () {
var spy = sinon.spy(JSON, 'stringify');
xde.sendTo(iframe, 'test', {a: 1});
sinon.assert.notCalled(spy);
spy.restore();
});
if (xde.onlyStringSupport === false) {
after(cleanupSpy);
test('should stringify to JSON when browser doesn\'t support postMessage with objects', function () {
xde._reset(true);
var spy = sinon.spy(JSON, 'stringify');
xde.sendTo(iframe, 'test', {a: 1});
sinon.assert.calledOnce(spy);
spy.restore();
});
it('should not stringify to JSON when browser supports postMessage with objects', function () {
var spy = sinon.spy(JSON, 'stringify');
xde.sendTo(iframeWindow, 'test', {a: 1});
sinon.assert.notCalled(spy);
});
}
if (xde.onlyStringSupport === true) {
after(cleanupSpy);
it('should stringify to JSON when browser doesn\'t support postMessage with objects', function () {
var spy = this.spy = sinon.spy(JSON, 'stringify');
xde.sendTo(iframeWindow, 'test', {a: 1});
sinon.assert.calledOnce(spy);
});
}
});
suite('off', function () {
test('should not throw exception when no listeners for given event name', function () {
describe('off', function () {
it('should not throw exception when no listeners for given event name', function () {
refute.exception(function () {

@@ -270,30 +319,31 @@ xde.off('foo', function () {});

test('should remove listener for given event name', function (done) {
it('should remove listener for given event name', function (done) {
var spy = sinon.spy();
var eventName = 'foo';
childXde.on(eventName, spy);
childXde.off(eventName, spy);
iframeWindow.xde.on(eventName, spy);
iframeWindow.xde.off(eventName, spy);
xde.sendTo(iframe, eventName);
setTimeout(async(function () {
xde.sendTo(iframeWindow, eventName);
asyncAssert(function () {
sinon.assert.notCalled(spy);
}, done), 50);
}, done);
});
test('should only remove the given listener on a particular event name', function (done) {
var spy1 = sinon.spy(), spy2 = sinon.spy();
it('should only remove the given listener on a particular event name', function (done) {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
var eventName = 'foo';
childXde.on(eventName, spy1);
childXde.on(eventName, spy2);
iframeWindow.xde.on(eventName, spy1);
iframeWindow.xde.on(eventName, spy2);
childXde.off(eventName, spy1);
iframeWindow.xde.off(eventName, spy1);
xde.sendTo(iframe, eventName);
xde.sendTo(iframeWindow, eventName);
setTimeout(async(function () {
asyncAssert(function () {
sinon.assert.calledOnce(spy2);
sinon.assert.notCalled(spy1);
}, done), 50);
}, done);

@@ -303,28 +353,40 @@ });

suite('targetOrigin', function () {
test('should pass * targetOrigin to postMessage as default', function () {
xde.sendTo(iframe, 'test');
assert.equals(postMessage.getCall(0).args[1], '*');
describe('targetOrigin', function () {
it('should pass * targetOrigin to postMessage as default', function () {
xde.sendTo(iframeWindow, 'test');
assert.equals(iframeWindow.spy.getCall(0).args[1], '*');
});
test('should pass specified targetOrigin to postMessage', function () {
var TARGET_ORIGIN = 'http://test.com';
xde.targetOrigin = TARGET_ORIGIN;
xde.sendTo(iframe, 'test');
assert.equals(postMessage.getCall(0).args[1], TARGET_ORIGIN);
before(cleanupSpy);
after(cleanupSpy);
it('should pass specified targetOrigin to postMessage', function (done) {
var spy = this.spy = wrapAndSpy(window, 'postMessage');
iframeWindow.xde.targetOrigin = 'http://test.com';
iframeWindow.xde.sendTo(window, 'test', {payload: Math.random()});
asyncAssert(function(){
iframeWindow.xde.targetOrigin = '*';
assert.equals(spy.callCount, 1);
assert.equals(spy.getCall(0).args[1], 'http://test.com');
spy.restore();
}, done);
});
test('should ignore messages from unknown origins', function (done) {
it('should ignore messages from unknown origins', function (done) {
var TARGET_ORIGIN = 'http://test.com';
var EVENT_NAME = 'test';
var spy = sinon.spy();
childXde.targetOrigin = TARGET_ORIGIN;
childXde.on(EVENT_NAME, spy);
xde.sendTo(iframe, EVENT_NAME);
setTimeout(async(function() {
iframeWindow.xde.targetOrigin = TARGET_ORIGIN;
iframeWindow.xde.on(EVENT_NAME, spy);
xde.sendTo(iframeWindow, EVENT_NAME);
asyncAssert(function() {
refute.called(spy);
}, done), 50);
}, done);
});
});
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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