Browse Source

Feature: Mobile - Replace usage of broadcast-channel package for authentication state browser tab sync.

Dominik Klein 2 years ago
parent
commit
0d98d8fabc

+ 2 - 5
app/frontend/shared/stores/authentication.ts

@@ -1,7 +1,7 @@
 // Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
 
-import { ref } from 'vue'
 import { defineStore } from 'pinia'
+import { useLocalStorage } from '@vueuse/core'
 import { MutationHandler } from '@shared/server/apollo/handler'
 import { useLoginMutation } from '@shared/graphql/mutations/login.api'
 import { useLogoutMutation } from '@shared/graphql/mutations/logout.api'
@@ -15,7 +15,7 @@ import { resetAndDisposeStores } from '.'
 export const useAuthenticationStore = defineStore(
   'authentication',
   () => {
-    const authenticated = ref(false)
+    const authenticated = useLocalStorage<boolean>('authenticated', false)
     const { fingerprint } = useFingerprint()
 
     const clearAuthentication = async (): Promise<void> => {
@@ -97,9 +97,6 @@ export const useAuthenticationStore = defineStore(
     }
   },
   {
-    shareState: {
-      enabled: true,
-    },
     requiresAuth: false,
   },
 )

+ 0 - 2
app/frontend/shared/stores/index.ts

@@ -3,7 +3,6 @@
 import type { App } from 'vue'
 import { createPinia, type Pinia } from 'pinia'
 import type { UsedStore } from '@shared/types/store'
-import PiniaSharedState from './plugins/sharedState'
 
 declare module 'pinia' {
   // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -15,7 +14,6 @@ declare module 'pinia' {
 const usedStores = new Set<UsedStore>()
 
 const pinia: Pinia = createPinia()
-pinia.use(PiniaSharedState({ enabled: false }))
 
 // Remember all stores, for example to cleanup the private stores after logout.
 pinia.use((context) => {

+ 0 - 73
app/frontend/shared/stores/plugins/sharedState.ts

@@ -1,73 +0,0 @@
-// Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
-
-import { watch } from 'vue'
-import { BroadcastChannel } from 'broadcast-channel'
-import type { PiniaPluginContext, Store } from 'pinia'
-import type { ShareStateOptions } from '@shared/types/stores/plugins'
-
-declare module 'pinia' {
-  // eslint-disable-next-line @typescript-eslint/no-unused-vars
-  export interface DefineStoreOptionsBase<S, Store> {
-    shareState?: ShareStateOptions
-  }
-}
-
-/**
- * Share state across multiple browser tabs.
- *
- * @param store - The store the plugin will augment.
- */
-const shareState = <T extends Store>(store: T): void => {
-  const channelName = `${store.$id}`
-
-  const channel = new BroadcastChannel(channelName)
-  let externalUpdate = false
-  let timestamp = 0
-
-  watch(
-    () => store.$state,
-    (state) => {
-      if (!externalUpdate) {
-        timestamp = Date.now()
-        channel.postMessage({ timestamp, state: JSON.stringify(state) })
-      }
-      externalUpdate = false
-    },
-    { deep: true },
-  )
-
-  channel.onmessage = (evt) => {
-    if (evt.timestamp <= timestamp) {
-      return
-    }
-    externalUpdate = true
-    timestamp = evt.timestamp
-
-    store.$state = JSON.parse(evt.state)
-  }
-}
-
-/**
- * Adds a `shareState` option to the store to share state across browser tabs.
- *
- * @example
- *
- * ```ts
- * pinia.use(piniaSharedState({ enabled: true }))
- * ```
- *
- * @param options - The Global plugin options.
- * @param options.enabled - Enable/disable sharing of state for all stores.
- */
-const PiniaSharedState = (
-  pluginOptions: ShareStateOptions = { enabled: true },
-) => {
-  return ({ store, options }: PiniaPluginContext) => {
-    const isEnabled = options?.shareState?.enabled ?? pluginOptions.enabled
-    if (!isEnabled) return
-
-    shareState(store)
-  }
-}
-
-export default PiniaSharedState

+ 0 - 1
package.json

@@ -115,7 +115,6 @@
     "@vueuse/router": "^9.4.0",
     "@vueuse/shared": "^9.4.0",
     "async-mutex": "^0.4.0",
-    "broadcast-channel": "4.13.0",
     "flatpickr": "^4.6.13",
     "graphql": "^16.6.0",
     "graphql-ruby-client": "^1.11.3",

+ 52 - 0
spec/system/apps/mobile/basic/shared_authentication_state_spec.rb

@@ -0,0 +1,52 @@
+# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
+
+require 'rails_helper'
+
+RSpec.describe 'Mobile > Basic > Share authentication state between browser tabs', app: :mobile, type: :system do
+  context 'when use logout action' do
+    let(:agent)    { create(:agent) }
+
+    it 'check that all tabs have been logged out', authenticated_as: :agent do
+      visit '/'
+
+      # open new tab
+      open_window_and_switch
+      visit '/'
+
+      logout
+
+      expect_current_route 'login'
+
+      # Check that cookies has no longer a expire date after logout.
+      cookie = cookie('^_zammad.+?')
+      expect(cookie[:expires]).to be_nil
+
+      switch_to_window_index(1)
+
+      expect_current_route 'login'
+    end
+  end
+
+  context 'when use login action' do
+    let(:agent)    { create(:agent) }
+
+    it 'check that all tabs have been logged in', authenticated_as: false do
+      visit '/'
+
+      # open new tab
+      open_window_and_switch
+      visit '/'
+
+      login(
+        username: agent.login,
+        password: 'test',
+      )
+
+      expect_current_route '/'
+
+      switch_to_window_index(1)
+
+      expect_current_route '/'
+    end
+  end
+end

+ 2 - 76
yarn.lock

@@ -1005,7 +1005,7 @@
     "@babel/types" "^7.4.4"
     esutils "^2.0.2"
 
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.9.2":
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.9.2":
   version "7.19.4"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.4.tgz#a42f814502ee467d55b38dd1c256f53a7b885c78"
   integrity sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==
@@ -3398,19 +3398,6 @@ braces@^3.0.2, braces@~3.0.2:
   dependencies:
     fill-range "^7.0.1"
 
-broadcast-channel@4.13.0:
-  version "4.13.0"
-  resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-4.13.0.tgz#21387b2602b9e9ec3b97b03bd8a8d2c198352ff6"
-  integrity sha512-fcDr8QNJ4SOb6jyjUNZatVNmcHtSWfW4PFcs4xIEFZAtorKCIFoEYtjIjaQ4c0jrbr/Bl8NIwOWiLSyspoAnEQ==
-  dependencies:
-    "@babel/runtime" "^7.16.0"
-    detect-node "^2.1.0"
-    microtime "3.0.0"
-    oblivious-set "1.1.1"
-    p-queue "6.6.2"
-    rimraf "3.0.2"
-    unload "2.3.1"
-
 browserslist@^4.21.3, browserslist@^4.21.4:
   version "4.21.4"
   resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987"
@@ -4140,11 +4127,6 @@ detect-indent@^6.0.0:
   resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6"
   integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==
 
-detect-node@2.1.0, detect-node@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
-  integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
-
 detective@^5.2.1:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034"
@@ -4851,11 +4833,6 @@ event-target-shim@^5.0.0:
   resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
   integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
 
-eventemitter3@^4.0.4:
-  version "4.0.7"
-  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
-  integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
-
 expand-brackets@^2.1.4:
   version "2.1.4"
   resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
@@ -6770,14 +6747,6 @@ micromatch@^4.0.4, micromatch@^4.0.5:
     braces "^3.0.2"
     picomatch "^2.3.1"
 
-microtime@3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/microtime/-/microtime-3.0.0.tgz#d140914bde88aa89b4f9fd2a18620b435af0f39b"
-  integrity sha512-SirJr7ZL4ow2iWcb54bekS4aWyBQNVcEDBiwAz9D/sTgY59A+uE8UJU15cp5wyZmPBwg/3zf8lyCJ5NUe1nVlQ==
-  dependencies:
-    node-addon-api "^1.2.0"
-    node-gyp-build "^3.8.0"
-
 mime-db@1.52.0:
   version "1.52.0"
   resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
@@ -6938,11 +6907,6 @@ no-case@^3.0.4:
     lower-case "^2.0.2"
     tslib "^2.0.3"
 
-node-addon-api@^1.2.0:
-  version "1.7.2"
-  resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.2.tgz#3df30b95720b53c24e59948b49532b662444f54d"
-  integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==
-
 node-domexception@1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
@@ -6955,11 +6919,6 @@ node-fetch@2.6.7, node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.x.x:
   dependencies:
     whatwg-url "^5.0.0"
 
-node-gyp-build@^3.8.0:
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.9.0.tgz#53a350187dd4d5276750da21605d1cb681d09e25"
-  integrity sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==
-
 node-int64@^0.4.0:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
@@ -7103,11 +7062,6 @@ object.values@^1.1.5:
     define-properties "^1.1.3"
     es-abstract "^1.19.1"
 
-oblivious-set@1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.1.1.tgz#d9d38e9491d51f27a5c3ec1681d2ba40aa81e98b"
-  integrity sha512-Oh+8fK09mgGmAshFdH6hSVco6KZmd1tTwNFWj35OvzdmJTMZtAkbn05zar2iG3v6sDs1JLEtOiBGNb6BHwkb2w==
-
 on-finished@~2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
@@ -7186,11 +7140,6 @@ os-tmpdir@~1.0.2:
   resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
   integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
 
-p-finally@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
-  integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==
-
 p-limit@3.1.0, p-limit@^3.0.2:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
@@ -7226,21 +7175,6 @@ p-map@^4.0.0:
   dependencies:
     aggregate-error "^3.0.0"
 
-p-queue@6.6.2:
-  version "6.6.2"
-  resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426"
-  integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==
-  dependencies:
-    eventemitter3 "^4.0.4"
-    p-timeout "^3.2.0"
-
-p-timeout@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
-  integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==
-  dependencies:
-    p-finally "^1.0.0"
-
 p-try@^2.0.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
@@ -8030,7 +7964,7 @@ rfdc@^1.3.0:
   resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
   integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
 
-rimraf@3.0.2, rimraf@^3.0.2:
+rimraf@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
   integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
@@ -9257,14 +9191,6 @@ unixify@^1.0.0:
   dependencies:
     normalize-path "^2.1.1"
 
-unload@2.3.1:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/unload/-/unload-2.3.1.tgz#9d16862d372a5ce5cb630ad1309c2fd6e35dacfe"
-  integrity sha512-MUZEiDqvAN9AIDRbbBnVYVvfcR6DrjCqeU2YQMmliFZl9uaBUjTkhuDQkBiyAy8ad5bx1TXVbqZ3gg7namsWjA==
-  dependencies:
-    "@babel/runtime" "^7.6.2"
-    detect-node "2.1.0"
-
 unpipe@~1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"