parent
54e9c51a1a
commit
9d77a4ef97
|
@ -2,11 +2,18 @@
|
|||
|
||||
## 6.0.0 (Unreleased)
|
||||
|
||||
- #129: Add support for XEP-0156: Disovering Alternative XMPP Connection Methods. Only XML is supported for now.
|
||||
- #1691 Fix `collection.chatbox is undefined` errors
|
||||
- Prevent editing of sent file uploads.
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- In order to add support for XEP-0156, the XMPP connection needs to be created
|
||||
only once we know the JID of the user that's logging in. This means that the
|
||||
[connectionInitialized](https://conversejs.org/docs/html/api/-_converse.html#event:connectionInitialized)
|
||||
event now fires much later than before. Plugins that rely on `connectionInitialized`
|
||||
being triggered before the user's JID has been provided will need to be updated.
|
||||
|
||||
- The following API methods now return promises:
|
||||
* `_converse.api.chats.get`
|
||||
* `_converse.api.chats.create`
|
||||
|
|
|
@ -639,6 +639,23 @@ The default chat status that the user wil have. If you for example set this to
|
|||
``'chat'``, then Converse will send out a presence stanza with ``"show"``
|
||||
set to ``'chat'`` as soon as you've been logged in.
|
||||
|
||||
|
||||
discover_connection_methods
|
||||
---------------------------
|
||||
|
||||
* Default: ``false``
|
||||
|
||||
Use `XEP-0156 <https://xmpp.org/extensions/xep-0156.html>`_ to discover whether
|
||||
the XMPP host for the current user advertises any Websocket or BOSH connection
|
||||
URLs that can be used.
|
||||
|
||||
If this is set to ``false``, then a `websocket_url`_ or `bosh_service_url`_ need to be
|
||||
set.
|
||||
|
||||
Currently only the XML encoded host-meta resource is supported as shown in
|
||||
`Example 2 under section 3.3 <https://xmpp.org/extensions/xep-0156.html#httpexamples>`_.
|
||||
|
||||
|
||||
domain_placeholder
|
||||
------------------
|
||||
|
||||
|
@ -647,8 +664,6 @@ domain_placeholder
|
|||
The placeholder text shown in the domain input on the registration form.
|
||||
|
||||
|
||||
|
||||
|
||||
emoji_image_path
|
||||
----------------
|
||||
|
||||
|
@ -1624,6 +1639,7 @@ Allows you to show or hide buttons on the chatboxes' toolbars.
|
|||
|
||||
.. _`websocket-url`:
|
||||
|
||||
|
||||
websocket_url
|
||||
-------------
|
||||
|
||||
|
|
|
@ -404,8 +404,8 @@
|
|||
|
||||
|
||||
it("can be retrieved from the XMPP server", mock.initConverse(
|
||||
{'connection': ['send']}, ['chatBoxesFetched', 'roomsPanelRendered', 'rosterGroupsFetched'], {},
|
||||
async function (done, _converse) {
|
||||
null, ['chatBoxesFetched', 'roomsPanelRendered', 'rosterGroupsFetched'], {},
|
||||
async function (done, _converse) {
|
||||
|
||||
await test_utils.waitUntilDiscoConfirmed(
|
||||
_converse, _converse.bare_jid,
|
||||
|
@ -421,25 +421,12 @@
|
|||
* </pubsub>
|
||||
* </iq>
|
||||
*/
|
||||
let IQ_id;
|
||||
const call = await u.waitUntil(() =>
|
||||
_.filter(
|
||||
_converse.connection.send.calls.all(),
|
||||
call => {
|
||||
const stanza = call.args[0];
|
||||
if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
|
||||
return;
|
||||
}
|
||||
if (sizzle('items[node="storage:bookmarks"]', stanza).length) {
|
||||
IQ_id = stanza.getAttribute('id');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
).pop()
|
||||
);
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
const sent_stanza = await u.waitUntil(
|
||||
() => IQ_stanzas.filter(s => sizzle('items[node="storage:bookmarks"]', s).length).pop());
|
||||
|
||||
expect(Strophe.serialize(call.args[0])).toBe(
|
||||
`<iq from="romeo@montague.lit/orchard" id="${IQ_id}" type="get" xmlns="jabber:client">`+
|
||||
expect(Strophe.serialize(sent_stanza)).toBe(
|
||||
`<iq from="romeo@montague.lit/orchard" id="${sent_stanza.getAttribute('id')}" type="get" xmlns="jabber:client">`+
|
||||
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
|
||||
'<items node="storage:bookmarks"/>'+
|
||||
'</pubsub>'+
|
||||
|
@ -469,7 +456,7 @@
|
|||
expect(_converse.bookmarks.models.length).toBe(0);
|
||||
|
||||
spyOn(_converse.bookmarks, 'onBookmarksReceived').and.callThrough();
|
||||
var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
|
||||
var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':sent_stanza.getAttribute('id')})
|
||||
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
|
||||
.c('items', {'node': 'storage:bookmarks'})
|
||||
.c('item', {'id': 'current'})
|
||||
|
@ -495,7 +482,7 @@
|
|||
describe("The rooms panel", function () {
|
||||
|
||||
it("shows a list of bookmarks", mock.initConverse(
|
||||
{'connection': ['send']}, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
async function (done, _converse) {
|
||||
|
||||
await test_utils.waitUntilDiscoConfirmed(
|
||||
|
@ -505,31 +492,19 @@
|
|||
);
|
||||
test_utils.openControlBox();
|
||||
|
||||
let IQ_id;
|
||||
const call = await u.waitUntil(() =>
|
||||
_.filter(
|
||||
_converse.connection.send.calls.all(),
|
||||
call => {
|
||||
const stanza = call.args[0];
|
||||
if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
|
||||
return;
|
||||
}
|
||||
if (sizzle('items[node="storage:bookmarks"]', stanza).length) {
|
||||
IQ_id = stanza.getAttribute('id');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
).pop()
|
||||
);
|
||||
expect(Strophe.serialize(call.args[0])).toBe(
|
||||
`<iq from="romeo@montague.lit/orchard" id="${IQ_id}" type="get" xmlns="jabber:client">`+
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
const sent_stanza = await u.waitUntil(
|
||||
() => IQ_stanzas.filter(s => sizzle('items[node="storage:bookmarks"]', s).length).pop());
|
||||
|
||||
expect(Strophe.serialize(sent_stanza)).toBe(
|
||||
`<iq from="romeo@montague.lit/orchard" id="${sent_stanza.getAttribute('id')}" type="get" xmlns="jabber:client">`+
|
||||
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
|
||||
'<items node="storage:bookmarks"/>'+
|
||||
'</pubsub>'+
|
||||
'</iq>'
|
||||
);
|
||||
|
||||
const stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
|
||||
const stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':sent_stanza.getAttribute('id')})
|
||||
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
|
||||
.c('items', {'node': 'storage:bookmarks'})
|
||||
.c('item', {'id': 'current'})
|
||||
|
@ -583,7 +558,7 @@
|
|||
|
||||
|
||||
it("remembers the toggle state of the bookmarks list", mock.initConverse(
|
||||
{'connection': ['send']}, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
async function (done, _converse) {
|
||||
|
||||
test_utils.openControlBox();
|
||||
|
@ -593,31 +568,19 @@
|
|||
['http://jabber.org/protocol/pubsub#publish-options']
|
||||
);
|
||||
|
||||
let IQ_id;
|
||||
const call = await u.waitUntil(() =>
|
||||
_.filter(
|
||||
_converse.connection.send.calls.all(),
|
||||
call => {
|
||||
const stanza = call.args[0];
|
||||
if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
|
||||
return;
|
||||
}
|
||||
if (sizzle('items[node="storage:bookmarks"]', stanza).length) {
|
||||
IQ_id = stanza.getAttribute('id');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
).pop()
|
||||
);
|
||||
expect(Strophe.serialize(call.args[0])).toBe(
|
||||
`<iq from="romeo@montague.lit/orchard" id="${IQ_id}" type="get" xmlns="jabber:client">`+
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
const sent_stanza = await u.waitUntil(
|
||||
() => IQ_stanzas.filter(s => sizzle('items[node="storage:bookmarks"]', s).length).pop());
|
||||
|
||||
expect(Strophe.serialize(sent_stanza)).toBe(
|
||||
`<iq from="romeo@montague.lit/orchard" id="${sent_stanza.getAttribute('id')}" type="get" xmlns="jabber:client">`+
|
||||
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
|
||||
'<items node="storage:bookmarks"/>'+
|
||||
'</pubsub>'+
|
||||
'</iq>'
|
||||
);
|
||||
|
||||
const stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
|
||||
const stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':sent_stanza.getAttribute('id')})
|
||||
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
|
||||
.c('items', {'node': 'storage:bookmarks'})
|
||||
.c('item', {'id': 'current'})
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
it("contains a checkbox to indicate whether the computer is trusted or not",
|
||||
mock.initConverse(
|
||||
null, ['connectionInitialized', 'chatBoxesInitialized'],
|
||||
null, ['chatBoxesInitialized'],
|
||||
{ auto_login: false,
|
||||
allow_registration: false },
|
||||
async function (done, _converse) {
|
||||
|
@ -42,7 +42,7 @@
|
|||
|
||||
it("checkbox can be set to false by default",
|
||||
mock.initConverse(
|
||||
null, ['connectionInitialized', 'chatBoxesInitialized'],
|
||||
null, ['chatBoxesInitialized'],
|
||||
{ auto_login: false,
|
||||
trusted: false,
|
||||
allow_registration: false },
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
it("is not available unless allow_registration=true",
|
||||
mock.initConverse(
|
||||
null, ['connectionInitialized', 'chatBoxesInitialized'],
|
||||
null, ['chatBoxesInitialized'],
|
||||
{ auto_login: false,
|
||||
allow_registration: false },
|
||||
async function (done, _converse) {
|
||||
|
@ -24,7 +24,7 @@
|
|||
|
||||
it("can be opened by clicking on the registration tab",
|
||||
mock.initConverse(
|
||||
null, ['connectionInitialized', 'chatBoxesInitialized'],
|
||||
null, ['chatBoxesInitialized'],
|
||||
{ auto_login: false,
|
||||
allow_registration: true },
|
||||
async function (done, _converse) {
|
||||
|
@ -45,18 +45,18 @@
|
|||
|
||||
it("allows the user to choose an XMPP provider's domain",
|
||||
mock.initConverse(
|
||||
null, ['connectionInitialized', 'chatBoxesInitialized'],
|
||||
null, ['chatBoxesInitialized'],
|
||||
{ auto_login: false,
|
||||
allow_registration: true },
|
||||
async function (done, _converse) {
|
||||
|
||||
spyOn(Strophe.Connection.prototype, 'connect');
|
||||
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
||||
test_utils.openControlBox();
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
const registerview = cbview.registerpanel;
|
||||
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
||||
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||
spyOn(_converse.connection, 'connect');
|
||||
|
||||
// Open the register panel
|
||||
cbview.el.querySelector('.toggle-register-login').click();
|
||||
|
@ -75,17 +75,18 @@
|
|||
form.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||
submit_button.click();
|
||||
expect(registerview.onProviderChosen).toHaveBeenCalled();
|
||||
expect(_converse.connection.connect).toHaveBeenCalled();
|
||||
await u.waitUntil(() => _converse.connection.connect.calls.count());
|
||||
done();
|
||||
}));
|
||||
|
||||
it("will render a registration form as received from the XMPP provider",
|
||||
mock.initConverse(
|
||||
null, ['connectionInitialized', 'chatBoxesInitialized'],
|
||||
null, ['chatBoxesInitialized'],
|
||||
{ auto_login: false,
|
||||
allow_registration: true },
|
||||
async function (done, _converse) {
|
||||
|
||||
spyOn(Strophe.Connection.prototype, 'connect');
|
||||
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
||||
test_utils.openControlBox();
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
|
@ -97,7 +98,6 @@
|
|||
spyOn(registerview, 'onRegistrationFields').and.callThrough();
|
||||
spyOn(registerview, 'renderRegistrationForm').and.callThrough();
|
||||
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||
spyOn(_converse.connection, 'connect').and.callThrough();
|
||||
|
||||
expect(registerview._registering).toBeFalsy();
|
||||
expect(_converse.connection.connected).toBeFalsy();
|
||||
|
@ -105,7 +105,7 @@
|
|||
registerview.el.querySelector('input[type=submit]').click();
|
||||
expect(registerview.onProviderChosen).toHaveBeenCalled();
|
||||
expect(registerview._registering).toBeTruthy();
|
||||
expect(_converse.connection.connect).toHaveBeenCalled();
|
||||
await u.waitUntil(() => _converse.connection.connect.calls.count());
|
||||
|
||||
let stanza = new Strophe.Builder("stream:features", {
|
||||
'xmlns:stream': "http://etherx.jabber.org/streams",
|
||||
|
@ -137,7 +137,7 @@
|
|||
|
||||
it("will set form_type to legacy and submit it as legacy",
|
||||
mock.initConverse(
|
||||
null, ['connectionInitialized', 'chatBoxesInitialized'],
|
||||
null, ['chatBoxesInitialized'],
|
||||
{ auto_login: false,
|
||||
allow_registration: true },
|
||||
async function (done, _converse) {
|
||||
|
@ -194,7 +194,7 @@
|
|||
|
||||
it("will set form_type to xform and submit it as xform",
|
||||
mock.initConverse(
|
||||
null, ['connectionInitialized', 'chatBoxesInitialized'],
|
||||
null, ['chatBoxesInitialized'],
|
||||
{ auto_login: false,
|
||||
allow_registration: true },
|
||||
async function (done, _converse) {
|
||||
|
@ -267,7 +267,7 @@
|
|||
|
||||
it("renders the account registration form",
|
||||
mock.initConverse(
|
||||
null, ['connectionInitialized', 'chatBoxesInitialized'],
|
||||
null, ['chatBoxesInitialized'],
|
||||
{ auto_login: false,
|
||||
view_mode: 'fullscreen',
|
||||
allow_registration: true },
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
|
||||
it("uses bookmarks to determine groupchat names",
|
||||
mock.initConverse(
|
||||
{'connection': ['send']},
|
||||
null,
|
||||
['rosterGroupsFetched', 'chatBoxesFetched', 'emojisInitialized'],
|
||||
{'view_mode': 'fullscreen'},
|
||||
async function (done, _converse) {
|
||||
|
@ -113,7 +113,7 @@
|
|||
|
||||
describe("A groupchat shown in the groupchats list", function () {
|
||||
|
||||
it("is highlighted if its currently open", mock.initConverse(
|
||||
it("is highlighted if it's currently open", mock.initConverse(
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched', 'emojisInitialized'],
|
||||
{ view_mode: 'fullscreen',
|
||||
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
|
||||
|
@ -137,8 +137,6 @@
|
|||
expect(room_els.length).toBe(1);
|
||||
item = room_els[0];
|
||||
expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit');
|
||||
const conv_el = document.querySelector('#conversejs');
|
||||
conv_el.parentElement.removeChild(conv_el);
|
||||
done();
|
||||
}));
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
it("gets enabled with an <enable> stanza and resumed with a <resume> stanza",
|
||||
mock.initConverse(
|
||||
null, ['connectionInitialized', 'chatBoxesInitialized'],
|
||||
null, ['chatBoxesInitialized'],
|
||||
{ 'auto_login': false,
|
||||
'enable_smacks': true,
|
||||
'show_controlbox_by_default': true,
|
||||
|
|
|
@ -1124,7 +1124,7 @@ converse.plugins.add('converse-chatview', {
|
|||
if (Backbone.history.getFragment() === "converse/chat?jid="+this.model.get('jid')) {
|
||||
_converse.router.navigate('');
|
||||
}
|
||||
if (_converse.connection.connected) {
|
||||
if (_converse.api.connection.connected()) {
|
||||
// Immediately sending the chat state, because the
|
||||
// model is going to be destroyed afterwards.
|
||||
this.model.setChatState(_converse.INACTIVE);
|
||||
|
|
|
@ -154,6 +154,7 @@ converse.plugins.add('converse-controlbox', {
|
|||
|
||||
_converse.api.promises.add('controlBoxInitialized');
|
||||
|
||||
|
||||
const addControlBox = () => _converse.chatboxes.add({'id': 'controlbox'});
|
||||
|
||||
_converse.ControlBox = _converse.ChatBox.extend({
|
||||
|
@ -220,9 +221,9 @@ converse.plugins.add('converse-controlbox', {
|
|||
} else {
|
||||
this.hide();
|
||||
}
|
||||
if (!_converse.connection.connected ||
|
||||
!_converse.connection.authenticated ||
|
||||
_converse.connection.disconnecting) {
|
||||
|
||||
const connection = get(_converse, 'connection', {});
|
||||
if (!connection.connected || !connection.authenticated || connection.disconnecting) {
|
||||
this.renderLoginPanel();
|
||||
} else if (this.model.get('connected')) {
|
||||
this.renderControlBoxPane();
|
||||
|
@ -296,7 +297,8 @@ converse.plugins.add('converse-controlbox', {
|
|||
if (_converse.sticky_controlbox) {
|
||||
return;
|
||||
}
|
||||
if (_converse.connection.connected && !_converse.connection.disconnecting) {
|
||||
const connection = get(_converse, 'connection', {});
|
||||
if (connection.connected && !connection.disconnecting) {
|
||||
this.model.save({'closed': true});
|
||||
} else {
|
||||
this.model.trigger('hide');
|
||||
|
@ -319,7 +321,8 @@ converse.plugins.add('converse-controlbox', {
|
|||
}
|
||||
u.addClass('hidden', this.el);
|
||||
_converse.api.trigger('chatBoxClosed', this);
|
||||
if (!_converse.connection.connected) {
|
||||
|
||||
if (!_converse.api.connection.connected()) {
|
||||
_converse.controlboxtoggle.render();
|
||||
}
|
||||
_converse.controlboxtoggle.show(callback);
|
||||
|
@ -464,7 +467,7 @@ converse.plugins.add('converse-controlbox', {
|
|||
if (["converse/login", "converse/register"].includes(Backbone.history.getFragment())) {
|
||||
_converse.router.navigate('', {'replace': true});
|
||||
}
|
||||
_converse.connection.reset();
|
||||
_converse.connection && _converse.connection.reset();
|
||||
_converse.api.user.login(jid, password);
|
||||
}
|
||||
});
|
||||
|
@ -510,7 +513,7 @@ converse.plugins.add('converse-controlbox', {
|
|||
// artifacts (i.e. on page load the toggle is shown only to then
|
||||
// seconds later be hidden in favor of the controlbox).
|
||||
this.el.innerHTML = tpl_controlbox_toggle({
|
||||
'label_toggle': _converse.connection.connected ? __('Chat Contacts') : __('Toggle chat')
|
||||
'label_toggle': _converse.api.connection.connected() ? __('Chat Contacts') : __('Toggle chat')
|
||||
})
|
||||
return this;
|
||||
},
|
||||
|
@ -529,7 +532,7 @@ converse.plugins.add('converse-controlbox', {
|
|||
if (!controlbox) {
|
||||
controlbox = addControlBox();
|
||||
}
|
||||
if (_converse.connection.connected) {
|
||||
if (_converse.api.connection.connected()) {
|
||||
controlbox.save({'closed': false});
|
||||
} else {
|
||||
controlbox.trigger('show');
|
||||
|
@ -540,7 +543,7 @@ converse.plugins.add('converse-controlbox', {
|
|||
e.preventDefault();
|
||||
if (u.isVisible(_converse.root.querySelector("#controlbox"))) {
|
||||
const controlbox = _converse.chatboxes.get('controlbox');
|
||||
if (_converse.connection.connected) {
|
||||
if (_converse.api.connection.connected) {
|
||||
controlbox.save({closed: true});
|
||||
} else {
|
||||
controlbox.trigger('hide');
|
||||
|
@ -582,10 +585,9 @@ converse.plugins.add('converse-controlbox', {
|
|||
});
|
||||
|
||||
|
||||
Promise.all([
|
||||
_converse.api.waitUntil('connectionInitialized'),
|
||||
_converse.api.waitUntil('chatBoxViewsInitialized')
|
||||
]).then(addControlBox).catch(e => _converse.log(e, Strophe.LogLevel.FATAL));
|
||||
_converse.api.waitUntil('chatBoxViewsInitialized')
|
||||
.then(addControlBox)
|
||||
.catch(e => _converse.log(e, Strophe.LogLevel.FATAL));
|
||||
|
||||
_converse.api.listen.on('chatBoxesFetched', () => {
|
||||
const controlbox = _converse.chatboxes.get('controlbox') || addControlBox();
|
||||
|
|
|
@ -351,7 +351,7 @@ converse.plugins.add('converse-dragresize', {
|
|||
_converse.resizing.chatbox.width,
|
||||
_converse.resizing.chatbox.model.get('default_width')
|
||||
);
|
||||
if (_converse.connection.connected) {
|
||||
if (_converse.api.connection.connected()) {
|
||||
_converse.resizing.chatbox.model.save({'height': height});
|
||||
_converse.resizing.chatbox.model.save({'width': width});
|
||||
} else {
|
||||
|
|
|
@ -318,7 +318,7 @@ converse.plugins.add('converse-minimize', {
|
|||
* @param { _converse.ChatBoxView|_converse.ChatRoomView|_converse.ControlBoxView|_converse.HeadlinesBoxView } [newchat]
|
||||
*/
|
||||
async trimChats (newchat) {
|
||||
if (_converse.no_trimming || !_converse.connection.connected || _converse.view_mode !== 'overlayed') {
|
||||
if (_converse.no_trimming || !_converse.api.connection.connected() || _converse.view_mode !== 'overlayed') {
|
||||
return;
|
||||
}
|
||||
const shown_chats = this.getShownChats();
|
||||
|
@ -556,10 +556,7 @@ converse.plugins.add('converse-minimize', {
|
|||
});
|
||||
|
||||
/************************ BEGIN Event Handlers ************************/
|
||||
Promise.all([
|
||||
_converse.api.waitUntil('connectionInitialized'),
|
||||
_converse.api.waitUntil('chatBoxViewsInitialized')
|
||||
]).then(() => {
|
||||
_converse.api.waitUntil('chatBoxViewsInitialized').then(() => {
|
||||
_converse.minimized_chats = new _converse.MinimizedChats({
|
||||
model: _converse.chatboxes
|
||||
});
|
||||
|
|
|
@ -240,8 +240,8 @@ converse.plugins.add('converse-omemo', {
|
|||
/* The initialize function gets called as soon as the plugin is
|
||||
* loaded by Converse.js's plugin machinery.
|
||||
*/
|
||||
const { _converse } = this,
|
||||
{ __ } = _converse;
|
||||
const { _converse } = this;
|
||||
const { __ } = _converse;
|
||||
|
||||
_converse.api.settings.update({
|
||||
'omemo_default': false,
|
||||
|
|
|
@ -175,7 +175,7 @@ converse.plugins.add('converse-register', {
|
|||
|
||||
initialize () {
|
||||
this.reset();
|
||||
this.registerHooks();
|
||||
_converse.api.listen.on('connectionInitialized', () => this.registerHooks());
|
||||
},
|
||||
|
||||
render () {
|
||||
|
@ -340,7 +340,7 @@ converse.plugins.add('converse-register', {
|
|||
* @method _converse.RegisterPanel#fetchRegistrationForm
|
||||
* @param { String } domain_name - XMPP server domain
|
||||
*/
|
||||
fetchRegistrationForm (domain_name) {
|
||||
async fetchRegistrationForm (domain_name) {
|
||||
if (!this.model.get('registration_form_rendered')) {
|
||||
this.renderRegistrationRequest();
|
||||
}
|
||||
|
@ -348,7 +348,8 @@ converse.plugins.add('converse-register', {
|
|||
'domain': Strophe.getDomainFromJid(domain_name),
|
||||
'_registering': true
|
||||
});
|
||||
_converse.connection.connect(this.domain, "", this.onConnectStatusChanged.bind(this));
|
||||
await _converse.initConnection(this.domain);
|
||||
_converse.connection.connect(this.domain, "", status => this.onConnectStatusChanged(status));
|
||||
return false;
|
||||
},
|
||||
|
||||
|
|
|
@ -19,6 +19,10 @@ const BOSH_SESSION_ID = 'converse.bosh-session';
|
|||
|
||||
converse.plugins.add('converse-bosh', {
|
||||
|
||||
enabled () {
|
||||
return true;
|
||||
},
|
||||
|
||||
initialize () {
|
||||
const { _converse } = this;
|
||||
|
||||
|
@ -35,9 +39,15 @@ converse.plugins.add('converse-bosh', {
|
|||
_converse.bosh_session.browserStorage = new BrowserStorage.session(id);
|
||||
await new Promise(resolve => _converse.bosh_session.fetch({'success': resolve, 'error': resolve}));
|
||||
}
|
||||
if (_converse.jid && _converse.bosh_session.get('jid') === _converse.jid) {
|
||||
_converse.bosh_session.clear({'silent': true });
|
||||
_converse.bosh_session.save({'jid': _converse.jid, id});
|
||||
if (_converse.jid) {
|
||||
if (_converse.bosh_session.get('jid') !== _converse.jid) {
|
||||
const jid = await _converse.setUserJID(_converse.jid);
|
||||
_converse.bosh_session.clear({'silent': true });
|
||||
_converse.bosh_session.save({jid});
|
||||
}
|
||||
} else { // Keepalive
|
||||
const jid = _converse.bosh_session.get('jid');
|
||||
jid && await _converse.setUserJID();
|
||||
}
|
||||
return _converse.bosh_session;
|
||||
}
|
||||
|
@ -45,17 +55,17 @@ converse.plugins.add('converse-bosh', {
|
|||
|
||||
_converse.startNewPreboundBOSHSession = function () {
|
||||
if (!_converse.prebind_url) {
|
||||
throw new Error(
|
||||
"attemptPreboundSession: If you use prebind then you MUST supply a prebind_url");
|
||||
throw new Error("startNewPreboundBOSHSession: If you use prebind then you MUST supply a prebind_url");
|
||||
}
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', _converse.prebind_url, true);
|
||||
xhr.setRequestHeader('Accept', 'application/json, text/javascript');
|
||||
xhr.onload = function () {
|
||||
xhr.onload = async function () {
|
||||
if (xhr.status >= 200 && xhr.status < 400) {
|
||||
const data = JSON.parse(xhr.responseText);
|
||||
const jid = await _converse.setUserJID(data.jid);
|
||||
_converse.connection.attach(
|
||||
data.jid,
|
||||
jid,
|
||||
data.sid,
|
||||
data.rid,
|
||||
_converse.onConnectStatusChanged
|
||||
|
@ -79,9 +89,6 @@ converse.plugins.add('converse-bosh', {
|
|||
|
||||
|
||||
_converse.restoreBOSHSession = async function () {
|
||||
if (!_converse.api.connection.isType('bosh')) {
|
||||
return false;
|
||||
}
|
||||
const jid = (await initBOSHSession()).get('jid');
|
||||
if (jid) {
|
||||
try {
|
||||
|
@ -119,9 +126,7 @@ converse.plugins.add('converse-bosh', {
|
|||
}
|
||||
});
|
||||
|
||||
_converse.api.listen.on('addClientFeatures',
|
||||
() => _converse.api.disco.own.features.add(Strophe.NS.BOSH)
|
||||
);
|
||||
_converse.api.listen.on('addClientFeatures', () => _converse.api.disco.own.features.add(Strophe.NS.BOSH));
|
||||
|
||||
/************************ END Event Handlers ************************/
|
||||
|
||||
|
|
|
@ -850,8 +850,8 @@ converse.plugins.add('converse-chatboxes', {
|
|||
'to': this.get('jid'),
|
||||
'type': 'chat'
|
||||
}).c(this.get('chat_state'), {'xmlns': Strophe.NS.CHATSTATES}).up()
|
||||
.c('no-store', {'xmlns': Strophe.NS.HINTS}).up()
|
||||
.c('no-permanent-store', {'xmlns': Strophe.NS.HINTS})
|
||||
.c('no-store', {'xmlns': Strophe.NS.HINTS}).up()
|
||||
.c('no-permanent-store', {'xmlns': Strophe.NS.HINTS})
|
||||
);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -230,6 +230,7 @@ _converse.default_settings = {
|
|||
csi_waiting_time: 0, // Support for XEP-0352. Seconds before client is considered idle and CSI is sent out.
|
||||
debug: false,
|
||||
default_state: 'online',
|
||||
discover_connection_methods: false,
|
||||
geouri_regex: /https\:\/\/www.openstreetmap.org\/.*#map=[0-9]+\/([\-0-9.]+)\/([\-0-9.]+)\S*/g,
|
||||
geouri_replacement: 'https://www.openstreetmap.org/?mlat=$1&mlon=$2#map=18/$1/$2',
|
||||
idle_presence_timeout: 300, // Seconds after which an idle presence is sent
|
||||
|
@ -330,7 +331,7 @@ function addPromise (promise) {
|
|||
}
|
||||
|
||||
_converse.isTestEnv = function () {
|
||||
return _.get(_converse.connection, 'service') === 'jasmine tests';
|
||||
return Strophe.Connection.name === 'MockConnection';
|
||||
}
|
||||
|
||||
|
||||
|
@ -457,7 +458,7 @@ async function attemptNonPreboundSession (credentials, automatic) {
|
|||
} else if (!_converse.isTestEnv() && window.PasswordCredential) {
|
||||
connect(await getLoginCredentialsFromBrowser());
|
||||
} else {
|
||||
throw new Error("attemptNonPreboundSession: Could not find any credentials to log you in with!");
|
||||
_converse.log("attemptNonPreboundSession: Could not find any credentials to log in with", Strophe.LogLevel.WARN);
|
||||
}
|
||||
} else if ([_converse.ANONYMOUS, _converse.EXTERNAL].includes(_converse.authentication) && (!automatic || _converse.auto_login)) {
|
||||
connect();
|
||||
|
@ -523,9 +524,7 @@ function reconnect () {
|
|||
const debouncedReconnect = _.debounce(reconnect, 2000);
|
||||
|
||||
|
||||
_converse.shouldClearCache = function () {
|
||||
return !_converse.config.get('trusted') || _converse.isTestEnv();
|
||||
}
|
||||
_converse.shouldClearCache = () => (!_converse.config.get('trusted') || _converse.isTestEnv());
|
||||
|
||||
function clearSession () {
|
||||
if (_converse.session !== undefined) {
|
||||
|
@ -548,36 +547,83 @@ function clearSession () {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new Strophe.Connection instance and if applicable, attempt to
|
||||
* restore the BOSH session or if `auto_login` is true, attempt to log in.
|
||||
async function onDomainDiscovered (response) {
|
||||
const text = await response.text();
|
||||
const xrd = (new window.DOMParser()).parseFromString(text, "text/xml").firstElementChild;
|
||||
if (xrd.nodeName != "XRD" || xrd.namespaceURI != "http://docs.oasis-open.org/ns/xri/xrd-1.0") {
|
||||
return _converse.log("Could not discover XEP-0156 connection methods", Strophe.LogLevel.WARN);
|
||||
}
|
||||
const bosh_links = sizzle(`Link[rel="urn:xmpp:alt-connections:xbosh"]`, xrd);
|
||||
const ws_links = sizzle(`Link[rel="urn:xmpp:alt-connections:websocket"]`, xrd);
|
||||
const bosh_methods = bosh_links.map(el => el.getAttribute('href'));
|
||||
const ws_methods = ws_links.map(el => el.getAttribute('href'));
|
||||
// TODO: support multiple endpoints
|
||||
_converse.websocket_url = ws_methods.pop();
|
||||
_converse.bosh_service_url = bosh_methods.pop();
|
||||
if (bosh_methods.length === 0 && ws_methods.length === 0) {
|
||||
_converse.log(
|
||||
"onDomainDiscovered: neither BOSH nor WebSocket connection methods have been specified with XEP-0156.",
|
||||
Strophe.LogLevel.WARN
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Use XEP-0156 to check whether this host advertises websocket or BOSH connection methods.
|
||||
*/
|
||||
_converse.initConnection = async function () {
|
||||
if (!_converse.connection) {
|
||||
if (!_converse.bosh_service_url && ! _converse.websocket_url) {
|
||||
async function discoverConnectionMethods (domain) {
|
||||
const options = {
|
||||
'mode': 'cors',
|
||||
'headers': {
|
||||
'Accept': 'application/xrd+xml, text/xml'
|
||||
}
|
||||
};
|
||||
const url = `https://${domain}/.well-known/host-meta`;
|
||||
let response;
|
||||
try {
|
||||
response = await fetch(url, options);
|
||||
} catch (e) {
|
||||
_converse.log(`Failed to discover alternative connection methods at ${url}`, Strophe.LogLevel.ERROR);
|
||||
return _converse.log(e, Strophe.LogLevel.ERROR);
|
||||
}
|
||||
if (response.status >= 200 && response.status < 400) {
|
||||
await onDomainDiscovered(response);
|
||||
} else {
|
||||
_converse.log("Could not discover XEP-0156 connection methods", Strophe.LogLevel.WARN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_converse.initConnection = async function (domain) {
|
||||
if (_converse.discover_connection_methods) {
|
||||
await discoverConnectionMethods(domain);
|
||||
}
|
||||
if (! _converse.bosh_service_url) {
|
||||
if (_converse.authentication === _converse.PREBIND) {
|
||||
throw new Error("authentication is set to 'prebind' but we don't have a BOSH connection");
|
||||
}
|
||||
if (! _converse.websocket_url) {
|
||||
throw new Error("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both.");
|
||||
}
|
||||
if (('WebSocket' in window || 'MozWebSocket' in window) && _converse.websocket_url) {
|
||||
_converse.connection = new Strophe.Connection(
|
||||
_converse.websocket_url,
|
||||
Object.assign(_converse.default_connection_options, _converse.connection_options)
|
||||
);
|
||||
} else if (_converse.bosh_service_url) {
|
||||
_converse.connection = new Strophe.Connection(
|
||||
_converse.bosh_service_url,
|
||||
Object.assign(
|
||||
_converse.default_connection_options,
|
||||
_converse.connection_options,
|
||||
{'keepalive': _converse.keepalive}
|
||||
)
|
||||
);
|
||||
} else {
|
||||
throw new Error("initConnection: this browser does not support "+
|
||||
"websockets and bosh_service_url wasn't specified.");
|
||||
}
|
||||
if (_converse.auto_login || _converse.keepalive) {
|
||||
await _converse.api.user.login(null, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (('WebSocket' in window || 'MozWebSocket' in window) && _converse.websocket_url) {
|
||||
_converse.connection = new Strophe.Connection(
|
||||
_converse.websocket_url,
|
||||
Object.assign(_converse.default_connection_options, _converse.connection_options)
|
||||
);
|
||||
} else if (_converse.bosh_service_url) {
|
||||
_converse.connection = new Strophe.Connection(
|
||||
_converse.bosh_service_url,
|
||||
Object.assign(
|
||||
_converse.default_connection_options,
|
||||
_converse.connection_options,
|
||||
{'keepalive': _converse.keepalive}
|
||||
)
|
||||
);
|
||||
} else {
|
||||
throw new Error("initConnection: this browser does not support "+
|
||||
"websockets and bosh_service_url wasn't specified.");
|
||||
}
|
||||
setUpXMLLogging();
|
||||
/**
|
||||
|
@ -587,10 +633,10 @@ _converse.initConnection = async function () {
|
|||
* @event _converse#connectionInitialized
|
||||
*/
|
||||
_converse.api.trigger('connectionInitialized');
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
async function setUserJID (jid) {
|
||||
async function initSession (jid) {
|
||||
const bare_jid = Strophe.getBareJidFromJid(jid).toLowerCase();
|
||||
const id = `converse.session-${bare_jid}`;
|
||||
if (!_converse.session || _converse.session.get('id') !== id) {
|
||||
|
@ -612,23 +658,14 @@ async function setUserJID (jid) {
|
|||
} else {
|
||||
saveJIDtoSession(jid);
|
||||
}
|
||||
/**
|
||||
* Triggered whenever the user's JID has been updated
|
||||
* @event _converse#setUserJID
|
||||
*/
|
||||
_converse.api.trigger('setUserJID');
|
||||
return jid;
|
||||
}
|
||||
|
||||
|
||||
function saveJIDtoSession (jid) {
|
||||
jid = _converse.session.get('jid') || jid;
|
||||
if (_converse.authentication !== _converse.ANONYMOUS && !Strophe.getResourceFromJid(jid)) {
|
||||
jid = jid.toLowerCase() + _converse.generateResource();
|
||||
}
|
||||
// Set JID on the connection object so that when we call
|
||||
// `connection.bind` the new resource is found by Strophe.js
|
||||
// and sent to the XMPP server.
|
||||
_converse.connection.jid = jid;
|
||||
_converse.jid = jid;
|
||||
_converse.bare_jid = Strophe.getBareJidFromJid(jid);
|
||||
_converse.resource = Strophe.getResourceFromJid(jid);
|
||||
|
@ -640,6 +677,37 @@ function saveJIDtoSession (jid) {
|
|||
'domain': _converse.domain,
|
||||
'active': true
|
||||
});
|
||||
// Set JID on the connection object so that when we call `connection.bind`
|
||||
// the new resource is found by Strophe.js and sent to the XMPP server.
|
||||
_converse.connection.jid = jid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stores the passed in JID for the current user, potentially creating a
|
||||
* resource if the JID is bare.
|
||||
*
|
||||
* Given that we can only create an XMPP connection if we know the domain of
|
||||
* the server connect to and we only know this once we know the JID, we also
|
||||
* call {@link _converse.initConnection } (if necessary) to make sure that the
|
||||
* connection is set up.
|
||||
*
|
||||
* @method _converse#setUserJID
|
||||
* @emits _converse#setUserJID
|
||||
* @params { String } jid
|
||||
*/
|
||||
_converse.setUserJID = async function (jid) {
|
||||
if (!_converse.connection || !u.isSameDomain(_converse.connection.jid, jid)) {
|
||||
const domain = Strophe.getDomainFromJid(jid)
|
||||
await _converse.initConnection(domain);
|
||||
}
|
||||
await initSession(jid);
|
||||
/**
|
||||
* Triggered whenever the user's JID has been updated
|
||||
* @event _converse#setUserJID
|
||||
*/
|
||||
_converse.api.trigger('setUserJID');
|
||||
return jid;
|
||||
}
|
||||
|
||||
|
||||
|
@ -649,7 +717,7 @@ async function onConnected (reconnecting) {
|
|||
*/
|
||||
delete _converse.connection.reconnecting;
|
||||
_converse.connection.flush(); // Solves problem of returned PubSub BOSH response not received by browser
|
||||
await setUserJID(_converse.connection.jid);
|
||||
await _converse.setUserJID(_converse.connection.jid);
|
||||
/**
|
||||
* Synchronous event triggered after we've sent an IQ to bind the
|
||||
* user's JID resource for this session.
|
||||
|
@ -681,9 +749,9 @@ function setUpXMLLogging () {
|
|||
async function finishInitialization () {
|
||||
initClientConfig();
|
||||
initPlugins();
|
||||
await _converse.initConnection();
|
||||
_converse.registerGlobalEventHandlers();
|
||||
if (!Backbone.history.started) {
|
||||
|
||||
if (!Backbone.History.started) {
|
||||
Backbone.history.start();
|
||||
}
|
||||
if (_converse.idle_presence_timeout > 0) {
|
||||
|
@ -691,6 +759,10 @@ async function finishInitialization () {
|
|||
_converse.api.disco.own.features.add(Strophe.NS.IDLE);
|
||||
});
|
||||
}
|
||||
if (_converse.auto_login ||
|
||||
_converse.keepalive && _.invoke(_converse.pluggable.plugins['converse-bosh'], 'enabled')) {
|
||||
await _converse.api.user.login(null, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -706,6 +778,7 @@ function finishDisconnection () {
|
|||
_converse.connection.reset();
|
||||
tearDown();
|
||||
clearSession();
|
||||
delete _converse.connection;
|
||||
/**
|
||||
* Triggered after converse.js has disconnected from the XMPP server.
|
||||
* @event _converse#disconnected
|
||||
|
@ -725,7 +798,7 @@ function fetchLoginCredentials (wait=0) {
|
|||
xhr.onload = () => {
|
||||
if (xhr.status >= 200 && xhr.status < 400) {
|
||||
const data = JSON.parse(xhr.responseText);
|
||||
setUserJID(data.jid).then(() => {
|
||||
_converse.setUserJID(data.jid).then(() => {
|
||||
resolve({
|
||||
jid: data.jid,
|
||||
password: data.password
|
||||
|
@ -761,7 +834,7 @@ async function getLoginCredentials () {
|
|||
async function getLoginCredentialsFromBrowser () {
|
||||
const creds = await navigator.credentials.get({'password': true});
|
||||
if (creds && creds.type == 'password' && u.isValidJID(creds.id)) {
|
||||
await setUserJID(creds.id);
|
||||
await _converse.setUserJID(creds.id);
|
||||
return {'jid': creds.id, 'password': creds.password};
|
||||
}
|
||||
}
|
||||
|
@ -782,18 +855,20 @@ function cleanup () {
|
|||
if (_converse.chatboxviews) {
|
||||
delete _converse.chatboxviews;
|
||||
}
|
||||
if (_converse.connection) {
|
||||
_converse.connection.reset();
|
||||
}
|
||||
_converse.stopListening();
|
||||
_converse.off();
|
||||
}
|
||||
|
||||
|
||||
_converse.initialize = async function (settings, callback) {
|
||||
cleanup();
|
||||
|
||||
settings = settings !== undefined ? settings : {};
|
||||
const init_promise = u.getResolveablePromise();
|
||||
PROMISES.forEach(addPromise);
|
||||
if (_converse.connection !== undefined) {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
if ('onpagehide' in window) {
|
||||
// Pagehide gets thrown in more cases than unload. Specifically it
|
||||
|
@ -877,7 +952,7 @@ _converse.initialize = async function (settings, callback) {
|
|||
if (_converse.idle_seconds > 0) {
|
||||
_converse.idle_seconds = 0;
|
||||
}
|
||||
if (!_converse.connection.authenticated) {
|
||||
if (!_.get(_converse.connection, 'authenticated')) {
|
||||
// We can't send out any stanzas when there's no authenticated connection.
|
||||
// This can happen when the connection reconnects.
|
||||
return;
|
||||
|
@ -901,7 +976,7 @@ _converse.initialize = async function (settings, callback) {
|
|||
/* An interval handler running every second.
|
||||
* Used for CSI and the auto_away and auto_xa features.
|
||||
*/
|
||||
if (!_converse.connection.authenticated) {
|
||||
if (!_.get(_converse.connection, 'authenticated')) {
|
||||
// We can't send out any stanzas when there's no authenticated connection.
|
||||
// This can happen when the connection reconnects.
|
||||
return;
|
||||
|
@ -1378,7 +1453,7 @@ _converse.api = {
|
|||
* @returns {boolean} Whether there is an established connection or not.
|
||||
*/
|
||||
connected () {
|
||||
return (_converse.connection && _converse.connection.connected) || false;
|
||||
return _.get(_converse, 'connection', {}).connected && true;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1417,7 +1492,7 @@ _converse.api = {
|
|||
// We also call `_proto._doDisconnect` so that connection event handlers
|
||||
// for the old transport are removed.
|
||||
if (_converse.api.connection.isType('websocket') && _converse.bosh_service_url) {
|
||||
await setUserJID(_converse.bare_jid);
|
||||
await _converse.setUserJID(_converse.bare_jid);
|
||||
_converse.connection._proto._doDisconnect();
|
||||
_converse.connection._proto = new Strophe.Bosh(_converse.connection);
|
||||
_converse.connection.service = _converse.bosh_service_url;
|
||||
|
@ -1426,9 +1501,9 @@ _converse.api = {
|
|||
// When reconnecting anonymously, we need to connect with only
|
||||
// the domain, not the full JID that we had in our previous
|
||||
// (now failed) session.
|
||||
await setUserJID(_converse.settings.jid);
|
||||
await _converse.setUserJID(_converse.settings.jid);
|
||||
} else {
|
||||
await setUserJID(_converse.bare_jid);
|
||||
await _converse.setUserJID(_converse.bare_jid);
|
||||
}
|
||||
_converse.connection._proto._doDisconnect();
|
||||
_converse.connection._proto = new Strophe.Websocket(_converse.connection);
|
||||
|
@ -1439,7 +1514,7 @@ _converse.api = {
|
|||
// When reconnecting anonymously, we need to connect with only
|
||||
// the domain, not the full JID that we had in our previous
|
||||
// (now failed) session.
|
||||
await setUserJID(_converse.settings.jid);
|
||||
await _converse.setUserJID(_converse.settings.jid);
|
||||
}
|
||||
if (_converse.connection.reconnecting) {
|
||||
debouncedReconnect();
|
||||
|
@ -1527,20 +1602,19 @@ _converse.api = {
|
|||
* fails to restore a previous auth'd session.
|
||||
*/
|
||||
async login (jid, password, automatic=false) {
|
||||
if (_converse.api.connection.isType('bosh')) {
|
||||
if (jid || _converse.jid) {
|
||||
jid = await _converse.setUserJID(jid || _converse.jid);
|
||||
}
|
||||
|
||||
// See whether there is a BOSH session to re-attach to
|
||||
if (_.invoke(_converse.pluggable.plugins['converse-bosh'], 'enabled')) {
|
||||
if (await _converse.restoreBOSHSession()) {
|
||||
return;
|
||||
} else if (_converse.authentication === _converse.PREBIND && (!automatic || _converse.auto_login)) {
|
||||
return _converse.startNewPreboundBOSHSession();
|
||||
}
|
||||
} else if (_converse.authentication === _converse.PREBIND) {
|
||||
throw new Error("authentication is set to 'prebind' but we don't have a BOSH connection");
|
||||
}
|
||||
|
||||
if (jid || _converse.jid) {
|
||||
// Reassign because we might have gained a resource
|
||||
jid = await setUserJID(jid || _converse.jid);
|
||||
}
|
||||
password = password || _converse.password;
|
||||
const credentials = (jid && password) ? { jid, password } : null;
|
||||
attemptNonPreboundSession(credentials, automatic);
|
||||
|
@ -1866,6 +1940,11 @@ _converse.api = {
|
|||
* _converse.api.send(msg);
|
||||
*/
|
||||
send (stanza) {
|
||||
if (!_converse.api.connection.connected()) {
|
||||
_converse.log("Not sending stanza because we're not connected!", Strophe.LogLevel.WARN);
|
||||
_converse.log(Strophe.serialize(stanza), Strophe.LogLevel.WARN);
|
||||
return;
|
||||
}
|
||||
if (_.isString(stanza)) {
|
||||
stanza = u.toStanza(stanza);
|
||||
}
|
||||
|
|
|
@ -633,7 +633,7 @@ converse.plugins.add('converse-muc', {
|
|||
disco_entity.destroy();
|
||||
}
|
||||
}
|
||||
if (_converse.connection.connected) {
|
||||
if (_converse.api.connection.connected()) {
|
||||
this.sendUnavailablePresence(exit_msg);
|
||||
}
|
||||
u.safeSave(this, {'connection_status': converse.ROOMSTATUS.DISCONNECTED});
|
||||
|
|
|
@ -107,6 +107,15 @@ u.isSameBareJID = function (jid1, jid2) {
|
|||
Strophe.getBareJidFromJid(jid2).toLowerCase();
|
||||
};
|
||||
|
||||
|
||||
u.isSameDomain = function (jid1, jid2) {
|
||||
if (!_.isString(jid1) || !_.isString(jid2)) {
|
||||
return false;
|
||||
}
|
||||
return Strophe.getDomainFromJid(jid1).toLowerCase() ===
|
||||
Strophe.getDomainFromJid(jid2).toLowerCase();
|
||||
};
|
||||
|
||||
u.isNewMessage = function (message) {
|
||||
/* Given a stanza, determine whether it's a new
|
||||
* message, i.e. not a MAM archived one.
|
||||
|
|
153
tests/mock.js
153
tests/mock.js
|
@ -9,7 +9,6 @@
|
|||
const Strophe = converse.env.Strophe;
|
||||
const dayjs = converse.env.dayjs;
|
||||
const $iq = converse.env.$iq;
|
||||
const u = converse.env.utils;
|
||||
|
||||
window.libsignal = {
|
||||
'SignalProtocolAddress': function (name, device_id) {
|
||||
|
@ -32,7 +31,7 @@
|
|||
return Promise.resolve(key_and_tag);
|
||||
}
|
||||
},
|
||||
'SessionBuilder': function (storage, remote_address) {
|
||||
'SessionBuilder': function (storage, remote_address) { // eslint-disable-line no-unused-vars
|
||||
this.processPreKey = function () {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
@ -116,95 +115,87 @@
|
|||
'preventDefault': function () {}
|
||||
};
|
||||
|
||||
mock.mock_connection = function () { // eslint-disable-line wrap-iife
|
||||
return function () {
|
||||
Strophe.Bosh.prototype._processRequest = function () {}; // Don't attempt to send out stanzas
|
||||
const c = new Strophe.Connection('jasmine tests');
|
||||
const sendIQ = c.sendIQ;
|
||||
|
||||
c.IQ_stanzas = [];
|
||||
c.IQ_ids = [];
|
||||
c.sendIQ = function (iq, callback, errback) {
|
||||
if (!_.isElement(iq)) {
|
||||
iq = iq.nodeTree;
|
||||
}
|
||||
this.IQ_stanzas.push(iq);
|
||||
const id = sendIQ.bind(this)(iq, callback, errback);
|
||||
this.IQ_ids.push(id);
|
||||
return id;
|
||||
const OriginalConnection = Strophe.Connection;
|
||||
|
||||
function MockConnection (service, options) {
|
||||
OriginalConnection.call(this, service, options);
|
||||
|
||||
Strophe.Bosh.prototype._processRequest = function () {}; // Don't attempt to send out stanzas
|
||||
const sendIQ = this.sendIQ;
|
||||
|
||||
this.IQ_stanzas = [];
|
||||
this.IQ_ids = [];
|
||||
this.sendIQ = function (iq, callback, errback) {
|
||||
if (!_.isElement(iq)) {
|
||||
iq = iq.nodeTree;
|
||||
}
|
||||
this.IQ_stanzas.push(iq);
|
||||
const id = sendIQ.bind(this)(iq, callback, errback);
|
||||
this.IQ_ids.push(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
const send = c.send;
|
||||
c.sent_stanzas = [];
|
||||
c.send = function (stanza) {
|
||||
if (_.isElement(stanza)) {
|
||||
this.sent_stanzas.push(stanza);
|
||||
} else {
|
||||
this.sent_stanzas.push(stanza.nodeTree);
|
||||
}
|
||||
return send.apply(this, arguments);
|
||||
const send = this.send;
|
||||
this.sent_stanzas = [];
|
||||
this.send = function (stanza) {
|
||||
if (_.isElement(stanza)) {
|
||||
this.sent_stanzas.push(stanza);
|
||||
} else {
|
||||
this.sent_stanzas.push(stanza.nodeTree);
|
||||
}
|
||||
return send.apply(this, arguments);
|
||||
}
|
||||
|
||||
c.features = Strophe.xmlHtmlNode(
|
||||
'<stream:features xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client">'+
|
||||
'<ver xmlns="urn:xmpp:features:rosterver"/>'+
|
||||
'<csi xmlns="urn:xmpp:csi:0"/>'+
|
||||
'<c xmlns="http://jabber.org/protocol/caps" ver="UwBpfJpEt3IoLYfWma/o/p3FFRo=" hash="sha-1" node="http://prosody.im"/>'+
|
||||
'<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">'+
|
||||
'<required/>'+
|
||||
'</bind>'+
|
||||
`<sm xmlns='urn:xmpp:sm:3'/>`+
|
||||
'<session xmlns="urn:ietf:params:xml:ns:xmpp-session">'+
|
||||
'<optional/>'+
|
||||
'</session>'+
|
||||
'</stream:features>').firstChild;
|
||||
this.features = Strophe.xmlHtmlNode(
|
||||
'<stream:features xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client">'+
|
||||
'<ver xmlns="urn:xmpp:features:rosterver"/>'+
|
||||
'<csi xmlns="urn:xmpp:csi:0"/>'+
|
||||
'<this xmlns="http://jabber.org/protocol/caps" ver="UwBpfJpEt3IoLYfWma/o/p3FFRo=" hash="sha-1" node="http://prosody.im"/>'+
|
||||
'<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">'+
|
||||
'<required/>'+
|
||||
'</bind>'+
|
||||
`<sm xmlns='urn:xmpp:sm:3'/>`+
|
||||
'<session xmlns="urn:ietf:params:xml:ns:xmpp-session">'+
|
||||
'<optional/>'+
|
||||
'</session>'+
|
||||
'</stream:features>').firstChild;
|
||||
|
||||
c._proto._connect = function () {
|
||||
c.connected = true;
|
||||
c.mock = true;
|
||||
c.jid = 'romeo@montague.lit/orchard';
|
||||
c._changeConnectStatus(Strophe.Status.BINDREQUIRED);
|
||||
};
|
||||
|
||||
c.bind = function () {
|
||||
c.authenticated = true;
|
||||
this.authenticated = true;
|
||||
c._changeConnectStatus(Strophe.Status.CONNECTED);
|
||||
};
|
||||
|
||||
c._proto._disconnect = function () {
|
||||
c._onDisconnectTimeout();
|
||||
}
|
||||
|
||||
c._proto._onDisconnectTimeout = _.noop;
|
||||
return c;
|
||||
this._proto._connect = () => {
|
||||
this.connected = true;
|
||||
this.mock = true;
|
||||
this.jid = 'romeo@montague.lit/orchard';
|
||||
this._changeConnectStatus(Strophe.Status.BINDREQUIRED);
|
||||
};
|
||||
}();
|
||||
|
||||
async function initConverse (settings, spies={}, promises) {
|
||||
this.bind = () => {
|
||||
this.authenticated = true;
|
||||
this.authenticated = true;
|
||||
this._changeConnectStatus(Strophe.Status.CONNECTED);
|
||||
};
|
||||
|
||||
this._proto._disconnect = () => this._onDisconnectTimeout();
|
||||
this._proto._onDisconnectTimeout = _.noop;
|
||||
}
|
||||
|
||||
MockConnection.prototype = Object.create(OriginalConnection.prototype);
|
||||
Strophe.Connection = MockConnection;
|
||||
|
||||
|
||||
async function initConverse (settings, spies={}) {
|
||||
window.localStorage.clear();
|
||||
window.sessionStorage.clear();
|
||||
const el = document.querySelector('#conversejs');
|
||||
if (el) {
|
||||
el.parentElement.removeChild(el);
|
||||
}
|
||||
|
||||
const connection = mock.mock_connection();
|
||||
if (spies && spies.connection) {
|
||||
spies.connection.forEach(method => spyOn(connection, method));
|
||||
}
|
||||
|
||||
const _converse = await converse.initialize(Object.assign({
|
||||
'i18n': 'en',
|
||||
'auto_subscribe': false,
|
||||
'play_sounds': false,
|
||||
'bosh_service_url': 'montague.lit/http-bind',
|
||||
'connection': connection,
|
||||
'animate': false,
|
||||
'use_emojione': false,
|
||||
'auto_subscribe': false,
|
||||
'bosh_service_url': 'montague.lit/http-bind',
|
||||
'debug': false,
|
||||
'i18n': 'en',
|
||||
'no_trimming': true,
|
||||
'play_sounds': false,
|
||||
'use_emojione': false,
|
||||
'view_mode': mock.view_mode,
|
||||
'debug': false
|
||||
}, settings || {}));
|
||||
|
||||
if (spies && spies._converse) {
|
||||
|
@ -214,7 +205,7 @@
|
|||
_converse.ChatBoxViews.prototype.trimChat = function () {};
|
||||
|
||||
_converse.api.vcard.get = function (model, force) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise(resolve => {
|
||||
let jid;
|
||||
if (_.isString(model)) {
|
||||
jid = model;
|
||||
|
@ -263,9 +254,13 @@
|
|||
return async done => {
|
||||
const _converse = await initConverse(settings, spies);
|
||||
async function _done () {
|
||||
await _converse.api.user.logout();
|
||||
if (_converse.api.connection.connected()) {
|
||||
await _converse.api.user.logout();
|
||||
}
|
||||
const el = document.querySelector('#conversejs');
|
||||
el.parentElement.removeChild(el);
|
||||
if (el) {
|
||||
el.parentElement.removeChild(el);
|
||||
}
|
||||
done();
|
||||
}
|
||||
await Promise.all((promise_names || []).map(_converse.api.waitUntil));
|
||||
|
|
Loading…
Reference in New Issue
Block a user