Skip to content

Commit

Permalink
feat: added inheritance auth wallet operation (#119)
Browse files Browse the repository at this point in the history
* feat: proto wallet key auth

* fix: update getchallenge return struct

* fix(app): wallet key integration issues

* feat(app): Add secure data operations

* fix: wallet sign params

* chore: common commit update

* fix: name conflicts

* fix: setup test data

* refactor: remove operations other than auth wallet

- refactored the code to only contain a single operation
- add status handling for auth wallet operation

* test: added tests for inheritance auth wallet operation

* fix: wallet auth status event

* refactor: auth wallet params

---------

Co-authored-by: Vaibhav Sethia <[email protected]>
Co-authored-by: Parnika Gupta <[email protected]>
Co-authored-by: Md Irshad Ansari <[email protected]>
  • Loading branch information
4 people authored Aug 10, 2024
1 parent 4443e73 commit d090cc9
Show file tree
Hide file tree
Showing 14 changed files with 465 additions and 7 deletions.
5 changes: 5 additions & 0 deletions packages/app-inheritance/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IDeviceConnection } from '@cypherock/sdk-interfaces';
import { SDK } from '@cypherock/sdk-core';
import * as operations from './operations';

export class InheritanceApp {
private readonly sdk: SDK;
Expand All @@ -15,6 +16,10 @@ export class InheritanceApp {
return new InheritanceApp(sdk);
}

public async authWallet(params: operations.IAuthWalletParams) {
return this.sdk.runOperation(() => operations.authWallet(this.sdk, params));
}

public async destroy() {
return this.sdk.destroy();
}
Expand Down
71 changes: 71 additions & 0 deletions packages/app-inheritance/src/operations/authWallet/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { ISDK } from '@cypherock/sdk-core';
import {
assert,
createLoggerWithPrefix,
createStatusListener,
} from '@cypherock/sdk-utils';
import { APP_VERSION } from '../../constants/appId';
import { IWalletAuthResultResponse } from '../../proto/generated/types';
import {
assertOrThrowInvalidResult,
OperationHelper,
logger as rootLogger,
} from '../../utils';
import { IAuthWalletParams, WALLET_ID_LENGTH, WalletAuthEvent } from './types';
import { WalletAuthStatus } from '../../proto/generated/inheritance/wallet_auth';

export * from './types';

const logger = createLoggerWithPrefix(rootLogger, 'authWallet');

export const authWallet = async (
sdk: ISDK,
params: IAuthWalletParams,
): Promise<IWalletAuthResultResponse> => {
assert(params, 'Params should be defined');
assert(params.walletId, 'walletId should be defined');
assert(params.challenge, 'challenge should be defined');
assert(
typeof params.isPublicKey === 'boolean',
'isPublicKey should be defined',
);
assert(
params.walletId.length === WALLET_ID_LENGTH,
`Wallet Id should be exactly ${WALLET_ID_LENGTH} bytes`,
);

await sdk.checkAppCompatibility(APP_VERSION);

logger.info('Started', { ...params, onEvent: undefined });
const { forceStatusUpdate, onStatus } = createStatusListener({
enums: WalletAuthEvent,
operationEnums: WalletAuthStatus,
onEvent: params.onEvent,
logger,
});

const helper = new OperationHelper({
sdk,
queryKey: 'walletAuth',
resultKey: 'walletAuth',
onStatus,
});

await helper.sendQuery({
initiate: {
challenge: params.challenge,
walletId: params.walletId,
isPublickey: params.isPublicKey,
},
});

const result = await helper.waitForResult();
logger.verbose('WalletAuthResponse', result);

assertOrThrowInvalidResult(result.result);

forceStatusUpdate(WalletAuthEvent.CARD_TAP);

logger.info('Completed');
return result.result;
};
14 changes: 14 additions & 0 deletions packages/app-inheritance/src/operations/authWallet/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export enum WalletAuthEvent {
INIT = 0,
CARD_TAP = 1,
}

export type AuthWalletEventHandler = (event: WalletAuthEvent) => void;
export const WALLET_ID_LENGTH = 32;

export interface IAuthWalletParams {
challenge: Uint8Array;
walletId: Uint8Array;
isPublicKey: boolean;
onEvent?: AuthWalletEventHandler;
}
1 change: 1 addition & 0 deletions packages/app-inheritance/src/operations/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './authWallet';
1 change: 1 addition & 0 deletions packages/app-inheritance/src/operations/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './authWallet/types';
1 change: 1 addition & 0 deletions packages/app-inheritance/src/types.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './proto/generated/types';
export * from './operations/types';
80 changes: 80 additions & 0 deletions packages/app-inheritance/tests/02.authWallet/__fixtures__/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {
DeviceAppError,
DeviceAppErrorType,
deviceAppErrorTypeDetails,
} from '@cypherock/sdk-interfaces';
import { Query } from '../../../src/proto/generated/inheritance/core';
import { IAuthWalletTestCase } from './types';

const commonParams = {
params: {
walletId: new Uint8Array([
199, 89, 252, 26, 32, 135, 183, 211, 90, 220, 38, 17, 160, 103, 233, 62,
110, 172, 92, 20, 35, 250, 190, 146, 62, 8, 53, 86, 128, 26, 3, 187,
]),
challenge: new Uint8Array([
199, 89, 252, 26, 32, 135, 183, 211, 90, 220, 38, 17, 160, 103, 233, 62,
110, 172, 92, 20, 35, 250, 190, 146, 62, 8, 53, 86, 128, 26, 3, 187, 121,
64,
]),
isPublicKey: true,
},
queries: [
{
name: 'Initate query',
data: Uint8Array.from(
Query.encode(
Query.create({
walletAuth: {
initiate: {
walletId: new Uint8Array([
199, 89, 252, 26, 32, 135, 183, 211, 90, 220, 38, 17, 160,
103, 233, 62, 110, 172, 92, 20, 35, 250, 190, 146, 62, 8, 53,
86, 128, 26, 3, 187,
]),
challenge: new Uint8Array([
199, 89, 252, 26, 32, 135, 183, 211, 90, 220, 38, 17, 160,
103, 233, 62, 110, 172, 92, 20, 35, 250, 190, 146, 62, 8, 53,
86, 128, 26, 3, 187, 121, 64,
]),
isPublickey: true,
},
},
}),
).finish(),
),
},
],
};

const withUnknownError: IAuthWalletTestCase = {
name: 'With unknown error',
...commonParams,
results: [
{
name: 'error',
data: new Uint8Array([10, 4, 18, 2, 8, 1]),
},
],
errorInstance: DeviceAppError,
errorMessage:
deviceAppErrorTypeDetails[DeviceAppErrorType.UNKNOWN_ERROR].message,
};

const withInvalidAppId: IAuthWalletTestCase = {
name: 'With invalid msg from device',
...commonParams,
results: [
{
name: 'error',
data: new Uint8Array([10, 4, 18, 2, 16, 1]),
},
],
errorInstance: DeviceAppError,
errorMessage:
deviceAppErrorTypeDetails[DeviceAppErrorType.CORRUPT_DATA].message,
};

const error: IAuthWalletTestCase[] = [withUnknownError, withInvalidAppId];

export default error;
12 changes: 12 additions & 0 deletions packages/app-inheritance/tests/02.authWallet/__fixtures__/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { IFixtures } from './types';
import error from './error';
import valid from './valid';
import invalidArgs from './invalidArgs';

const fixtures: IFixtures = {
valid,
error,
invalidArgs,
};

export default fixtures;
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { IAuthWalletTestCase } from './types';

const commonParams = {
queries: [{ name: 'empty', data: new Uint8Array([]) }],
results: [{ name: 'empty', data: new Uint8Array([]) }],
errorInstance: Error,
errorMessage: /AssertionError/,
};

const validParams = {
walletId: new Uint8Array([
199, 89, 252, 26, 32, 135, 183, 211, 90, 220, 38, 17, 160, 103, 233, 62,
110, 172, 92, 20, 35, 250, 190, 146, 62, 8, 53, 86, 128, 26, 3, 187,
]),
challenge: new Uint8Array([
199, 89, 252, 26, 32, 135, 183, 211, 90, 220, 38, 17, 160, 103, 233, 62,
110, 172, 92, 20, 35, 250, 190, 146, 62, 8, 53, 86, 128, 26, 3, 187, 121,
64,
]),
isPublicKey: true,
};

const invalidArgs: IAuthWalletTestCase[] = [
{
name: 'Null',
...commonParams,
params: null as any,
},
{
name: 'Undefined',
...commonParams,
params: null as any,
},
{
name: 'Empty Object',
...commonParams,
params: {} as any,
},
{
name: 'No challenge',
...commonParams,
params: { ...validParams, challenge: undefined } as any,
},
{
name: 'No wallet id',
...commonParams,
params: { ...validParams, walletId: undefined } as any,
},
{
name: 'No isPublicKey',
...commonParams,
params: { ...validParams, isPublicKey: undefined } as any,
},
{
name: 'Incorrect length walletId',
...commonParams,
params: {
...validParams,
walletId: [0],
} as any,
},
];

export default invalidArgs;
27 changes: 27 additions & 0 deletions packages/app-inheritance/tests/02.authWallet/__fixtures__/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { IAuthWalletParams, IWalletAuthResultResponse } from '../../../src';

export interface IAuthWalletTestCase {
name: string;
params: IAuthWalletParams;
queries: {
name: string;
data: Uint8Array;
}[];
results: {
name: string;
data: Uint8Array;
statuses?: { flowStatus: number; expectEventCalls?: number[] }[];
}[];
mocks?: {
eventCalls?: number[][];
};
output?: Partial<IWalletAuthResultResponse>;
errorInstance?: any;
[key: string]: any;
}

export interface IFixtures {
valid: IAuthWalletTestCase[];
error: IAuthWalletTestCase[];
invalidArgs: IAuthWalletTestCase[];
}
89 changes: 89 additions & 0 deletions packages/app-inheritance/tests/02.authWallet/__fixtures__/valid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { hexToUint8Array, createFlowStatus } from '@cypherock/sdk-utils';
import { Query, Result } from '../../../src/proto/generated/inheritance/core';
import { IAuthWalletTestCase } from './types';

const authenticateWalletWithPublicKey: IAuthWalletTestCase = {
name: 'Authenticate wallet with publickey',
params: {
walletId: new Uint8Array([
199, 89, 252, 26, 32, 135, 183, 211, 90, 220, 38, 17, 160, 103, 233, 62,
110, 172, 92, 20, 35, 250, 190, 146, 62, 8, 53, 86, 128, 26, 3, 187,
]),
challenge: new Uint8Array([
199, 89, 252, 26, 32, 135, 183, 211, 90, 220, 38, 17, 160, 103, 233, 62,
110, 172, 92, 20, 35, 250, 190, 146, 62, 8, 53, 86, 128, 26, 3, 187, 121,
64,
]),
isPublicKey: true,
},
queries: [
{
name: 'Initate query',
data: Uint8Array.from(
Query.encode(
Query.create({
walletAuth: {
initiate: {
walletId: new Uint8Array([
199, 89, 252, 26, 32, 135, 183, 211, 90, 220, 38, 17, 160,
103, 233, 62, 110, 172, 92, 20, 35, 250, 190, 146, 62, 8, 53,
86, 128, 26, 3, 187,
]),
challenge: new Uint8Array([
199, 89, 252, 26, 32, 135, 183, 211, 90, 220, 38, 17, 160,
103, 233, 62, 110, 172, 92, 20, 35, 250, 190, 146, 62, 8, 53,
86, 128, 26, 3, 187, 121, 64,
]),
isPublickey: true,
},
},
}),
).finish(),
),
},
],
results: [
{
name: 'result',
data: Uint8Array.from(
Result.encode(
Result.create({
walletAuth: {
result: {
signature: hexToUint8Array(
'0x032891c403786eed3405bf29304abbcbb5282bc2b30eb3c45759f42bc9bb1b62c6',
),
publicKey: hexToUint8Array(
'0x032891c403786eed3405bf29304abbcbb5282bc2b30eb3c45759f42bc9bb1b62c6',
),
},
},
}),
).finish(),
),
statuses: [
{
flowStatus: createFlowStatus(0, 0),
expectEventCalls: [0],
},
{
flowStatus: createFlowStatus(1, 0),
expectEventCalls: [1],
},
],
},
],
mocks: { eventCalls: [[0], [1]] },
output: {
signature: hexToUint8Array(
'0x032891c403786eed3405bf29304abbcbb5282bc2b30eb3c45759f42bc9bb1b62c6',
),
publicKey: hexToUint8Array(
'0x032891c403786eed3405bf29304abbcbb5282bc2b30eb3c45759f42bc9bb1b62c6',
),
},
};

const valid: IAuthWalletTestCase[] = [authenticateWalletWithPublicKey];

export default valid;
Loading

0 comments on commit d090cc9

Please sign in to comment.