Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove multi auth error checking #2018

Merged
merged 2 commits into from
Mar 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 11 additions & 62 deletions components/account.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
import { useRouter } from 'next/router'
import * as cookie from 'cookie'
import { useMe } from '@/components/me'
import { USER_ID, SSR } from '@/lib/constants'
import { USER } from '@/fragments/users'
import { useQuery } from '@apollo/client'
import { UserListRow } from '@/components/user-list'
import Link from 'next/link'
import AddIcon from '@/svgs/add-fill.svg'
import { MultiAuthErrorBanner } from '@/components/banners'
import { cookieOptions, MULTI_AUTH_ANON, MULTI_AUTH_LIST, MULTI_AUTH_POINTER } from '@/lib/auth'

const AccountContext = createContext()

const CHECK_ERRORS_INTERVAL_MS = 5_000

const b64Decode = str => Buffer.from(str, 'base64').toString('utf-8')

export const AccountProvider = ({ children }) => {
const [accounts, setAccounts] = useState([])
const [meAnon, setMeAnon] = useState(true)
const [errors, setErrors] = useState([])
const [selected, setSelected] = useState(null)

const updateAccountsFromCookie = useCallback(() => {
const { [MULTI_AUTH_LIST]: listCookie } = cookie.parse(document.cookie)
Expand All @@ -39,51 +34,29 @@ export const AccountProvider = ({ children }) => {
return switchSuccess
}, [updateAccountsFromCookie])

const checkErrors = useCallback(() => {
const {
[MULTI_AUTH_LIST]: listCookie,
[MULTI_AUTH_POINTER]: pointerCookie
} = cookie.parse(document.cookie)

const errors = []

if (!listCookie) errors.push(`${MULTI_AUTH_LIST} cookie not found`)
if (!pointerCookie) errors.push(`${MULTI_AUTH_POINTER} cookie not found`)

setErrors(errors)
}, [])

useEffect(() => {
if (SSR) return

updateAccountsFromCookie()

const { [MULTI_AUTH_POINTER]: pointerCookie } = cookie.parse(document.cookie)
setMeAnon(pointerCookie === 'anonymous')

const interval = setInterval(checkErrors, CHECK_ERRORS_INTERVAL_MS)
return () => clearInterval(interval)
}, [updateAccountsFromCookie, checkErrors])
setSelected(pointerCookie === MULTI_AUTH_ANON ? USER_ID.anon : Number(pointerCookie))
}, [updateAccountsFromCookie])

const value = useMemo(
() => ({
accounts,
meAnon,
setMeAnon,
nextAccount,
multiAuthErrors: errors
selected,
nextAccount
}),
[accounts, meAnon, setMeAnon, nextAccount])
[accounts, selected, nextAccount])
return <AccountContext.Provider value={value}>{children}</AccountContext.Provider>
}

export const useAccounts = () => useContext(AccountContext)

const AccountListRow = ({ account, ...props }) => {
const { meAnon, setMeAnon } = useAccounts()
const { me, refreshMe } = useMe()
const anonRow = account.id === USER_ID.anon
const selected = (meAnon && anonRow) || Number(me?.id) === Number(account.id)
const { selected } = useAccounts()
const router = useRouter()

// fetch updated names and photo ids since they might have changed since we were issued the JWTs
Expand All @@ -103,18 +76,8 @@ const AccountListRow = ({ account, ...props }) => {

// update pointer cookie
const options = cookieOptions({ httpOnly: false })
document.cookie = cookie.serialize(MULTI_AUTH_POINTER, anonRow ? MULTI_AUTH_ANON : account.id, options)

// update state
if (anonRow) {
// order is important to prevent flashes of no session
setMeAnon(true)
await refreshMe()
} else {
await refreshMe()
// order is important to prevent flashes of inconsistent data in switch account dialog
setMeAnon(account.id === USER_ID.anon)
}
const anon = account.id === USER_ID.anon
document.cookie = cookie.serialize(MULTI_AUTH_POINTER, anon ? MULTI_AUTH_ANON : account.id, options)

// reload whatever page we're on to avoid any bugs due to missing authorization etc.
router.reload()
Expand All @@ -127,30 +90,16 @@ const AccountListRow = ({ account, ...props }) => {
className='d-flex align-items-center me-2'
{...props}
onNymClick={onClick}
selected={selected}
selected={selected === account.id}
/>
</div>
)
}

export default function SwitchAccountList () {
const { accounts, multiAuthErrors } = useAccounts()
const { accounts } = useAccounts()
const router = useRouter()

const hasError = multiAuthErrors.length > 0

if (hasError) {
return (
<>
<div className='my-2'>
<div className='d-flex flex-column flex-wrap mt-2 mb-3'>
<MultiAuthErrorBanner errors={multiAuthErrors} />
</div>
</div>
</>
)
}

// can't show hat since the streak is not included in the JWT payload
return (
<>
Expand Down
22 changes: 0 additions & 22 deletions components/banners.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { useMutation } from '@apollo/client'
import { WELCOME_BANNER_MUTATION } from '@/fragments/users'
import { useToast } from '@/components/toast'
import Link from 'next/link'
import AccordianItem from '@/components/accordian-item'

export function WelcomeBanner ({ Banner }) {
const { me } = useMe()
Expand Down Expand Up @@ -124,24 +123,3 @@ export function AuthBanner () {
</Alert>
)
}

export function MultiAuthErrorBanner ({ errors }) {
return (
<Alert className={styles.banner} key='info' variant='danger'>
<div className='fw-bold mb-3'>Account switching is currently unavailable</div>
<AccordianItem
className='my-3'
header='We have detected the following issues:'
headerColor='var(--bs-danger-text-emphasis)'
body={
<ul>
{errors.map((err, i) => (
<li key={i}>{err}</li>
))}
</ul>
}
/>
<div className='mt-3'>To resolve these issues, please sign out and sign in again.</div>
</Alert>
)
}