feat(release): prepare 1.1.0 candidate
This commit is contained in:
parent
5a34f66981
commit
5205dcdfa9
736 changed files with 115667 additions and 12203 deletions
72
apps/mobile-rn/__tests__/pending-invite.test.ts
Normal file
72
apps/mobile-rn/__tests__/pending-invite.test.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
jest.mock('react-native-keychain', () => ({
|
||||
ACCESSIBLE: { AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY: 'device-only' },
|
||||
SECURITY_LEVEL: { SECURE_SOFTWARE: 1 },
|
||||
STORAGE_TYPE: { AES_GCM_NO_AUTH: 'aes-gcm' },
|
||||
getGenericPassword: jest.fn().mockResolvedValue(false),
|
||||
setGenericPassword: jest.fn(),
|
||||
resetGenericPassword: jest.fn(),
|
||||
}))
|
||||
|
||||
import * as Keychain from 'react-native-keychain'
|
||||
import {
|
||||
loadPendingInviteToken,
|
||||
savePendingInviteToken,
|
||||
} from '../src/features/teams/pending-invite'
|
||||
|
||||
const TOKEN = 'Abcdefghijklmnopqrstuvwxyz_12345'
|
||||
const PENDING_SERVICE = 'com.d3ro.voice.pending-team-invite.v1'
|
||||
|
||||
describe('pending invitation secure storage', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
;(Keychain.getGenericPassword as jest.Mock).mockReset().mockResolvedValue(false)
|
||||
})
|
||||
|
||||
test('stores only a validated token in device-bound secure storage', async () => {
|
||||
;(Keychain.setGenericPassword as jest.Mock).mockResolvedValue({ service: 'stored' })
|
||||
|
||||
await savePendingInviteToken(TOKEN)
|
||||
|
||||
expect(Keychain.setGenericPassword).toHaveBeenCalledWith(
|
||||
'pending-invite',
|
||||
TOKEN,
|
||||
expect.objectContaining({
|
||||
service: 'com.d3ro.voice.pending-team-invite.v1',
|
||||
accessible: 'device-only',
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
test('rejects malformed tokens before touching secure storage', async () => {
|
||||
await expect(savePendingInviteToken('short')).rejects.toMatchObject({
|
||||
code: 'invalid-token',
|
||||
})
|
||||
expect(Keychain.setGenericPassword).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('clears corrupt or foreign secure-storage records', async () => {
|
||||
const pendingResponses = [
|
||||
{ username: 'other', password: TOKEN },
|
||||
{ username: 'pending-invite', password: 'short' },
|
||||
]
|
||||
;(Keychain.getGenericPassword as jest.Mock).mockImplementation(
|
||||
async ({ service }: { service?: string } = {}) => (
|
||||
service === PENDING_SERVICE ? pendingResponses.shift() ?? false : false
|
||||
),
|
||||
)
|
||||
;(Keychain.resetGenericPassword as jest.Mock).mockResolvedValue(true)
|
||||
|
||||
await expect(loadPendingInviteToken()).resolves.toBeNull()
|
||||
await expect(loadPendingInviteToken()).resolves.toBeNull()
|
||||
expect(Keychain.resetGenericPassword).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
test('returns a valid stored invitation token', async () => {
|
||||
;(Keychain.getGenericPassword as jest.Mock).mockImplementation(
|
||||
async ({ service }: { service?: string } = {}) => service === PENDING_SERVICE
|
||||
? { username: 'pending-invite', password: TOKEN }
|
||||
: false,
|
||||
)
|
||||
await expect(loadPendingInviteToken()).resolves.toBe(TOKEN)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue