2
0
JC Brand 3 жил өмнө
parent
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.
 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).
 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
 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/smacks/tests/smacks.js", type: 'module' },
       { pattern: "src/headless/plugins/status/tests/status.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/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/converse.js", type: 'module' },
       { pattern: "src/headless/tests/eventemitter.js", type: 'module' },
       { pattern: "src/headless/tests/eventemitter.js", type: 'module' },
       { pattern: "src/modals/tests/user-details-modal.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
 // Add Strophe Namespaces
 Strophe.addNamespace('ACTIVITY', 'http://jabber.org/protocol/activity');
 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('CARBONS', 'urn:xmpp:carbons:2');
 Strophe.addNamespace('CHATSTATES', 'http://jabber.org/protocol/chatstates');
 Strophe.addNamespace('CHATSTATES', 'http://jabber.org/protocol/chatstates');
 Strophe.addNamespace('CSI', 'urn:xmpp:csi:0');
 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();
         super.bind();
     }
     }
 
 
-
-    async onDomainDiscovered (response) {
+    async onDomainDiscoveredViaXML (response) {
         const text = await response.text();
         const text = await response.text();
         const xrd = (new window.DOMParser()).parseFromString(text, "text/xml").firstElementChild;
         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") {
         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 {
         } else {
             // TODO: support multiple endpoints
             // 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.service = api.settings.get("websocket_url") || api.settings.get('bosh_service_url');
             this.setProtocol();
             this.setProtocol();
         }
         }
@@ -66,27 +88,23 @@ export class Connection extends Strophe.Connection {
      * @method Connnection.discoverConnectionMethods
      * @method Connnection.discoverConnectionMethods
      */
      */
     async discoverConnectionMethods (domain) {
     async discoverConnectionMethods (domain) {
-        // Use XEP-0156 to check whether this host advertises websocket or BOSH connection methods.
         const options = {
         const options = {
             'mode': 'cors',
             'mode': 'cors',
-            'headers': {
-                'Accept': 'application/xrd+xml, text/xml'
-            }
+            'headers': { 'Accept': 'application/xrd+xml, text/xml' }
         };
         };
         const url = `https://${domain}/.well-known/host-meta`;
         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);
+    }));
+});