@ledgerhq/ledger-key-ring-protocol 0.5.1-nightly.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +33 -0
- package/.turbo/turbo-build.log +4 -0
- package/.unimportedrc.json +16 -0
- package/CHANGELOG.md +299 -0
- package/LICENSE.txt +21 -0
- package/README.md +3 -0
- package/jest.config.js +13 -0
- package/lib/HWDeviceProvider.d.ts +25 -0
- package/lib/HWDeviceProvider.d.ts.map +1 -0
- package/lib/HWDeviceProvider.js +88 -0
- package/lib/HWDeviceProvider.js.map +1 -0
- package/lib/api.d.ts +77 -0
- package/lib/api.d.ts.map +1 -0
- package/lib/api.js +150 -0
- package/lib/api.js.map +1 -0
- package/lib/auth.d.ts +3 -0
- package/lib/auth.d.ts.map +1 -0
- package/lib/auth.js +79 -0
- package/lib/auth.js.map +1 -0
- package/lib/errors.d.ts +40 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +18 -0
- package/lib/errors.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +17 -0
- package/lib/index.js.map +1 -0
- package/lib/mockSdk.d.ts +22 -0
- package/lib/mockSdk.d.ts.map +1 -0
- package/lib/mockSdk.js +208 -0
- package/lib/mockSdk.js.map +1 -0
- package/lib/qrcode/cipher.d.ts +12 -0
- package/lib/qrcode/cipher.d.ts.map +1 -0
- package/lib/qrcode/cipher.js +69 -0
- package/lib/qrcode/cipher.js.map +1 -0
- package/lib/qrcode/cipher.test.d.ts +2 -0
- package/lib/qrcode/cipher.test.d.ts.map +1 -0
- package/lib/qrcode/cipher.test.js +40 -0
- package/lib/qrcode/cipher.test.js.map +1 -0
- package/lib/qrcode/index.d.ts +70 -0
- package/lib/qrcode/index.d.ts.map +1 -0
- package/lib/qrcode/index.js +312 -0
- package/lib/qrcode/index.js.map +1 -0
- package/lib/qrcode/index.test.d.ts +2 -0
- package/lib/qrcode/index.test.d.ts.map +1 -0
- package/lib/qrcode/index.test.js +131 -0
- package/lib/qrcode/index.test.js.map +1 -0
- package/lib/qrcode/types.d.ts +69 -0
- package/lib/qrcode/types.d.ts.map +1 -0
- package/lib/qrcode/types.js +3 -0
- package/lib/qrcode/types.js.map +1 -0
- package/lib/sdk.d.ts +31 -0
- package/lib/sdk.d.ts.map +1 -0
- package/lib/sdk.js +380 -0
- package/lib/sdk.js.map +1 -0
- package/lib/store.d.ts +71 -0
- package/lib/store.d.ts.map +1 -0
- package/lib/store.js +62 -0
- package/lib/store.js.map +1 -0
- package/lib/types.d.ts +181 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +10 -0
- package/lib/types.js.map +1 -0
- package/lib-es/HWDeviceProvider.d.ts +25 -0
- package/lib-es/HWDeviceProvider.d.ts.map +1 -0
- package/lib-es/HWDeviceProvider.js +81 -0
- package/lib-es/HWDeviceProvider.js.map +1 -0
- package/lib-es/api.d.ts +77 -0
- package/lib-es/api.d.ts.map +1 -0
- package/lib-es/api.js +145 -0
- package/lib-es/api.js.map +1 -0
- package/lib-es/auth.d.ts +3 -0
- package/lib-es/auth.d.ts.map +1 -0
- package/lib-es/auth.js +75 -0
- package/lib-es/auth.js.map +1 -0
- package/lib-es/errors.d.ts +40 -0
- package/lib-es/errors.d.ts.map +1 -0
- package/lib-es/errors.js +15 -0
- package/lib-es/errors.js.map +1 -0
- package/lib-es/index.d.ts +6 -0
- package/lib-es/index.d.ts.map +1 -0
- package/lib-es/index.js +13 -0
- package/lib-es/index.js.map +1 -0
- package/lib-es/mockSdk.d.ts +22 -0
- package/lib-es/mockSdk.d.ts.map +1 -0
- package/lib-es/mockSdk.js +201 -0
- package/lib-es/mockSdk.js.map +1 -0
- package/lib-es/qrcode/cipher.d.ts +12 -0
- package/lib-es/qrcode/cipher.d.ts.map +1 -0
- package/lib-es/qrcode/cipher.js +61 -0
- package/lib-es/qrcode/cipher.js.map +1 -0
- package/lib-es/qrcode/cipher.test.d.ts +2 -0
- package/lib-es/qrcode/cipher.test.d.ts.map +1 -0
- package/lib-es/qrcode/cipher.test.js +38 -0
- package/lib-es/qrcode/cipher.test.js.map +1 -0
- package/lib-es/qrcode/index.d.ts +70 -0
- package/lib-es/qrcode/index.d.ts.map +1 -0
- package/lib-es/qrcode/index.js +304 -0
- package/lib-es/qrcode/index.js.map +1 -0
- package/lib-es/qrcode/index.test.d.ts +2 -0
- package/lib-es/qrcode/index.test.d.ts.map +1 -0
- package/lib-es/qrcode/index.test.js +126 -0
- package/lib-es/qrcode/index.test.js.map +1 -0
- package/lib-es/qrcode/types.d.ts +69 -0
- package/lib-es/qrcode/types.d.ts.map +1 -0
- package/lib-es/qrcode/types.js +2 -0
- package/lib-es/qrcode/types.js.map +1 -0
- package/lib-es/sdk.d.ts +31 -0
- package/lib-es/sdk.d.ts.map +1 -0
- package/lib-es/sdk.js +371 -0
- package/lib-es/sdk.js.map +1 -0
- package/lib-es/store.d.ts +71 -0
- package/lib-es/store.d.ts.map +1 -0
- package/lib-es/store.js +51 -0
- package/lib-es/store.js.map +1 -0
- package/lib-es/types.d.ts +181 -0
- package/lib-es/types.d.ts.map +1 -0
- package/lib-es/types.js +7 -0
- package/lib-es/types.js.map +1 -0
- package/mocks/scenarios/addSameMemberMultipleTimes.json +426 -0
- package/mocks/scenarios/create2trustchainInARow.json +616 -0
- package/mocks/scenarios/getOrCreateTransactionCases.json +591 -0
- package/mocks/scenarios/member3implicitlyAdded.json +648 -0
- package/mocks/scenarios/membersManySelfAdd.json +1427 -0
- package/mocks/scenarios/randomMemberTryToDestroy.json +371 -0
- package/mocks/scenarios/removeMemberWithTheWrongSeed.json +510 -0
- package/mocks/scenarios/removedMemberEjectedOnDeletedTrustchain.json +481 -0
- package/mocks/scenarios/removedMemberEjectedOnGetMembers.json +648 -0
- package/mocks/scenarios/removedMemberEjectedOnRestore.json +648 -0
- package/mocks/scenarios/removingAMemberCreatesAnInteraction.json +593 -0
- package/mocks/scenarios/removingYourselfIsForbidden.json +397 -0
- package/mocks/scenarios/success.json +978 -0
- package/mocks/scenarios/tokenExpires.json +371 -0
- package/mocks/scenarios/twoAddMembersFollowedByDeviceAdd.json +705 -0
- package/mocks/scenarios/userRefusesAuth.json +40 -0
- package/mocks/scenarios/userRefusesRemoveMember.json +542 -0
- package/package.json +91 -0
- package/scripts/README.md +15 -0
- package/scripts/e2e.ts +57 -0
- package/src/HWDeviceProvider.ts +105 -0
- package/src/__tests__/integration/mock.sdk.test.ts +47 -0
- package/src/__tests__/integration/sdk.test.ts +20 -0
- package/src/__tests__/tsconfig.json +8 -0
- package/src/__tests__/unit/sdk.test.ts +236 -0
- package/src/api.ts +202 -0
- package/src/auth.ts +81 -0
- package/src/errors.ts +18 -0
- package/src/index.ts +20 -0
- package/src/mockSdk.ts +253 -0
- package/src/qrcode/cipher.test.ts +30 -0
- package/src/qrcode/cipher.ts +63 -0
- package/src/qrcode/index.test.ts +138 -0
- package/src/qrcode/index.ts +395 -0
- package/src/qrcode/types.ts +70 -0
- package/src/sdk.ts +542 -0
- package/src/store.ts +99 -0
- package/src/types.ts +242 -0
- package/tests/scenarios/_template.ts +18 -0
- package/tests/scenarios/addSameMemberMultipleTimes.ts +20 -0
- package/tests/scenarios/create2trustchainInARow.ts +14 -0
- package/tests/scenarios/getOrCreateTransactionCases.ts +74 -0
- package/tests/scenarios/member3implicitlyAdded.ts +51 -0
- package/tests/scenarios/membersManySelfAdd.ts +18 -0
- package/tests/scenarios/randomMemberTryToDestroy.ts +23 -0
- package/tests/scenarios/removeMemberWithTheWrongSeed.ts +28 -0
- package/tests/scenarios/removedMemberEjectedOnDeletedTrustchain.ts +31 -0
- package/tests/scenarios/removedMemberEjectedOnGetMembers.ts +29 -0
- package/tests/scenarios/removedMemberEjectedOnRestore.ts +31 -0
- package/tests/scenarios/removingAMemberCreatesAnInteraction.ts +42 -0
- package/tests/scenarios/removingYourselfIsForbidden.ts +11 -0
- package/tests/scenarios/success.ts +94 -0
- package/tests/scenarios/tokenExpires.ts +20 -0
- package/tests/scenarios/twoAddMembersFollowedByDeviceAdd.ts +49 -0
- package/tests/scenarios/userRefusesAuth.ts +28 -0
- package/tests/scenarios/userRefusesRemoveMember.ts +66 -0
- package/tests/test-helpers/recordTrustchainSdkTests.ts +178 -0
- package/tests/test-helpers/replayTrustchainSdkTests.ts +141 -0
- package/tests/test-helpers/types.ts +45 -0
- package/tests/tsconfig.json +8 -0
- package/tsconfig.json +15 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { Observable } from "rxjs";
|
|
2
|
+
import Transport from "@ledgerhq/hw-transport";
|
|
3
|
+
import { TrustchainsResponse } from "./api";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The JWT is a JSON Web Token that is used to authenticate the user.
|
|
7
|
+
*/
|
|
8
|
+
export type JWT = {
|
|
9
|
+
accessToken: string;
|
|
10
|
+
permissions: {
|
|
11
|
+
[trustchainId: string]: {
|
|
12
|
+
[path: string]: string[];
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A function which allow all interactions with the hardware device.
|
|
19
|
+
*/
|
|
20
|
+
export type WithDevice = (
|
|
21
|
+
deviceId: string,
|
|
22
|
+
options?: { openTimeoutMs?: number },
|
|
23
|
+
) => <T>(fn: (transport: Transport) => Observable<T>) => Observable<T>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A Trustchain contains the identifier and the contextual data we need to manage members and encrypt/decrypt data.
|
|
27
|
+
*/
|
|
28
|
+
export type Trustchain = {
|
|
29
|
+
/**
|
|
30
|
+
* The immutable id of the trustchain root
|
|
31
|
+
*/
|
|
32
|
+
rootId: string;
|
|
33
|
+
/**
|
|
34
|
+
* The secret used to encrypt/decrypt the wallet sync data
|
|
35
|
+
*/
|
|
36
|
+
walletSyncEncryptionKey: string;
|
|
37
|
+
/**
|
|
38
|
+
* The derivation path on which the current walletSyncEncryptionKey value is stored
|
|
39
|
+
*/
|
|
40
|
+
applicationPath: string;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The Trustchain member credentials are stored on each client, with the privatekey only known by the current client.
|
|
45
|
+
*/
|
|
46
|
+
export type MemberCredentials = {
|
|
47
|
+
/**
|
|
48
|
+
* The public key of the member (in hexadecimal)
|
|
49
|
+
*/
|
|
50
|
+
pubkey: string;
|
|
51
|
+
/**
|
|
52
|
+
* The private key of the member (in hexadecimal)
|
|
53
|
+
*/
|
|
54
|
+
privatekey: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* A member of the trustchain
|
|
59
|
+
*/
|
|
60
|
+
export type TrustchainMember = {
|
|
61
|
+
/**
|
|
62
|
+
* The id of the member. It corresponds to the MemberCredentials.pubkey
|
|
63
|
+
*/
|
|
64
|
+
id: string;
|
|
65
|
+
/**
|
|
66
|
+
* The name of the member as displayed in the UI
|
|
67
|
+
*/
|
|
68
|
+
name: string;
|
|
69
|
+
/**
|
|
70
|
+
* a technical permissions of the member. it will often just be Permissions.OWNER
|
|
71
|
+
*/
|
|
72
|
+
permissions: number;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The TrustchainSDKContext is a context that is used to initialize the TrustchainSDK.
|
|
77
|
+
*/
|
|
78
|
+
export type TrustchainSDKContext = {
|
|
79
|
+
applicationId: number;
|
|
80
|
+
name: string;
|
|
81
|
+
apiBaseUrl: string;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* provide global callbacks for specific lifecycles.
|
|
86
|
+
* this allows us to decouple trustchain with the rest of Ledger Live.
|
|
87
|
+
* For now, we only introduce very specific hooks we need.
|
|
88
|
+
*/
|
|
89
|
+
export type TrustchainLifecycle = {
|
|
90
|
+
/**
|
|
91
|
+
* called when a trustchain rotation is occuring
|
|
92
|
+
* the first function is called when the rotation is starting
|
|
93
|
+
* the second function is called when the rotation is done.
|
|
94
|
+
*
|
|
95
|
+
* in that case, we typically want to delete all other resources depending on it.
|
|
96
|
+
* we do this with the existing jwt token before refreshing it.
|
|
97
|
+
*/
|
|
98
|
+
onTrustchainRotation: (
|
|
99
|
+
trustchainSdk: TrustchainSDK,
|
|
100
|
+
oldTrustchain: Trustchain,
|
|
101
|
+
memberCredentials: MemberCredentials,
|
|
102
|
+
) => Promise<(newTrustchain: Trustchain) => Promise<void>>;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export enum TrustchainResultType {
|
|
106
|
+
created = "created",
|
|
107
|
+
updated = "updated",
|
|
108
|
+
restored = "restored",
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* the trustchain with a result type indicating what happened during getOrCreateTrustchain
|
|
113
|
+
*/
|
|
114
|
+
export type TrustchainResult =
|
|
115
|
+
| {
|
|
116
|
+
// the trustchain didn't exist and was created
|
|
117
|
+
type: TrustchainResultType.created;
|
|
118
|
+
trustchain: Trustchain;
|
|
119
|
+
}
|
|
120
|
+
| {
|
|
121
|
+
// the trustchain already existed and was updated (typically the current member was added)
|
|
122
|
+
type: TrustchainResultType.updated;
|
|
123
|
+
trustchain: Trustchain;
|
|
124
|
+
}
|
|
125
|
+
| {
|
|
126
|
+
// the trustchain existed and was just retrieved (no need to update it)
|
|
127
|
+
type: TrustchainResultType.restored;
|
|
128
|
+
trustchain: Trustchain;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* cache (default): the SDK will use the cached JWT if it's still valid, otherwise it will refresh it.
|
|
133
|
+
* refresh: the SDK will always refresh the JWT if possible.
|
|
134
|
+
* no-cache: the SDK will always request a new JWT.
|
|
135
|
+
*/
|
|
136
|
+
export type AuthCachePolicy = "no-cache" | "refresh" | "cache";
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* The main interface for the UI to interact with the trustchain protocol.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
*
|
|
143
|
+
* import { sdk } from "@ledgerhq/ledger-key-ring-protocol";
|
|
144
|
+
*
|
|
145
|
+
* sdk.getOrCreateTrustchain(deviceId, memberCredentials).then(trustchain => console.log(trustchain));
|
|
146
|
+
*/
|
|
147
|
+
export interface TrustchainSDK {
|
|
148
|
+
/**
|
|
149
|
+
* Generate the live credentials that represents a Live instance, member of the trustchain.
|
|
150
|
+
* This method is expected to be used the first time Ledger Live is opened (if Live never generated them before) and then persisted over the future user sessions of Ledger Live in order for the member to be able to authenticate and manage the trustchain.
|
|
151
|
+
*/
|
|
152
|
+
initMemberCredentials(): Promise<MemberCredentials>;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Access a JWT from the TrustchainSDK. manage the reauthentication if needed.
|
|
156
|
+
* A trustchain must have been created and the Live instance must have been added as a member.
|
|
157
|
+
* The returned token will typically be used for regular operations like wallet sync.
|
|
158
|
+
*/
|
|
159
|
+
withAuth<T>(
|
|
160
|
+
trustchain: Trustchain,
|
|
161
|
+
memberCredentials: MemberCredentials,
|
|
162
|
+
f: (jwt: JWT) => Promise<T>,
|
|
163
|
+
policy?: AuthCachePolicy,
|
|
164
|
+
ignorePermissionsChecks?: boolean,
|
|
165
|
+
): Promise<T>;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* This method will either create the required trustchains (root and application) or restore them.
|
|
169
|
+
* The returned trustchain will be initialized on the root level and also will have the branch derivation corresponding to the contextual applicationId.
|
|
170
|
+
* It will also have the wallet sync encryption key initialized.
|
|
171
|
+
* The latest jwt is also returned because it was potentially updated during the process.
|
|
172
|
+
*/
|
|
173
|
+
getOrCreateTrustchain(
|
|
174
|
+
deviceId: string,
|
|
175
|
+
memberCredentials: MemberCredentials,
|
|
176
|
+
callbacks?: GetOrCreateTrustchainCallbacks,
|
|
177
|
+
topic?: Uint8Array,
|
|
178
|
+
currentTrustchain?: Trustchain,
|
|
179
|
+
): Promise<TrustchainResult>;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Restore the current trustchain encryption key, typically due to a key rotation.
|
|
183
|
+
*/
|
|
184
|
+
restoreTrustchain(
|
|
185
|
+
trustchain: Trustchain,
|
|
186
|
+
memberCredentials: MemberCredentials,
|
|
187
|
+
): Promise<Trustchain>;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* list the current members of the application trustchain
|
|
191
|
+
*/
|
|
192
|
+
getMembers(
|
|
193
|
+
trustchain: Trustchain,
|
|
194
|
+
memberCredentials: MemberCredentials,
|
|
195
|
+
): Promise<TrustchainMember[]>;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* remove a member from the application trustchain
|
|
199
|
+
*/
|
|
200
|
+
removeMember(
|
|
201
|
+
deviceId: string,
|
|
202
|
+
trustchain: Trustchain,
|
|
203
|
+
memberCredentials: MemberCredentials,
|
|
204
|
+
member: TrustchainMember,
|
|
205
|
+
callbacks?: TrustchainDeviceCallbacks,
|
|
206
|
+
): Promise<Trustchain>;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* add a member to the application trustchain
|
|
210
|
+
*/
|
|
211
|
+
addMember(
|
|
212
|
+
trustchain: Trustchain,
|
|
213
|
+
memberCredentials: MemberCredentials,
|
|
214
|
+
member: TrustchainMember,
|
|
215
|
+
): Promise<void>;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* destroy the trustchain
|
|
219
|
+
*/
|
|
220
|
+
destroyTrustchain(trustchain: Trustchain, memberCredentials: MemberCredentials): Promise<void>;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* encrypt data with the trustchain encryption key
|
|
224
|
+
*/
|
|
225
|
+
encryptUserData(trustchain: Trustchain, obj: object): Promise<Uint8Array>;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* decrypt data with the trustchain encryption key
|
|
229
|
+
*/
|
|
230
|
+
decryptUserData(trustchain: Trustchain, data: Uint8Array): Promise<Uint8Array>;
|
|
231
|
+
|
|
232
|
+
invalidateJwt(): void;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export interface TrustchainDeviceCallbacks {
|
|
236
|
+
onStartRequestUserInteraction?: () => void;
|
|
237
|
+
onEndRequestUserInteraction?: () => void;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export interface GetOrCreateTrustchainCallbacks extends TrustchainDeviceCallbacks {
|
|
241
|
+
onInitialResponse?: (trustchains: TrustchainsResponse) => void;
|
|
242
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
2
|
+
|
|
3
|
+
export async function scenario(deviceId: string, { sdkForName }: ScenarioOptions) {
|
|
4
|
+
/**
|
|
5
|
+
* Edit this code to the test you want.
|
|
6
|
+
* This script will be used both as a end-to-end tests and unit tests.
|
|
7
|
+
* The end-to-end tests are used to generate mock for the same unit tests.
|
|
8
|
+
*/
|
|
9
|
+
const name1 = "cli-member1";
|
|
10
|
+
const sdk1 = sdkForName(name1);
|
|
11
|
+
const memberCredentials = await sdk1.initMemberCredentials();
|
|
12
|
+
const { trustchain } = await sdk1.getOrCreateTrustchain(deviceId, memberCredentials);
|
|
13
|
+
|
|
14
|
+
await sdk1.destroyTrustchain(trustchain, memberCredentials);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// this can overrides the default config used by the recorder
|
|
18
|
+
export const recorderConfig = {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
2
|
+
|
|
3
|
+
export async function scenario(deviceId: string, { sdkForName }: ScenarioOptions) {
|
|
4
|
+
const name1 = "Member 1";
|
|
5
|
+
const sdk = sdkForName(name1);
|
|
6
|
+
const member1creds = await sdk.initMemberCredentials();
|
|
7
|
+
const { trustchain } = await sdk.getOrCreateTrustchain(deviceId, member1creds);
|
|
8
|
+
|
|
9
|
+
const name2 = "Member 2";
|
|
10
|
+
const member2creds = await sdk.initMemberCredentials();
|
|
11
|
+
const member2 = { name: name2, id: member2creds.pubkey, permissions: 0xffffffff };
|
|
12
|
+
|
|
13
|
+
await sdk.addMember(trustchain, member1creds, member2);
|
|
14
|
+
await sdk.addMember(trustchain, member1creds, member2);
|
|
15
|
+
|
|
16
|
+
const members = await sdk.getMembers(trustchain, member1creds);
|
|
17
|
+
await sdk.destroyTrustchain(trustchain, member1creds);
|
|
18
|
+
|
|
19
|
+
expect(members.length).toBe(2);
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
2
|
+
|
|
3
|
+
export async function scenario(deviceId: string, { sdkForName }: ScenarioOptions) {
|
|
4
|
+
const sdk = sdkForName("Foo");
|
|
5
|
+
const creds = await sdk.initMemberCredentials();
|
|
6
|
+
|
|
7
|
+
const t1 = await sdk.getOrCreateTrustchain(deviceId, creds);
|
|
8
|
+
await sdk.destroyTrustchain(t1.trustchain, creds);
|
|
9
|
+
expect(t1.type).toBe("created");
|
|
10
|
+
|
|
11
|
+
const t2 = await sdk.getOrCreateTrustchain(deviceId, creds);
|
|
12
|
+
await sdk.destroyTrustchain(t2.trustchain, creds);
|
|
13
|
+
expect(t2.type).toBe("created");
|
|
14
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
2
|
+
|
|
3
|
+
export async function scenario(deviceId: string, { sdkForName }: ScenarioOptions) {
|
|
4
|
+
const name1 = "Member 1";
|
|
5
|
+
const sdk1 = sdkForName(name1);
|
|
6
|
+
const member1creds = await sdk1.initMemberCredentials();
|
|
7
|
+
|
|
8
|
+
let interactionCounter = 0;
|
|
9
|
+
let totalInteractionCounter = 0;
|
|
10
|
+
const callbacks = {
|
|
11
|
+
onStartRequestUserInteraction: () => {
|
|
12
|
+
totalInteractionCounter++;
|
|
13
|
+
interactionCounter++;
|
|
14
|
+
},
|
|
15
|
+
onEndRequestUserInteraction: () => {
|
|
16
|
+
interactionCounter--;
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// verify that getOrCreateTrustchain is idempotent
|
|
21
|
+
const { trustchain: t1, type: type1 } = await sdk1.getOrCreateTrustchain(
|
|
22
|
+
deviceId,
|
|
23
|
+
member1creds,
|
|
24
|
+
callbacks,
|
|
25
|
+
);
|
|
26
|
+
expect(type1).toBe("created");
|
|
27
|
+
expect(totalInteractionCounter).toBe(2); // there are two interaction: one for device auth, one for trustchain addition
|
|
28
|
+
const { trustchain: t2, type: type2 } = await sdk1.getOrCreateTrustchain(
|
|
29
|
+
deviceId,
|
|
30
|
+
member1creds,
|
|
31
|
+
callbacks,
|
|
32
|
+
);
|
|
33
|
+
expect(type2).toBe("restored");
|
|
34
|
+
expect(totalInteractionCounter).toBe(3); // one more device auth interaction happened
|
|
35
|
+
expect(t1).toEqual(t2);
|
|
36
|
+
|
|
37
|
+
// verify that a second member can join the trustchain and get the same trustchain
|
|
38
|
+
const name2 = "Member 2";
|
|
39
|
+
const sdk2 = sdkForName(name2);
|
|
40
|
+
const member2creds = await sdk2.initMemberCredentials();
|
|
41
|
+
const { trustchain: t3, type: type3 } = await sdk2.getOrCreateTrustchain(
|
|
42
|
+
deviceId,
|
|
43
|
+
member2creds,
|
|
44
|
+
callbacks,
|
|
45
|
+
);
|
|
46
|
+
expect(type3).toBe("updated");
|
|
47
|
+
expect(t1).toEqual(t3);
|
|
48
|
+
|
|
49
|
+
// check there are indeed our two members in the trustchain
|
|
50
|
+
const members = await sdk1.getMembers(t1, member1creds);
|
|
51
|
+
expect(members).toEqual([
|
|
52
|
+
{
|
|
53
|
+
id: member1creds.pubkey,
|
|
54
|
+
name: name1,
|
|
55
|
+
permissions: 0xffffffff,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: member2creds.pubkey,
|
|
59
|
+
name: name2,
|
|
60
|
+
permissions: 0xffffffff,
|
|
61
|
+
},
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
// destroy
|
|
65
|
+
await sdk1.destroyTrustchain(t1, member1creds);
|
|
66
|
+
|
|
67
|
+
expect({
|
|
68
|
+
interactionCounter,
|
|
69
|
+
totalInteractionCounter,
|
|
70
|
+
}).toEqual({
|
|
71
|
+
interactionCounter: 0, // total of interaction+- is back at 0
|
|
72
|
+
totalInteractionCounter: 5,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* a complete scenario with 3 members and various sdk successful interactions.
|
|
5
|
+
*/
|
|
6
|
+
export async function scenario(deviceId: string, { sdkForName }: ScenarioOptions) {
|
|
7
|
+
// members
|
|
8
|
+
const name1 = "Member 1";
|
|
9
|
+
const sdk1 = sdkForName(name1);
|
|
10
|
+
const member1creds = await sdk1.initMemberCredentials();
|
|
11
|
+
|
|
12
|
+
const name2 = "Member 2";
|
|
13
|
+
const sdk2 = sdkForName(name2);
|
|
14
|
+
const member2creds = await sdk2.initMemberCredentials();
|
|
15
|
+
|
|
16
|
+
const name3 = "Member 3";
|
|
17
|
+
const sdk3 = sdkForName(name3);
|
|
18
|
+
const member3creds = await sdk3.initMemberCredentials();
|
|
19
|
+
|
|
20
|
+
// auth with the device and init the first trustchain
|
|
21
|
+
const { trustchain } = await sdk1.getOrCreateTrustchain(deviceId, member1creds);
|
|
22
|
+
|
|
23
|
+
// member 1 adds member 2
|
|
24
|
+
const member2 = { name: name2, id: member2creds.pubkey, permissions: 0xffffffff };
|
|
25
|
+
await sdk1.addMember(trustchain, member1creds, member2);
|
|
26
|
+
|
|
27
|
+
// member 3 do a getOrCreateTrustchain that should add itself implicitly
|
|
28
|
+
const { trustchain: trustchain3 } = await sdk3.getOrCreateTrustchain(deviceId, member3creds);
|
|
29
|
+
|
|
30
|
+
// list members
|
|
31
|
+
const members = await sdk3.getMembers(trustchain3, member3creds);
|
|
32
|
+
expect(members).toEqual([
|
|
33
|
+
{
|
|
34
|
+
id: member1creds.pubkey,
|
|
35
|
+
name: name1,
|
|
36
|
+
permissions: 0xffffffff,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: member2creds.pubkey,
|
|
40
|
+
name: name2,
|
|
41
|
+
permissions: 0xffffffff,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: member3creds.pubkey,
|
|
45
|
+
name: name3,
|
|
46
|
+
permissions: 0xffffffff,
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
await sdk2.destroyTrustchain(trustchain, member2creds);
|
|
51
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
2
|
+
|
|
3
|
+
export async function scenario(deviceId: string, { sdkForName }: ScenarioOptions) {
|
|
4
|
+
let trustchainId;
|
|
5
|
+
const n = 10;
|
|
6
|
+
for (let i = 1; i < n; i++) {
|
|
7
|
+
const name = "Member " + i;
|
|
8
|
+
const sdk = sdkForName(name);
|
|
9
|
+
const creds = await sdk.initMemberCredentials();
|
|
10
|
+
const { trustchain } = await sdk.getOrCreateTrustchain(deviceId, creds);
|
|
11
|
+
if (!trustchainId) trustchainId = trustchain.rootId;
|
|
12
|
+
expect(trustchain.rootId).toBe(trustchainId);
|
|
13
|
+
if (i === n - 1) {
|
|
14
|
+
// cleanup
|
|
15
|
+
await sdk.destroyTrustchain(trustchain, creds);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { TrustchainEjected } from "../../src/errors";
|
|
2
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
3
|
+
|
|
4
|
+
export async function scenario(deviceId: string, { sdkForName }: ScenarioOptions) {
|
|
5
|
+
// first member initializes itself
|
|
6
|
+
const name1 = "Member 1";
|
|
7
|
+
const sdk1 = sdkForName(name1);
|
|
8
|
+
const member1creds = await sdk1.initMemberCredentials();
|
|
9
|
+
|
|
10
|
+
// second member initializes itself
|
|
11
|
+
const name2 = "Member 2";
|
|
12
|
+
const sdk2 = sdkForName(name2);
|
|
13
|
+
const member2creds = await sdk2.initMemberCredentials();
|
|
14
|
+
|
|
15
|
+
// auth with the device and init the first trustchain
|
|
16
|
+
const { trustchain } = await sdk1.getOrCreateTrustchain(deviceId, member1creds);
|
|
17
|
+
|
|
18
|
+
// now member2 will get an ejected error when trying to destroy the trustchain
|
|
19
|
+
await expect(sdk2.destroyTrustchain(trustchain, member2creds)).rejects.toThrow(TrustchainEjected);
|
|
20
|
+
|
|
21
|
+
// member1 can destroy the trustchain
|
|
22
|
+
await sdk1.destroyTrustchain(trustchain, member1creds);
|
|
23
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
2
|
+
import { TrustchainNotAllowed } from "../../src/errors";
|
|
3
|
+
|
|
4
|
+
export async function scenario(
|
|
5
|
+
deviceId: string,
|
|
6
|
+
{ sdkForName, switchDeviceSeed }: ScenarioOptions,
|
|
7
|
+
) {
|
|
8
|
+
const name1 = "Member 1";
|
|
9
|
+
const sdk1 = sdkForName(name1);
|
|
10
|
+
const member1creds = await sdk1.initMemberCredentials();
|
|
11
|
+
const member1 = { name: name1, id: member1creds.pubkey, permissions: 0xffffffff };
|
|
12
|
+
|
|
13
|
+
const name2 = "Member 2";
|
|
14
|
+
const sdk2 = sdkForName(name2);
|
|
15
|
+
const member2creds = await sdk2.initMemberCredentials();
|
|
16
|
+
const member2 = { name: name2, id: member2creds.pubkey, permissions: 0xffffffff };
|
|
17
|
+
|
|
18
|
+
const { trustchain } = await sdk1.getOrCreateTrustchain(deviceId, member1creds);
|
|
19
|
+
await sdk1.addMember(trustchain, member1creds, member2);
|
|
20
|
+
|
|
21
|
+
const device = await switchDeviceSeed();
|
|
22
|
+
|
|
23
|
+
await expect(sdk1.removeMember(device.id, trustchain, member2creds, member1)).rejects.toThrow(
|
|
24
|
+
TrustchainNotAllowed,
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
await sdk2.destroyTrustchain(trustchain, member2creds);
|
|
28
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
2
|
+
|
|
3
|
+
export async function scenario(deviceId: string, { sdkForName }: ScenarioOptions) {
|
|
4
|
+
// first member initializes itself
|
|
5
|
+
const name1 = "Member 1";
|
|
6
|
+
const sdk1 = sdkForName(name1);
|
|
7
|
+
const member1creds = await sdk1.initMemberCredentials();
|
|
8
|
+
// second member initializes itself
|
|
9
|
+
const name2 = "Member 2";
|
|
10
|
+
const sdk2 = sdkForName(name2);
|
|
11
|
+
const member2creds = await sdk2.initMemberCredentials();
|
|
12
|
+
const member2 = { name: name2, id: member2creds.pubkey, permissions: 0xffffffff };
|
|
13
|
+
|
|
14
|
+
// auth with the device and init the first trustchain
|
|
15
|
+
const { trustchain } = await sdk1.getOrCreateTrustchain(deviceId, member1creds);
|
|
16
|
+
|
|
17
|
+
// member 1 adds member 2 (= qr code flow)
|
|
18
|
+
await sdk1.addMember(trustchain, member1creds, member2);
|
|
19
|
+
|
|
20
|
+
// member2 can get the members
|
|
21
|
+
await sdk2.getMembers(trustchain, member2creds);
|
|
22
|
+
|
|
23
|
+
// member1 removes trustchain
|
|
24
|
+
await sdk1.destroyTrustchain(trustchain, member1creds);
|
|
25
|
+
|
|
26
|
+
// force a refresh to happen (which normally happen after some time)
|
|
27
|
+
await sdk2.withAuth(trustchain, member2creds, jwt => Promise.resolve(jwt), "refresh", true);
|
|
28
|
+
|
|
29
|
+
// member2 is no longer a member so is not authorized to get the members
|
|
30
|
+
await expect(sdk2.getMembers(trustchain, member2creds)).rejects.toThrow();
|
|
31
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { TrustchainEjected } from "../../src/errors";
|
|
2
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
3
|
+
|
|
4
|
+
export async function scenario(deviceId: string, { sdkForName }: ScenarioOptions) {
|
|
5
|
+
// first member initializes itself
|
|
6
|
+
const name1 = "Member 1";
|
|
7
|
+
const sdk1 = sdkForName(name1);
|
|
8
|
+
const member1creds = await sdk1.initMemberCredentials();
|
|
9
|
+
// second member initializes itself
|
|
10
|
+
const name2 = "Member 2";
|
|
11
|
+
const sdk2 = sdkForName(name2);
|
|
12
|
+
const member2creds = await sdk2.initMemberCredentials();
|
|
13
|
+
const member2 = { name: name2, id: member2creds.pubkey, permissions: 0xffffffff };
|
|
14
|
+
|
|
15
|
+
// auth with the device and init the first trustchain
|
|
16
|
+
const { trustchain } = await sdk1.getOrCreateTrustchain(deviceId, member1creds);
|
|
17
|
+
|
|
18
|
+
// member 1 adds member 2 (= qr code flow)
|
|
19
|
+
await sdk1.addMember(trustchain, member1creds, member2);
|
|
20
|
+
|
|
21
|
+
// member1 removes member2
|
|
22
|
+
const newTrustchain = await sdk1.removeMember(deviceId, trustchain, member1creds, member2);
|
|
23
|
+
|
|
24
|
+
// member2 is no longer a member so is not authorized to get the members
|
|
25
|
+
await expect(sdk2.getMembers(trustchain, member2creds)).rejects.toThrow(TrustchainEjected);
|
|
26
|
+
|
|
27
|
+
// member3 destroy the trustchain
|
|
28
|
+
await sdk1.destroyTrustchain(newTrustchain, member1creds);
|
|
29
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { TrustchainEjected } from "../../src/errors";
|
|
2
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
3
|
+
|
|
4
|
+
export async function scenario(deviceId: string, { sdkForName }: ScenarioOptions) {
|
|
5
|
+
// first member initializes itself
|
|
6
|
+
const name1 = "Member 1";
|
|
7
|
+
const sdk1 = sdkForName(name1);
|
|
8
|
+
const member1creds = await sdk1.initMemberCredentials();
|
|
9
|
+
|
|
10
|
+
// auth with the device and init the first trustchain
|
|
11
|
+
const { trustchain } = await sdk1.getOrCreateTrustchain(deviceId, member1creds);
|
|
12
|
+
|
|
13
|
+
// second member initializes itself
|
|
14
|
+
const name2 = "Member 2";
|
|
15
|
+
const sdk2 = sdkForName(name2);
|
|
16
|
+
const member2creds = await sdk2.initMemberCredentials();
|
|
17
|
+
|
|
18
|
+
// member 1 adds member 2 (= qr code flow)
|
|
19
|
+
const member2 = { name: name2, id: member2creds.pubkey, permissions: 0xffffffff };
|
|
20
|
+
await sdk1.addMember(trustchain, member1creds, member2);
|
|
21
|
+
|
|
22
|
+
// member1 removes member2
|
|
23
|
+
const newTrustchain = await sdk1.removeMember(deviceId, trustchain, member1creds, member2);
|
|
24
|
+
|
|
25
|
+
// now member2 will get an ejected error when trying to restore the trustchain
|
|
26
|
+
// NB: restoreTrustchain is typically what we would call when member2 see that the encryptionKey no longer work after the rotation
|
|
27
|
+
await expect(sdk2.restoreTrustchain(trustchain, member2creds)).rejects.toThrow(TrustchainEjected);
|
|
28
|
+
|
|
29
|
+
// member3 destroy the trustchain
|
|
30
|
+
await sdk1.destroyTrustchain(newTrustchain, member1creds);
|
|
31
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
2
|
+
|
|
3
|
+
export async function scenario(deviceId: string, { sdkForName }: ScenarioOptions) {
|
|
4
|
+
const name1 = "Member 1";
|
|
5
|
+
const sdk1 = sdkForName(name1);
|
|
6
|
+
const member1creds = await sdk1.initMemberCredentials();
|
|
7
|
+
|
|
8
|
+
const name2 = "Member 2";
|
|
9
|
+
const sdk2 = sdkForName(name2);
|
|
10
|
+
const member2creds = await sdk2.initMemberCredentials();
|
|
11
|
+
const member2 = { name: name2, id: member2creds.pubkey, permissions: 0xffffffff };
|
|
12
|
+
|
|
13
|
+
let interactionCounter = 0;
|
|
14
|
+
let totalInteractionCounter = 0;
|
|
15
|
+
const callbacks = {
|
|
16
|
+
onStartRequestUserInteraction: () => {
|
|
17
|
+
totalInteractionCounter++;
|
|
18
|
+
interactionCounter++;
|
|
19
|
+
},
|
|
20
|
+
onEndRequestUserInteraction: () => {
|
|
21
|
+
interactionCounter--;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const { trustchain } = await sdk1.getOrCreateTrustchain(deviceId, member1creds, callbacks);
|
|
26
|
+
expect(totalInteractionCounter).toBe(2); // there are two interaction: one for device auth, one for trustchain addition
|
|
27
|
+
|
|
28
|
+
await sdk1.addMember(trustchain, member1creds, member2);
|
|
29
|
+
|
|
30
|
+
const newTrustchain = await sdk1.removeMember(
|
|
31
|
+
deviceId,
|
|
32
|
+
trustchain,
|
|
33
|
+
member1creds,
|
|
34
|
+
member2,
|
|
35
|
+
callbacks,
|
|
36
|
+
);
|
|
37
|
+
expect(totalInteractionCounter).toBe(5); // there are 2 interactions for trustchain addition
|
|
38
|
+
|
|
39
|
+
// destroy the trustchain
|
|
40
|
+
await sdk1.destroyTrustchain(newTrustchain, member1creds);
|
|
41
|
+
expect(interactionCounter).toBe(0); // the start/stop is coherent
|
|
42
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ScenarioOptions } from "../test-helpers/types";
|
|
2
|
+
|
|
3
|
+
export async function scenario(deviceId: string, { sdkForName }: ScenarioOptions) {
|
|
4
|
+
const name1 = "Member 1";
|
|
5
|
+
const sdk1 = sdkForName(name1);
|
|
6
|
+
const member1creds = await sdk1.initMemberCredentials();
|
|
7
|
+
const { trustchain } = await sdk1.getOrCreateTrustchain(deviceId, member1creds);
|
|
8
|
+
const members = await sdk1.getMembers(trustchain, member1creds);
|
|
9
|
+
await expect(sdk1.removeMember(deviceId, trustchain, member1creds, members[0])).rejects.toThrow();
|
|
10
|
+
await sdk1.destroyTrustchain(trustchain, member1creds);
|
|
11
|
+
}
|