quickblox 2.17.2-beta.2-logger → 2.17.3-logger
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +330 -201
- package/README.md +2 -2
- package/package.json +1 -2
- package/quickblox.js +19389 -21772
- package/quickblox.min.js +1 -1
- package/src/libs/strophe/strophe.common.js +6657 -0
- package/src/libs/strophe/strophe.esm.js +6649 -0
- package/src/libs/strophe/strophe.umd.js +6862 -0
- package/src/libs/strophe/strophe.umd.min.js +1 -0
- package/src/modules/chat/qbChat.js +131 -11
- package/src/modules/webrtc/qbWebRTCSignalingProcessor.js +2 -1
- package/src/modules/webrtc/qbWebRTCSignalingProvider.js +2 -1
- package/src/qbConfig.js +2 -2
- package/src/qbProxy.js +1 -1
- package/src/qbStrophe.js +2 -6
- package/strophejs-1.4.0/.eslintrc.json +264 -0
- package/strophejs-1.4.0/.gitattributes +1 -0
- package/strophejs-1.4.0/CHANGELOG.md +250 -0
- package/strophejs-1.4.0/LICENSE.txt +19 -0
- package/strophejs-1.4.0/Makefile +92 -0
- package/strophejs-1.4.0/README.md +45 -0
- package/strophejs-1.4.0/RELEASE_CHECKLIST.md +16 -0
- package/strophejs-1.4.0/contrib/discojs/README.txt +42 -0
- package/strophejs-1.4.0/contrib/discojs/css/disco.css +16 -0
- package/strophejs-1.4.0/contrib/discojs/index.html +47 -0
- package/strophejs-1.4.0/contrib/discojs/punjab.tac +18 -0
- package/strophejs-1.4.0/contrib/discojs/scripts/basic.js +102 -0
- package/strophejs-1.4.0/contrib/discojs/scripts/disco.js +60 -0
- package/strophejs-1.4.0/docs.css +797 -0
- package/strophejs-1.4.0/examples/amd.html +21 -0
- package/strophejs-1.4.0/examples/attach/README +37 -0
- package/strophejs-1.4.0/examples/attach/__init__.py +0 -0
- package/strophejs-1.4.0/examples/attach/attacher/__init__.py +0 -0
- package/strophejs-1.4.0/examples/attach/attacher/views.py +18 -0
- package/strophejs-1.4.0/examples/attach/boshclient.py +158 -0
- package/strophejs-1.4.0/examples/attach/manage.py +11 -0
- package/strophejs-1.4.0/examples/attach/settings.py +85 -0
- package/strophejs-1.4.0/examples/attach/templates/attacher/index.html +88 -0
- package/strophejs-1.4.0/examples/attach/urls.py +19 -0
- package/strophejs-1.4.0/examples/basic.html +23 -0
- package/strophejs-1.4.0/examples/basic.js +73 -0
- package/strophejs-1.4.0/examples/echobot.html +25 -0
- package/strophejs-1.4.0/examples/echobot.js +79 -0
- package/strophejs-1.4.0/examples/main.js +59 -0
- package/strophejs-1.4.0/examples/prebind.html +39 -0
- package/strophejs-1.4.0/examples/prebind.js +103 -0
- package/strophejs-1.4.0/examples/restore.html +24 -0
- package/strophejs-1.4.0/examples/restore.js +71 -0
- package/strophejs-1.4.0/package-lock.json +8631 -0
- package/strophejs-1.4.0/package.json +84 -0
- package/strophejs-1.4.0/rollup.config.js +76 -0
- package/strophejs-1.4.0/src/bosh.js +916 -0
- package/strophejs-1.4.0/src/core.js +3530 -0
- package/strophejs-1.4.0/src/md5.js +204 -0
- package/strophejs-1.4.0/src/sha1.js +172 -0
- package/strophejs-1.4.0/src/shared-connection-worker.js +114 -0
- package/strophejs-1.4.0/src/shims.js +123 -0
- package/strophejs-1.4.0/src/strophe.js +14 -0
- package/strophejs-1.4.0/src/utils.js +63 -0
- package/strophejs-1.4.0/src/websocket.js +557 -0
- package/strophejs-1.4.0/src/worker-websocket.js +150 -0
- package/strophejs-1.4.0/tests/index.html +21 -0
- package/strophejs-1.4.0/tests/main.js +49 -0
- package/strophejs-1.4.0/tests/tests.js +929 -0
- package/strophejs-1.6.1/.eslintrc.json +264 -0
- package/strophejs-1.6.1/.gitattributes +1 -0
- package/strophejs-1.6.1/.nvmrc +1 -0
- package/strophejs-1.6.1/CHANGELOG.md +288 -0
- package/strophejs-1.6.1/LICENSE.txt +19 -0
- package/strophejs-1.6.1/Makefile +92 -0
- package/strophejs-1.6.1/README.md +46 -0
- package/strophejs-1.6.1/RELEASE_CHECKLIST.md +18 -0
- package/strophejs-1.6.1/babel.config.json +10 -0
- package/strophejs-1.6.1/contrib/discojs/README.txt +42 -0
- package/strophejs-1.6.1/contrib/discojs/css/disco.css +16 -0
- package/strophejs-1.6.1/contrib/discojs/index.html +47 -0
- package/strophejs-1.6.1/contrib/discojs/punjab.tac +18 -0
- package/strophejs-1.6.1/contrib/discojs/scripts/basic.js +102 -0
- package/strophejs-1.6.1/contrib/discojs/scripts/disco.js +60 -0
- package/strophejs-1.6.1/docs.css +797 -0
- package/strophejs-1.6.1/examples/amd.html +21 -0
- package/strophejs-1.6.1/examples/attach/README +37 -0
- package/strophejs-1.6.1/examples/attach/__init__.py +0 -0
- package/strophejs-1.6.1/examples/attach/attacher/__init__.py +0 -0
- package/strophejs-1.6.1/examples/attach/attacher/views.py +18 -0
- package/strophejs-1.6.1/examples/attach/boshclient.py +158 -0
- package/strophejs-1.6.1/examples/attach/manage.py +11 -0
- package/strophejs-1.6.1/examples/attach/settings.py +85 -0
- package/strophejs-1.6.1/examples/attach/templates/attacher/index.html +88 -0
- package/strophejs-1.6.1/examples/attach/urls.py +19 -0
- package/strophejs-1.6.1/examples/basic.html +23 -0
- package/strophejs-1.6.1/examples/basic.js +73 -0
- package/strophejs-1.6.1/examples/echobot.html +25 -0
- package/strophejs-1.6.1/examples/echobot.js +79 -0
- package/strophejs-1.6.1/examples/main.js +59 -0
- package/strophejs-1.6.1/examples/prebind.html +39 -0
- package/strophejs-1.6.1/examples/prebind.js +103 -0
- package/strophejs-1.6.1/examples/restore.html +24 -0
- package/strophejs-1.6.1/examples/restore.js +71 -0
- package/strophejs-1.6.1/package-lock.json +18461 -0
- package/strophejs-1.6.1/package.json +87 -0
- package/strophejs-1.6.1/rollup.config.js +70 -0
- package/strophejs-1.6.1/src/bosh.js +916 -0
- package/strophejs-1.6.1/src/builder.js +239 -0
- package/strophejs-1.6.1/src/constants.js +155 -0
- package/strophejs-1.6.1/src/core.js +2377 -0
- package/strophejs-1.6.1/src/sasl-anon.js +17 -0
- package/strophejs-1.6.1/src/sasl-external.js +27 -0
- package/strophejs-1.6.1/src/sasl-oauthbearer.js +30 -0
- package/strophejs-1.6.1/src/sasl-plain.js +32 -0
- package/strophejs-1.6.1/src/sasl-sha1.js +24 -0
- package/strophejs-1.6.1/src/sasl-sha256.js +24 -0
- package/strophejs-1.6.1/src/sasl-sha384.js +24 -0
- package/strophejs-1.6.1/src/sasl-sha512.js +24 -0
- package/strophejs-1.6.1/src/sasl-xoauth2.js +27 -0
- package/strophejs-1.6.1/src/sasl.js +143 -0
- package/strophejs-1.6.1/src/scram.js +182 -0
- package/strophejs-1.6.1/src/shared-connection-worker.js +114 -0
- package/strophejs-1.6.1/src/shims.js +122 -0
- package/strophejs-1.6.1/src/strophe.js +15 -0
- package/strophejs-1.6.1/src/utils.js +626 -0
- package/strophejs-1.6.1/src/websocket.js +556 -0
- package/strophejs-1.6.1/src/worker-websocket.js +149 -0
- package/strophejs-1.6.1/tests.js +993 -0
|
@@ -0,0 +1,929 @@
|
|
|
1
|
+
/*global equal, notEqual, ok, module, test */
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
define([
|
|
5
|
+
'jquery',
|
|
6
|
+
'sinon',
|
|
7
|
+
'sinon-qunit',
|
|
8
|
+
'strophe'
|
|
9
|
+
], function($, sinon, sinon_qunit, wrapper) {
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Mock xhr, provides getAllResponseHeaders function.
|
|
13
|
+
* @param status
|
|
14
|
+
* @param readyState
|
|
15
|
+
* @param responseText
|
|
16
|
+
*/
|
|
17
|
+
const xhr = function (status, readyState, responseText) {
|
|
18
|
+
this.status = status;
|
|
19
|
+
this.readyState = readyState;
|
|
20
|
+
this.responseText = responseText;
|
|
21
|
+
this.getAllResponseHeaders = function () {
|
|
22
|
+
return null;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const run = function () {
|
|
27
|
+
const $build = wrapper.$build;
|
|
28
|
+
const $iq = wrapper.$iq;
|
|
29
|
+
const $msg = wrapper.$msg;
|
|
30
|
+
const $pres = wrapper.$pres;
|
|
31
|
+
const Strophe = wrapper.Strophe;
|
|
32
|
+
|
|
33
|
+
class SASLFoo extends Strophe.SASLMechanism {
|
|
34
|
+
constructor () {
|
|
35
|
+
super("FOO", false, 10);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static get name () {
|
|
39
|
+
return "FOO";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
module("Utility Methods");
|
|
45
|
+
|
|
46
|
+
test("validTag", function () {
|
|
47
|
+
/* Utility method to determine whether a tag is allowed
|
|
48
|
+
* in the XHTML_IM namespace.
|
|
49
|
+
*
|
|
50
|
+
* Used in the createHtml function to filter incoming html into the allowed XHTML-IM subset.
|
|
51
|
+
* See http://xmpp.org/extensions/xep-0071.html#profile-summary for the list of recommended
|
|
52
|
+
*/
|
|
53
|
+
// Tags must always be lower case (as per XHMTL)
|
|
54
|
+
equal(Strophe.XHTML.validTag('BODY'), false);
|
|
55
|
+
equal(Strophe.XHTML.validTag('A'), false);
|
|
56
|
+
equal(Strophe.XHTML.validTag('Img'), false);
|
|
57
|
+
equal(Strophe.XHTML.validTag('IMg'), false);
|
|
58
|
+
|
|
59
|
+
// Check all tags mentioned in XEP-0071
|
|
60
|
+
equal(Strophe.XHTML.validTag('a'), true);
|
|
61
|
+
equal(Strophe.XHTML.validTag('blockquote'), true);
|
|
62
|
+
equal(Strophe.XHTML.validTag('body'), true);
|
|
63
|
+
equal(Strophe.XHTML.validTag('br'), true);
|
|
64
|
+
equal(Strophe.XHTML.validTag('cite'), true);
|
|
65
|
+
equal(Strophe.XHTML.validTag('em'), true);
|
|
66
|
+
equal(Strophe.XHTML.validTag('img'), true);
|
|
67
|
+
equal(Strophe.XHTML.validTag('li'), true);
|
|
68
|
+
equal(Strophe.XHTML.validTag('ol'), true);
|
|
69
|
+
equal(Strophe.XHTML.validTag('p'), true);
|
|
70
|
+
equal(Strophe.XHTML.validTag('span'), true);
|
|
71
|
+
equal(Strophe.XHTML.validTag('strong'), true);
|
|
72
|
+
equal(Strophe.XHTML.validTag('ul'), true);
|
|
73
|
+
|
|
74
|
+
// Check tags not mentioned in XEP-0071
|
|
75
|
+
equal(Strophe.XHTML.validTag('script'), false);
|
|
76
|
+
equal(Strophe.XHTML.validTag('blink'), false);
|
|
77
|
+
equal(Strophe.XHTML.validTag('article'), false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("_getRequestStatus", function () {
|
|
81
|
+
const req = new Strophe.Request('', function(){});
|
|
82
|
+
req.xhr = new xhr(200, 4);
|
|
83
|
+
equal(Strophe.Bosh._getRequestStatus(req), 200, "Returns the status");
|
|
84
|
+
req.xhr = new xhr(500, 4);
|
|
85
|
+
equal(Strophe.Bosh._getRequestStatus(req), 500,
|
|
86
|
+
"Returns the default if the request is not finished yet");
|
|
87
|
+
|
|
88
|
+
req.xhr = new xhr(200, 3);
|
|
89
|
+
equal(Strophe.Bosh._getRequestStatus(req), 0,
|
|
90
|
+
"Returns the default if the request is not finished yet");
|
|
91
|
+
|
|
92
|
+
req.xhr = new xhr(undefined, 4);
|
|
93
|
+
equal(Strophe.Bosh._getRequestStatus(req, -1), -1,
|
|
94
|
+
"Returns the default if the request doesn't have a status");
|
|
95
|
+
|
|
96
|
+
equal(Strophe.Bosh._getRequestStatus(req, 0), 0,
|
|
97
|
+
"Returns the default if the request doesn't have a status");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
module("JIDs");
|
|
101
|
+
|
|
102
|
+
test("Normal JID", function () {
|
|
103
|
+
var jid = "darcy@pemberley.lit/library";
|
|
104
|
+
equal(Strophe.getNodeFromJid(jid), "darcy",
|
|
105
|
+
"Node should be 'darcy'");
|
|
106
|
+
equal(Strophe.getDomainFromJid(jid), "pemberley.lit",
|
|
107
|
+
"Domain should be 'pemberley.lit'");
|
|
108
|
+
equal(Strophe.getResourceFromJid(jid), "library",
|
|
109
|
+
"Node should be 'library'");
|
|
110
|
+
equal(Strophe.getBareJidFromJid(jid),
|
|
111
|
+
"darcy@pemberley.lit",
|
|
112
|
+
"Bare JID should be 'darcy@pemberley.lit'");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("Weird node (unescaped)", function () {
|
|
116
|
+
var jid = "darcy@netherfield.lit@pemberley.lit/library";
|
|
117
|
+
equal(Strophe.getNodeFromJid(jid), "darcy",
|
|
118
|
+
"Node should be 'darcy'");
|
|
119
|
+
equal(Strophe.getDomainFromJid(jid),
|
|
120
|
+
"netherfield.lit@pemberley.lit",
|
|
121
|
+
"Domain should be 'netherfield.lit@pemberley.lit'");
|
|
122
|
+
equal(Strophe.getResourceFromJid(jid), "library",
|
|
123
|
+
"Resource should be 'library'");
|
|
124
|
+
equal(Strophe.getBareJidFromJid(jid),
|
|
125
|
+
"darcy@netherfield.lit@pemberley.lit",
|
|
126
|
+
"Bare JID should be 'darcy@netherfield.lit@pemberley.lit'");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("Weird node (escaped)", function () {
|
|
130
|
+
var escapedNode = Strophe.escapeNode("darcy@netherfield.lit");
|
|
131
|
+
var jid = escapedNode + "@pemberley.lit/library";
|
|
132
|
+
equal(Strophe.getNodeFromJid(jid), "darcy\\40netherfield.lit",
|
|
133
|
+
"Node should be 'darcy\\40netherfield.lit'");
|
|
134
|
+
equal(Strophe.getDomainFromJid(jid),
|
|
135
|
+
"pemberley.lit",
|
|
136
|
+
"Domain should be 'pemberley.lit'");
|
|
137
|
+
equal(Strophe.getResourceFromJid(jid), "library",
|
|
138
|
+
"Resource should be 'library'");
|
|
139
|
+
equal(Strophe.getBareJidFromJid(jid),
|
|
140
|
+
"darcy\\40netherfield.lit@pemberley.lit",
|
|
141
|
+
"Bare JID should be 'darcy\\40netherfield.lit@pemberley.lit'");
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("Weird resource", function () {
|
|
145
|
+
var jid = "books@chat.pemberley.lit/darcy@pemberley.lit/library";
|
|
146
|
+
equal(Strophe.getNodeFromJid(jid), "books",
|
|
147
|
+
"Node should be 'books'");
|
|
148
|
+
equal(Strophe.getDomainFromJid(jid), "chat.pemberley.lit",
|
|
149
|
+
"Domain should be 'chat.pemberley.lit'");
|
|
150
|
+
equal(Strophe.getResourceFromJid(jid),
|
|
151
|
+
"darcy@pemberley.lit/library",
|
|
152
|
+
"Resource should be 'darcy@pemberley.lit/library'");
|
|
153
|
+
equal(Strophe.getBareJidFromJid(jid),
|
|
154
|
+
"books@chat.pemberley.lit",
|
|
155
|
+
"Bare JID should be 'books@chat.pemberley.lit'");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
module("Builder");
|
|
159
|
+
|
|
160
|
+
test("The root() method", function () {
|
|
161
|
+
var builder = new Strophe.Builder('root');
|
|
162
|
+
var el = builder.c('child').c('grandchild').c('greatgrandchild').root();
|
|
163
|
+
equal(el.node.nodeName, 'root', 'root() jump back to the root of the tree');
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("Correct namespace (#32)", function () {
|
|
167
|
+
var stanzas = [new Strophe.Builder("message", {foo: "asdf"}).tree(),
|
|
168
|
+
$build("iq", {}).tree(),
|
|
169
|
+
$pres().tree()];
|
|
170
|
+
$.each(stanzas, function () {
|
|
171
|
+
equal($(this).attr('xmlns'), Strophe.NS.CLIENT,
|
|
172
|
+
"Namespace should be '" + Strophe.NS.CLIENT + "'");
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test("Strophe.Connection.prototype.send() accepts Builders (#27)", function () {
|
|
177
|
+
var stanza = $pres();
|
|
178
|
+
var conn = new Strophe.Connection("");
|
|
179
|
+
var sendStub = sinon.stub(XMLHttpRequest.prototype, "send");
|
|
180
|
+
var timeoutStub = sinon.stub(window, "setTimeout", function (func) {
|
|
181
|
+
// Stub setTimeout to immediately call functions, otherwise our
|
|
182
|
+
// assertions fail due to async execution.
|
|
183
|
+
func.apply(arguments);
|
|
184
|
+
});
|
|
185
|
+
conn.send(stanza);
|
|
186
|
+
equal(sendStub.called, true, "XMLHttpRequest.send was called");
|
|
187
|
+
sendStub.restore();
|
|
188
|
+
timeoutStub.restore();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
module("Strophe.Connection options");
|
|
192
|
+
|
|
193
|
+
test("withCredentials can be set on the XMLHttpRequest object", function () {
|
|
194
|
+
var stanza = $pres();
|
|
195
|
+
// Stub XMLHttpRequest.protototype.send so that it doesn't
|
|
196
|
+
// actually try to send out the request.
|
|
197
|
+
var sendStub = sinon.stub(XMLHttpRequest.prototype, "send");
|
|
198
|
+
// Stub setTimeout to immediately call functions, otherwise our
|
|
199
|
+
// assertions fail due to async execution.
|
|
200
|
+
var timeoutStub = sinon.stub(window, "setTimeout", function (func) {
|
|
201
|
+
func.apply(arguments);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
var conn = new Strophe.Connection("example.org");
|
|
205
|
+
conn.send(stanza);
|
|
206
|
+
equal(sendStub.called, true);
|
|
207
|
+
equal(sendStub.getCalls()[0].thisValue.withCredentials, false);
|
|
208
|
+
|
|
209
|
+
conn = new Strophe.Connection(
|
|
210
|
+
"example.org",
|
|
211
|
+
{ "withCredentials": true });
|
|
212
|
+
conn.send(stanza);
|
|
213
|
+
equal(sendStub.called, true);
|
|
214
|
+
equal(sendStub.getCalls()[1].thisValue.withCredentials, true);
|
|
215
|
+
sendStub.restore();
|
|
216
|
+
timeoutStub.restore();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test("content type can be set on the XMLHttpRequest object", function () {
|
|
220
|
+
var stanza = $pres();
|
|
221
|
+
// Stub XMLHttpRequest.protototype.send so that it doesn't
|
|
222
|
+
// actually try to send out the request.
|
|
223
|
+
var sendStub = sinon.stub(XMLHttpRequest.prototype, "send");
|
|
224
|
+
// Stub setTimeout to immediately call functions, otherwise our
|
|
225
|
+
// assertions fail due to async execution.
|
|
226
|
+
var timeoutStub = sinon.stub(window, "setTimeout", function (func) {
|
|
227
|
+
func.apply(arguments);
|
|
228
|
+
});
|
|
229
|
+
var setRetRequestHeaderStub = sinon.stub(XMLHttpRequest.prototype, "setRequestHeader");
|
|
230
|
+
var conn = new Strophe.Connection("example.org");
|
|
231
|
+
conn.send(stanza);
|
|
232
|
+
equal(setRetRequestHeaderStub.getCalls()[0].args[0], "Content-Type");
|
|
233
|
+
equal(setRetRequestHeaderStub.getCalls()[0].args[1], "text/xml; charset=utf-8");
|
|
234
|
+
|
|
235
|
+
conn = new Strophe.Connection(
|
|
236
|
+
"example.org",
|
|
237
|
+
{ contentType: "text/plain; charset=utf-8" });
|
|
238
|
+
conn.send(stanza);
|
|
239
|
+
equal(setRetRequestHeaderStub.getCalls()[1].args[0], "Content-Type");
|
|
240
|
+
equal(setRetRequestHeaderStub.getCalls()[1].args[1], "text/plain; charset=utf-8");
|
|
241
|
+
sendStub.restore();
|
|
242
|
+
timeoutStub.restore();
|
|
243
|
+
setRetRequestHeaderStub.restore();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("Cookies can be added to the document passing them as options to Strophe.Connection", function () {
|
|
247
|
+
var stanza = $pres();
|
|
248
|
+
var conn = new Strophe.Connection(
|
|
249
|
+
"localhost",
|
|
250
|
+
{ "cookies": {
|
|
251
|
+
"_xxx": {
|
|
252
|
+
"value": "1234",
|
|
253
|
+
"path": "/",
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
notEqual(document.cookie.indexOf('_xxx'), -1);
|
|
258
|
+
var start = document.cookie.indexOf('_xxx');
|
|
259
|
+
var end = document.cookie.indexOf(";", start);
|
|
260
|
+
end = end == -1 ? document.cookie.length : end;
|
|
261
|
+
equal(document.cookie.substring(start, end), '_xxx=1234');
|
|
262
|
+
|
|
263
|
+
// Also test when passing only a string
|
|
264
|
+
conn = new Strophe.Connection(
|
|
265
|
+
"localhost",
|
|
266
|
+
{ "cookies": { "_yyy": "4321" },
|
|
267
|
+
"withCredentials": true
|
|
268
|
+
});
|
|
269
|
+
notEqual(document.cookie.indexOf('_yyy'), -1);
|
|
270
|
+
start = document.cookie.indexOf('_yyy');
|
|
271
|
+
end = document.cookie.indexOf(";", start);
|
|
272
|
+
end = end == -1 ? document.cookie.length : end;
|
|
273
|
+
equal(document.cookie.substring(start, end), '_yyy=4321');
|
|
274
|
+
|
|
275
|
+
// Stub XMLHttpRequest.protototype.send so that it doesn't
|
|
276
|
+
// actually try to send out the request.
|
|
277
|
+
var sendStub = sinon.stub(XMLHttpRequest.prototype, "send");
|
|
278
|
+
// Stub setTimeout to immediately call functions, otherwise our
|
|
279
|
+
// assertions fail due to async execution.
|
|
280
|
+
var timeoutStub = sinon.stub(window, "setTimeout", function (func) {
|
|
281
|
+
func.apply(arguments);
|
|
282
|
+
});
|
|
283
|
+
conn.send(stanza);
|
|
284
|
+
// Unfortunately there's no way to test the headers set in the
|
|
285
|
+
// request (only in the response). They can however be checked with
|
|
286
|
+
// the browser's developer tools.
|
|
287
|
+
equal(sendStub.called, true);
|
|
288
|
+
sendStub.restore();
|
|
289
|
+
timeoutStub.restore();
|
|
290
|
+
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
test("send() does not accept strings", function () {
|
|
294
|
+
const stanza = "<presence/>";
|
|
295
|
+
const conn = new Strophe.Connection("");
|
|
296
|
+
// fake connection callback to avoid errors
|
|
297
|
+
conn.connect_callback = function () {};
|
|
298
|
+
try {
|
|
299
|
+
conn.send(stanza);
|
|
300
|
+
} catch (e) {
|
|
301
|
+
equal(e.name, "StropheError", "send() should throw exception");
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
test("Builder with XML attribute escaping test", function () {
|
|
306
|
+
var text = "<b>";
|
|
307
|
+
var expected = '<presence to="<b>" xmlns="jabber:client"/>';
|
|
308
|
+
var pres = $pres({to: text});
|
|
309
|
+
equal(pres.toString(), expected, "< should be escaped");
|
|
310
|
+
|
|
311
|
+
text = "foo&bar";
|
|
312
|
+
expected = '<presence to="foo&bar" xmlns="jabber:client"/>';
|
|
313
|
+
pres = $pres({to: text});
|
|
314
|
+
equal(pres.toString(), expected, "& should be escaped");
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test("c() accepts text and passes it to xmlElement", function () {
|
|
318
|
+
var pres = $pres({from: "darcy@pemberley.lit", to: "books@chat.pemberley.lit"})
|
|
319
|
+
.c("nick", {xmlns: "http://jabber.org/protocol/nick"}, "Darcy");
|
|
320
|
+
var expected = '<presence from="darcy@pemberley.lit" to="books@chat.pemberley.lit" xmlns="jabber:client">'+
|
|
321
|
+
'<nick xmlns="http://jabber.org/protocol/nick">Darcy</nick>'+
|
|
322
|
+
'</presence>';
|
|
323
|
+
equal(pres.toString(), expected, "'Darcy' should be a child of <presence>");
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test("c() return the child element if it is a text node.", function () {
|
|
327
|
+
// See this issue: https://github.com/strophe/strophejs/issues/124
|
|
328
|
+
|
|
329
|
+
var pres = $pres({from: "darcy@pemberley.lit", to: "books@chat.pemberley.lit"})
|
|
330
|
+
.c("show", {}, "dnd")
|
|
331
|
+
.c("status", {}, "In a meeting");
|
|
332
|
+
var expected = '<presence from="darcy@pemberley.lit" to="books@chat.pemberley.lit" xmlns="jabber:client">'+
|
|
333
|
+
'<show>dnd</show><status>In a meeting</status>'+
|
|
334
|
+
'</presence>';
|
|
335
|
+
equal(pres.toString(), expected, "");
|
|
336
|
+
|
|
337
|
+
pres = $pres({from: "darcy@pemberley.lit", to: "books@chat.pemberley.lit"})
|
|
338
|
+
.c("show", {}, "")
|
|
339
|
+
.c("status", {}, "");
|
|
340
|
+
expected = '<presence from="darcy@pemberley.lit" to="books@chat.pemberley.lit" xmlns="jabber:client">'+
|
|
341
|
+
'<show/><status/>'+
|
|
342
|
+
'</presence>';
|
|
343
|
+
equal(pres.toString(), expected, "");
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
module("XML");
|
|
347
|
+
|
|
348
|
+
test("XML escaping test", function () {
|
|
349
|
+
var text = "s & p";
|
|
350
|
+
var textNode = Strophe.xmlTextNode(text);
|
|
351
|
+
equal(Strophe.getText(textNode), "s & p", "should be escaped");
|
|
352
|
+
var text0 = "s < & > p";
|
|
353
|
+
var textNode0 = Strophe.xmlTextNode(text0);
|
|
354
|
+
equal(Strophe.getText(textNode0), "s < & > p", "should be escaped");
|
|
355
|
+
var text1 = "s's or \"p\"";
|
|
356
|
+
var textNode1 = Strophe.xmlTextNode(text1);
|
|
357
|
+
equal(Strophe.getText(textNode1), "s's or "p"", "should be escaped");
|
|
358
|
+
var text2 = "<![CDATA[<foo>]]>";
|
|
359
|
+
var textNode2 = Strophe.xmlTextNode(text2);
|
|
360
|
+
equal(Strophe.getText(textNode2), "<![CDATA[<foo>]]>", "should be escaped");
|
|
361
|
+
var text3 = "<![CDATA[]]]]><![CDATA[>]]>";
|
|
362
|
+
var textNode3 = Strophe.xmlTextNode(text3);
|
|
363
|
+
equal(Strophe.getText(textNode3), "<![CDATA[]]]]><![CDATA[>]]>", "should be escaped");
|
|
364
|
+
var text4 = "<foo><![CDATA[<foo>]]>";
|
|
365
|
+
var textNode4 = Strophe.xmlTextNode(text4);
|
|
366
|
+
equal(Strophe.getText(textNode4), "&lt;foo&gt;<![CDATA[<foo>]]>", "should be escaped");
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
test("XML element creation", function () {
|
|
370
|
+
var elem = Strophe.xmlElement("message");
|
|
371
|
+
equal(elem.tagName, "message", "Element name should be the same");
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
test("copyElement() double escape bug", function() {
|
|
375
|
+
var cloned = Strophe.copyElement(Strophe.xmlGenerator()
|
|
376
|
+
.createTextNode('<><>'));
|
|
377
|
+
equal(cloned.nodeValue, '<><>');
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
test("XML serializing", function() {
|
|
381
|
+
var parser = new DOMParser();
|
|
382
|
+
// Attributes
|
|
383
|
+
var element1 = parser.parseFromString("<foo attr1='abc' attr2='edf'>bar</foo>", "text/xml").documentElement;
|
|
384
|
+
equal(Strophe.serialize(element1), '<foo attr1="abc" attr2="edf">bar</foo>', 'should be serialized');
|
|
385
|
+
var element2 = parser.parseFromString("<foo attr1=\"abc\" attr2=\"edf\">bar</foo>","text/xml").documentElement;
|
|
386
|
+
equal(Strophe.serialize(element2), '<foo attr1="abc" attr2="edf">bar</foo>', 'should be serialized');
|
|
387
|
+
// Escaping values
|
|
388
|
+
var element3 = parser.parseFromString("<foo>a > 'b' & "b" < c</foo>","text/xml").documentElement;
|
|
389
|
+
equal(Strophe.serialize(element3), '<foo>a > 'b' & "b" < c</foo>', 'should be serialized');
|
|
390
|
+
// Escaping attributes
|
|
391
|
+
var element4 = parser.parseFromString("<foo attr='<a> 'b''>bar</foo>","text/xml").documentElement;
|
|
392
|
+
equal(Strophe.serialize(element4), '<foo attr="<a> 'b'">bar</foo>', 'should be serialized');
|
|
393
|
+
var element5 = parser.parseFromString("<foo attr=\"<a> "b"\">bar</foo>","text/xml").documentElement;
|
|
394
|
+
equal(Strophe.serialize(element5), '<foo attr="<a> "b"">bar</foo>', 'should be serialized');
|
|
395
|
+
// Empty elements
|
|
396
|
+
var element6 = parser.parseFromString("<foo><empty></empty></foo>","text/xml").documentElement;
|
|
397
|
+
equal(Strophe.serialize(element6), "<foo><empty/></foo>", "should be serialized");
|
|
398
|
+
// Children
|
|
399
|
+
var element7 = parser.parseFromString("<foo><bar>a</bar><baz><wibble>b</wibble></baz></foo>","text/xml").documentElement;
|
|
400
|
+
equal(Strophe.serialize(element7), "<foo><bar>a</bar><baz><wibble>b</wibble></baz></foo>", "should be serialized");
|
|
401
|
+
var element8 = parser.parseFromString("<foo><bar>a</bar><baz>b<wibble>c</wibble>d</baz></foo>","text/xml").documentElement;
|
|
402
|
+
equal(Strophe.serialize(element8), "<foo><bar>a</bar><baz>b<wibble>c</wibble>d</baz></foo>", "should be serialized");
|
|
403
|
+
// CDATA
|
|
404
|
+
var element9 = parser.parseFromString("<foo><![CDATA[<foo>]]></foo>","text/xml").documentElement;
|
|
405
|
+
equal(Strophe.serialize(element9), "<foo><![CDATA[<foo>]]></foo>", "should be serialized");
|
|
406
|
+
var element10 = parser.parseFromString("<foo><![CDATA[]]]]><![CDATA[>]]></foo>","text/xml").documentElement;
|
|
407
|
+
equal(Strophe.serialize(element10), "<foo><![CDATA[]]]]><![CDATA[>]]></foo>", "should be serialized");
|
|
408
|
+
var element11 = parser.parseFromString("<foo><foo><![CDATA[<foo>]]></foo>","text/xml").documentElement;
|
|
409
|
+
equal(Strophe.serialize(element11), "<foo><foo><![CDATA[<foo>]]></foo>", "should be serialized");
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
module("Handler");
|
|
413
|
+
|
|
414
|
+
test("HTTP errors", function () {
|
|
415
|
+
var spy500 = sinon.spy();
|
|
416
|
+
var spy401 = sinon.spy();
|
|
417
|
+
var conn = new Strophe.Connection("http://fake");
|
|
418
|
+
conn.addProtocolErrorHandler('HTTP', 500, spy500);
|
|
419
|
+
conn.addProtocolErrorHandler('HTTP', 401, spy401);
|
|
420
|
+
var req = new Strophe.Request('', function(){});
|
|
421
|
+
req.xhr = new xhr(200, 4);
|
|
422
|
+
conn._proto._onRequestStateChange(function () {}, req);
|
|
423
|
+
equal(spy500.called, false, "Error handler does not get called when no HTTP error");
|
|
424
|
+
equal(spy401.called, false, "Error handler does not get called when no HTTP error");
|
|
425
|
+
|
|
426
|
+
req.xhr = new xhr(401, 4);
|
|
427
|
+
conn._proto._onRequestStateChange(function () {}, req);
|
|
428
|
+
equal(spy500.called, false, "Error handler does not get called when no HTTP 500 error");
|
|
429
|
+
equal(spy401.called, true, "Error handler does get called when HTTP 401 error");
|
|
430
|
+
|
|
431
|
+
req.xhr = new xhr(500, 4);
|
|
432
|
+
conn._proto._onRequestStateChange(function () {}, req);
|
|
433
|
+
equal(spy500.called, true, "Error handler gets called on HTTP 500 error");
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
test("Full JID matching", function () {
|
|
437
|
+
var elem = $msg({from: 'darcy@pemberley.lit/library'}).tree();
|
|
438
|
+
|
|
439
|
+
var hand = new Strophe.Handler(null, null, null, null, null,
|
|
440
|
+
'darcy@pemberley.lit/library');
|
|
441
|
+
equal(hand.isMatch(elem), true, "Full JID should match");
|
|
442
|
+
|
|
443
|
+
hand = new Strophe.Handler(null, null, null, null, null,
|
|
444
|
+
'darcy@pemberley.lit');
|
|
445
|
+
equal(hand.isMatch(elem), false, "Bare JID shouldn't match");
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
test("Bare JID matching", function () {
|
|
449
|
+
var elem = $msg({from: 'darcy@pemberley.lit/library'}).tree();
|
|
450
|
+
|
|
451
|
+
var hand = new Strophe.Handler(null, null, null, null, null,
|
|
452
|
+
'darcy@pemberley.lit/library',
|
|
453
|
+
{matchBareFromJid: true});
|
|
454
|
+
equal(hand.isMatch(elem), true, "Full JID should match");
|
|
455
|
+
|
|
456
|
+
hand = new Strophe.Handler(null, null, null, null, null,
|
|
457
|
+
'darcy@pemberley.lit',
|
|
458
|
+
{matchBareFromJid: true});
|
|
459
|
+
equal(hand.isMatch(elem), true, "Bare JID should match");
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
test("Namespace matching", function () {
|
|
463
|
+
var elemNoFrag = $msg({xmlns: 'http://jabber.org/protocol/muc'}).tree();
|
|
464
|
+
var elemWithFrag = $msg({xmlns: 'http://jabber.org/protocol/muc#user'}).tree();
|
|
465
|
+
var hand = new Strophe.Handler(
|
|
466
|
+
null, 'http://jabber.org/protocol/muc',
|
|
467
|
+
null, null, null, null
|
|
468
|
+
);
|
|
469
|
+
equal(hand.isMatch(elemNoFrag), true, "The handler should match on stanza namespace");
|
|
470
|
+
equal(hand.isMatch(elemWithFrag), false, "The handler should not match on stanza namespace with fragment");
|
|
471
|
+
|
|
472
|
+
hand = new Strophe.Handler(
|
|
473
|
+
null, 'http://jabber.org/protocol/muc',
|
|
474
|
+
null, null, null, null,
|
|
475
|
+
{'ignoreNamespaceFragment': true}
|
|
476
|
+
);
|
|
477
|
+
equal(hand.isMatch(elemNoFrag), true, "The handler should match on stanza namespace");
|
|
478
|
+
equal(hand.isMatch(elemWithFrag), true, "The handler should match on stanza namespace, even with fragment");
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test("Stanza name matching", function () {
|
|
482
|
+
var elem = $iq().tree();
|
|
483
|
+
var hand = new Strophe.Handler(null, null, 'iq');
|
|
484
|
+
equal(hand.isMatch(elem), true, "The handler should match on stanza name");
|
|
485
|
+
|
|
486
|
+
hand = new Strophe.Handler(null, null, 'message');
|
|
487
|
+
notEqual(hand.isMatch(elem), true, "The handler should not match wrong stanza name");
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
test("Stanza type matching", function () {
|
|
491
|
+
var elem = $iq({type: 'error'}).tree();
|
|
492
|
+
var hand = new Strophe.Handler(null, null, 'iq', 'error');
|
|
493
|
+
equal(hand.isMatch(elem), true, "The handler should match on stanza type");
|
|
494
|
+
|
|
495
|
+
hand = new Strophe.Handler(null, null, 'iq', 'result');
|
|
496
|
+
notEqual(hand.isMatch(elem), true, "The handler should not match wrong stanza type");
|
|
497
|
+
|
|
498
|
+
hand = new Strophe.Handler(null, null, 'iq', ['error', 'result']);
|
|
499
|
+
equal(hand.isMatch(elem), true, "The handler should match if stanza type is in array of types");
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
module("Misc");
|
|
503
|
+
|
|
504
|
+
test("Function binding", function () {
|
|
505
|
+
var spy = sinon.spy();
|
|
506
|
+
var obj = {};
|
|
507
|
+
var arg1 = "foo";
|
|
508
|
+
var arg2 = "bar";
|
|
509
|
+
var arg3 = "baz";
|
|
510
|
+
|
|
511
|
+
var f = spy.bind(obj, arg1, arg2);
|
|
512
|
+
f(arg3);
|
|
513
|
+
equal(spy.called, true, "bound function should be called");
|
|
514
|
+
equal(spy.calledOn(obj), true,
|
|
515
|
+
"bound function should have correct context");
|
|
516
|
+
equal(spy.alwaysCalledWithExactly(arg1, arg2, arg3),
|
|
517
|
+
true,
|
|
518
|
+
"bound function should get all arguments");
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
test("Connfail for invalid XML", function () {
|
|
522
|
+
var req = new Strophe.Request('', function(){});
|
|
523
|
+
req.xhr = new xhr(undefined, undefined, 'text')
|
|
524
|
+
|
|
525
|
+
var conn = new Strophe.Connection("http://fake");
|
|
526
|
+
conn.connect_callback = function (status, condition) {
|
|
527
|
+
if (status === Strophe.Status.CONNFAIL) {
|
|
528
|
+
equal(condition, "bad-format", "connection should fail with condition bad-format");
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
conn._connect_cb(req);
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
module("XHR error handling");
|
|
535
|
+
|
|
536
|
+
// Note that these tests are pretty dependent on the actual code.
|
|
537
|
+
|
|
538
|
+
test("Aborted requests do nothing", function () {
|
|
539
|
+
Strophe.Connection.prototype._onIdle = function () {};
|
|
540
|
+
var conn = new Strophe.Connection("http://fake");
|
|
541
|
+
|
|
542
|
+
// simulate a finished but aborted request
|
|
543
|
+
var req = {id: 43,
|
|
544
|
+
sends: 1,
|
|
545
|
+
xhr: new xhr(undefined, 4),
|
|
546
|
+
abort: true};
|
|
547
|
+
|
|
548
|
+
conn._requests = [req];
|
|
549
|
+
var spy = sinon.spy();
|
|
550
|
+
conn._proto._onRequestStateChange(spy, req);
|
|
551
|
+
|
|
552
|
+
equal(req.abort, false, "abort flag should be toggled");
|
|
553
|
+
equal(conn._requests.length, 1, "_requests should be same length");
|
|
554
|
+
equal(spy.called, false, "callback should not be called");
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
test("Incomplete requests do nothing", function () {
|
|
558
|
+
Strophe.Connection.prototype._onIdle = function () {};
|
|
559
|
+
const conn = new Strophe.Connection("http://fake");
|
|
560
|
+
// simulate a finished but aborted request
|
|
561
|
+
const req = {id: 44,
|
|
562
|
+
sends: 1,
|
|
563
|
+
xhr: new xhr(undefined, 3)
|
|
564
|
+
};
|
|
565
|
+
conn._requests = [req];
|
|
566
|
+
const spy = sinon.spy();
|
|
567
|
+
conn._proto._onRequestStateChange(spy, req);
|
|
568
|
+
equal(conn._requests.length, 1, "_requests should be same length");
|
|
569
|
+
equal(spy.called, false, "callback should not be called");
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
module("SASL Mechanisms");
|
|
573
|
+
|
|
574
|
+
test("Default mechanisms will be registered if none are provided", function () {
|
|
575
|
+
const conn = new Strophe.Connection('localhost');
|
|
576
|
+
equal(Object.keys(conn.mechanisms).length, 6, 'Seven by default registered SASL mechanisms');
|
|
577
|
+
equal('ANONYMOUS' in conn.mechanisms, true, 'ANONYMOUS is registered');
|
|
578
|
+
equal('EXTERNAL' in conn.mechanisms, true, 'EXTERNAL is registered');
|
|
579
|
+
equal('OAUTHBEARER' in conn.mechanisms, true, 'OAUTHBEARER is registered');
|
|
580
|
+
equal('PLAIN' in conn.mechanisms, true, 'PLAIN is registered');
|
|
581
|
+
equal('SCRAM-SHA-1' in conn.mechanisms, true, 'SCRAM-SHA-1 is registered');
|
|
582
|
+
equal('X-OAUTH2' in conn.mechanisms, true, 'X-OAUTH2 is registered');
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
test("Custom mechanisms be specified when instantiating Strophe.Connection", function () {
|
|
586
|
+
let conn = new Strophe.Connection('localhost', {'mechanisms': [SASLFoo]});
|
|
587
|
+
equal(Object.keys(conn.mechanisms).length, 1, 'Only one registered SASL mechanism');
|
|
588
|
+
equal('FOO' in conn.mechanisms, true, 'FOO is registered');
|
|
589
|
+
notEqual('PLAIN' in conn.mechanisms, true, 'PLAIN is not registered');
|
|
590
|
+
|
|
591
|
+
conn = new Strophe.Connection('localhost',
|
|
592
|
+
{ 'mechanisms': [
|
|
593
|
+
SASLFoo,
|
|
594
|
+
Strophe.SASLPlain
|
|
595
|
+
]});
|
|
596
|
+
equal(Object.keys(conn.mechanisms).length, 2, 'Only two registered SASL mechanisms');
|
|
597
|
+
equal('FOO' in conn.mechanisms, true, 'FOO is registered');
|
|
598
|
+
equal('PLAIN' in conn.mechanisms, true, 'PLAIN is registered');
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
test("The supported mechanism with the highest priority will be used", function () {
|
|
602
|
+
Strophe.SASLExternal.prototype.priority = 10;
|
|
603
|
+
Strophe.SASLSHA1.prototype.priority = 20;
|
|
604
|
+
const conn = new Strophe.Connection('localhost',
|
|
605
|
+
{ 'mechanisms': [
|
|
606
|
+
Strophe.SASLSHA1,
|
|
607
|
+
Strophe.SASLExternal
|
|
608
|
+
]});
|
|
609
|
+
const authSpy = sinon.spy(conn, '_attemptSASLAuth');
|
|
610
|
+
equal(authSpy.called, false);
|
|
611
|
+
conn.connect('dummy@localhost', 'secret');
|
|
612
|
+
|
|
613
|
+
const mechanisms = Object.values(conn.mechanisms);
|
|
614
|
+
conn.authenticate(mechanisms);
|
|
615
|
+
equal(authSpy.called, true);
|
|
616
|
+
equal(authSpy.returnValues.length, 1);
|
|
617
|
+
equal(authSpy.returnValues[0], true);
|
|
618
|
+
equal(conn._sasl_mechanism.mechname, 'SCRAM-SHA-1');
|
|
619
|
+
|
|
620
|
+
mechanisms[0].priority = 20;
|
|
621
|
+
mechanisms[1].priority = 30;
|
|
622
|
+
conn.connect('dummy@localhost', 'secret');
|
|
623
|
+
conn.authenticate(Object.values(mechanisms));
|
|
624
|
+
equal(conn._sasl_mechanism.mechname, 'EXTERNAL');
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
test("SASL PLAIN Auth", function () {
|
|
628
|
+
const conn = {pass: "password", authcid: "user", authzid: "user@xmpp.org", domain: "xmpp.org"};
|
|
629
|
+
const saslplain = new Strophe.SASLPlain();
|
|
630
|
+
saslplain.onStart(conn);
|
|
631
|
+
ok(saslplain.test(conn), "PLAIN is enabled by default.");
|
|
632
|
+
const response = saslplain.onChallenge(conn);
|
|
633
|
+
equal(response, ['', conn.authcid, conn.pass].join("\u0000"),
|
|
634
|
+
"checking plain auth challenge");
|
|
635
|
+
saslplain.onSuccess();
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
test("SASL PLAIN Auth with authzid", function () {
|
|
639
|
+
const conn = {pass: "password", authcid: "user", authzid: "admin@xmpp.org", domain: "xmpp.org"};
|
|
640
|
+
const saslplain = new Strophe.SASLPlain();
|
|
641
|
+
saslplain.onStart(conn);
|
|
642
|
+
ok(saslplain.test(conn), "PLAIN is enabled by default.");
|
|
643
|
+
const response = saslplain.onChallenge(conn, null);
|
|
644
|
+
equal(response, [conn.authzid, conn.authcid, conn.pass].join("\u0000"),
|
|
645
|
+
"checking plain auth challenge");
|
|
646
|
+
saslplain.onSuccess();
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
test("SASL SCRAM-SHA-1 Auth", function () {
|
|
650
|
+
/* This is a simple example of a SCRAM-SHA-1 authentication exchange
|
|
651
|
+
* when the client doesn't support channel bindings (username 'user' and
|
|
652
|
+
* password 'pencil' are used):
|
|
653
|
+
*
|
|
654
|
+
* C: n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
|
|
655
|
+
* S: r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,
|
|
656
|
+
* i=4096
|
|
657
|
+
* C: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,
|
|
658
|
+
* p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=
|
|
659
|
+
* S: v=rmF9pqV8S7suAoZWja4dJRkFsKQ=
|
|
660
|
+
*
|
|
661
|
+
*/
|
|
662
|
+
const conn = {
|
|
663
|
+
pass: "pencil",
|
|
664
|
+
authcid: "user",
|
|
665
|
+
authzid: "user@xmpp.org",
|
|
666
|
+
_sasl_data: []
|
|
667
|
+
};
|
|
668
|
+
const saslsha1 = new Strophe.SASLSHA1();
|
|
669
|
+
saslsha1.onStart(conn);
|
|
670
|
+
ok(saslsha1.test(conn), "SHA-1 is enabled by default.");
|
|
671
|
+
// test taken from example section on:
|
|
672
|
+
// URL: http://tools.ietf.org/html/rfc5802#section-5
|
|
673
|
+
let response = saslsha1.onChallenge(conn, null, "fyko+d2lbbFgONRv9qkxdawL");
|
|
674
|
+
equal(response, "n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL", "checking first auth challenge");
|
|
675
|
+
|
|
676
|
+
response = saslsha1.onChallenge(conn, "r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096");
|
|
677
|
+
equal(response, "c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=",
|
|
678
|
+
"checking second auth challenge");
|
|
679
|
+
saslsha1.onSuccess();
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
test("SASL EXTERNAL Auth", function () {
|
|
683
|
+
let conn = {pass: "password", authcid: "user", authzid: "user@xmpp.org"};
|
|
684
|
+
let sasl_external = new Strophe.SASLExternal();
|
|
685
|
+
ok(sasl_external.test(conn), "EXTERNAL is enabled by default.");
|
|
686
|
+
sasl_external.onStart(conn);
|
|
687
|
+
|
|
688
|
+
let response = sasl_external.onChallenge(conn, null);
|
|
689
|
+
equal(response, conn.authzid,
|
|
690
|
+
"Response to EXTERNAL auth challenge should be authzid if different authcid was passed in.");
|
|
691
|
+
sasl_external.onSuccess();
|
|
692
|
+
|
|
693
|
+
conn = {pass: "password", authcid: "user", authzid: "user@xmpp.org"};
|
|
694
|
+
sasl_external = new Strophe.SASLExternal();
|
|
695
|
+
ok(sasl_external.test(conn), "EXTERNAL is enabled by default.");
|
|
696
|
+
sasl_external.onStart(conn);
|
|
697
|
+
response = sasl_external.onChallenge(conn, null);
|
|
698
|
+
equal(response, conn.authzid,
|
|
699
|
+
"Response to EXTERNAL auth challenge should be empty string if authcid = authzid");
|
|
700
|
+
sasl_external.onSuccess();
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
module("BOSH Session resumption");
|
|
704
|
+
|
|
705
|
+
test("When passing in {keepalive: true} to Strophe.Connection, then the session tokens get cached automatically", function () {
|
|
706
|
+
var conn = new Strophe.Connection("", {"keepalive": true});
|
|
707
|
+
conn.jid = 'dummy@localhost';
|
|
708
|
+
conn._proto.sid = "5332346";
|
|
709
|
+
var cacheSpy = sinon.spy(conn._proto, '_cacheSession');
|
|
710
|
+
equal(cacheSpy.called, false);
|
|
711
|
+
conn._proto._buildBody();
|
|
712
|
+
equal(cacheSpy.called, true);
|
|
713
|
+
equal(window.sessionStorage.getItem('strophe-bosh-session'), null);
|
|
714
|
+
conn.authenticated = true;
|
|
715
|
+
conn._proto._buildBody();
|
|
716
|
+
ok(window.sessionStorage.getItem('strophe-bosh-session'));
|
|
717
|
+
equal(cacheSpy.called, true);
|
|
718
|
+
conn.authenticated = false;
|
|
719
|
+
conn._proto._buildBody();
|
|
720
|
+
equal(window.sessionStorage.getItem('strophe-bosh-session'), null);
|
|
721
|
+
equal(cacheSpy.called, true);
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
test('the request ID (RID) has the proper value whenever a session is restored', function () {
|
|
725
|
+
window.sessionStorage.removeItem('strophe-bosh-session');
|
|
726
|
+
var conn = new Strophe.Connection("", {"keepalive": true});
|
|
727
|
+
conn.authenticated = true;
|
|
728
|
+
conn.jid = 'dummy@localhost';
|
|
729
|
+
conn._proto.rid = '123456';
|
|
730
|
+
conn._proto.sid = '987654321';
|
|
731
|
+
conn._proto._cacheSession();
|
|
732
|
+
delete conn._proto.rid;
|
|
733
|
+
conn.restore();
|
|
734
|
+
var body = conn._proto._buildBody();
|
|
735
|
+
equal(body.tree().getAttribute('rid'), '123456');
|
|
736
|
+
body = conn._proto._buildBody();
|
|
737
|
+
equal(body.tree().getAttribute('rid'), '123457');
|
|
738
|
+
body = conn._proto._buildBody();
|
|
739
|
+
equal(body.tree().getAttribute('rid'), '123458');
|
|
740
|
+
delete conn._proto.rid;
|
|
741
|
+
conn.restore();
|
|
742
|
+
body = conn._proto._buildBody();
|
|
743
|
+
equal(body.tree().getAttribute('rid'), '123459');
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
test("restore can only be called with BOSH and when {keepalive: true} is passed to Strophe.Connection", function () {
|
|
747
|
+
var conn = new Strophe.Connection("");
|
|
748
|
+
var boshSpy = sinon.spy(conn._proto, "_restore");
|
|
749
|
+
var checkSpy = sinon.spy(conn, "_sessionCachingSupported");
|
|
750
|
+
equal(conn.restored, false);
|
|
751
|
+
try {
|
|
752
|
+
conn.restore();
|
|
753
|
+
} catch (e) {
|
|
754
|
+
equal(e.name, "StropheSessionError",
|
|
755
|
+
"conn.restore() should throw an exception when keepalive is false.");
|
|
756
|
+
equal(e.message, "_restore: no restoreable session.",
|
|
757
|
+
"conn.restore() should throw an exception when keepalive is false");
|
|
758
|
+
}
|
|
759
|
+
equal(boshSpy.called, true);
|
|
760
|
+
equal(checkSpy.called, true);
|
|
761
|
+
|
|
762
|
+
conn = new Strophe.Connection("ws:localhost");
|
|
763
|
+
try {
|
|
764
|
+
conn.restore();
|
|
765
|
+
} catch (e) {
|
|
766
|
+
equal(e.name, "StropheSessionError",
|
|
767
|
+
"conn.restore() should throw an exception when keepalive is false.");
|
|
768
|
+
equal(e.message, 'The "restore" method can only be used with a BOSH connection.',
|
|
769
|
+
'The conn.restore method can only be used with a BOSH connection.');
|
|
770
|
+
}
|
|
771
|
+
equal(conn.restored, false);
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
test('the _cacheSession method caches the BOSH session tokens', function () {
|
|
775
|
+
window.sessionStorage.removeItem('strophe-bosh-session');
|
|
776
|
+
var conn = new Strophe.Connection("http://fake", {"keepalive": true});
|
|
777
|
+
// Nothing gets cached if there aren't tokens to cache
|
|
778
|
+
conn._proto._cacheSession();
|
|
779
|
+
equal(window.sessionStorage.getItem('strophe-bosh-session'), null);
|
|
780
|
+
// Let's create some tokens to cache
|
|
781
|
+
conn.authenticated = true;
|
|
782
|
+
conn.jid = 'dummy@localhost';
|
|
783
|
+
conn._proto.rid = '123456';
|
|
784
|
+
conn._proto.sid = '987654321';
|
|
785
|
+
equal(window.sessionStorage.getItem('strophe-bosh-session'), null);
|
|
786
|
+
conn._proto._cacheSession();
|
|
787
|
+
notEqual(window.sessionStorage.getItem('strophe-bosh-session'), null);
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
test('when calling "restore" without a restorable session, an exception is raised', function () {
|
|
791
|
+
window.sessionStorage.removeItem('strophe-bosh-session');
|
|
792
|
+
var conn = new Strophe.Connection("", {"keepalive": true});
|
|
793
|
+
var boshSpy = sinon.spy(conn._proto, "_restore");
|
|
794
|
+
var checkSpy = sinon.spy(conn, "_sessionCachingSupported");
|
|
795
|
+
equal(conn.restored, false);
|
|
796
|
+
try {
|
|
797
|
+
conn.restore();
|
|
798
|
+
} catch (e) {
|
|
799
|
+
equal(e.name, "StropheSessionError");
|
|
800
|
+
equal(e.message, "_restore: no restoreable session.");
|
|
801
|
+
}
|
|
802
|
+
equal(conn.restored, false);
|
|
803
|
+
equal(boshSpy.called, true);
|
|
804
|
+
equal(checkSpy.called, true);
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
test('"restore" takes an optional JID argument for more precise session verification', function () {
|
|
808
|
+
window.sessionStorage.removeItem('strophe-bosh-session');
|
|
809
|
+
var conn = new Strophe.Connection("", {"keepalive": true});
|
|
810
|
+
var boshSpy = sinon.spy(conn._proto, "_restore");
|
|
811
|
+
var checkSpy = sinon.spy(conn, "_sessionCachingSupported");
|
|
812
|
+
// Let's create some tokens to cache
|
|
813
|
+
conn.authenticated = true;
|
|
814
|
+
conn.jid = 'dummy@localhost';
|
|
815
|
+
conn._proto.rid = '1234567';
|
|
816
|
+
conn._proto.sid = '9876543210';
|
|
817
|
+
conn._proto._cacheSession();
|
|
818
|
+
|
|
819
|
+
// Check that giving a different jid causes an exception to be
|
|
820
|
+
// raised.
|
|
821
|
+
try {
|
|
822
|
+
conn.restore('differentdummy@localhost');
|
|
823
|
+
} catch (e) {
|
|
824
|
+
equal(e.name, "StropheSessionError");
|
|
825
|
+
equal(e.message, "_restore: no restoreable session.");
|
|
826
|
+
}
|
|
827
|
+
equal(conn.restored, false);
|
|
828
|
+
equal(boshSpy.called, true);
|
|
829
|
+
equal(checkSpy.called, true);
|
|
830
|
+
|
|
831
|
+
// Check that passing in the right jid but with a resource is not a problem.
|
|
832
|
+
conn.restore('dummy@localhost/with_resource');
|
|
833
|
+
equal(conn.jid,'dummy@localhost');
|
|
834
|
+
equal(conn._proto.rid,'1234567');
|
|
835
|
+
equal(conn._proto.sid,'9876543210');
|
|
836
|
+
equal(conn.restored, true);
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
test('when calling "restore" with a restorable session, bosh._attach is called with the session tokens', function () {
|
|
840
|
+
window.sessionStorage.removeItem('strophe-bosh-session');
|
|
841
|
+
var conn = new Strophe.Connection("", {"keepalive": true});
|
|
842
|
+
conn.authenticated = true;
|
|
843
|
+
conn.jid = 'dummy@localhost';
|
|
844
|
+
conn._proto.rid = '123456';
|
|
845
|
+
conn._proto.sid = '987654321';
|
|
846
|
+
conn._proto._cacheSession();
|
|
847
|
+
delete conn._proto.rid;
|
|
848
|
+
delete conn._proto.sid;
|
|
849
|
+
delete conn._proto.jid;
|
|
850
|
+
equal(conn.restored, false);
|
|
851
|
+
|
|
852
|
+
var boshSpy = sinon.spy(conn._proto, "_restore");
|
|
853
|
+
var checkSpy = sinon.spy(conn, "_sessionCachingSupported");
|
|
854
|
+
var attachSpsy = sinon.spy(conn._proto, "_attach");
|
|
855
|
+
conn.restore();
|
|
856
|
+
equal(conn.jid,'dummy@localhost');
|
|
857
|
+
equal(conn._proto.rid,'123456');
|
|
858
|
+
equal(conn._proto.sid,'987654321');
|
|
859
|
+
equal(conn.restored, true);
|
|
860
|
+
equal(boshSpy.called, true);
|
|
861
|
+
equal(checkSpy.called, true);
|
|
862
|
+
equal(attachSpsy.called, true);
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
module("BOSH next valid request id");
|
|
866
|
+
|
|
867
|
+
test("nextValidRid is called after successful request", function () {
|
|
868
|
+
Strophe.Connection.prototype._onIdle = function () {};
|
|
869
|
+
var conn = new Strophe.Connection("http://fake");
|
|
870
|
+
var spy = sinon.spy(conn, 'nextValidRid');
|
|
871
|
+
var req = {id: 43,
|
|
872
|
+
sends: 1,
|
|
873
|
+
xhr: new xhr(200, 4),
|
|
874
|
+
rid: 42
|
|
875
|
+
};
|
|
876
|
+
conn._requests = [req];
|
|
877
|
+
conn._proto._onRequestStateChange(function(){}, req);
|
|
878
|
+
equal(spy.calledOnce, true, "nextValidRid was called only once");
|
|
879
|
+
equal(spy.calledWith(43), true, "The RID was valid");
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
test("nextValidRid is not called after failed request", function () {
|
|
883
|
+
Strophe.Connection.prototype._onIdle = function () {};
|
|
884
|
+
var conn = new Strophe.Connection("http://fake");
|
|
885
|
+
var spy = sinon.spy(conn, 'nextValidRid');
|
|
886
|
+
var req = {id: 43,
|
|
887
|
+
sends: 1,
|
|
888
|
+
xhr: new xhr(0, 4),
|
|
889
|
+
rid: 42
|
|
890
|
+
};
|
|
891
|
+
conn._requests = [req];
|
|
892
|
+
conn._proto._onRequestStateChange(function(){}, req);
|
|
893
|
+
equal(spy.called, false, "nextValidRid was not called");
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
test("nextValidRid is called after failed request with disconnection", function () {
|
|
897
|
+
sinon.stub(Math, "random", function(){
|
|
898
|
+
return 1;
|
|
899
|
+
});
|
|
900
|
+
Strophe.Connection.prototype._onIdle = function () {};
|
|
901
|
+
var conn = new Strophe.Connection("http://fake");
|
|
902
|
+
var spy = sinon.spy(conn, 'nextValidRid');
|
|
903
|
+
var req = {id: 43,
|
|
904
|
+
sends: 1,
|
|
905
|
+
xhr: new xhr(404, 4),
|
|
906
|
+
rid: 42
|
|
907
|
+
};
|
|
908
|
+
conn._requests = [req];
|
|
909
|
+
conn._proto._onRequestStateChange(function(){}, req);
|
|
910
|
+
equal(spy.calledOnce, true, "nextValidRid was called only once");
|
|
911
|
+
equal(spy.calledWith(4294967295), true, "The RID was valid");
|
|
912
|
+
Math.random.restore();
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
test("nextValidRid is called after connection reset", function () {
|
|
916
|
+
sinon.stub(Math, "random", function(){
|
|
917
|
+
return 1;
|
|
918
|
+
});
|
|
919
|
+
Strophe.Connection.prototype._onIdle = function () {};
|
|
920
|
+
var conn = new Strophe.Connection("http://fake");
|
|
921
|
+
var spy = sinon.spy(conn, 'nextValidRid');
|
|
922
|
+
conn.reset();
|
|
923
|
+
equal(spy.calledOnce, true, "nextValidRid was called only once");
|
|
924
|
+
equal(spy.calledWith(4294967295), true, "The RID was valid");
|
|
925
|
+
Math.random.restore();
|
|
926
|
+
});
|
|
927
|
+
};
|
|
928
|
+
return {run: run};
|
|
929
|
+
});
|