Browse Source

WIP: XEP 156 via JSON

JC Brand 3 năm trước cách đây
mục cha
commit
e3a2bfff29

+ 1 - 1
docs/source/configuration.rst

@@ -1290,7 +1290,7 @@ muc_domain
 
 The default MUC (multi-user chat) domain that should be used.
 
-When setting this value, users can only enter the name when opening a new MUC,
+When setting this value, users can enter only the name when opening a new MUC,
 and don't have to add the whole address (i.e. including the domain part).
 
 Users can however still enter the domain and they can still open MUCs with

+ 1 - 0
karma.conf.js

@@ -39,6 +39,7 @@ module.exports = function(config) {
       { pattern: "src/headless/plugins/smacks/tests/smacks.js", type: 'module' },
       { pattern: "src/headless/plugins/status/tests/status.js", type: 'module' },
       { pattern: "src/headless/shared/settings/tests/settings.js", type: 'module' },
+      { pattern: "src/headless/tests/connection.js", type: 'module' },
       { pattern: "src/headless/tests/converse.js", type: 'module' },
       { pattern: "src/headless/tests/eventemitter.js", type: 'module' },
       { pattern: "src/modals/tests/user-details-modal.js", type: 'module' },

+ 1 - 0
src/headless/core.js

@@ -44,6 +44,7 @@ dayjs.extend(advancedFormat);
 
 // Add Strophe Namespaces
 Strophe.addNamespace('ACTIVITY', 'http://jabber.org/protocol/activity');
+Strophe.addNamespace('ALTCONN', 'urn:xmpp:alt-connections:xbosh');
 Strophe.addNamespace('CARBONS', 'urn:xmpp:carbons:2');
 Strophe.addNamespace('CHATSTATES', 'http://jabber.org/protocol/chatstates');
 Strophe.addNamespace('CSI', 'urn:xmpp:csi:0');

+ 44 - 26
src/headless/shared/connection.js

@@ -36,23 +36,45 @@ export class Connection extends Strophe.Connection {
         super.bind();
     }
 
-
-    async onDomainDiscovered (response) {
+    async onDomainDiscoveredViaXML (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 log.warn("Could not discover XEP-0156 connection methods");
+            return log.warn("Could not discover XEP-0156 connection method from host-meta response");
+        }
+        const bosh_hrefs = sizzle(`Link[rel="${Strophe.NS.ALTCONN}:xbosh"]`, xrd)
+            .map(el => el.getAttribute('href'));
+
+        const ws_hrefs = sizzle(`Link[rel="${Strophe.NS.ALTCONN}:websocket"]`, xrd)
+            .map(el => el.getAttribute('href'));
+
+        if (bosh_hrefs.length === 0 && ws_hrefs.length === 0) {
+            return log.warn("Could not discover XEP-0156 connection method from host-meta response");
+        } else {
+            // TODO: support multiple endpoints
+            api.settings.set("websocket_url", ws_hrefs.pop());
+            api.settings.set('bosh_service_url', bosh_hrefs.pop());
+            this.service = api.settings.get("websocket_url") || api.settings.get('bosh_service_url');
+            this.setProtocol();
+        }
+    }
+
+    async onDomainDiscoveredViaJSON (response) {
+        const text = await response.text();
+        const { links } = JSON.parse(text);
+        if (!links || links?.length === 0) {
+            return log.warn("Could not discover XEP-0156 connection method from host-meta.json response");
         }
-        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'));
-        if (bosh_methods.length === 0 && ws_methods.length === 0) {
-            log.warn("Neither BOSH nor WebSocket connection methods have been specified with XEP-0156.");
+
+        const bosh_links = links.filter(l => l.rel === `${Strophe.NS.ALTCONN}:xbosh` && l.href);
+        const ws_links = links.filter(l => l.rel === `S{Strophe.NS.ALTCONN}:websocket` && l.href);
+
+        if (bosh_links.length === 0 && ws_links.length === 0) {
+            return log.warn("Could not discover XEP-0156 connection method from host-meta.json response");
         } else {
             // TODO: support multiple endpoints
-            api.settings.set("websocket_url", ws_methods.pop());
-            api.settings.set('bosh_service_url', bosh_methods.pop());
+            api.settings.set("websocket_url", ws_links.pop().href);
+            api.settings.set('bosh_service_url', bosh_links.pop().href);
             this.service = api.settings.get("websocket_url") || api.settings.get('bosh_service_url');
             this.setProtocol();
         }
@@ -66,27 +88,23 @@ export class Connection extends Strophe.Connection {
      * @method Connnection.discoverConnectionMethods
      */
     async discoverConnectionMethods (domain) {
-        // Use XEP-0156 to check whether this host advertises websocket or BOSH connection methods.
         const options = {
             'mode': 'cors',
-            'headers': {
-                'Accept': 'application/xrd+xml, text/xml'
-            }
+            '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) {
-            log.error(`Failed to discover alternative connection methods at ${url}`);
-            log.error(e);
-            return;
+        let response = await fetch(url, options).catch((e) => log.warn(e));
+        if (response?.status >= 200 && response?.status < 400) {
+            return this.onDomainDiscoveredViaXML(response);
         }
-        if (response.status >= 200 && response.status < 400) {
-            await this.onDomainDiscovered(response);
-        } else {
-            log.warn("Could not discover XEP-0156 connection methods");
+
+        options.headers = { 'Accept': 'application/json' };
+        response = await fetch(url+'.json', options).catch((e) => log.warn(e));
+        if (response?.status >= 200 && response?.status < 400) {
+            return this.onDomainDiscoveredViaJSON(response);
         }
+
+        log.warn(`Failed to discover alternative connection method at ${url}`);
     }
 
     /**

+ 30 - 0
src/headless/tests/connection.js

@@ -0,0 +1,30 @@
+/*global mock */
+
+describe("The Converse connection object", function () {
+
+    it("will discover alternative connection methods", mock.initConverse([], {'auto_login': false}, function (_converse) {
+        const { api } = _converse;
+        const ws_url = "wss://web.example.com:443/ws";
+        const bosh_url = "https://web.example.com:5280/bosh";
+
+        const response = new Response(JSON.stringify({
+            "links": [{
+                    "rel": "urn:xmpp:alt-connections:xbosh",
+                    "href": bosh_url
+                },
+                {
+                    "rel": "urn:xmpp:alt-connections:websocket",
+                    "href": ws_url
+                }
+            ]
+        })
+        , { 'status': 200 });
+
+        spyOn(window, 'fetch').and.returnValue(Promise.resolve(response));
+
+        _converse.connection.discoverConnectionMethods('chat.example.org')
+
+        expect(api.settings.get('websocket_url')).toBe(ws_url);
+        expect(api.settings.get('bosh_url')).toBe(ws_url);
+    }));
+});