This repository has been archived by the owner on Apr 20, 2023. It is now read-only.
/
NixTransport.js
148 lines (145 loc) · 6.62 KB
/
NixTransport.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
/*global global, GetNixProxy, easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, isHostMethod, apply*/
/**
* @class easyXDM.stack.NixTransport
* NixTransport is a transport class that uses the strange fact that in IE <8, the window.opener property can be written to and read from all windows.<br/>
* This is used to pass methods that are able to relay messages back and forth. To avoid context-leakage a VBScript (COM) object is used to relay all the strings.<br/>
* This transport is loosely based on the work done by <a href="https://issues.apache.org/jira/browse/SHINDIG-416">Shindig</a>
* @namespace easyXDM.stack
* @constructor
* @param {Object} config The transports configuration.
* @cfg {String} remote The remote domain to communicate with.
* @cfg {String} secret the pre-shared secret used to secure the communication.
*/
easyXDM.stack.NixTransport = function(config){
// #ifdef debug
var trace = debug.getTracer("easyXDM.stack.NixMessageTransport");
trace("constructor");
// #endif
var pub, // the public interface
frame, send, targetOrigin, proxy;
return (pub = {
outgoing: function(message, domain, fn){
send(message);
fn();
},
destroy: function(){
// #ifdef debug
trace("destroy");
// #endif
proxy = null;
if (frame) {
frame.parentNode.removeChild(frame);
frame = null;
}
},
init: function(){
// #ifdef debug
trace("init");
// #endif
targetOrigin = getLocation(config.remote);
if (config.isHost) {
try {
if (!isHostMethod(window, "GetNixProxy")) {
window.execScript('Class NixProxy\n' +
' Private m_parent, m_child, m_Auth\n' +
'\n' +
' Public Sub SetParent(obj, auth)\n' +
' If isEmpty(m_Auth) Then m_Auth = auth\n' +
' SET m_parent = obj\n' +
' End Sub\n' +
' Public Sub SetChild(obj)\n' +
' SET m_child = obj\n' +
' m_parent.ready()\n' +
' End Sub\n' +
'\n' +
// The auth string, which is a pre-shared key between the parent and the child,
// and that can only be set once by the parent, secures the communication, and also serves to provide
// 'proof' of the origin of the messages.
// Before passing the message on to the recipent we convert the message into a primitive,
// this mitigates modifying .toString as an attack vector.
' Public Sub SendToParent(data, auth)\n' +
' If m_Auth = auth Then m_parent.send(CStr(data))\n' +
' End Sub\n' +
' Public Sub SendToChild(data, auth)\n' +
' If m_Auth = auth Then m_child.send(CStr(data))\n' +
' End Sub\n' +
'End Class\n' +
'Function GetNixProxy()\n' +
' Set GetNixProxy = New NixProxy\n' +
'End Function\n', 'vbscript');
}
proxy = GetNixProxy();
proxy.SetParent({
send: function(msg){
// #ifdef debug
trace("received message");
// #endif
pub.up.incoming(msg, targetOrigin);
},
ready: function(){
setTimeout(function(){
// #ifdef debug
trace("firing onReady");
// #endif
pub.up.callback(true);
}, 0);
}
}, config.secret);
send = function(msg){
// #ifdef debug
trace("sending message");
// #endif
proxy.SendToChild(msg, config.secret);
};
}
catch (e) {
throw new Error("Could not set up VBScript NixProxy:" + e.message);
}
// set up the iframe
apply(config.props, {
src: appendQueryParameters(config.remote, {
xdm_e: location.protocol + "//" + location.host,
xdm_c: config.channel,
xdm_s: config.secret,
xdm_p: 3 // 3 = NixTransport
})
});
frame = createFrame(config);
frame.contentWindow.opener = proxy;
}
else {
// by storing this in a variable we negate replacement attacks
try {
proxy = window.opener;
}
catch (e) {
throw new Error("Cannot access window.opener");
}
proxy.SetChild({
send: function(msg){
// the timeout is necessary to have execution continue in the correct context
global.setTimeout(function(){
// #ifdef debug
trace("received message");
// #endif
pub.up.incoming(msg, targetOrigin);
}, 0);
}
});
send = function(msg){
// #ifdef debug
trace("sending");
// #endif
proxy.SendToParent(msg, config.secret);
};
setTimeout(function(){
// #ifdef debug
trace("firing onReady");
// #endif
pub.up.callback(true);
}, 0);
}
}
});
};