Skip to content

Commit

Permalink
More Seedless Reauth Improvement (#2113)
Browse files Browse the repository at this point in the history
  • Loading branch information
atn4z7 authored Nov 22, 2024
1 parent d729626 commit 35f9cef
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 5 deletions.
42 changes: 40 additions & 2 deletions packages/core-mobile/app/seedless/store/listeners.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { configureStore, createListenerMiddleware } from '@reduxjs/toolkit'
import { noop } from 'lodash'
import { AppStartListening } from 'store/middleware/listener'
import { onAppUnlocked, onLogOut, onRehydrationComplete } from 'store/app'
import {
onAppUnlocked,
onLogOut,
onRehydrationComplete,
selectWalletType
} from 'store/app'
import { WalletType } from 'services/wallet/types'
import SeedlessService from 'seedless/services/SeedlessService'
import { ErrorEvent, GlobalEvents } from '@cubist-labs/cubesigner-sdk'
import * as Navigation from 'utils/Navigation'
Expand All @@ -13,6 +19,15 @@ import { onTokenExpired, reducerName } from './slice'
jest.mock('services/wallet/WalletService', () => ({
walletType: 'SEEDLESS'
}))

jest.mock('store/app', () => {
const actual = jest.requireActual('store/app')
return {
...actual,
selectWalletType: jest.fn()
}
})

jest.mock('seedless/services/SeedlessService', () => ({
sessionManager: {
refreshToken: jest.fn()
Expand Down Expand Up @@ -62,6 +77,12 @@ describe('seedless - listeners', () => {
expect(SeedlessService.sessionManager.refreshToken).toHaveBeenCalled()
})
it('should have dispatched onTokenExpired action', async () => {
const mockSelectWalletType =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
selectWalletType as jest.MockedFunction<any>
mockSelectWalletType.mockImplementationOnce(() => {
return WalletType.SEEDLESS
})
store.dispatch(onRehydrationComplete())
GlobalEvents.triggerErrorEvent({
status: 403,
Expand All @@ -72,7 +93,24 @@ describe('seedless - listeners', () => {
params: expect.anything()
})
})
it('should have signed out', async () => {
it('should have not dispatched onTokenExpired action when wallet is not seedless', async () => {
const mockSelectWalletType =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
selectWalletType as jest.MockedFunction<any>
mockSelectWalletType.mockImplementationOnce(() => {
return WalletType.MNEMONIC
})
store.dispatch(onRehydrationComplete())
GlobalEvents.triggerErrorEvent({
status: 403,
isSessionExpiredError: () => true
} as ErrorEvent)
expect(mockNavigate).not.toHaveBeenCalledWith({
name: 'Root.RefreshToken',
params: expect.anything()
})
})
it('should have signed out', async () => {
store.dispatch(onLogOut())
expect(GoogleSigninService.signOut).toHaveBeenCalled()
})
Expand Down
11 changes: 9 additions & 2 deletions packages/core-mobile/app/seedless/store/listeners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
onLogOut,
onRehydrationComplete,
selectWalletState,
selectWalletType,
WalletState
} from 'store/app'
import * as Navigation from 'utils/Navigation'
Expand Down Expand Up @@ -45,7 +46,7 @@ const registerSeedlessErrorHandler = async (
_: Action,
listenerApi: AppListenerEffectAPI
): Promise<void> => {
const { dispatch } = listenerApi
const { dispatch, getState } = listenerApi

const onErrorHandler = async (e: ErrResponse): Promise<void> => {
// log error
Expand All @@ -54,14 +55,20 @@ const registerSeedlessErrorHandler = async (
// an example url https://prod.signer.cubist.dev/v1/org/Org%23db7f2cac-7bd0-4e5f-b7c2-b5881a4bb4e7/eth1/sign/0xD0E99cEa490Cdb54ba555922bf325952F0DE38bd
Logger.error('seedless error', JSON.stringify({ ...e, url: '' }))

const walletType = selectWalletType(getState())

// the following check is what cubist does internally for GlobalEvents.onSessionExpired
//
// if status is 403 and error matches one of the "invalid session" error codes
// or when "signerSessionRefresh" fails (errors returned by the authorizer lambda are not forwarded to the client)
// or when e.errorCode is undefined, it means that the error came from the authorizer, which is currently the only place cubist cannot set errorCode
// we will prompt user to re-authenticate
if (
walletType === WalletType.SEEDLESS &&
e.status === 403 &&
(e.isSessionExpiredError() || e.operation === 'signerSessionRefresh')
(e.isSessionExpiredError() ||
e.operation === 'signerSessionRefresh' ||
e.errorCode === undefined)
) {
dispatch(onTokenExpired)
}
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -26357,7 +26357,7 @@ react-native-webview@ava-labs/react-native-webview:
peerDependencies:
react: "*"
react-native: "*"
checksum: a187edd718e1ea3a6b1e5da167744e6ee324bc3c3e492bcb0a9d028ab68a82907f053f37c23aa4229d6a9091541cee3c73549c3c850056e4cf5eb5b3cb2c9ffc
checksum: d396f3dea807077e8789e1d463c87024e1633481d3dff53c0650c82a08d8b7d699db97ceab4e8d2c9de85c3d5378d192c968487254c62edadff77e82a9b8c929
languageName: node
linkType: hard

Expand Down

0 comments on commit 35f9cef

Please sign in to comment.