From 2334a5f8614fd9adc44843c40fb3d4f748b745e8 Mon Sep 17 00:00:00 2001 From: John Livingston Date: Thu, 18 Apr 2024 16:24:09 +0200 Subject: [PATCH] Possibility to configure an OpenID Connect provider on the instance level WIP (#128). Sign out button for external accounts. --- conversejs/builtin.ts | 7 +++ conversejs/lib/auth.ts | 4 +- conversejs/lib/plugins/livechat-specific.ts | 48 ++++++++++++++++++++- server/lib/routers/api/auth.ts | 6 ++- 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/conversejs/builtin.ts b/conversejs/builtin.ts index f5b93c3d..e09943c0 100644 --- a/conversejs/builtin.ts +++ b/conversejs/builtin.ts @@ -105,6 +105,7 @@ async function initConverse ( params.allow_url_history_change = chatIncludeMode === 'chat-only' let isAuthenticated: boolean = false + let isAuthenticatedWithExternalAccount: boolean = false let isRemoteWithNicknameSet: boolean = false // OIDC (OpenID Connect): @@ -116,9 +117,11 @@ async function initConverse ( if (!isRemoteChat) { localRoomAuthenticatedParams(initConverseParams, auth, params) isAuthenticated = true + isAuthenticatedWithExternalAccount = auth.type !== 'peertube' } else if (remoteAuthenticatedXMPPServer) { remoteRoomAuthenticatedParams(initConverseParams, auth, params) isAuthenticated = true + isAuthenticatedWithExternalAccount = auth.type !== 'peertube' } else if (remoteAnonymousXMPPServer) { // remote server does not allow remote authenticated users, falling back to anonymous mode remoteRoomAnonymousParams(initConverseParams, auth, params) @@ -165,10 +168,14 @@ async function initConverse ( // no viewer mode if authenticated. params.livechat_enable_viewer_mode = autoViewerMode && !isAuthenticated && !isRemoteWithNicknameSet + params.livechat_specific_external_authent = isAuthenticatedWithExternalAccount + if (tryOIDC && !isAuthenticated) { params.livechat_external_auth_oidc_button_label = initConverseParams.externalAuthOIDC?.buttonLabel params.livechat_external_auth_oidc_url = initConverseParams.externalAuthOIDC?.url + } + if (tryOIDC) { // also needed when authenticated (for the signout button) switch (chatIncludeMode) { case 'peertube-video': params.livechat_external_auth_reconnect_mode = 'button-close-open' diff --git a/conversejs/lib/auth.ts b/conversejs/lib/auth.ts index fb369e44..9745e5c3 100644 --- a/conversejs/lib/auth.ts +++ b/conversejs/lib/auth.ts @@ -1,4 +1,5 @@ interface AuthentInfos { + type: 'peertube' | 'oidc' jid: string password: string nickname?: string @@ -87,7 +88,8 @@ async function getLocalAuthentInfos ( return { jid: data.jid, password: data.password, - nickname: data.nickname + nickname: data.nickname, + type: data.type ?? 'peertube' } } catch (error) { console.error(error) diff --git a/conversejs/lib/plugins/livechat-specific.ts b/conversejs/lib/plugins/livechat-specific.ts index e6dc0399..3020f1d1 100644 --- a/conversejs/lib/plugins/livechat-specific.ts +++ b/conversejs/lib/plugins/livechat-specific.ts @@ -2,6 +2,51 @@ export const livechatSpecificsPlugin = { dependencies: ['converse-muc', 'converse-muc-views'], initialize: function (this: any) { const _converse = this._converse + + _converse.api.settings.extend({ + // if user is authenticated with an external account (to add a logout button) + livechat_specific_external_authent: false + }) + + _converse.api.listen.on('getHeadingButtons', (view: any, buttons: any[]) => { + if (view.model.get('type') !== _converse.CHATROOMS_TYPE) { + // only on MUC. + return + } + + if (_converse.api.settings.get('livechat_specific_external_authent')) { + // Adding a logout button + buttons.push({ + i18n_text: _converse.__('Log out'), + handler: async (ev: Event) => { + ev.preventDefault() + ev.stopPropagation() + + const messages = [_converse.__('Are you sure you want to leave this groupchat?')] + const result = await _converse.api.confirm(_converse.__('Confirm'), messages) + if (!result) { return } + + // Deleting access token in sessionStorage. + window.sessionStorage.removeItem('peertube-plugin-livechat-oidc-token') + + const reconnectMode = _converse.api.settings.get('livechat_external_auth_reconnect_mode') + if (reconnectMode === 'button-close-open') { + const button = document.getElementsByClassName('peertube-plugin-livechat-button-close')[0] + if ((button as HTMLAnchorElement).click) { (button as HTMLAnchorElement).click() } + return + } + + window.location.reload() + }, + a_class: 'close-chatbox-button', + icon_class: 'fa-sign-out-alt', + name: 'signout' + }) + } + + return buttons + }) + _converse.api.listen.on('chatRoomViewInitialized', function (this: any, _model: any): void { // Remove the spinner if present... document.getElementById('livechat-loading-spinner')?.remove() @@ -39,7 +84,8 @@ export const livechatSpecificsPlugin = { 'livechat_enable_viewer_mode', 'livechat_external_auth_oidc_button_label', 'livechat_external_auth_oidc_url', 'livechat_external_auth_reconnect_mode', - 'livechat_mini_muc_head' + 'livechat_mini_muc_head', + 'livechat_specific_external_authent' ]) { _converse.api.settings.set(k, params[k]) } diff --git a/server/lib/routers/api/auth.ts b/server/lib/routers/api/auth.ts index 99bca1b4..221dc2b9 100644 --- a/server/lib/routers/api/auth.ts +++ b/server/lib/routers/api/auth.ts @@ -28,7 +28,8 @@ async function initAuthApiRouter (options: RegisterServerOptions, router: Router res.status(200).json({ jid: unserializedToken.jid, password: unserializedToken.password, - nickname: unserializedToken.nickname + nickname: unserializedToken.nickname, + type: 'oidc' }) return } @@ -59,7 +60,8 @@ async function initAuthApiRouter (options: RegisterServerOptions, router: Router res.status(200).json({ jid: normalizedUsername + '@' + prosodyDomain, password: password, - nickname: nickname + nickname: nickname, + type: 'peertube' }) } ))