From 048560908e06fee75a4377fa04328568d8748e4e Mon Sep 17 00:00:00 2001 From: JC Brand Date: Sat, 4 Dec 2021 23:42:42 +0100 Subject: [PATCH] Login form: Allow user to choose the connection URL if `websocket_url` and `bosh_service_url` are not set and XEP-0156 lookup was unsuccessful. --- src/headless/core.js | 30 ++++++------- src/headless/shared/connection.js | 3 ++ src/headless/tests/converse.js | 20 +-------- src/plugins/controlbox/loginform.js | 42 ++++++++++++++++++- src/plugins/controlbox/templates/loginform.js | 21 +++++++++- webpack.html | 3 +- 6 files changed, 78 insertions(+), 41 deletions(-) diff --git a/src/headless/core.js b/src/headless/core.js index 63851d93f..0bf4464e3 100644 --- a/src/headless/core.js +++ b/src/headless/core.js @@ -612,30 +612,24 @@ _converse.initConnection = function () { if (api.settings.get("authentication") === _converse.PREBIND) { throw new Error("authentication is set to 'prebind' but we don't have a BOSH connection"); } - if (! api.settings.get("websocket_url")) { - throw new Error("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both."); - } } + let connection_url = ''; const XMPPConnection = _converse.isTestEnv() ? MockConnection : Connection; if (('WebSocket' in window || 'MozWebSocket' in window) && api.settings.get("websocket_url")) { - _converse.connection = new XMPPConnection( - api.settings.get("websocket_url"), - Object.assign(_converse.default_connection_options, api.settings.get("connection_options")) - ); + connection_url = api.settings.get('websocket_url'); } else if (api.settings.get('bosh_service_url')) { - _converse.connection = new XMPPConnection( - api.settings.get('bosh_service_url'), - Object.assign( - _converse.default_connection_options, - api.settings.get("connection_options"), - {'keepalive': api.settings.get("keepalive")} - ) - ); - } else { - throw new Error("initConnection: this browser does not support "+ - "websockets and bosh_service_url wasn't specified."); + connection_url = api.settings.get('bosh_service_url'); } + _converse.connection = new XMPPConnection( + connection_url, + Object.assign( + _converse.default_connection_options, + api.settings.get("connection_options"), + {'keepalive': api.settings.get("keepalive")} + ) + ); + setUpXMLLogging(); /** * Triggered once the `Connection` constructor has been initialized, which diff --git a/src/headless/shared/connection.js b/src/headless/shared/connection.js index 4a16fa021..9eab4007d 100644 --- a/src/headless/shared/connection.js +++ b/src/headless/shared/connection.js @@ -102,6 +102,9 @@ export class Connection extends Strophe.Connection { const domain = Strophe.getDomainFromJid(jid); await this.discoverConnectionMethods(domain); } + if (!api.settings.get('bosh_service_url') && !api.settings.get("websocket_url")) { + throw new Error("You must supply a value for either the bosh_service_url or websocket_url or both."); + } super.connect(jid, password, callback || this.onConnectStatusChanged, BOSH_WAIT); } diff --git a/src/headless/tests/converse.js b/src/headless/tests/converse.js index e6c94fbb1..0455c11fe 100644 --- a/src/headless/tests/converse.js +++ b/src/headless/tests/converse.js @@ -4,24 +4,6 @@ const { Strophe } = converse.env; describe("Converse", function() { - describe("Authentication", function () { - - it("needs either a bosh_service_url a websocket_url or both", mock.initConverse(async (_converse) => { - const { api } = _converse; - const url = api.settings.get('bosh_service_url'); - const connection = _converse.connection; - _converse.api.settings.set('bosh_service_url', undefined); - delete _converse.connection; - try { - await _converse.initConnection(); - } catch (e) { - _converse.api.settings.set('bosh_service_url', url); - _converse.connection = connection; - expect(e.message).toBe("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both."); - } - })); - }); - describe("A chat state indication", function () { it("are sent out when the client becomes or stops being idle", @@ -53,7 +35,7 @@ describe("Converse", function() { describe("Automatic status change", function () { it("happens when the client is idle for long enough", - mock.initConverse(['initialized'], {}, async (_converse) => { + mock.initConverse(['chatBoxesFetched'], {}, async (_converse) => { const { api } = _converse; let i = 0; diff --git a/src/plugins/controlbox/loginform.js b/src/plugins/controlbox/loginform.js index f86fe5901..9bf979c6e 100644 --- a/src/plugins/controlbox/loginform.js +++ b/src/plugins/controlbox/loginform.js @@ -1,6 +1,7 @@ import bootstrap from 'bootstrap.native'; import tpl_login_panel from './templates/loginform.js'; import { CustomElement } from 'shared/components/element.js'; +import { Model } from '@converse/skeletor/src/model.js'; import { __ } from 'i18n'; import { _converse, api, converse } from '@converse/headless/core'; @@ -10,7 +11,9 @@ const { Strophe, u } = converse.env; class LoginForm extends CustomElement { initialize () { - this.listenTo(_converse.connfeedback, 'change', this.requesUpdate); + this.model = new Model(); + this.listenTo(_converse.connfeedback, 'change', () => this.requestUpdate()); + this.listenTo(this.model, 'change', () => this.requestUpdate()); } render () { @@ -21,6 +24,35 @@ class LoginForm extends CustomElement { this.initPopovers(); } + async onLoginFormSubmitted (ev) { + ev?.preventDefault(); + if (api.settings.get('bosh_service_url') || + api.settings.get('websocket_url') || + this.model.get('show_connection_url_input')) { + this.authenticate(ev); + } + await this.discoverConnectionMethods(ev); + if (api.settings.get('bosh_service_url') || api.settings.get('websocket_url')) { + this.authenticate(ev); + } else { + this.model.set('show_connection_url_input', true); + } + } + + // eslint-disable-next-line class-methods-use-this + async discoverConnectionMethods (ev) { + if (!api.settings.get("discover_connection_methods")) { + return; + } + const form_data = new FormData(ev.target); + const jid = form_data.get('jid'); + const domain = Strophe.getDomainFromJid(jid); + if (!_converse.connection?.jid || (jid && !u.isSameDomain(_converse.connection.jid, jid))) { + await _converse.initConnection(); + } + return _converse.connection.discoverConnectionMethods(domain); + } + initPopovers () { Array.from(this.querySelectorAll('[data-title]')).forEach(el => { new bootstrap.Popover(el, { @@ -52,7 +84,6 @@ class LoginForm extends CustomElement { * @param { Event } ev */ authenticate (ev) { - ev?.preventDefault(); if (api.settings.get('authentication') === _converse.ANONYMOUS) { return this.connect(_converse.jid, null); } @@ -61,6 +92,13 @@ class LoginForm extends CustomElement { } const form_data = new FormData(ev.target); + const connection_url = form_data.get('connection-url'); + if (connection_url?.startsWith('ws')) { + api.settings.set('websocket_url', connection_url); + } else if (connection_url?.startsWith('http')) { + api.settings.set('bosh_service_url', connection_url); + } + _converse.config.save({ 'trusted': (form_data.get('trusted') && true) || false }); let jid = form_data.get('jid'); diff --git a/src/plugins/controlbox/templates/loginform.js b/src/plugins/controlbox/templates/loginform.js index 87abbfe45..395450d29 100644 --- a/src/plugins/controlbox/templates/loginform.js +++ b/src/plugins/controlbox/templates/loginform.js @@ -24,6 +24,24 @@ const trust_checkbox = (checked) => { `; } +const connection_url_input = () => { + const i18n_connection_url = __('Connection URL'); + const i18n_form_help = __('HTTP or websocket URL that is used to connect to your XMPP server'); + const i18n_placeholder = __('e.g. wss://example.org/xmpp-websocket'); + return html` +
+ +

${i18n_form_help}

+ +
+ `; +} + const password_input = () => { const i18n_password = __('Password'); return html` @@ -73,6 +91,7 @@ const auth_fields = (el) => { placeholder="${placeholder_username}"/> ${ (authentication !== _converse.EXTERNAL) ? password_input() : '' } + ${ el.model.get('show_connection_url_input') ? connection_url_input() : '' } ${ show_trust_checkbox ? trust_checkbox(show_trust_checkbox === 'off' ? false : true) : '' }
@@ -105,7 +124,7 @@ export default (el) => { const conn_feedback_message = _converse.connfeedback.get('message'); return html` -
+