From ec95c32c7ab3e91983fcbeb0d283ee2fb6147f3f Mon Sep 17 00:00:00 2001 From: Stojan Dimitrovski Date: Fri, 18 Aug 2023 12:56:18 +0200 Subject: [PATCH] feat: enable `navigatorLock` completely, track random logouts --- packages/common/gotrue.ts | 10 ++++-- studio/lib/gotrue.ts | 66 +++++-------------------------------- studio/lib/local-storage.ts | 44 +++++++------------------ 3 files changed, 28 insertions(+), 92 deletions(-) diff --git a/packages/common/gotrue.ts b/packages/common/gotrue.ts index 1f6444c9002..22b0b68aeb8 100644 --- a/packages/common/gotrue.ts +++ b/packages/common/gotrue.ts @@ -3,8 +3,8 @@ import { GoTrueClient, navigatorLock } from '@supabase/gotrue-js' export const STORAGE_KEY = process.env.NEXT_PUBLIC_STORAGE_KEY || 'supabase.dashboard.auth.token' export const AUTH_DEBUG_KEY = process.env.NEXT_PUBLIC_AUTH_DEBUG_KEY || 'supabase.dashboard.auth.debug' -export const AUTH_NAVIGATOR_LOCK_KEY = - process.env.NEXT_PUBLIC_AUTH_NAVIGATOR_LOCK_KEY || 'supabase.dashboard.auth.navigatorLock.enabled' +export const AUTH_NAVIGATOR_LOCK_DISABLED_KEY = + process.env.NEXT_PUBLIC_AUTH_NAVIGATOR_LOCK_KEY || 'supabase.dashboard.auth.navigatorLock.disabled' const debug = process.env.NEXT_PUBLIC_IS_PLATFORM === 'true' && @@ -12,10 +12,14 @@ const debug = const navigatorLockEnabled = !!( process.env.NEXT_PUBLIC_IS_PLATFORM === 'true' && - globalThis?.localStorage?.getItem(AUTH_NAVIGATOR_LOCK_KEY) === 'true' && + !(globalThis?.localStorage?.getItem(AUTH_NAVIGATOR_LOCK_DISABLED_KEY) === 'true') && globalThis?.navigator?.locks ) +if (!globalThis?.navigator?.locks) { + console.warn('This browser does not support the Navigator Locks API. Please update it.') +} + export const gotrueClient = new GoTrueClient({ url: process.env.NEXT_PUBLIC_GOTRUE_URL, storageKey: STORAGE_KEY, diff --git a/studio/lib/gotrue.ts b/studio/lib/gotrue.ts index c89d359bf2f..0b7e7f7a41d 100644 --- a/studio/lib/gotrue.ts +++ b/studio/lib/gotrue.ts @@ -1,51 +1,21 @@ import { IS_PLATFORM } from './constants' import { User, Session } from '@supabase/gotrue-js' import { gotrueClient } from 'common' + import { getFlags } from './configcat' -import { getNavigatorLockFeatureFlagThreshold, setNavigatorLockEnabled } from './local-storage' - -// The first time this file is imported, ConfigCat will be asked for all -// available feature flags. The client that this is running in will have -// determined and saved a random number [0, 100) under -// `supabase.dashboard.ff.threshold.navigatorLock`. If there is a number-valued -// feature flag `navigatorLockThreshold`, the -// `supabase.dashboard.auth.navigatorLock.enabled` localStorage key will be set -// to true if the value chosen by the browser is <= the value in the feature -// flag.On the _following_ refresh of the page, `packages/common/gotrue.ts` -// will read this value and enable the GoTrueClient navigatorLock. -// ConfigCat does not have a native way to do this, as percent-based rollouts -// are only available when ConfigCat has a user ID, and not without one, which -// can be the case here (GoTrue is used when not authenticated too). -async function determineNavigatorLockFeatureFlag() { - const flags = await getFlags() - const value = flags.find((flag) => flag.settingKey === 'navigatorLockThreshold')?.settingValue - - if (typeof value === 'number' && value > 0) { - const threshold = getNavigatorLockFeatureFlagThreshold() - - if (typeof threshold === 'number') { - setNavigatorLockEnabled(threshold <= value) - } else { - setNavigatorLockEnabled(false) - } - } else { - setNavigatorLockEnabled(false) - } -} export { STORAGE_KEY } from 'common' export const auth = gotrueClient let currentSession: Session | null = null -let getAccessTokenPromise: Promise | null = null auth.onAuthStateChange((event, session) => { currentSession = session }) /** - * Grabs the currently available access token, or starts a single getSession call. + * Grabs the currently available access token, or calls getSession. */ export async function getAccessToken() { // ignore if server-side @@ -56,29 +26,15 @@ export async function getAccessToken() { : false if (!currentSession || aboutToExpire) { - if (!getAccessTokenPromise) { - const promise = (async () => { - try { - const { - data: { session }, - error, - } = await auth.getSession() - if (error) { - throw error - } - - return session?.access_token - } finally { - getAccessTokenPromise = null - } - })() - - getAccessTokenPromise = promise - - return await promise + const { + data: { session }, + error, + } = await auth.getSession() + if (error) { + throw error } - return await getAccessTokenPromise + return session?.access_token } return currentSession.access_token @@ -142,7 +98,3 @@ export const getReturnToPath = (fallback = '/projects') => { return validReturnTo + (remainingSearchParams ? `?${remainingSearchParams}` : '') } - -if (IS_PLATFORM && globalThis.window) { - determineNavigatorLockFeatureFlag() -} diff --git a/studio/lib/local-storage.ts b/studio/lib/local-storage.ts index 6c37492a46e..19f8258e6ff 100644 --- a/studio/lib/local-storage.ts +++ b/studio/lib/local-storage.ts @@ -4,10 +4,9 @@ export const LOCAL_STORAGE_KEYS_ALLOWLIST = [ 'graphiql:theme', 'theme', 'supabaseDarkMode', - 'supabase.dashboard.sign_in_clicks_v2', + 'supabase.dashboard.sign_in_clicks_v3', 'supabase.dashboard.auth.debug', - 'supabase.dashboard.auth.navigatorLock.enabled', - 'supabase.dashboard.auth.ff.threshold.navigatorLock', + 'supabase.dashboard.auth.navigatorLock.disabled', ] export function clearLocalStorage() { @@ -19,12 +18,17 @@ export function clearLocalStorage() { } function inferSignInClicks() { - if (localStorage.getItem('supabase.dashboard.sign_in_clicks_v2')) { + // remove old data from local storage + ['', '_v2'].forEach(suffix => { + localStorage.removeItem(`supabase.dashboard.sign_in_clicks${suffix}`) + }) + + if (localStorage.getItem('supabase.dashboard.sign_in_clicks_v3')) { return } localStorage.setItem( - 'supabase.dashboard.sign_in_clicks_v2', + 'supabase.dashboard.sign_in_clicks_v3', localStorage.getItem('supabase.dashboard.auth.token') ? '1' : '0' ) } @@ -33,7 +37,7 @@ export function getSignInClicks(): number { let count: number | null = null try { - count = JSON.parse(localStorage.getItem('supabase.dashboard.sign_in_clicks_v2') || '0') + count = JSON.parse(localStorage.getItem('supabase.dashboard.sign_in_clicks_v3') || '0') } catch (e: any) { // do nothing } @@ -44,7 +48,7 @@ export function getSignInClicks(): number { export function incrementSignInClicks(): number { const clicks = getSignInClicks() - localStorage.setItem('supabase.dashboard.sign_in_clicks_v2', JSON.stringify(clicks + 1)) + localStorage.setItem('supabase.dashboard.sign_in_clicks_v3', JSON.stringify(clicks + 1)) return clicks + 1 } @@ -52,36 +56,12 @@ export function incrementSignInClicks(): number { export function resetSignInClicks(): number { const clicks = getSignInClicks() - localStorage.setItem('supabase.dashboard.sign_in_clicks_v2', '0') + localStorage.setItem('supabase.dashboard.sign_in_clicks_v3', '0') return clicks } -export function getNavigatorLockFeatureFlagThreshold() { - const str = localStorage.getItem('supabase.dashboard.auth.ff.threshold.navigatorLock') - - return str ? parseInt(str) : null -} - -function determineNavigatorLockFeatureFlagThreshold() { - if (getNavigatorLockFeatureFlagThreshold()) { - return - } - - localStorage.setItem( - 'supabase.dashboard.auth.ff.threshold.navigatorLock', - `${Math.floor(Math.random() * 100)}` - ) -} - -export function setNavigatorLockEnabled(enabled: boolean) { - localStorage.setItem('supabase.dashboard.auth.navigatorLock.enabled', enabled ? 'true' : 'false') -} - if (globalThis && globalThis.localStorage && IS_PLATFORM) { // populate the value based on the current local storage state inferSignInClicks() - - // setup the navigator lock group on initial load - determineNavigatorLockFeatureFlagThreshold() }