Add a plugin for XEP-0357

Currently only allows enabling an "App Service", based on pass-in
configuration values.
This commit is contained in:
JC Brand 2018-06-06 11:07:59 +02:00
parent eed141b53e
commit 7ee71b0132
9 changed files with 363 additions and 44 deletions

View File

@ -9,6 +9,7 @@
"plugins": ["lodash"], "plugins": ["lodash"],
"extends": ["eslint:recommended", "plugin:lodash/canonical"], "extends": ["eslint:recommended", "plugin:lodash/canonical"],
"globals": { "globals": {
"Promise": true,
"converse": true, "converse": true,
"window": true, "window": true,
"sinon": true, "sinon": true,

View File

@ -19,6 +19,7 @@
- Add a checkbox to indicate whether a trusted device is being used or not. - Add a checkbox to indicate whether a trusted device is being used or not.
If the device is not trusted, sessionStorage is used and all user data is deleted from the browser cache upon logout. If the device is not trusted, sessionStorage is used and all user data is deleted from the browser cache upon logout.
If the device is trusted, localStorage is used and user data is cached indefinitely. If the device is trusted, localStorage is used and user data is cached indefinitely.
- Initial support for XEP-0357 Push Notifications, specifically registering an "App Server".
### Bugfixes ### Bugfixes

113
dist/converse.js vendored
View File

@ -64922,11 +64922,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
})(void 0, function (sizzle, Promise, _, f, polyfill, i18n, u, moment, Strophe, pluggable, Backbone) { })(void 0, function (sizzle, Promise, _, f, polyfill, i18n, u, moment, Strophe, pluggable, Backbone) {
/* Cannot use this due to Safari bug. "use strict"; // Strophe globals
* See https://github.com/jcbrand/converse.js/issues/196
*/
// "use strict";
// Strophe globals
const _Strophe = Strophe, const _Strophe = Strophe,
$build = _Strophe.$build, $build = _Strophe.$build,
$iq = _Strophe.$iq, $iq = _Strophe.$iq,
@ -64974,7 +64971,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
_.extend(_converse, Backbone.Events); // Core plugins are whitelisted automatically _.extend(_converse, Backbone.Events); // Core plugins are whitelisted automatically
_converse.core_plugins = ['converse-bookmarks', 'converse-chatboxes', 'converse-chatview', 'converse-caps', 'converse-controlbox', 'converse-core', 'converse-disco', 'converse-dragresize', 'converse-embedded', 'converse-fullscreen', 'converse-headline', 'converse-mam', 'converse-message-view', 'converse-minimize', 'converse-modal', 'converse-muc', 'converse-muc-views', 'converse-notification', 'converse-otr', 'converse-ping', 'converse-profile', 'converse-register', 'converse-roomslist', 'converse-roster', 'converse-rosterview', 'converse-singleton', 'converse-spoilers', 'converse-vcard']; // Make converse pluggable _converse.core_plugins = ['converse-bookmarks', 'converse-caps', 'converse-chatboxes', 'converse-chatview', 'converse-controlbox', 'converse-core', 'converse-disco', 'converse-dragresize', 'converse-embedded', 'converse-fullscreen', 'converse-headline', 'converse-mam', 'converse-message-view', 'converse-minimize', 'converse-modal', 'converse-muc', 'converse-muc-views', 'converse-notification', 'converse-ping', 'converse-profile', 'converse-push', 'converse-register', 'converse-roomslist', 'converse-roster', 'converse-rosterview', 'converse-singleton', 'converse-spoilers', 'converse-vcard']; // Make converse pluggable
pluggable.enable(_converse, '_converse', 'pluggable'); // Module-level constants pluggable.enable(_converse, '_converse', 'pluggable'); // Module-level constants
@ -65004,6 +65001,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
_converse.LOGOUT = "logout"; _converse.LOGOUT = "logout";
_converse.OPENED = 'opened'; _converse.OPENED = 'opened';
_converse.PREBIND = "prebind"; _converse.PREBIND = "prebind";
_converse.IQ_TIMEOUT = 30000;
_converse.CONNECTION_STATUS = { _converse.CONNECTION_STATUS = {
0: 'ERROR', 0: 'ERROR',
1: 'CONNECTING', 1: 'CONNECTING',
@ -65173,8 +65171,6 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
_converse.router = new Backbone.Router(); _converse.router = new Backbone.Router();
_converse.initialize = function (settings, callback) { _converse.initialize = function (settings, callback) {
"use strict";
settings = !_.isUndefined(settings) ? settings : {}; settings = !_.isUndefined(settings) ? settings : {};
const init_promise = u.getResolveablePromise(); const init_promise = u.getResolveablePromise();
@ -65564,7 +65560,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
const id = b64_sha1('converse.bosh-session'); const id = b64_sha1('converse.bosh-session');
_converse.session.id = id; // Appears to be necessary for backbone.browserStorage _converse.session.id = id; // Appears to be necessary for backbone.browserStorage
_converse.session.browserStorage = new Backbone.BrowserStorage[_converse.storage](id); _converse.session.browserStorage = new Backbone.BrowserStorage.session(id);
_converse.session.fetch(); _converse.session.fetch();
@ -65682,7 +65678,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
_converse.log('An error occured while trying to enable message carbons.', Strophe.LogLevel.ERROR); _converse.log('An error occured while trying to enable message carbons.', Strophe.LogLevel.ERROR);
} else { } else {
this.session.save({ this.session.save({
carbons_enabled: true 'carbons_enabled': true
}); });
_converse.log('Message carbons have been enabled.'); _converse.log('Message carbons have been enabled.');
@ -66272,6 +66268,12 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
'send'(stanza) { 'send'(stanza) {
_converse.connection.send(stanza); _converse.connection.send(stanza);
},
'sendIQ'(stanza) {
return new Promise((resolve, reject) => {
_converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT);
});
} }
}; // The public API }; // The public API
@ -73287,6 +73289,94 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
/***/ }), /***/ }),
/***/ "./src/converse-push.js":
/*!******************************!*\
!*** ./src/converse-push.js ***!
\******************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;
// Converse.js
// https://conversejs.org
//
// Copyright (c) 2013-2018, the Converse.js developers
// Licensed under the Mozilla Public License (MPLv2)
/* This is a Converse.js plugin which add support for registering
* an "App Server" as defined in XEP-0357
*/
(function (root, factory) {
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! converse-core */ "./src/converse-core.js")], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
})(void 0, function (converse) {
"use strict";
const _converse$env = converse.env,
Strophe = _converse$env.Strophe,
$iq = _converse$env.$iq;
Strophe.addNamespace('PUSH', 'urn:xmpp:push:0');
converse.plugins.add('converse-push', {
initialize() {
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
const _converse = this._converse,
__ = _converse.__;
_converse.api.settings.update({
'push_service': undefined,
'push_service_node': undefined,
'push_service_secret': undefined
});
function enablePush() {
if (_converse.session.get('push_enabled')) {
return;
}
if (_converse.push_service && _converse.push_service_node) {
Promise.all([_converse.api.disco.getIdentity('pubsub', 'push', _converse.push_service), _converse.api.disco.supports(Strophe.NS.PUSH, _converse.push_service)]).then(() => _converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid)).then(() => {
const stanza = $iq({
'type': 'set'
}).c('enable', {
'xmlns': Strophe.NS.PUSH,
'jid': _converse.push_service,
'node': _converse.push_service_node
});
if (_converse.push_service_secret) {
stanza.c('x', {
'xmlns': Strophe.NS.XFORM,
'type': 'submit'
}).c('field', {
'var': 'FORM_TYPE'
}).c('value').t(`${Strophe.NS.PUBSUB}#publish-options`).up().up().c('field', {
'var': 'secret'
}).c('value').t(_converse.push_service_secret);
}
_converse.api.sendIQ(stanza).then(() => _converse.session.set('push_enabled', true)).catch(e => {
_converse.log(`Could not enable push service for ${_converse.push_service}`, Strophe.LogLevel.ERROR);
_converse.log(e, Strophe.LogLevel.ERROR);
});
});
}
}
_converse.api.listen.on('statusInitialized', enablePush);
}
});
});
/***/ }),
/***/ "./src/converse-register.js": /***/ "./src/converse-register.js":
/*!**********************************!*\ /*!**********************************!*\
!*** ./src/converse-register.js ***! !*** ./src/converse-register.js ***!
@ -76844,7 +76934,8 @@ if (true) {
__webpack_require__(/*! converse-chatview */ "./src/converse-chatview.js"), // Renders standalone chat boxes for single user chat __webpack_require__(/*! converse-chatview */ "./src/converse-chatview.js"), // Renders standalone chat boxes for single user chat
__webpack_require__(/*! converse-controlbox */ "./src/converse-controlbox.js"), // The control box __webpack_require__(/*! converse-controlbox */ "./src/converse-controlbox.js"), // The control box
__webpack_require__(/*! converse-dragresize */ "./src/converse-dragresize.js"), // Allows chat boxes to be resized by dragging them __webpack_require__(/*! converse-dragresize */ "./src/converse-dragresize.js"), // Allows chat boxes to be resized by dragging them
__webpack_require__(/*! converse-embedded */ "./src/converse-embedded.js"), __webpack_require__(/*! converse-fullscreen */ "./src/converse-fullscreen.js"), __webpack_require__(/*! converse-headline */ "./src/converse-headline.js"), // Support for headline messages __webpack_require__(/*! converse-embedded */ "./src/converse-embedded.js"), __webpack_require__(/*! converse-fullscreen */ "./src/converse-fullscreen.js"), __webpack_require__(/*! converse-push */ "./src/converse-push.js"), // XEP-0357 Push Notifications
__webpack_require__(/*! converse-headline */ "./src/converse-headline.js"), // Support for headline messages
__webpack_require__(/*! converse-mam */ "./src/converse-mam.js"), // XEP-0313 Message Archive Management __webpack_require__(/*! converse-mam */ "./src/converse-mam.js"), // XEP-0313 Message Archive Management
__webpack_require__(/*! converse-minimize */ "./src/converse-minimize.js"), // Allows chat boxes to be minimized __webpack_require__(/*! converse-minimize */ "./src/converse-minimize.js"), // Allows chat boxes to be minimized
__webpack_require__(/*! converse-muc */ "./src/converse-muc.js"), // XEP-0045 Multi-user chat __webpack_require__(/*! converse-muc */ "./src/converse-muc.js"), // XEP-0045 Multi-user chat

