|
@@ -32610,6 +32610,8 @@ if (!root.atob) {
|
|
|
define('strophe-sha1', [],function () {
|
|
|
return factory();
|
|
|
});
|
|
|
+ } else if (typeof exports === 'object') {
|
|
|
+ module.exports = factory();
|
|
|
} else {
|
|
|
// Browser globals
|
|
|
root.SHA1 = factory();
|
|
@@ -32804,6 +32806,8 @@ return {
|
|
|
define('strophe-md5',[], function () {
|
|
|
return factory();
|
|
|
});
|
|
|
+ } else if (typeof exports === 'object') {
|
|
|
+ module.exports = factory();
|
|
|
} else {
|
|
|
// Browser globals
|
|
|
root.MD5 = factory();
|
|
@@ -33006,6 +33010,8 @@ return {
|
|
|
define('strophe-utils',[], function () {
|
|
|
return factory();
|
|
|
});
|
|
|
+ } else if (typeof exports === 'object') {
|
|
|
+ module.exports = factory();
|
|
|
} else {
|
|
|
// Browser globals
|
|
|
root.stropheUtils = factory();
|
|
@@ -33094,6 +33100,12 @@ return {
|
|
|
], function () {
|
|
|
return factory.apply(this, arguments);
|
|
|
});
|
|
|
+ } else if (typeof exports === 'object') {
|
|
|
+ module.exports = factory(
|
|
|
+ require('./sha1'),
|
|
|
+ require('./md5'),
|
|
|
+ require('./utils')
|
|
|
+ );
|
|
|
} else {
|
|
|
// Browser globals
|
|
|
var o = factory(root.SHA1, root.MD5, root.stropheUtils);
|
|
@@ -33168,7 +33180,7 @@ function $pres(attrs) { return new Strophe.Builder("presence", attrs); }
|
|
|
*/
|
|
|
Strophe = {
|
|
|
/** Constant: VERSION */
|
|
|
- VERSION: "1.2.14",
|
|
|
+ VERSION: "1.2.15",
|
|
|
|
|
|
/** Constants: XMPP Namespace Constants
|
|
|
* Common namespace constants from the XMPP RFCs and XEPs.
|
|
@@ -33306,6 +33318,14 @@ Strophe = {
|
|
|
CONNTIMEOUT: 10
|
|
|
},
|
|
|
|
|
|
+ ErrorCondition: {
|
|
|
+ BAD_FORMAT: "bad-format",
|
|
|
+ CONFLICT: "conflict",
|
|
|
+ MISSING_JID_NODE: "x-strophe-bad-non-anon-jid",
|
|
|
+ NO_AUTH_MECH: "no-auth-mech",
|
|
|
+ UNKNOWN_REASON: "unknown",
|
|
|
+ },
|
|
|
+
|
|
|
/** Constants: Log Level Constants
|
|
|
* Logging level indicators.
|
|
|
*
|
|
@@ -33882,7 +33902,7 @@ Strophe = {
|
|
|
*
|
|
|
* This function is called whenever the Strophe library calls any
|
|
|
* of the logging functions. The default implementation of this
|
|
|
- * function does nothing. If client code wishes to handle the logging
|
|
|
+ * function logs only fatal errors. If client code wishes to handle the logging
|
|
|
* messages, it should override this with
|
|
|
* > Strophe.log = function (level, msg) {
|
|
|
* > (user code here)
|
|
@@ -33906,11 +33926,13 @@ Strophe = {
|
|
|
* be one of the values in Strophe.LogLevel.
|
|
|
* (String) msg - The log message.
|
|
|
*/
|
|
|
- /* jshint ignore:start */
|
|
|
log: function (level, msg) {
|
|
|
- return;
|
|
|
+ if (level === this.LogLevel.FATAL &&
|
|
|
+ typeof window.console === 'object' &&
|
|
|
+ typeof window.console.error === 'function') {
|
|
|
+ window.console.error(msg);
|
|
|
+ }
|
|
|
},
|
|
|
- /* jshint ignore:end */
|
|
|
|
|
|
/** Function: debug
|
|
|
* Log a message at the Strophe.LogLevel.DEBUG level.
|
|
@@ -34576,10 +34598,11 @@ Strophe.TimedHandler.prototype = {
|
|
|
* If nothing is specified, then the following mechanisms (and their
|
|
|
* priorities) are registered:
|
|
|
*
|
|
|
- * OAUTHBEARER - 60
|
|
|
- * SCRAM-SHA1 - 50
|
|
|
- * DIGEST-MD5 - 40
|
|
|
- * PLAIN - 30
|
|
|
+ * SCRAM-SHA1 - 70
|
|
|
+ * DIGEST-MD5 - 60
|
|
|
+ * PLAIN - 50
|
|
|
+ * OAUTH-BEARER - 40
|
|
|
+ * OAUTH-2 - 30
|
|
|
* ANONYMOUS - 20
|
|
|
* EXTERNAL - 10
|
|
|
*
|
|
@@ -35460,6 +35483,7 @@ Strophe.Connection.prototype = {
|
|
|
Strophe.SASLExternal,
|
|
|
Strophe.SASLMD5,
|
|
|
Strophe.SASLOAuthBearer,
|
|
|
+ Strophe.SASLXOAuth2,
|
|
|
Strophe.SASLPlain,
|
|
|
Strophe.SASLSHA1
|
|
|
];
|
|
@@ -35526,8 +35550,9 @@ Strophe.Connection.prototype = {
|
|
|
* (Integer) status - the new connection status, one of the values
|
|
|
* in Strophe.Status
|
|
|
* (String) condition - the error condition or null
|
|
|
+ * (XMLElement) elem - The triggering stanza.
|
|
|
*/
|
|
|
- _changeConnectStatus: function (status, condition) {
|
|
|
+ _changeConnectStatus: function (status, condition, elem) {
|
|
|
// notify all plugins listening for status changes
|
|
|
for (var k in Strophe._connectionPlugins) {
|
|
|
if (Strophe._connectionPlugins.hasOwnProperty(k)) {
|
|
@@ -35546,7 +35571,7 @@ Strophe.Connection.prototype = {
|
|
|
// notify the user's callback
|
|
|
if (this.connect_callback) {
|
|
|
try {
|
|
|
- this.connect_callback(status, condition);
|
|
|
+ this.connect_callback(status, condition, elem);
|
|
|
} catch (e) {
|
|
|
Strophe._handleError(e);
|
|
|
Strophe.error(
|
|
@@ -35662,7 +35687,10 @@ Strophe.Connection.prototype = {
|
|
|
}
|
|
|
this._changeConnectStatus(Strophe.Status.CONNFAIL, cond);
|
|
|
} else {
|
|
|
- this._changeConnectStatus(Strophe.Status.CONNFAIL, "unknown");
|
|
|
+ this._changeConnectStatus(
|
|
|
+ Strophe.Status.CONNFAIL,
|
|
|
+ Strophe.ErrorCondition.UNKOWN_REASON
|
|
|
+ );
|
|
|
}
|
|
|
this._doDisconnect(cond);
|
|
|
return;
|
|
@@ -35702,6 +35730,26 @@ Strophe.Connection.prototype = {
|
|
|
*/
|
|
|
mechanisms: {},
|
|
|
|
|
|
+ /** PrivateFunction: _no_auth_received
|
|
|
+ *
|
|
|
+ * Called on stream start/restart when no stream:features
|
|
|
+ * has been received or when no viable authentication mechanism is offered.
|
|
|
+ *
|
|
|
+ * Sends a blank poll request.
|
|
|
+ */
|
|
|
+ _no_auth_received: function (_callback) {
|
|
|
+ var error_msg = "Server did not offer a supported authentication mechanism";
|
|
|
+ Strophe.error(error_msg);
|
|
|
+ this._changeConnectStatus(
|
|
|
+ Strophe.Status.CONNFAIL,
|
|
|
+ Strophe.ErrorCondition.NO_AUTH_MECH
|
|
|
+ );
|
|
|
+ if (_callback) {
|
|
|
+ _callback.call(this);
|
|
|
+ }
|
|
|
+ this._doDisconnect();
|
|
|
+ },
|
|
|
+
|
|
|
/** PrivateFunction: _connect_cb
|
|
|
* _Private_ handler for initial connection request.
|
|
|
*
|
|
@@ -35715,7 +35763,7 @@ Strophe.Connection.prototype = {
|
|
|
* Parameters:
|
|
|
* (Strophe.Request) req - The current request.
|
|
|
* (Function) _callback - low level (xmpp) connect callback function.
|
|
|
- * Useful for plugins with their own xmpp connect callback (when their)
|
|
|
+ * Useful for plugins with their own xmpp connect callback (when they
|
|
|
* want to do something special).
|
|
|
*/
|
|
|
_connect_cb: function (req, _callback, raw) {
|
|
@@ -35727,8 +35775,11 @@ Strophe.Connection.prototype = {
|
|
|
bodyWrap = this._proto._reqToData(req);
|
|
|
} catch (e) {
|
|
|
if (e !== "badformat") { throw e; }
|
|
|
- this._changeConnectStatus(Strophe.Status.CONNFAIL, 'bad-format');
|
|
|
- this._doDisconnect('bad-format');
|
|
|
+ this._changeConnectStatus(
|
|
|
+ Strophe.Status.CONNFAIL,
|
|
|
+ Strophe.ErrorCondition.BAD_FORMAT
|
|
|
+ );
|
|
|
+ this._doDisconnect(Strophe.ErrorCondition.BAD_FORMAT);
|
|
|
}
|
|
|
if (!bodyWrap) { return; }
|
|
|
|
|
@@ -35761,7 +35812,7 @@ Strophe.Connection.prototype = {
|
|
|
bodyWrap.getElementsByTagName("features").length > 0;
|
|
|
}
|
|
|
if (!hasFeatures) {
|
|
|
- this._proto._no_auth_received(_callback);
|
|
|
+ this._no_auth_received(_callback);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -35777,7 +35828,7 @@ Strophe.Connection.prototype = {
|
|
|
if (bodyWrap.getElementsByTagName("auth").length === 0) {
|
|
|
// There are no matching SASL mechanisms and also no legacy
|
|
|
// auth available.
|
|
|
- this._proto._no_auth_received(_callback);
|
|
|
+ this._no_auth_received(_callback);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
@@ -35873,9 +35924,9 @@ Strophe.Connection.prototype = {
|
|
|
// client connections
|
|
|
this._changeConnectStatus(
|
|
|
Strophe.Status.CONNFAIL,
|
|
|
- 'x-strophe-bad-non-anon-jid'
|
|
|
+ Strophe.ErrorCondition.MISSING_JID_NODE
|
|
|
);
|
|
|
- this.disconnect('x-strophe-bad-non-anon-jid');
|
|
|
+ this.disconnect(Strophe.ErrorCondition.MISSING_JID_NODE);
|
|
|
} else {
|
|
|
// Fall back to legacy authentication
|
|
|
this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);
|
|
@@ -36093,9 +36144,9 @@ Strophe.Connection.prototype = {
|
|
|
Strophe.info("SASL binding failed.");
|
|
|
var conflict = elem.getElementsByTagName("conflict"), condition;
|
|
|
if (conflict.length > 0) {
|
|
|
- condition = 'conflict';
|
|
|
+ condition = Strophe.ErrorCondition.CONFLICT;
|
|
|
}
|
|
|
- this._changeConnectStatus(Strophe.Status.AUTHFAIL, condition);
|
|
|
+ this._changeConnectStatus(Strophe.Status.AUTHFAIL, condition, elem);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
@@ -36122,7 +36173,7 @@ Strophe.Connection.prototype = {
|
|
|
}
|
|
|
} else {
|
|
|
Strophe.info("SASL binding failed.");
|
|
|
- this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
|
|
|
+ this._changeConnectStatus(Strophe.Status.AUTHFAIL, null, elem);
|
|
|
return false;
|
|
|
}
|
|
|
},
|
|
@@ -36145,7 +36196,7 @@ Strophe.Connection.prototype = {
|
|
|
this._changeConnectStatus(Strophe.Status.CONNECTED, null);
|
|
|
} else if (elem.getAttribute("type") === "error") {
|
|
|
Strophe.info("Session creation failed.");
|
|
|
- this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
|
|
|
+ this._changeConnectStatus(Strophe.Status.AUTHFAIL, null, elem);
|
|
|
return false;
|
|
|
}
|
|
|
return false;
|
|
@@ -36174,7 +36225,7 @@ Strophe.Connection.prototype = {
|
|
|
|
|
|
if(this._sasl_mechanism)
|
|
|
this._sasl_mechanism.onFailure();
|
|
|
- this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
|
|
|
+ this._changeConnectStatus(Strophe.Status.AUTHFAIL, null, elem);
|
|
|
return false;
|
|
|
},
|
|
|
/* jshint unused:true */
|
|
@@ -36196,7 +36247,7 @@ Strophe.Connection.prototype = {
|
|
|
this.authenticated = true;
|
|
|
this._changeConnectStatus(Strophe.Status.CONNECTED, null);
|
|
|
} else if (elem.getAttribute("type") === "error") {
|
|
|
- this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);
|
|
|
+ this._changeConnectStatus(Strophe.Status.AUTHFAIL, null, elem);
|
|
|
this.disconnect('authentication failed');
|
|
|
}
|
|
|
return false;
|
|
@@ -36453,6 +36504,7 @@ Strophe.SASLMechanism.prototype = {
|
|
|
* Strophe.SASLSHA1 - SASL SCRAM-SHA1 authentication
|
|
|
* Strophe.SASLOAuthBearer - SASL OAuth Bearer authentication
|
|
|
* Strophe.SASLExternal - SASL EXTERNAL authentication
|
|
|
+ * Strophe.SASLXOAuth2 - SASL X-OAuth2 authentication
|
|
|
*/
|
|
|
|
|
|
// Building SASL callbacks
|
|
@@ -36472,7 +36524,7 @@ Strophe.SASLAnonymous.prototype.test = function(connection) {
|
|
|
* SASL PLAIN authentication.
|
|
|
*/
|
|
|
Strophe.SASLPlain = function() {};
|
|
|
-Strophe.SASLPlain.prototype = new Strophe.SASLMechanism("PLAIN", true, 30);
|
|
|
+Strophe.SASLPlain.prototype = new Strophe.SASLMechanism("PLAIN", true, 50);
|
|
|
|
|
|
Strophe.SASLPlain.prototype.test = function(connection) {
|
|
|
return connection.authcid !== null;
|
|
@@ -36492,7 +36544,7 @@ Strophe.SASLPlain.prototype.onChallenge = function(connection) {
|
|
|
* SASL SCRAM SHA 1 authentication.
|
|
|
*/
|
|
|
Strophe.SASLSHA1 = function() {};
|
|
|
-Strophe.SASLSHA1.prototype = new Strophe.SASLMechanism("SCRAM-SHA-1", true, 50);
|
|
|
+Strophe.SASLSHA1.prototype = new Strophe.SASLMechanism("SCRAM-SHA-1", true, 70);
|
|
|
|
|
|
Strophe.SASLSHA1.prototype.test = function(connection) {
|
|
|
return connection.authcid !== null;
|
|
@@ -36576,7 +36628,7 @@ Strophe.SASLSHA1.prototype.onChallenge = function(connection, challenge, test_cn
|
|
|
* SASL DIGEST MD5 authentication.
|
|
|
*/
|
|
|
Strophe.SASLMD5 = function() {};
|
|
|
-Strophe.SASLMD5.prototype = new Strophe.SASLMechanism("DIGEST-MD5", false, 40);
|
|
|
+Strophe.SASLMD5.prototype = new Strophe.SASLMechanism("DIGEST-MD5", false, 60);
|
|
|
|
|
|
Strophe.SASLMD5.prototype.test = function(connection) {
|
|
|
return connection.authcid !== null;
|
|
@@ -36659,7 +36711,7 @@ Strophe.SASLMD5.prototype.onChallenge = function(connection, challenge, test_cno
|
|
|
* SASL OAuth Bearer authentication.
|
|
|
*/
|
|
|
Strophe.SASLOAuthBearer = function() {};
|
|
|
-Strophe.SASLOAuthBearer.prototype = new Strophe.SASLMechanism("OAUTHBEARER", true, 60);
|
|
|
+Strophe.SASLOAuthBearer.prototype = new Strophe.SASLMechanism("OAUTHBEARER", true, 40);
|
|
|
|
|
|
Strophe.SASLOAuthBearer.prototype.test = function(connection) {
|
|
|
return connection.pass !== null;
|
|
@@ -36703,6 +36755,29 @@ Strophe.SASLExternal.prototype.onChallenge = function(connection) {
|
|
|
return connection.authcid === connection.authzid ? '' : connection.authzid;
|
|
|
};
|
|
|
|
|
|
+
|
|
|
+/** PrivateConstructor: SASLXOAuth2
|
|
|
+ * SASL X-OAuth2 authentication.
|
|
|
+ */
|
|
|
+Strophe.SASLXOAuth2 = function () { };
|
|
|
+Strophe.SASLXOAuth2.prototype = new Strophe.SASLMechanism("X-OAUTH2", true, 30);
|
|
|
+
|
|
|
+Strophe.SASLXOAuth2.prototype.test = function (connection) {
|
|
|
+ return connection.pass !== null;
|
|
|
+};
|
|
|
+
|
|
|
+Strophe.SASLXOAuth2.prototype.onChallenge = function (connection) {
|
|
|
+ var auth_str = '\u0000';
|
|
|
+ if (connection.authcid !== null) {
|
|
|
+ auth_str = auth_str + connection.authzid;
|
|
|
+ }
|
|
|
+ auth_str = auth_str + "\u0000";
|
|
|
+ auth_str = auth_str + connection.pass;
|
|
|
+
|
|
|
+ return utils.utf16to8(auth_str);
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
return {
|
|
|
'Strophe': Strophe,
|
|
|
'$build': $build,
|
|
@@ -36736,6 +36811,10 @@ return {
|
|
|
core.$build
|
|
|
);
|
|
|
});
|
|
|
+ } else if (typeof exports === 'object') {
|
|
|
+ var core = require('./core');
|
|
|
+
|
|
|
+ module.exports = factory(core.Strophe, core.$build);
|
|
|
} else {
|
|
|
// Browser globals
|
|
|
return factory(Strophe, $build);
|
|
@@ -36813,11 +36892,17 @@ Strophe.Request.prototype = {
|
|
|
throw "parsererror";
|
|
|
}
|
|
|
} else if (this.xhr.responseText) {
|
|
|
- Strophe.error("invalid response received");
|
|
|
- Strophe.error("responseText: " + this.xhr.responseText);
|
|
|
- throw "badformat";
|
|
|
+ // In React Native, we may get responseText but no responseXML. We can try to parse it manually.
|
|
|
+ Strophe.debug("Got responseText but no responseXML; attempting to parse it with DOMParser...");
|
|
|
+ node = new DOMParser().parseFromString(this.xhr.responseText, 'application/xml').documentElement;
|
|
|
+ if (!node) {
|
|
|
+ throw new Error('Parsing produced null node');
|
|
|
+ } else if (node.querySelector('parsererror')) {
|
|
|
+ Strophe.error("invalid response received: " + node.querySelector('parsererror').textContent);
|
|
|
+ Strophe.error("responseText: " + this.xhr.responseText);
|
|
|
+ throw "badformat";
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
return node;
|
|
|
},
|
|
|
|
|
@@ -36883,6 +36968,8 @@ Strophe.Bosh = function(connection) {
|
|
|
this.errors = 0;
|
|
|
this.inactivity = null;
|
|
|
|
|
|
+ this.lastResponseHeaders = null;
|
|
|
+
|
|
|
this._requests = [];
|
|
|
};
|
|
|
|
|
@@ -37190,26 +37277,6 @@ Strophe.Bosh.prototype = {
|
|
|
}
|
|
|
},
|
|
|
|
|
|
- /** PrivateFunction: _no_auth_received
|
|
|
- *
|
|
|
- * Called on stream start/restart when no stream:features
|
|
|
- * has been received and sends a blank poll request.
|
|
|
- */
|
|
|
- _no_auth_received: function (_callback) {
|
|
|
- if (_callback) {
|
|
|
- _callback = _callback.bind(this._conn);
|
|
|
- } else {
|
|
|
- _callback = this._conn._connect_cb.bind(this._conn);
|
|
|
- }
|
|
|
- var body = this._buildBody();
|
|
|
- this._requests.push(
|
|
|
- new Strophe.Request(body.tree(),
|
|
|
- this._onRequestStateChange.bind(
|
|
|
- this, _callback.bind(this._conn)),
|
|
|
- body.tree().getAttribute("rid")));
|
|
|
- this._throttledRequestHandler();
|
|
|
- },
|
|
|
-
|
|
|
/** PrivateFunction: _onDisconnectTimeout
|
|
|
* _Private_ timeout handler for handling non-graceful disconnection.
|
|
|
*
|
|
@@ -37350,6 +37417,7 @@ Strophe.Bosh.prototype = {
|
|
|
return;
|
|
|
}
|
|
|
var reqStatus = this._getRequestStatus(req);
|
|
|
+ this.lastResponseHeaders = req.xhr.getAllResponseHeaders();
|
|
|
if (this.disconnecting && reqStatus >= 400) {
|
|
|
this._hitError(reqStatus);
|
|
|
this._callProtocolErrorHandlers(req);
|
|
@@ -37674,6 +37742,10 @@ return Strophe;
|
|
|
core.$build
|
|
|
);
|
|
|
});
|
|
|
+ } else if (typeof exports === 'object') {
|
|
|
+ var core = require('./core');
|
|
|
+
|
|
|
+ module.exports = factory(core.Strophe, core.$build);
|
|
|
} else {
|
|
|
// Browser globals
|
|
|
return factory(Strophe, $build);
|
|
@@ -37948,7 +38020,7 @@ Strophe.Websocket.prototype = {
|
|
|
this._conn.send(pres);
|
|
|
}
|
|
|
var close = $build("close", { "xmlns": Strophe.NS.FRAMING });
|
|
|
- this._conn.xmlOutput(close);
|
|
|
+ this._conn.xmlOutput(close.tree());
|
|
|
var closeString = Strophe.serialize(close);
|
|
|
this._conn.rawOutput(closeString);
|
|
|
try {
|
|
@@ -37986,6 +38058,7 @@ Strophe.Websocket.prototype = {
|
|
|
*/
|
|
|
_closeSocket: function () {
|
|
|
if (this.socket) { try {
|
|
|
+ this.socket.onerror = null;
|
|
|
this.socket.close();
|
|
|
} catch (e) {} }
|
|
|
this.socket = null;
|
|
@@ -38026,24 +38099,6 @@ Strophe.Websocket.prototype = {
|
|
|
}
|
|
|
},
|
|
|
|
|
|
- /** PrivateFunction: _no_auth_received
|
|
|
- *
|
|
|
- * Called on stream start/restart when no stream:features
|
|
|
- * has been received.
|
|
|
- */
|
|
|
- _no_auth_received: function (_callback) {
|
|
|
- Strophe.error("Server did not send any auth methods");
|
|
|
- this._conn._changeConnectStatus(
|
|
|
- Strophe.Status.CONNFAIL,
|
|
|
- "Server did not send any auth methods"
|
|
|
- );
|
|
|
- if (_callback) {
|
|
|
- _callback = _callback.bind(this._conn);
|
|
|
- _callback();
|
|
|
- }
|
|
|
- this._conn._doDisconnect();
|
|
|
- },
|
|
|
-
|
|
|
/** PrivateFunction: _onDisconnectTimeout
|
|
|
* _Private_ timeout handler for handling non-graceful disconnection.
|
|
|
*
|
|
@@ -38219,6 +38274,11 @@ return Strophe;
|
|
|
], function (wrapper) {
|
|
|
return wrapper;
|
|
|
});
|
|
|
+ } else if (typeof exports === 'object') {
|
|
|
+ var core = require('./core');
|
|
|
+ require('./bosh');
|
|
|
+ require('./websocket');
|
|
|
+ module.exports = core;
|
|
|
}
|
|
|
})(this);
|
|
|
|
|
@@ -43335,7 +43395,7 @@ return Backbone.BrowserStorage;
|
|
|
// Converse.js
|
|
|
// https://conversejs.org
|
|
|
//
|
|
|
-// Copyright (c) 2012-2018, the Converse.js developers
|
|
|
+// Copyright (c) 2013-2018, the Converse.js developers
|
|
|
// Licensed under the Mozilla Public License (MPLv2)
|
|
|
(function (root, factory) {
|
|
|
define('converse-core',["sizzle", "es6-promise", "lodash.noconflict", "lodash.fp", "polyfill", "i18n", "utils", "moment", "strophe", "pluggable", "backbone.noconflict", "backbone.nativeview", "backbone.browserStorage"], factory);
|
|
@@ -44002,6 +44062,8 @@ return Backbone.BrowserStorage;
|
|
|
_converse.session.browserStorage = new Backbone.BrowserStorage[_converse.storage](id);
|
|
|
|
|
|
_converse.session.fetch();
|
|
|
+
|
|
|
+ _converse.emit('sessionInitialized');
|
|
|
};
|
|
|
|
|
|
this.clearSession = function () {
|
|
@@ -45661,15 +45723,15 @@ define("emojione", (function (global) {
|
|
|
initialize: function initialize() {
|
|
|
this.waitUntilFeaturesDiscovered = utils.getResolveablePromise();
|
|
|
this.dataforms = new Backbone.Collection();
|
|
|
- this.dataforms.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.dataforms-{this.get('jid')}"));
|
|
|
+ this.dataforms.browserStorage = new Backbone.BrowserStorage.session(b64_sha1("converse.dataforms-{this.get('jid')}"));
|
|
|
this.features = new Backbone.Collection();
|
|
|
- this.features.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.features-".concat(this.get('jid'))));
|
|
|
+ this.features.browserStorage = new Backbone.BrowserStorage.session(b64_sha1("converse.features-".concat(this.get('jid'))));
|
|
|
this.features.on('add', this.onFeatureAdded, this);
|
|
|
this.identities = new Backbone.Collection();
|
|
|
- this.identities.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.identities-".concat(this.get('jid'))));
|
|
|
+ this.identities.browserStorage = new Backbone.BrowserStorage.session(b64_sha1("converse.identities-".concat(this.get('jid'))));
|
|
|
this.fetchFeatures();
|
|
|
this.items = new _converse.DiscoEntities();
|
|
|
- this.items.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.disco-items-".concat(this.get('jid'))));
|
|
|
+ this.items.browserStorage = new Backbone.BrowserStorage.session(b64_sha1("converse.disco-items-".concat(this.get('jid'))));
|
|
|
this.items.fetch();
|
|
|
},
|
|
|
getIdentity: function getIdentity(category, type) {
|
|
@@ -45850,13 +45912,33 @@ define("emojione", (function (global) {
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
+ function initStreamFeatures() {
|
|
|
+ _converse.stream_features = new Backbone.Collection();
|
|
|
+ _converse.stream_features.browserStorage = new Backbone.BrowserStorage.session(b64_sha1("converse.stream-features-".concat(_converse.bare_jid)));
|
|
|
+
|
|
|
+ _converse.stream_features.fetch({
|
|
|
+ success: function success(collection) {
|
|
|
+ if (collection.length === 0 && _converse.connection.features) {
|
|
|
+ _.forEach(_converse.connection.features.childNodes, function (feature) {
|
|
|
+ _converse.stream_features.create({
|
|
|
+ 'name': feature.nodeName,
|
|
|
+ 'xmlns': feature.getAttribute('xmlns')
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ _converse.emit('streamFeaturesAdded');
|
|
|
+ }
|
|
|
+
|
|
|
function initializeDisco() {
|
|
|
addClientFeatures();
|
|
|
|
|
|
_converse.connection.addHandler(onDiscoInfoRequest, Strophe.NS.DISCO_INFO, 'iq', 'get', null, null);
|
|
|
|
|
|
_converse.disco_entities = new _converse.DiscoEntities();
|
|
|
- _converse.disco_entities.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.disco-entities-".concat(_converse.bare_jid)));
|
|
|
+ _converse.disco_entities.browserStorage = new Backbone.BrowserStorage.session(b64_sha1("converse.disco-entities-".concat(_converse.bare_jid)));
|
|
|
|
|
|
_converse.disco_entities.fetchEntities().then(function (collection) {
|
|
|
if (collection.length === 0 || !collection.get(_converse.domain)) {
|
|
@@ -45871,6 +45953,8 @@ define("emojione", (function (global) {
|
|
|
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
|
|
}
|
|
|
|
|
|
+ _converse.api.listen.on('sessionInitialized', initStreamFeatures);
|
|
|
+
|
|
|
_converse.api.listen.on('reconnected', initializeDisco);
|
|
|
|
|
|
_converse.api.listen.on('connected', initializeDisco);
|
|
@@ -45951,6 +46035,19 @@ define("emojione", (function (global) {
|
|
|
* @namespace
|
|
|
*/
|
|
|
'disco': {
|
|
|
+ 'stream': {
|
|
|
+ 'getFeature': function getFeature(name, xmlns) {
|
|
|
+ if (_.isNil(name) || _.isNil(xmlns)) {
|
|
|
+ throw new Error("name and xmlns need to be provided when calling disco.stream.getFeature");
|
|
|
+ }
|
|
|
+
|
|
|
+ return _converse.stream_features.findWhere({
|
|
|
+ 'name': name,
|
|
|
+ 'xmlns': xmlns
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
/**
|
|
|
* The "own" grouping
|
|
|
* @namespace
|
|
@@ -48627,19 +48724,24 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
|
this.on('change:image_hash', this.onAvatarChanged, this);
|
|
|
},
|
|
|
onAvatarChanged: function onAvatarChanged() {
|
|
|
- var vcard = _converse.vcards.findWhere({
|
|
|
- 'jid': this.get('from')
|
|
|
- });
|
|
|
+ var hash = this.get('image_hash');
|
|
|
+ var vcards = [];
|
|
|
|
|
|
- if (!vcard) {
|
|
|
- return;
|
|
|
+ if (this.get('jid')) {
|
|
|
+ vcards.push(this.updateVCard(_converse.vcards.findWhere({
|
|
|
+ 'jid': this.get('jid')
|
|
|
+ })));
|
|
|
}
|
|
|
|
|
|
- var hash = this.get('image_hash');
|
|
|
+ vcards.push(this.updateVCard(_converse.vcards.findWhere({
|
|
|
+ 'jid': this.get('from')
|
|
|
+ })));
|
|
|
|
|
|
- if (hash && vcard.get('image_hash') !== hash) {
|
|
|
- _converse.api.vcard.update(vcard);
|
|
|
- }
|
|
|
+ _.forEach(_.filter(vcards, undefined), function (vcard) {
|
|
|
+ if (hash && vcard.get('image_hash') !== hash) {
|
|
|
+ _converse.api.vcard.update(vcard);
|
|
|
+ }
|
|
|
+ });
|
|
|
},
|
|
|
getDisplayName: function getDisplayName() {
|
|
|
return this.get('nick') || this.get('jid');
|
|
@@ -48687,6 +48789,10 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
|
'jid': removed_jid
|
|
|
});
|
|
|
|
|
|
+ if (!occupant) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
if (occupant.get('show') === 'offline') {
|
|
|
occupant.destroy();
|
|
|
}
|
|
@@ -60751,7 +60857,7 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
|
// Converse.js
|
|
|
// http://conversejs.org
|
|
|
//
|
|
|
-// Copyright (c) 2012-2018, the Converse.js developers
|
|
|
+// Copyright (c) 2013-2018, the Converse.js developers
|
|
|
// Licensed under the Mozilla Public License (MPLv2)
|
|
|
(function (root, factory) {
|
|
|
define('converse-vcard',["converse-core", "crypto", "tpl!vcard"], factory);
|
|
@@ -60824,7 +60930,9 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
|
'image_type': _.get(vcard.querySelector('PHOTO TYPE'), 'textContent'),
|
|
|
'url': _.get(vcard.querySelector('URL'), 'textContent'),
|
|
|
'role': _.get(vcard.querySelector('ROLE'), 'textContent'),
|
|
|
- 'email': _.get(vcard.querySelector('EMAIL USERID'), 'textContent')
|
|
|
+ 'email': _.get(vcard.querySelector('EMAIL USERID'), 'textContent'),
|
|
|
+ 'vcard_updated': moment().format(),
|
|
|
+ 'vcard_error': undefined
|
|
|
};
|
|
|
}
|
|
|
|
|
@@ -60842,7 +60950,8 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
|
if (errback) {
|
|
|
errback({
|
|
|
'stanza': iq,
|
|
|
- 'jid': jid
|
|
|
+ 'jid': jid,
|
|
|
+ 'vcard_error': moment().format()
|
|
|
});
|
|
|
}
|
|
|
}
|
|
@@ -60908,8 +61017,8 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
|
'get': function get(model, force) {
|
|
|
if (_.isString(model)) {
|
|
|
return getVCard(_converse, model);
|
|
|
- } else if (!model.get('vcard_updated') || force) {
|
|
|
- var jid = model.get('jid') || model.get('muc_jid');
|
|
|
+ } else if (force || !model.get('vcard_updated') || !moment(model.get('vcard_error')).isSame(new Date(), "day")) {
|
|
|
+ var jid = model.get('jid');
|
|
|
|
|
|
if (!jid) {
|
|
|
throw new Error("No JID to get vcard for!");
|
|
@@ -60925,9 +61034,8 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
|
_this.get(model, force).then(function (vcard) {
|
|
|
- model.save(_.extend(_.pick(vcard, ['fullname', 'nickname', 'email', 'url', 'role', 'image_type', 'image', 'image_hash']), {
|
|
|
- 'vcard_updated': moment().format()
|
|
|
- }));
|
|
|
+ delete vcard['stanza'];
|
|
|
+ model.save(vcard);
|
|
|
resolve();
|
|
|
});
|
|
|
});
|
|
@@ -72046,6 +72154,13 @@ return __p
|
|
|
*/
|
|
|
_converse.roster = new _converse.RosterContacts();
|
|
|
_converse.roster.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.contacts-".concat(_converse.bare_jid)));
|
|
|
+ _converse.roster.data = new Backbone.Model();
|
|
|
+ var id = b64_sha1("converse-roster-model-".concat(_converse.bare_jid));
|
|
|
+ _converse.roster.data.id = id;
|
|
|
+ _converse.roster.data.browserStorage = new Backbone.BrowserStorage[_converse.storage](id);
|
|
|
+
|
|
|
+ _converse.roster.data.fetch();
|
|
|
+
|
|
|
_converse.rostergroups = new _converse.RosterGroups();
|
|
|
_converse.rostergroups.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.roster.groups".concat(_converse.bare_jid)));
|
|
|
|
|
@@ -72350,23 +72465,27 @@ return __p
|
|
|
},
|
|
|
onConnected: function onConnected() {
|
|
|
/* Called as soon as the connection has been established
|
|
|
- * (either after initial login, or after reconnection).
|
|
|
- *
|
|
|
- * Use the opportunity to register stanza handlers.
|
|
|
- */
|
|
|
+ * (either after initial login, or after reconnection).
|
|
|
+ *
|
|
|
+ * Use the opportunity to register stanza handlers.
|
|
|
+ */
|
|
|
this.registerRosterHandler();
|
|
|
this.registerRosterXHandler();
|
|
|
},
|
|
|
registerRosterHandler: function registerRosterHandler() {
|
|
|
/* Register a handler for roster IQ "set" stanzas, which update
|
|
|
- * roster contacts.
|
|
|
- */
|
|
|
- _converse.connection.addHandler(_converse.roster.onRosterPush.bind(_converse.roster), Strophe.NS.ROSTER, 'iq', "set");
|
|
|
+ * roster contacts.
|
|
|
+ */
|
|
|
+ _converse.connection.addHandler(function (iq) {
|
|
|
+ _converse.roster.onRosterPush(iq);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }, Strophe.NS.ROSTER, 'iq', "set");
|
|
|
},
|
|
|
registerRosterXHandler: function registerRosterXHandler() {
|
|
|
/* Register a handler for RosterX message stanzas, which are
|
|
|
- * used to suggest roster contacts to a user.
|
|
|
- */
|
|
|
+ * used to suggest roster contacts to a user.
|
|
|
+ */
|
|
|
var t = 0;
|
|
|
|
|
|
_converse.connection.addHandler(function (msg) {
|
|
@@ -72389,12 +72508,13 @@ return __p
|
|
|
* Returns a promise which resolves once the contacts have been
|
|
|
* fetched.
|
|
|
*/
|
|
|
+ var that = this;
|
|
|
return new Promise(function (resolve, reject) {
|
|
|
_this2.fetch({
|
|
|
'add': true,
|
|
|
'silent': true,
|
|
|
success: function success(collection) {
|
|
|
- if (collection.length === 0) {
|
|
|
+ if (collection.length === 0 || that.rosterVersioningSupported() && !_converse.session.get('roster_fetched')) {
|
|
|
_converse.send_initial_presence = true;
|
|
|
|
|
|
_converse.roster.fetchFromServer().then(resolve).catch(reject);
|
|
@@ -72536,30 +72656,22 @@ return __p
|
|
|
},
|
|
|
onRosterPush: function onRosterPush(iq) {
|
|
|
/* Handle roster updates from the XMPP server.
|
|
|
- * See: https://xmpp.org/rfcs/rfc6121.html#roster-syntax-actions-push
|
|
|
- *
|
|
|
- * Parameters:
|
|
|
- * (XMLElement) IQ - The IQ stanza received from the XMPP server.
|
|
|
- */
|
|
|
+ * See: https://xmpp.org/rfcs/rfc6121.html#roster-syntax-actions-push
|
|
|
+ *
|
|
|
+ * Parameters:
|
|
|
+ * (XMLElement) IQ - The IQ stanza received from the XMPP server.
|
|
|
+ */
|
|
|
var id = iq.getAttribute('id');
|
|
|
var from = iq.getAttribute('from');
|
|
|
|
|
|
- if (from && from !== "" && Strophe.getBareJidFromJid(from) !== _converse.bare_jid) {
|
|
|
- // Receiving client MUST ignore stanza unless it has no from or from = user's bare JID.
|
|
|
- // XXX: Some naughty servers apparently send from a full
|
|
|
- // JID so we need to explicitly compare bare jids here.
|
|
|
- // https://github.com/jcbrand/converse.js/issues/493
|
|
|
- _converse.connection.send($iq({
|
|
|
- type: 'error',
|
|
|
- id: id,
|
|
|
- from: _converse.connection.jid
|
|
|
- }).c('error', {
|
|
|
- 'type': 'cancel'
|
|
|
- }).c('service-unavailable', {
|
|
|
- 'xmlns': Strophe.NS.ROSTER
|
|
|
- }));
|
|
|
-
|
|
|
- return true;
|
|
|
+ if (from && from !== _converse.connection.jid) {
|
|
|
+ // https://tools.ietf.org/html/rfc6121#page-15
|
|
|
+ //
|
|
|
+ // A receiving client MUST ignore the stanza unless it has no 'from'
|
|
|
+ // attribute (i.e., implicitly from the bare JID of the user's
|
|
|
+ // account) or it has a 'from' attribute whose value matches the
|
|
|
+ // user's bare JID <user@domainpart>.
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
_converse.connection.send($iq({
|
|
@@ -72568,13 +72680,32 @@ return __p
|
|
|
from: _converse.connection.jid
|
|
|
}));
|
|
|
|
|
|
- var items = sizzle("query[xmlns=\"".concat(Strophe.NS.ROSTER, "\"] item"), iq);
|
|
|
+ var query = sizzle("query[xmlns=\"".concat(Strophe.NS.ROSTER, "\"]"), iq).pop();
|
|
|
+ this.data.save('version', query.getAttribute('ver'));
|
|
|
+ var items = sizzle("item", query);
|
|
|
+
|
|
|
+ if (items.length > 1) {
|
|
|
+ _converse.log(iq, Strophe.LogLevel.ERROR);
|
|
|
+
|
|
|
+ throw new Error('Roster push query may not contain more than one "item" element.');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (items.length === 0) {
|
|
|
+ _converse.log(iq, Strophe.LogLevel.WARN);
|
|
|
+
|
|
|
+ _converse.log('Received a roster push stanza without an "item" element.', Strophe.LogLevel.WARN);
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- _.each(items, this.updateContact.bind(this));
|
|
|
+ this.updateContact(items.pop());
|
|
|
|
|
|
_converse.emit('rosterPush', iq);
|
|
|
|
|
|
- return true;
|
|
|
+ return;
|
|
|
+ },
|
|
|
+ rosterVersioningSupported: function rosterVersioningSupported() {
|
|
|
+ return _converse.api.disco.stream.getFeature('ver', 'urn:xmpp:features:rosterver') && this.data.get('version');
|
|
|
},
|
|
|
fetchFromServer: function fetchFromServer() {
|
|
|
var _this4 = this;
|
|
@@ -72588,6 +72719,12 @@ return __p
|
|
|
xmlns: Strophe.NS.ROSTER
|
|
|
});
|
|
|
|
|
|
+ if (_this4.rosterVersioningSupported()) {
|
|
|
+ iq.attrs({
|
|
|
+ 'ver': _this4.data.get('version')
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
var callback = _.flow(_this4.onReceivedFromServer.bind(_this4), resolve);
|
|
|
|
|
|
var errback = function errback(iq) {
|
|
@@ -72602,19 +72739,31 @@ return __p
|
|
|
});
|
|
|
},
|
|
|
onReceivedFromServer: function onReceivedFromServer(iq) {
|
|
|
+ var _this5 = this;
|
|
|
+
|
|
|
/* An IQ stanza containing the roster has been received from
|
|
|
- * the XMPP server.
|
|
|
- */
|
|
|
- var items = sizzle("query[xmlns=\"".concat(Strophe.NS.ROSTER, "\"] item"), iq);
|
|
|
+ * the XMPP server.
|
|
|
+ */
|
|
|
+ var query = sizzle("query[xmlns=\"".concat(Strophe.NS.ROSTER, "\"]"), iq).pop();
|
|
|
+
|
|
|
+ if (query) {
|
|
|
+ var items = sizzle("item", query);
|
|
|
+
|
|
|
+ _.each(items, function (item) {
|
|
|
+ return _this5.updateContact(item);
|
|
|
+ });
|
|
|
+
|
|
|
+ this.data.save('version', query.getAttribute('ver'));
|
|
|
|
|
|
- _.each(items, this.updateContact.bind(this));
|
|
|
+ _converse.session.save('roster_fetched', true);
|
|
|
+ }
|
|
|
|
|
|
_converse.emit('roster', iq);
|
|
|
},
|
|
|
updateContact: function updateContact(item) {
|
|
|
/* Update or create RosterContact models based on items
|
|
|
- * received in the IQ from the server.
|
|
|
- */
|
|
|
+ * received in the IQ from the server.
|
|
|
+ */
|
|
|
var jid = item.getAttribute('jid');
|
|
|
|
|
|
if (this.isSelf(jid)) {
|
|
@@ -72795,7 +72944,7 @@ return __p
|
|
|
_converse.RosterGroups = Backbone.Collection.extend({
|
|
|
model: _converse.RosterGroup,
|
|
|
fetchRosterGroups: function fetchRosterGroups() {
|
|
|
- var _this5 = this;
|
|
|
+ var _this6 = this;
|
|
|
|
|
|
/* Fetches all the roster groups from sessionStorage.
|
|
|
*
|
|
@@ -72803,7 +72952,7 @@ return __p
|
|
|
* returned.
|
|
|
*/
|
|
|
return new Promise(function (resolve, reject) {
|
|
|
- _this5.fetch({
|
|
|
+ _this6.fetch({
|
|
|
silent: true,
|
|
|
// We need to first have all groups before
|
|
|
// we can start positioning them, so we set
|