mirror of
https://github.com/trezor/trezor-suite.git
synced 2026-02-20 00:33:07 +01:00
feat(suite-sync): separate quota check from getting keys
# Conflicts: # suite-common/suite-sync-types/src/refreshSuiteSyncKeys.ts # Conflicts: # suite-common/suite-sync-types/src/refreshSuiteSyncKeys.ts # suite-common/suite-sync/src/createRefreshSuiteSyncKeys.ts
This commit is contained in:
committed by
Bohdan Juříček
parent
f0726ae443
commit
0ed2ee89a5
@@ -10,6 +10,7 @@ export type {
|
||||
export type {
|
||||
RefreshSuiteSyncKeys,
|
||||
RefreshSuiteSyncKeysDep,
|
||||
RefreshSuiteSyncKeysResult,
|
||||
WriteModeRequiredForAllocationErrType,
|
||||
} from './refreshSuiteSyncKeys';
|
||||
export type { TurnOffSuiteSyncDep, TurnOffSuiteSync } from './turnOffSuiteSync';
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { SuiteSyncOwner } from '@suite-common/suite-sync-storage';
|
||||
import { DelegatedIdentityKey, TrezorDevice } from '@suite-common/suite-types';
|
||||
import type { DeviceCancelledErrType, DeviceErrorType } from '@suite-common/suite-types';
|
||||
import { TrezorDevice } from '@suite-common/suite-types';
|
||||
import { Result } from '@trezor/type-utils';
|
||||
|
||||
type RefreshSuiteSyncKeysParams = {
|
||||
device: TrezorDevice;
|
||||
isWriteMode: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -22,15 +21,17 @@ export type WriteModeRequiredForAllocationErrType = {
|
||||
type: 'WriteModeRequiredForAllocation';
|
||||
};
|
||||
|
||||
export type RefreshSuiteSyncKeysResult = {
|
||||
owner: SuiteSyncOwner;
|
||||
delegatedKey: DelegatedIdentityKey;
|
||||
};
|
||||
|
||||
export type RefreshSuiteSyncKeys = (
|
||||
params: RefreshSuiteSyncKeysParams,
|
||||
) => Promise<
|
||||
Result<
|
||||
SuiteSyncOwner,
|
||||
| SuiteSyncUnavailableOnDeviceErrorType
|
||||
| DeviceErrorType
|
||||
| DeviceCancelledErrType
|
||||
| WriteModeRequiredForAllocationErrType
|
||||
RefreshSuiteSyncKeysResult,
|
||||
SuiteSyncUnavailableOnDeviceErrorType | DeviceErrorType | DeviceCancelledErrType
|
||||
>
|
||||
>;
|
||||
|
||||
|
||||
@@ -2,23 +2,15 @@ import { Dispatch } from '@reduxjs/toolkit';
|
||||
|
||||
import { EnsureDelegatedIdentityKeyDep } from '@suite-common/delegated-identity-key-types';
|
||||
import { isTrezorDeviceWithState } from '@suite-common/device';
|
||||
import {
|
||||
WriteModeRequiredForAllocation,
|
||||
ensureDeviceHasQuotaThunk,
|
||||
ensureOwnerHasAllocatedQuotaThunk,
|
||||
} from '@suite-common/suite-sync-quota-manager';
|
||||
import {
|
||||
EnsureSuiteSyncOwnerDep,
|
||||
RefreshSuiteSyncKeys,
|
||||
SuiteSyncUnavailableOnDeviceErrorType,
|
||||
} from '@suite-common/suite-sync-types';
|
||||
import { notificationsActions } from '@suite-common/toast-notifications';
|
||||
import { parseDeviceStaticSessionId } from '@suite-common/wallet-utils';
|
||||
import { err, exhaustive, ok } from '@trezor/type-utils';
|
||||
|
||||
import { GetDeviceForStaticSessionIdDep } from './getDeviceForStaticSessionId';
|
||||
import { GetDeviceHasAllowance } from './getDeviceHasAllowance';
|
||||
import { LoadSuiteSyncOwnerFromStateDep } from './owner/createLoadSuiteSyncOwnerFromState';
|
||||
|
||||
/**
|
||||
* Device is not connected or device is in a state/configuration, that does not
|
||||
@@ -30,31 +22,19 @@ export const SuiteSyncUnavailableOnDeviceError = (): SuiteSyncUnavailableOnDevic
|
||||
|
||||
export type RefreshSuiteSyncKeysDeps = {
|
||||
dispatch: Dispatch;
|
||||
hasAllowance: GetDeviceHasAllowance;
|
||||
} & EnsureSuiteSyncOwnerDep &
|
||||
LoadSuiteSyncOwnerFromStateDep &
|
||||
EnsureDelegatedIdentityKeyDep &
|
||||
GetDeviceForStaticSessionIdDep;
|
||||
|
||||
export const createRefreshSuiteSync =
|
||||
(deps: RefreshSuiteSyncKeysDeps): RefreshSuiteSyncKeys =>
|
||||
async ({ device, isWriteMode }): ReturnType<RefreshSuiteSyncKeys> => {
|
||||
async ({ device }): ReturnType<RefreshSuiteSyncKeys> => {
|
||||
if (!device || !isTrezorDeviceWithState(device)) {
|
||||
return err(SuiteSyncUnavailableOnDeviceError());
|
||||
}
|
||||
|
||||
const deviceStaticId = device.state.staticSessionId;
|
||||
|
||||
const owner = await deps.loadSuiteSyncOwnerFromState({ deviceStaticId });
|
||||
|
||||
const { walletDescriptor } = parseDeviceStaticSessionId(device.state.staticSessionId);
|
||||
|
||||
// If device has an owner, is registered in quota manager and the owner
|
||||
// already has an allowance, there's nothing to refresh — return success.
|
||||
if (owner !== null && deps.hasAllowance({ walletDescriptor, deviceId: device.id })) {
|
||||
return ok(owner);
|
||||
}
|
||||
|
||||
if (
|
||||
!device.connected || // disconnected device cannot resolve Evolu-Keys
|
||||
device.mode !== 'normal' // bootloader
|
||||
@@ -62,7 +42,7 @@ export const createRefreshSuiteSync =
|
||||
return err(SuiteSyncUnavailableOnDeviceError());
|
||||
}
|
||||
|
||||
const getKeys = async () => {
|
||||
const getDelegatedIdentityKeys = async () => {
|
||||
const delegatedKeyResult = await deps.ensureDelegatedIdentityKey({ device });
|
||||
|
||||
if (!delegatedKeyResult.success) {
|
||||
@@ -76,13 +56,6 @@ export const createRefreshSuiteSync =
|
||||
return err({ type: 'RefreshDeviceFailed' as const });
|
||||
}
|
||||
|
||||
await deps.dispatch(
|
||||
ensureDeviceHasQuotaThunk({
|
||||
device: refreshedDevice,
|
||||
delegatedKey: delegatedKeyResult.payload,
|
||||
}),
|
||||
);
|
||||
|
||||
const ownerResult = await deps.ensureSuiteSyncOwner({
|
||||
device: refreshedDevice,
|
||||
delegatedKey: delegatedKeyResult.payload,
|
||||
@@ -92,26 +65,10 @@ export const createRefreshSuiteSync =
|
||||
return ownerResult;
|
||||
}
|
||||
|
||||
const allocatedQuota = await deps.dispatch(
|
||||
ensureOwnerHasAllocatedQuotaThunk({
|
||||
walletDescriptor,
|
||||
ownerId: ownerResult.payload.ownerId,
|
||||
delegatedKey: delegatedKeyResult.payload,
|
||||
isWriteMode,
|
||||
}),
|
||||
);
|
||||
|
||||
if (
|
||||
allocatedQuota.success === false &&
|
||||
allocatedQuota.error.type === 'WriteModeRequiredForAllocation'
|
||||
) {
|
||||
return err(WriteModeRequiredForAllocation());
|
||||
}
|
||||
|
||||
return ok(ownerResult.payload);
|
||||
return ok({ owner: ownerResult.payload, delegatedKey: delegatedKeyResult.payload });
|
||||
};
|
||||
|
||||
const result = await getKeys();
|
||||
const result = await getDelegatedIdentityKeys();
|
||||
|
||||
if (!result.success) {
|
||||
const errType = result.error.type;
|
||||
@@ -119,7 +76,6 @@ export const createRefreshSuiteSync =
|
||||
switch (errType) {
|
||||
case 'DeviceError':
|
||||
case 'DeviceCancelled':
|
||||
case 'WriteModeRequiredForAllocation':
|
||||
return err(result.error);
|
||||
|
||||
// Those errors are most likely due to Bug in the code or data corruption
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
import { createSaveSuiteSyncOwner } from './owner/createSaveSuiteSyncOwner';
|
||||
import { createChangeRelayUrl } from './relay/createChangeRelayUrl';
|
||||
import { DEFAULT_SUITE_SYNC_RELAY_URL } from './relay/relayUrl';
|
||||
import { createEnsureQuota } from './storage/createEnsureQuota';
|
||||
import { createEnsureStorage } from './storage/createEnsureStorage';
|
||||
import { createEnsureWalletSuiteSyncOn } from './storage/createEnsureWalletSuiteSyncOn';
|
||||
import { createEnsureWalletSuiteSyncOnWithErrorHandler } from './storage/createEnsureWalletSuiteSyncOnWithErrorHandler';
|
||||
@@ -94,7 +95,11 @@ export const createSuiteSyncCompositionRoot = (
|
||||
dispatch: deps.dispatch,
|
||||
ensureDelegatedIdentityKey: deps.ensureDelegatedIdentityKey,
|
||||
ensureSuiteSyncOwner,
|
||||
loadSuiteSyncOwnerFromState,
|
||||
getDeviceForStaticSessionId,
|
||||
});
|
||||
|
||||
const ensureQuota = createEnsureQuota({
|
||||
dispatch: deps.dispatch,
|
||||
getDeviceForStaticSessionId,
|
||||
hasAllowance: ({ walletDescriptor, deviceId }) =>
|
||||
selectHasDeviceAllowance(deps.getState(), deviceId ?? null, walletDescriptor),
|
||||
@@ -108,6 +113,7 @@ export const createSuiteSyncCompositionRoot = (
|
||||
|
||||
const ensureStorage = createEnsureStorage({
|
||||
refreshSuiteSyncKeys,
|
||||
ensureQuota,
|
||||
suiteSyncStorageRepository,
|
||||
createSuiteStorage,
|
||||
defaultRelayUrl: DEFAULT_SUITE_SYNC_RELAY_URL,
|
||||
|
||||
78
suite-common/suite-sync/src/storage/createEnsureQuota.ts
Normal file
78
suite-common/suite-sync/src/storage/createEnsureQuota.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { Dispatch } from '@reduxjs/toolkit';
|
||||
|
||||
import {
|
||||
WriteModeRequiredForAllocation,
|
||||
ensureDeviceHasQuotaThunk,
|
||||
ensureOwnerHasAllocatedQuotaThunk,
|
||||
} from '@suite-common/suite-sync-quota-manager';
|
||||
import type { WriteModeRequiredForAllocationErrType } from '@suite-common/suite-sync-types';
|
||||
import { DelegatedIdentityKey, SuiteSyncOwner } from '@suite-common/suite-types';
|
||||
import { isTrezorDeviceWithState, parseDeviceStaticSessionId } from '@suite-common/wallet-utils';
|
||||
import { StaticSessionId } from '@trezor/connect';
|
||||
import { Result, err, ok } from '@trezor/type-utils';
|
||||
|
||||
import { GetDeviceForStaticSessionIdDep } from '../getDeviceForStaticSessionId';
|
||||
import { GetDeviceHasAllowance } from '../getDeviceHasAllowance';
|
||||
|
||||
export type EnsureQuotaDeps = {
|
||||
dispatch: Dispatch;
|
||||
hasAllowance: GetDeviceHasAllowance;
|
||||
} & GetDeviceForStaticSessionIdDep;
|
||||
|
||||
export type EnsureQuotaParams = {
|
||||
deviceStaticSessionId: StaticSessionId;
|
||||
delegatedKey: DelegatedIdentityKey;
|
||||
owner: SuiteSyncOwner;
|
||||
isWriteMode: boolean;
|
||||
};
|
||||
|
||||
export type EnsureQuota = (
|
||||
params: EnsureQuotaParams,
|
||||
) => Promise<Result<void, WriteModeRequiredForAllocationErrType>>;
|
||||
|
||||
export type EnsureQuotaDep = {
|
||||
ensureQuota: EnsureQuota;
|
||||
};
|
||||
|
||||
export const createEnsureQuota =
|
||||
(deps: EnsureQuotaDeps): EnsureQuota =>
|
||||
async ({ deviceStaticSessionId, delegatedKey, owner, isWriteMode }) => {
|
||||
const { walletDescriptor } = parseDeviceStaticSessionId(deviceStaticSessionId);
|
||||
|
||||
const device = deps.getDeviceForStaticSessionId(deviceStaticSessionId);
|
||||
|
||||
if (
|
||||
device?.id !== null &&
|
||||
device?.id !== undefined &&
|
||||
deps.hasAllowance({ walletDescriptor, deviceId: device.id })
|
||||
) {
|
||||
return ok(undefined);
|
||||
}
|
||||
|
||||
if (device !== null && isTrezorDeviceWithState(device)) {
|
||||
await deps.dispatch(
|
||||
ensureDeviceHasQuotaThunk({
|
||||
device,
|
||||
delegatedKey,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const allocatedQuota = await deps.dispatch(
|
||||
ensureOwnerHasAllocatedQuotaThunk({
|
||||
walletDescriptor,
|
||||
ownerId: owner.ownerId,
|
||||
delegatedKey,
|
||||
isWriteMode,
|
||||
}),
|
||||
);
|
||||
|
||||
if (
|
||||
allocatedQuota.success === false &&
|
||||
allocatedQuota.error.type === 'WriteModeRequiredForAllocation'
|
||||
) {
|
||||
return err(WriteModeRequiredForAllocation());
|
||||
}
|
||||
|
||||
return ok(undefined);
|
||||
};
|
||||
@@ -9,6 +9,7 @@ import { DeviceCancelledErrType, DeviceErrorType } from '@suite-common/suite-typ
|
||||
import { StaticSessionId } from '@trezor/connect';
|
||||
import { Result, err, ok } from '@trezor/type-utils';
|
||||
|
||||
import { EnsureQuotaDep } from './createEnsureQuota';
|
||||
import { createStorageIdFromDeviceStaticSessionId } from './createStorageIdFromDeviceStaticSessionId';
|
||||
import { SuiteSyncUnavailableOnDeviceError } from '../createRefreshSuiteSyncKeys';
|
||||
import { GetDeviceForStaticSessionIdDep } from '../getDeviceForStaticSessionId';
|
||||
@@ -19,7 +20,8 @@ export type EnsureStorageDeps = {
|
||||
} & SuiteSyncStorageRepositoryDep &
|
||||
CreateSuiteStorageDep &
|
||||
RefreshSuiteSyncKeysDep &
|
||||
GetDeviceForStaticSessionIdDep;
|
||||
GetDeviceForStaticSessionIdDep &
|
||||
EnsureQuotaDep;
|
||||
|
||||
export type EnsureStorageParams = {
|
||||
deviceStaticSessionId: StaticSessionId;
|
||||
@@ -59,15 +61,28 @@ export const createEnsureStorage =
|
||||
return err(SuiteSyncUnavailableOnDeviceError());
|
||||
}
|
||||
|
||||
const ownerResult = await deps.refreshSuiteSyncKeys({ device, isWriteMode });
|
||||
const keysResult = await deps.refreshSuiteSyncKeys({ device });
|
||||
|
||||
if (!ownerResult.success) {
|
||||
return ownerResult;
|
||||
if (!keysResult.success) {
|
||||
return keysResult;
|
||||
}
|
||||
|
||||
const { owner, delegatedKey } = keysResult.payload;
|
||||
|
||||
const quotaResult = await deps.ensureQuota({
|
||||
deviceStaticSessionId,
|
||||
delegatedKey,
|
||||
owner,
|
||||
isWriteMode,
|
||||
});
|
||||
|
||||
if (!quotaResult.success) {
|
||||
return quotaResult;
|
||||
}
|
||||
|
||||
const relayUrl = deps.getRelayUrl();
|
||||
const newStorage = deps.createSuiteStorage({
|
||||
suiteSyncOwner: ownerResult.payload,
|
||||
suiteSyncOwner: owner,
|
||||
relayUrl: relayUrl !== null && relayUrl.trim() !== '' ? relayUrl : deps.defaultRelayUrl,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createMockDeps, mock } from '@suite-common/dependency-injection';
|
||||
import {
|
||||
SuiteSyncOwner,
|
||||
asDelegatedIdentityKey,
|
||||
asSuiteSyncOwnerId,
|
||||
asSuiteSyncOwnerSecretHex,
|
||||
} from '@suite-common/suite-sync-storage';
|
||||
@@ -18,6 +19,8 @@ const OWNER_ABCD: SuiteSyncOwner = {
|
||||
ownerSecret: asSuiteSyncOwnerSecretHex('owner-secret-abcd'),
|
||||
};
|
||||
|
||||
const DELEGATED_KEY = asDelegatedIdentityKey('delegated-key-abcd');
|
||||
|
||||
const deviceStaticSessionId: StaticSessionId = '1@2:3';
|
||||
|
||||
describe(createEnsureStorage.name, () => {
|
||||
@@ -34,6 +37,7 @@ describe(createEnsureStorage.name, () => {
|
||||
},
|
||||
createSuiteStorage: null,
|
||||
refreshSuiteSyncKeys: null,
|
||||
ensureQuota: null,
|
||||
getDeviceForStaticSessionId: null,
|
||||
});
|
||||
|
||||
@@ -60,6 +64,7 @@ describe(createEnsureStorage.name, () => {
|
||||
},
|
||||
createSuiteStorage: null,
|
||||
refreshSuiteSyncKeys: null,
|
||||
ensureQuota: null,
|
||||
getDeviceForStaticSessionId: () => null,
|
||||
});
|
||||
|
||||
@@ -89,6 +94,7 @@ describe(createEnsureStorage.name, () => {
|
||||
},
|
||||
createSuiteStorage: null,
|
||||
refreshSuiteSyncKeys: () => Promise.resolve(refreshError),
|
||||
ensureQuota: null,
|
||||
getDeviceForStaticSessionId: () => device,
|
||||
});
|
||||
|
||||
@@ -99,7 +105,67 @@ describe(createEnsureStorage.name, () => {
|
||||
|
||||
expect(result).toBe(refreshError);
|
||||
expect(deps.getDeviceForStaticSessionId).toHaveBeenCalledWith(deviceStaticSessionId);
|
||||
expect(deps.refreshSuiteSyncKeys).toHaveBeenCalledWith({ device, isWriteMode: false });
|
||||
expect(deps.refreshSuiteSyncKeys).toHaveBeenCalledWith({ device });
|
||||
expect(deps.createSuiteStorage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls ensureQuota with correct params after refreshSuiteSyncKeys succeeds', async () => {
|
||||
const device = mockSuiteDevice();
|
||||
const newStorage = createSuiteSyncStorageMock();
|
||||
|
||||
const deps = createMockDeps<EnsureStorageDeps>({
|
||||
defaultRelayUrl: 'wss://default-relay.example.com',
|
||||
getRelayUrl: () => null,
|
||||
suiteSyncStorageRepository: {
|
||||
get: () => null,
|
||||
set: mock(() => {}),
|
||||
delete: null,
|
||||
},
|
||||
createSuiteStorage: () => newStorage,
|
||||
refreshSuiteSyncKeys: () =>
|
||||
Promise.resolve(ok({ owner: OWNER_ABCD, delegatedKey: DELEGATED_KEY })),
|
||||
ensureQuota: () => Promise.resolve(ok(undefined)),
|
||||
getDeviceForStaticSessionId: () => device,
|
||||
});
|
||||
|
||||
await createEnsureStorage(deps)({
|
||||
deviceStaticSessionId,
|
||||
isWriteMode: false,
|
||||
});
|
||||
|
||||
expect(deps.ensureQuota).toHaveBeenCalledWith({
|
||||
deviceStaticSessionId,
|
||||
delegatedKey: DELEGATED_KEY,
|
||||
owner: OWNER_ABCD,
|
||||
isWriteMode: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('returns error when ensureQuota fails', async () => {
|
||||
const device = mockSuiteDevice();
|
||||
const quotaError = err({ type: 'WriteModeRequiredForAllocation' as const });
|
||||
|
||||
const deps = createMockDeps<EnsureStorageDeps>({
|
||||
defaultRelayUrl: 'wss://default-relay.example.com',
|
||||
getRelayUrl: () => null,
|
||||
suiteSyncStorageRepository: {
|
||||
get: () => null,
|
||||
set: null,
|
||||
delete: null,
|
||||
},
|
||||
createSuiteStorage: null,
|
||||
refreshSuiteSyncKeys: () =>
|
||||
Promise.resolve(ok({ owner: OWNER_ABCD, delegatedKey: DELEGATED_KEY })),
|
||||
ensureQuota: () => Promise.resolve(quotaError),
|
||||
getDeviceForStaticSessionId: () => device,
|
||||
});
|
||||
|
||||
const result = await createEnsureStorage(deps)({
|
||||
deviceStaticSessionId,
|
||||
isWriteMode: true,
|
||||
});
|
||||
|
||||
expect(result).toBe(quotaError);
|
||||
expect(deps.createSuiteStorage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -116,7 +182,9 @@ describe(createEnsureStorage.name, () => {
|
||||
delete: null,
|
||||
},
|
||||
createSuiteStorage: () => newStorage,
|
||||
refreshSuiteSyncKeys: () => Promise.resolve(ok(OWNER_ABCD)),
|
||||
refreshSuiteSyncKeys: () =>
|
||||
Promise.resolve(ok({ owner: OWNER_ABCD, delegatedKey: DELEGATED_KEY })),
|
||||
ensureQuota: () => Promise.resolve(ok(undefined)),
|
||||
getDeviceForStaticSessionId: () => device,
|
||||
});
|
||||
|
||||
@@ -127,7 +195,7 @@ describe(createEnsureStorage.name, () => {
|
||||
|
||||
expect(result).toEqual(ok(newStorage));
|
||||
expect(deps.getDeviceForStaticSessionId).toHaveBeenCalledWith(deviceStaticSessionId);
|
||||
expect(deps.refreshSuiteSyncKeys).toHaveBeenCalledWith({ device, isWriteMode: false });
|
||||
expect(deps.refreshSuiteSyncKeys).toHaveBeenCalledWith({ device });
|
||||
expect(deps.createSuiteStorage).toHaveBeenCalledWith({
|
||||
suiteSyncOwner: OWNER_ABCD,
|
||||
relayUrl: 'wss://default-relay.example.com',
|
||||
@@ -150,7 +218,9 @@ describe(createEnsureStorage.name, () => {
|
||||
delete: null,
|
||||
},
|
||||
createSuiteStorage: () => newStorage,
|
||||
refreshSuiteSyncKeys: () => Promise.resolve(ok(OWNER_ABCD)),
|
||||
refreshSuiteSyncKeys: () =>
|
||||
Promise.resolve(ok({ owner: OWNER_ABCD, delegatedKey: DELEGATED_KEY })),
|
||||
ensureQuota: () => Promise.resolve(ok(undefined)),
|
||||
getDeviceForStaticSessionId: () => device,
|
||||
});
|
||||
|
||||
@@ -178,7 +248,9 @@ describe(createEnsureStorage.name, () => {
|
||||
delete: null,
|
||||
},
|
||||
createSuiteStorage: () => newStorage,
|
||||
refreshSuiteSyncKeys: () => Promise.resolve(ok(OWNER_ABCD)),
|
||||
refreshSuiteSyncKeys: () =>
|
||||
Promise.resolve(ok({ owner: OWNER_ABCD, delegatedKey: DELEGATED_KEY })),
|
||||
ensureQuota: () => Promise.resolve(ok(undefined)),
|
||||
getDeviceForStaticSessionId: () => device,
|
||||
});
|
||||
|
||||
@@ -208,7 +280,9 @@ describe(createEnsureStorage.name, () => {
|
||||
delete: null,
|
||||
},
|
||||
createSuiteStorage: () => newStorage,
|
||||
refreshSuiteSyncKeys: () => Promise.resolve(ok(OWNER_ABCD)),
|
||||
refreshSuiteSyncKeys: () =>
|
||||
Promise.resolve(ok({ owner: OWNER_ABCD, delegatedKey: DELEGATED_KEY })),
|
||||
ensureQuota: () => Promise.resolve(ok(undefined)),
|
||||
getDeviceForStaticSessionId: () => device,
|
||||
});
|
||||
|
||||
|
||||
@@ -9,16 +9,11 @@ import { ok } from '@trezor/type-utils';
|
||||
|
||||
import { RefreshSuiteSyncKeysDeps, createRefreshSuiteSync } from '../createRefreshSuiteSyncKeys';
|
||||
import { GetDeviceForStaticSessionId } from '../getDeviceForStaticSessionId';
|
||||
import { LoadSuiteSyncOwnerFromState } from '../owner/createLoadSuiteSyncOwnerFromState';
|
||||
|
||||
const createMockDeps = () =>
|
||||
({
|
||||
dispatch: mockNotExpected<Dispatch>('dispatch'),
|
||||
hasAllowance: mockNotExpected<RefreshSuiteSyncKeysDeps['hasAllowance']>('hasAllowance'),
|
||||
ensureSuiteSyncOwner: mockNotExpected<EnsureSuiteSyncOwner>('ensureSuiteSyncOwner'),
|
||||
loadSuiteSyncOwnerFromState: mockNotExpected<LoadSuiteSyncOwnerFromState>(
|
||||
'loadSuiteSyncOwnerFromState',
|
||||
),
|
||||
ensureDelegatedIdentityKey: mockNotExpected<EnsureDelegatedIdentityKey>(
|
||||
'ensureDelegatedIdentityKey',
|
||||
),
|
||||
@@ -61,46 +56,27 @@ describe(createRefreshSuiteSync.name, () => {
|
||||
const refreshSuiteSyncKeys = createRefreshSuiteSync(deps);
|
||||
const result = await refreshSuiteSyncKeys({
|
||||
device: createDevice({}, null),
|
||||
isWriteMode: false,
|
||||
});
|
||||
|
||||
expect(result.success).toEqual(false);
|
||||
expect(!result.success && result.error.type).toBe('SuiteSyncUnavailableOnDeviceError');
|
||||
});
|
||||
|
||||
it('returns an suite sync owner when device has state and is available', async () => {
|
||||
it('fails to get keys when device is disconnected', async () => {
|
||||
const deps = createMockDeps();
|
||||
deps.loadSuiteSyncOwnerFromState.mockResolvedValue(OWNER_1);
|
||||
deps.hasAllowance.mockReturnValue(true);
|
||||
|
||||
const refreshSuiteSyncKeys = createRefreshSuiteSync(deps);
|
||||
const result = await refreshSuiteSyncKeys({
|
||||
device: createDevice(),
|
||||
isWriteMode: false,
|
||||
});
|
||||
|
||||
expect(result.success).toEqual(true);
|
||||
expect(result.success && result.payload).toEqual(OWNER_1);
|
||||
});
|
||||
|
||||
it('fails to get keys, when device is disconnected', async () => {
|
||||
const deps = createMockDeps();
|
||||
deps.loadSuiteSyncOwnerFromState.mockResolvedValue(null);
|
||||
|
||||
const refreshSuiteSyncKeys = createRefreshSuiteSync(deps);
|
||||
const result = await refreshSuiteSyncKeys({
|
||||
device: createDevice({ connected: false }),
|
||||
isWriteMode: false,
|
||||
});
|
||||
|
||||
expect(result.success).toEqual(false);
|
||||
expect(!result.success && result.error.type).toEqual('SuiteSyncUnavailableOnDeviceError');
|
||||
});
|
||||
|
||||
it('ensures that the delegated identity key is available when owner is not in state', async () => {
|
||||
it('ensures that the delegated identity key is available', async () => {
|
||||
const deps = createMockDeps();
|
||||
deps.dispatch.mockImplementation(() => Promise.resolve(ok()));
|
||||
deps.loadSuiteSyncOwnerFromState.mockResolvedValue(null);
|
||||
deps.ensureSuiteSyncOwner.mockResolvedValue(ok(OWNER_1));
|
||||
deps.ensureDelegatedIdentityKey.mockResolvedValue(
|
||||
ok(asDelegatedIdentityKey('delegated-key-value')),
|
||||
@@ -110,25 +86,23 @@ describe(createRefreshSuiteSync.name, () => {
|
||||
deps.getDeviceForStaticSessionId.mockImplementation(() => mockDevice);
|
||||
|
||||
const refreshSuiteSyncKeys = createRefreshSuiteSync(deps);
|
||||
await refreshSuiteSyncKeys({
|
||||
const result = await refreshSuiteSyncKeys({
|
||||
device: mockDevice,
|
||||
isWriteMode: false,
|
||||
});
|
||||
|
||||
expect(deps.ensureDelegatedIdentityKey).toHaveBeenCalledWith({
|
||||
device: mockDevice,
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.success && result.payload).toEqual({
|
||||
owner: OWNER_1,
|
||||
delegatedKey: asDelegatedIdentityKey('delegated-key-value'),
|
||||
});
|
||||
});
|
||||
|
||||
it('requests ensureSuiteSyncOwner when owner is not in state', async () => {
|
||||
it('requests ensureSuiteSyncOwner', async () => {
|
||||
const deps = createMockDeps();
|
||||
deps.dispatch.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
success: false,
|
||||
error: { type: 'WriteModeRequiredForAllocation' },
|
||||
}),
|
||||
);
|
||||
deps.loadSuiteSyncOwnerFromState.mockResolvedValue(null);
|
||||
deps.dispatch.mockImplementation(() => Promise.resolve(ok()));
|
||||
deps.ensureSuiteSyncOwner.mockResolvedValue(ok(OWNER_1));
|
||||
deps.ensureDelegatedIdentityKey.mockResolvedValue(
|
||||
ok(asDelegatedIdentityKey('delegated-key-value')),
|
||||
@@ -140,7 +114,6 @@ describe(createRefreshSuiteSync.name, () => {
|
||||
const refreshSuiteSyncKeys = createRefreshSuiteSync(deps);
|
||||
await refreshSuiteSyncKeys({
|
||||
device: mockDevice,
|
||||
isWriteMode: false,
|
||||
});
|
||||
|
||||
expect(deps.ensureSuiteSyncOwner).toHaveBeenCalledWith({
|
||||
@@ -149,10 +122,9 @@ describe(createRefreshSuiteSync.name, () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('finally returns the new refreshed owner', async () => {
|
||||
it('returns owner and delegatedKey on success', async () => {
|
||||
const deps = createMockDeps();
|
||||
deps.dispatch.mockImplementation(() => Promise.resolve(ok()));
|
||||
deps.loadSuiteSyncOwnerFromState.mockResolvedValue(null);
|
||||
deps.ensureDelegatedIdentityKey.mockResolvedValue(
|
||||
ok(asDelegatedIdentityKey('delegated-key-value')),
|
||||
);
|
||||
@@ -169,11 +141,15 @@ describe(createRefreshSuiteSync.name, () => {
|
||||
const refreshSuiteSyncKeys = createRefreshSuiteSync(deps);
|
||||
const result = await refreshSuiteSyncKeys({
|
||||
device: mockDevice,
|
||||
isWriteMode: false,
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.success && result.payload.ownerId).toEqual('new-owner-id');
|
||||
expect(result.success && result.payload.ownerSecret).toEqual('new-secret-public-key');
|
||||
expect(result.success && result.payload).toEqual({
|
||||
owner: {
|
||||
ownerId: asSuiteSyncOwnerId('new-owner-id'),
|
||||
ownerSecret: asSuiteSyncOwnerSecretHex('new-secret-public-key'),
|
||||
},
|
||||
delegatedKey: asDelegatedIdentityKey('delegated-key-value'),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user