View File

@ -7,10 +7,10 @@ Configuration
============= =============
The included minified JavaScript and CSS files can be used for demoing or testing, but The included minified JavaScript and CSS files can be used for demoing or testing, but
you'll want to configure *Converse.js* to suit your needs before you deploy it you'll want to configure *Converse* to suit your needs before you deploy it
on your website. on your website.
*Converse.js* is passed its configuration settings when you call its *initialize* method. *Converse* is passed its configuration settings when you call its *initialize* method.
You'll most likely want to call the *initialize* method in your HTML page. For You'll most likely want to call the *initialize* method in your HTML page. For
an example of how this is done, please see the bottom of the *./index.html* page. an example of how this is done, please see the bottom of the *./index.html* page.
@ -18,7 +18,7 @@ an example of how this is done, please see the bottom of the *./index.html* page
Please refer to the `Configuration settings`_ section below for info on Please refer to the `Configuration settings`_ section below for info on
all the available configuration settings. all the available configuration settings.
After you have configured *Converse.js*, you'll have to regenerate the minified After you have configured *Converse*, you'll have to regenerate the minified
JavaScript file so that it will include the new settings. Please refer to the JavaScript file so that it will include the new settings. Please refer to the
:ref:`minification` section for more info on how to do this. :ref:`minification` section for more info on how to do this.
@ -83,7 +83,7 @@ requiring them to log in manually.
When a BOSH session is initially created, you'll receive three tokens. When a BOSH session is initially created, you'll receive three tokens.
A JID (jabber ID), SID (session ID) and RID (Request ID). A JID (jabber ID), SID (session ID) and RID (Request ID).
Converse.js needs these tokens in order to attach to that same session. Converse needs these tokens in order to attach to that same session.
There are two complementary configuration settings to ``prebind``. There are two complementary configuration settings to ``prebind``.
They are :ref:`keepalive` and `prebind_url`_. They are :ref:`keepalive` and `prebind_url`_.
@ -200,7 +200,7 @@ allow_public_bookmarks
Some XMPP servers don't support private PEP/PubSub nodes, as required for Some XMPP servers don't support private PEP/PubSub nodes, as required for
private bookmarks and outlined in `XEP-0223 <https://xmpp.org/extensions/xep-0223.html>`_. private bookmarks and outlined in `XEP-0223 <https://xmpp.org/extensions/xep-0223.html>`_.
Even though Converse.js asks for the bookmarks to be kept private (via the Even though Converse asks for the bookmarks to be kept private (via the
`<publish-options>` XML node), the server simply ignores the privacy settings `<publish-options>` XML node), the server simply ignores the privacy settings
and publishes the node contents under the default privacy setting, which makes and publishes the node contents under the default privacy setting, which makes
the information available to all roster contacts. the information available to all roster contacts.
@ -382,7 +382,7 @@ A list of plugin names that are blacklisted and will therefore not be
initialized once ``converse.initialize`` is called, even if the same plugin is initialized once ``converse.initialize`` is called, even if the same plugin is
whitelisted. whitelisted.
From Converse.js 3.0 onwards most of the API is available only to plugins and From Converse 3.0 onwards most of the API is available only to plugins and
all plugins need to be whitelisted first. all plugins need to be whitelisted first.
The usecase for blacklisting is generally to disable removed core plugins The usecase for blacklisting is generally to disable removed core plugins
@ -495,7 +495,7 @@ connection_options
* Default: ``{}`` * Default: ``{}``
* Type: Object * Type: Object
Converse.js relies on `Strophe.js <http://strophe.im>`_ to establish and Converse relies on `Strophe.js <http://strophe.im>`_ to establish and
maintain a connection to the XMPP server. maintain a connection to the XMPP server.
This option allows you to pass a map of configuration options to be passed into This option allows you to pass a map of configuration options to be passed into
@ -725,7 +725,7 @@ The translations for that locale must be available in JSON format at the
If an explicit locale is specified via the ``i18n`` setting and the If an explicit locale is specified via the ``i18n`` setting and the
translations for that locale are not found at the `locales_url``, then translations for that locale are not found at the `locales_url``, then
then Converse.js will fall back to trying to determine the browser's language then Converse will fall back to trying to determine the browser's language
and fetching those translations, or if that fails the default English texts and fetching those translations, or if that fails the default English texts
will be used. will be used.
@ -747,7 +747,7 @@ keepalive
* Default: ``true`` * Default: ``true``
Determines whether Converse.js will maintain the chat session across page Determines whether Converse will maintain the chat session across page
loads. loads.
This setting should also be used in conjunction with ``authentication`` set to `prebind`_. This setting should also be used in conjunction with ``authentication`` set to `prebind`_.
@ -785,7 +785,7 @@ locales
'ru', 'uk', 'zh' 'ru', 'uk', 'zh'
] ]
This setting restricts the locales that are supported by Converse.js and This setting restricts the locales that are supported by Converse and
therefore what may be given as value for the :ref:`i18n` option. therefore what may be given as value for the :ref:`i18n` option.
Any other locales will be ignored. Any other locales will be ignored.
@ -800,7 +800,7 @@ locales_url
* Default: ``/locale/{{{locale}}}/LC_MESSAGES/converse.json``, * Default: ``/locale/{{{locale}}}/LC_MESSAGES/converse.json``,
The URL from where Converse.js should fetch translation JSON. The URL from where Converse should fetch translation JSON.
The three curly braces ``{{{ }}}`` are The three curly braces ``{{{ }}}`` are
`Mustache <https://github.com/janl/mustache.js#readme>`_-style `Mustache <https://github.com/janl/mustache.js#readme>`_-style
@ -812,7 +812,7 @@ The variable being interpolated via the curly braces is ``locale``, which is
the value passed in to the `i18n`_ setting, or the browser's locale or the the value passed in to the `i18n`_ setting, or the browser's locale or the
default local or `en` (resolved in that order). default local or `en` (resolved in that order).
From version 3.3.0, Converse.js no longer bundles all translations into its From version 3.3.0, Converse no longer bundles all translations into its
final build file. Instead, only the relevant translations are fetched at final build file. Instead, only the relevant translations are fetched at
runtime. runtime.
@ -953,7 +953,7 @@ muc_show_join_leave
* Default; ``true`` * Default; ``true``
Determines whether Converse.js will show info messages inside a chatroom Determines whether Converse will show info messages inside a chatroom
whenever a user joins or leaves it. whenever a user joins or leaves it.
nickname nickname
@ -1007,7 +1007,7 @@ play_sounds
Plays a notification sound when you receive a personal message or when your Plays a notification sound when you receive a personal message or when your
nickname is mentioned in a chatroom. nickname is mentioned in a chatroom.
Inside the ``./sounds`` directory of the Converse.js repo you'll see MP3 and Ogg Inside the ``./sounds`` directory of the Converse repo you'll see MP3 and Ogg
formatted sound files. We need both, because neither format is supported by all browsers. formatted sound files. We need both, because neither format is supported by all browsers.
You can set the URL where the sound files are hosted with the `sounds_path`_ You can set the URL where the sound files are hosted with the `sounds_path`_
@ -1047,12 +1047,12 @@ priority
* Type: Number * Type: Number
Determines the priority used for presence stanzas sent out from this resource Determines the priority used for presence stanzas sent out from this resource
(i.e. this instance of Converse.js). (i.e. this instance of Converse).
The priority of a given XMPP chat client determines the importance of its presence The priority of a given XMPP chat client determines the importance of its presence
stanzas in relation to stanzas received from other clients of the same user. stanzas in relation to stanzas received from other clients of the same user.
In Converse.js, the indicated chat status of a roster contact will be taken from the In Converse, the indicated chat status of a roster contact will be taken from the
presence stanza (and associated resource) with the highest priority. presence stanza (and associated resource) with the highest priority.
If multiple resources have the same top priority, then the chat status will be If multiple resources have the same top priority, then the chat status will be
@ -1068,6 +1068,39 @@ providers_link
The hyperlink on the registration form which points to a directory of public The hyperlink on the registration form which points to a directory of public
XMPP servers. XMPP servers.
push_service
------------
* Default: ``undefined``
This option allows you to specify a URI for the push notifications service
(called an "App Server" by `XEP-0357 <https://xmpp.org/extensions/xep-0357.html>`_).
If provided, together with a `push_service_node`_, then Converse will instruct
the user's XMPP server to send push notificatiosn to that URI.
push_service_node
-----------------
* Default: ``undefined``
This is the PubSub node of the push notifications service (aka "App Server") specified with the
`push_service`_ setting.
Push notifications will be sent to this node. If this value is not set, then
push notifications won't be sent out.
push_service_secret
-------------------
* Default: ``undefined``
Some push notification services (aka "App Servers") require a secret token to
be used when sending out notifications.
This setting enables you to provide such a secret to Converse which will
forward it to your XMPP server to be included in push notifications.
root root
---- ----
@ -1108,7 +1141,7 @@ configured.
.. note:: .. note::
It's currently not possible to use converse.js to assign contacts to groups. It's currently not possible to use converse.js to assign contacts to groups.
Converse.js can only show users and groups that were previously configured Converse can only show users and groups that were previously configured
elsewhere. elsewhere.
show_chatstate_notifications show_chatstate_notifications
@ -1262,10 +1295,10 @@ loaded), then an error will be raised.
Otherwise a message will simply be logged and the override instruction ignored. Otherwise a message will simply be logged and the override instruction ignored.
The Converse.js plugins architecture can have an :ref:`dependencies` The Converse plugins architecture can have an :ref:`dependencies`
plugin attribute. This enables you to specify an array of other plugins which plugin attribute. This enables you to specify an array of other plugins which
this one depends on. this one depends on.
Converse.js (more specifically, `pluggable.js <https://jcbrand.github.io/pluggable.js/>`_) Converse (more specifically, `pluggable.js <https://jcbrand.github.io/pluggable.js/>`_)
will first load these dependencies before executing the plugin's overrides and will first load these dependencies before executing the plugin's overrides and
calling its ``initialize`` method. calling its ``initialize`` method.
@ -1302,7 +1335,7 @@ This setting determines whether the default value of the "This is a trusted devi
When the current device is not trusted, then localStorage and sessionStorage When the current device is not trusted, then localStorage and sessionStorage
will be cleared when the user logs out, thereby removing all cached data. will be cleared when the user logs out, thereby removing all cached data.
Clearing the cache in this way makes Converse.js much slower when the user logs Clearing the cache in this way makes Converse much slower when the user logs
in again, because all data needs to be fetch anew. in again, because all data needs to be fetch anew.
See also `storage`_. See also `storage`_.
@ -1323,7 +1356,7 @@ use_otr_by_default
* Default: ``false`` * Default: ``false``
If set to ``true``, Converse.js will automatically try to initiate an OTR (off-the-record) If set to ``true``, Converse will automatically try to initiate an OTR (off-the-record)
encrypted chat session every time you open a chatbox. encrypted chat session every time you open a chatbox.
visible_toolbar_buttons visible_toolbar_buttons
@ -1382,7 +1415,7 @@ support.
configuration setting). configuration setting).
.. note:: .. note::
Converse.js does not yet support "keepalive" with websockets. Converse does not yet support "keepalive" with websockets.
.. _`view_mode`: .. _`view_mode`:
@ -1448,7 +1481,7 @@ whitelisted_plugins
A list of plugin names that are whitelisted and will therefore be A list of plugin names that are whitelisted and will therefore be
initialized once ``converse.initialize`` is called. initialized once ``converse.initialize`` is called.
From Converse.js 3.0 onwards most of the API is available only to plugins and From Converse 3.0 onwards most of the API is available only to plugins and
all plugins need to be whitelisted first. all plugins need to be whitelisted first.
This is done to prevent malicious scripts from using the API to trick users or This is done to prevent malicious scripts from using the API to trick users or

119
spec/push.js Normal file
View File

@ -0,0 +1,119 @@
(function (root, factory) {
define(["jasmine", "mock", "test-utils"], factory);
} (this, function (jasmine, mock, test_utils) {
"use strict";
var $iq = converse.env.$iq;
var Strophe = converse.env.Strophe;
var _ = converse.env._;
describe("XEP-0357 Push Notifications", function () {
it("can be enabled by specifying a push_service and push_service_node",
mock.initConverseWithPromises(null,
['rosterGroupsFetched'], {
'push_service': 'push-5@client.example',
'push_service_node': 'yxs32uqsflafdk3iuqo'
}, function (done, _converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas;
let stanza;
expect(_converse.push_service).toBe('push-5@client.example');
expect(_converse.push_service_node).toBe('yxs32uqsflafdk3iuqo');
expect(_converse.session.get('push_enabled')).toBeFalsy();
test_utils.waitUntilDiscoConfirmed(
_converse, _converse.push_service,
[{'category': 'pubsub', 'type':'push'}],
['urn:xmpp:push:0'], [], 'info')
.then(() => test_utils.waitUntilDiscoConfirmed(
_converse,
_converse.bare_jid,
[{'category': 'account', 'type':'registered'}],
['urn:xmpp:push:0'], [], 'info'))
.then(() => {
return test_utils.waitUntil(() => {
const node = _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[type="set"] enable[xmlns="urn:xmpp:push:0"]');
}).pop();
if (node) {
stanza = node.nodeTree;
return true;
}
})
}).then(() => {
expect(stanza.outerHTML).toEqual(
`<iq type="set" xmlns="jabber:client" id="${stanza.getAttribute('id')}">`+
'<enable xmlns="urn:xmpp:push:0" jid="push-5@client.example" node="yxs32uqsflafdk3iuqo"/>'+
'</iq>'
)
_converse.connection._dataRecv(test_utils.createRequest($iq({
'to': _converse.connection.jid,
'type': 'result',
'id': stanza.getAttribute('id')
})));
return test_utils.waitUntil(() => _converse.session.get('push_enabled'))
}).then(() => {
done();
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
}));
it("can require a secret token to be included",
mock.initConverseWithPromises(null,
['rosterGroupsFetched'], {
'push_service': 'push-5@client.example',
'push_service_node': 'yxs32uqsflafdk3iuqo',
'push_service_secret': 'eruio234vzxc2kla-91'
}, function (done, _converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas;
let stanza;
expect(_converse.push_service).toBe('push-5@client.example');
expect(_converse.push_service_node).toBe('yxs32uqsflafdk3iuqo');
expect(_converse.push_service_secret).toBe('eruio234vzxc2kla-91');
expect(_converse.session.get('push_enabled')).toBeFalsy();
test_utils.waitUntilDiscoConfirmed(
_converse, _converse.push_service,
[{'category': 'pubsub', 'type':'push'}],
['urn:xmpp:push:0'], [], 'info')
.then(() => test_utils.waitUntilDiscoConfirmed(
_converse,
_converse.bare_jid,
[{'category': 'account', 'type':'registered'}],
['urn:xmpp:push:0'], [], 'info'))
.then(() => {
return test_utils.waitUntil(() => {
const node = _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[type="set"] enable[xmlns="urn:xmpp:push:0"]');
}).pop();
if (node) {
stanza = node.nodeTree;
return true;
}
})
}).then(() => {
expect(stanza.outerHTML).toEqual(
`<iq type="set" xmlns="jabber:client" id="${stanza.getAttribute('id')}">`+
'<enable xmlns="urn:xmpp:push:0" jid="push-5@client.example" node="yxs32uqsflafdk3iuqo">'+
'<x xmlns="jabber:x:data" type="submit">'+
'<field var="FORM_TYPE"><value>http://jabber.org/protocol/pubsub#publish-options</value></field>'+
'<field var="secret"><value>eruio234vzxc2kla-91</value></field>'+
'</x>'+
'</enable>'+
'</iq>'
)
_converse.connection._dataRecv(test_utils.createRequest($iq({
'to': _converse.connection.jid,
'type': 'result',
'id': stanza.getAttribute('id')
})));
return test_utils.waitUntil(() => _converse.session.get('push_enabled'))
}).then(() => {
done();
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
}));
});
}));

View File

@ -20,11 +20,7 @@
"backbone.browserStorage" "backbone.browserStorage"
], factory); ], factory);
}(this, function (sizzle, Promise, _, f, polyfill, i18n, u, moment, Strophe, pluggable, Backbone) { }(this, function (sizzle, Promise, _, f, polyfill, i18n, u, moment, Strophe, pluggable, Backbone) {
"use strict";
/* Cannot use this due to Safari bug.
* See https://github.com/jcbrand/converse.js/issues/196
*/
// "use strict";
// Strophe globals // Strophe globals
const { $build, $iq, $msg, $pres } = Strophe; const { $build, $iq, $msg, $pres } = Strophe;
@ -72,9 +68,9 @@
// Core plugins are whitelisted automatically // Core plugins are whitelisted automatically
_converse.core_plugins = [ _converse.core_plugins = [
'converse-bookmarks', 'converse-bookmarks',
'converse-caps',
'converse-chatboxes', 'converse-chatboxes',
'converse-chatview', 'converse-chatview',
'converse-caps',
'converse-controlbox', 'converse-controlbox',
'converse-core', 'converse-core',
'converse-disco', 'converse-disco',
@ -89,9 +85,9 @@
'converse-muc', 'converse-muc',
'converse-muc-views', 'converse-muc-views',
'converse-notification', 'converse-notification',
'converse-otr',
'converse-ping', 'converse-ping',
'converse-profile', 'converse-profile',
'converse-push',
'converse-register', 'converse-register',
'converse-roomslist', 'converse-roomslist',
'converse-roster', 'converse-roster',
@ -131,6 +127,8 @@
_converse.OPENED = 'opened'; _converse.OPENED = 'opened';
_converse.PREBIND = "prebind"; _converse.PREBIND = "prebind";
_converse.IQ_TIMEOUT = 30000;
_converse.CONNECTION_STATUS = { _converse.CONNECTION_STATUS = {
0: 'ERROR', 0: 'ERROR',
1: 'CONNECTING', 1: 'CONNECTING',
@ -298,7 +296,6 @@
_converse.initialize = function (settings, callback) { _converse.initialize = function (settings, callback) {
"use strict";
settings = !_.isUndefined(settings) ? settings : {}; settings = !_.isUndefined(settings) ? settings : {};
const init_promise = u.getResolveablePromise(); const init_promise = u.getResolveablePromise();
@ -638,7 +635,7 @@
_converse.session = new Backbone.Model(); _converse.session = new Backbone.Model();
const id = b64_sha1('converse.bosh-session'); const id = b64_sha1('converse.bosh-session');
_converse.session.id = id; // Appears to be necessary for backbone.browserStorage _converse.session.id = id; // Appears to be necessary for backbone.browserStorage
_converse.session.browserStorage = new Backbone.BrowserStorage[_converse.storage](id); _converse.session.browserStorage = new Backbone.BrowserStorage.session(id);
_converse.session.fetch(); _converse.session.fetch();
_converse.emit('sessionInitialized'); _converse.emit('sessionInitialized');
}; };
@ -739,7 +736,7 @@
'An error occured while trying to enable message carbons.', 'An error occured while trying to enable message carbons.',
Strophe.LogLevel.ERROR); Strophe.LogLevel.ERROR);
} else { } else {
this.session.save({carbons_enabled: true}); this.session.save({'carbons_enabled': true});
_converse.log('Message carbons have been enabled.'); _converse.log('Message carbons have been enabled.');
} }
}, null, "iq", null, "enablecarbons"); }, null, "iq", null, "enablecarbons");
@ -1289,6 +1286,11 @@
'send' (stanza) { 'send' (stanza) {
_converse.connection.send(stanza); _converse.connection.send(stanza);
}, },
'sendIQ' (stanza) {
return new Promise((resolve, reject) => {
_converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT);
});
}
}; };
// The public API // The public API

70
src/converse-push.js Normal file
View File

@ -0,0 +1,70 @@
// Converse.js
// https://conversejs.org
//
// Copyright (c) 2013-2018, the Converse.js developers
// Licensed under the Mozilla Public License (MPLv2)
/* This is a Converse.js plugin which add support for registering
* an "App Server" as defined in XEP-0357
*/
(function (root, factory) {
define(["converse-core"], factory);
}(this, function (converse) {
"use strict";
const { Strophe, $iq } = converse.env;
Strophe.addNamespace('PUSH', 'urn:xmpp:push:0');
converse.plugins.add('converse-push', {
initialize () {
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
const { _converse } = this,
{ __ } = _converse;
_converse.api.settings.update({
'push_service': undefined,
'push_service_node': undefined,
'push_service_secret': undefined
});
function enablePush() {
if (_converse.session.get('push_enabled')) {
return;
}
if (_converse.push_service && _converse.push_service_node) {
Promise.all([
_converse.api.disco.getIdentity('pubsub', 'push', _converse.push_service),
_converse.api.disco.supports(Strophe.NS.PUSH, _converse.push_service)
]).then(() => _converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid))
.then(() => {
const stanza = $iq({'type': 'set'})
.c('enable', {
'xmlns': Strophe.NS.PUSH,
'jid': _converse.push_service,
'node': _converse.push_service_node
});
if (_converse.push_service_secret) {
stanza.c('x', {'xmlns': Strophe.NS.XFORM, 'type': 'submit'})
.c('field', {'var': 'FORM_TYPE'})
.c('value').t(`${Strophe.NS.PUBSUB}#publish-options`).up().up()
.c('field', {'var': 'secret'})
.c('value').t(_converse.push_service_secret);
}
_converse.api.sendIQ(stanza)
.then(() => _converse.session.set('push_enabled', true))
.catch((e) => {
_converse.log(`Could not enable push service for ${_converse.push_service}`, Strophe.LogLevel.ERROR);
_converse.log(e, Strophe.LogLevel.ERROR);
});
});
}
}
_converse.api.listen.on('statusInitialized', enablePush);
}
});
}));

View File

@ -14,6 +14,7 @@ if (typeof define !== 'undefined') {
"converse-dragresize", // Allows chat boxes to be resized by dragging them "converse-dragresize", // Allows chat boxes to be resized by dragging them
"converse-embedded", "converse-embedded",
"converse-fullscreen", "converse-fullscreen",
"converse-push", // XEP-0357 Push Notifications
"converse-headline", // Support for headline messages "converse-headline", // Support for headline messages
"converse-mam", // XEP-0313 Message Archive Management "converse-mam", // XEP-0313 Message Archive Management
"converse-minimize", // Allows chat boxes to be minimized "converse-minimize", // Allows chat boxes to be minimized

View File

@ -191,6 +191,7 @@ var specs = [
"spec/presence", "spec/presence",
"spec/eventemitter", "spec/eventemitter",
"spec/ping", "spec/ping",
"spec/push",
"spec/xmppstatus", "spec/xmppstatus",
"spec/mam", "spec/mam",
// "spec/otr", // "spec/otr",