-
Notifications
You must be signed in to change notification settings - Fork 0
/
types.ts
345 lines (290 loc) · 11.2 KB
/
types.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
import z from "zod";
import sanitizeHtml from "sanitize-html";
/**
* Transforms any html into an escaped version of self.
* For example "<p>haha</p>" will become "<p>haha<p>"
*
* @param dirty
* @returns { string } - sanitized string
*/
export function escapeHtml(dirty: string): string {
return sanitizeHtml(dirty, {
allowedTags: [],
allowedAttributes: {},
disallowedTagsMode: "escape",
});
}
/**
* A non-negative integer, e.g. 1337
*/
export const ZNonNegativeInt = z.number().int().nonnegative();
/**
* A non-empty safe-to-use string
*/
export const ZNonEmptyStrSanitized = z.string().min(1).transform(escapeHtml);
/**
* A principal string, e.g. aaaaa-aa
*/
export const ZPrincipalStrSanitized = z.string().regex(/^[0-9a-zA-Z]{1,5}(\-[0-9a-zA-Z]{1,5})*$/);
export const ZICRC1Subaccount = z.instanceof(Uint8Array);
/**
* A 6-digit hex color code, e.g. #12beef
*/
export const ZHexColorSanitized = z.string().regex(/^#[a-fA-F0-9]{6}$/);
/**
* Website origin, for example `https://google.com`
*/
export type TOrigin = z.infer<typeof ZOrigin>;
export const ZOrigin = z.string().url();
/**
* Timestamp in millis
*/
export type TTimestamp = z.infer<typeof ZTimestamp>;
export const ZTimestamp = z.number().nonnegative();
/**
* Blob of bytes
*/
export type TBlob = z.infer<typeof ZBlob>;
export const ZBlob = z.instanceof(ArrayBuffer).or(z.instanceof(Uint8Array));
/**
* Identity ID
*/
export type TIdentityId = z.infer<typeof ZIdentityId>;
export const ZIdentityId = ZNonNegativeInt;
export type TAccountId = z.infer<typeof ZAccountId>;
export const ZAccountId = ZNonNegativeInt;
/**
* Session object
*/
export type ISession = z.infer<typeof ZSession>;
export const ZSession = z.object({
/** chosen user identity ID (unique for each website) */
identityId: ZIdentityId,
/** an origin used for key deriviation (actual or linked) */
deriviationOrigin: ZOrigin,
/** logged in timestamp */
timestampMs: ZTimestamp,
});
export type IMask = z.infer<typeof ZMask>;
export const ZMask = z.object({ pseudonym: ZNonEmptyStrSanitized, principal: ZPrincipalStrSanitized });
/**
* Various data for each website the user interacts with
*/
export type IOriginData = z.infer<typeof ZOriginData>;
export const ZOriginData = z.object({
/** identities (and their pseudonyms) a user has on this website */
masks: z.record(ZNonEmptyStrSanitized, z.optional(ZMask)),
/** which websites shared the user's identity with this website */
linksFrom: z.record(ZOrigin, z.optional(z.literal(true))),
/** to which websites the user shared their identities from this website */
linksTo: z.record(ZOrigin, z.optional(z.literal(true))),
/** session object, exists if the user is logged in */
currentSession: z.optional(ZSession),
});
export type IOriginDataExternal = z.infer<typeof ZOriginDataExternal>;
export const ZOriginDataExternal = z.object({
masks: z.array(ZMask),
linksFrom: z.array(ZOrigin),
linksTo: z.array(ZOrigin),
currentSession: z.optional(ZSession),
});
export const ZStatisticsData = z.object({
login: ZNonNegativeInt,
transfer: ZNonNegativeInt,
origin_link: ZNonNegativeInt,
origin_unlink: ZNonNegativeInt,
});
export type IStatisticsData = z.infer<typeof ZStatisticsData>;
/**
* Anonimized and squashed activities the user does with MSQ
*/
export type IStatistics = z.infer<typeof ZStatistics>;
export const ZStatistics = z.object({
/** when was the last time the user sent the stats to the server */
lastResetTimestamp: ZNonNegativeInt,
/** how many activities were performed in any production environment by each activity type */
data: ZStatisticsData,
});
export const ZAmountStrSanitized = z.string().regex(/^[0-9',\.]+$/);
const ZAssetNameSanitized = z.string().min(1).transform(escapeHtml);
export const ZTickerStrSanitized = z.string().regex(/^[A-Za-z0-9]+$/);
export type IAssetData = z.infer<typeof ZAssetData>;
export const ZAssetData = z.object({
name: ZAssetNameSanitized,
symbol: ZTickerStrSanitized,
accounts: z.record(ZNonEmptyStrSanitized, ZNonEmptyStrSanitized),
});
export const ZAssetDataExternal = z.object({
accounts: z.array(ZNonEmptyStrSanitized),
});
export type IAssetDataExternal = z.infer<typeof ZAssetDataExternal>;
/**
* Snap state that is stored in encrypted form on user's device.
*
* !!! WARNING !!!
* The state is only allowed to consist of records. No arrays. No classes. No recursion.
* Only plain key-value pairs nested in each other.
* This is required because of our deepProxy implementation.
* If you break this rule, our state won't persist after mutations.
*/
export type IState = z.infer<typeof ZState>;
export const ZState = z.object({
/** version of the state, for future migrations */
version: ZNonNegativeInt,
/** user data on each origin */
originData: z.record(ZOrigin, z.optional(ZOriginData)),
/** accounts for each asset */
assetData: z.record(ZPrincipalStrSanitized, z.optional(ZAssetData)),
/** anonymous usage stats */
statistics: ZStatistics,
});
export const ZSnapRPCRequest = z.object({
method: z.string(),
params: z.object({
body: z.string(),
}),
});
export type ISnapRpcRequest = z.infer<typeof ZSnapRPCRequest>;
// ----------- IDENTITY PROTOCOL RELATED TYPES ---------
export const ZIdentityGetLoginOptionsRequest = z.object({
forOrigin: ZOrigin,
});
export type IIdentityGetLoginOptionsRequest = z.infer<typeof ZIdentityGetLoginOptionsRequest>;
export const ZIdentityGetLoginOptionsResponse = z.array(z.tuple([ZOrigin, z.array(ZMask)]));
export type IIdentityGetLoginOptionsResponse = z.infer<typeof ZIdentityGetLoginOptionsResponse>;
export const ZIdentityAddRequest = z.object({
toOrigin: ZOrigin,
});
export type IIdentityAddRequest = z.infer<typeof ZIdentityAddRequest>;
export const ZIdentityLoginRequest = z.object({
/** Origin of the website to log in to */
toOrigin: ZOrigin,
/** Identity (mask) id of the user to use */
withIdentityId: ZIdentityId,
/** Linked origin, if the user wants to use it to log in */
withLinkedOrigin: z.optional(ZOrigin),
});
export type IIdentityLoginRequest = z.infer<typeof ZIdentityLoginRequest>;
export const ZIdentitySignRequest = z.object({
challenge: ZBlob,
salt: z.instanceof(Uint8Array),
});
export type IIdentitySignRequest = z.infer<typeof ZIdentitySignRequest>;
export const ZIdentityGetPublicKeyRequest = z.object({
salt: z.instanceof(Uint8Array),
});
export type IIdentityGetPublicKeyRequest = z.infer<typeof ZIdentityGetPublicKeyRequest>;
export const ZIdentityLinkRequest = z.object({
withOrigin: ZOrigin,
});
export type IIdentityLinkRequest = z.infer<typeof ZIdentityLinkRequest>;
export const ZIdentityUnlinkRequest = z.object({
withOrigin: ZOrigin,
});
export type IIdentityUnlinkRequest = z.infer<typeof ZIdentityUnlinkRequest>;
export const ZIdentityEditPseudonymRequest = z.object({
origin: ZOrigin,
identityId: ZIdentityId,
newPseudonym: ZNonEmptyStrSanitized,
});
export type IIdentityEditPseudonymRequest = z.infer<typeof ZIdentityEditPseudonymRequest>;
export const ZIdentityStopSessionRequest = z.object({
origin: ZOrigin,
});
export type IIdentityStopSessionRequest = z.infer<typeof ZIdentityStopSessionRequest>;
export const ZIdentityUnlinkOneRequest = z.object({
origin: ZOrigin,
withOrigin: ZOrigin,
});
export type IIdentityUnlinkOneRequest = z.infer<typeof ZIdentityUnlinkOneRequest>;
export const ZIdentityUnlinkAllRequest = z.object({
origin: ZOrigin,
});
export type IIdentityUnlinkAllRequest = z.infer<typeof ZIdentityUnlinkAllRequest>;
// ----------- STATISTICS PROTOCOL RELATED TYPES --------
export const ZStatisticsIncrementRequest = z.object({ data: ZStatisticsData.partial() });
export type IStatisticsIncrementRequest = z.infer<typeof ZStatisticsIncrementRequest>;
// ----------- STATE PROTOCOL RELATED TYPES -------------
export const ZStateGetAllOriginDataRequest = z.object({ origins: z.optional(z.array(ZOrigin)) });
export type IStateGetAllOriginDataRequest = z.infer<typeof ZStateGetAllOriginDataRequest>;
export const ZStateGetAllOriginDataResponse = z.record(ZOrigin, z.optional(ZOriginDataExternal));
export type IStateGetAllOriginDataResponse = z.infer<typeof ZStateGetAllOriginDataResponse>;
export const ZStateGetAllAssetDataRequest = z.object({ assetIds: z.optional(z.array(ZPrincipalStrSanitized)) });
export type IStateGetAllAssetDataRequest = z.infer<typeof ZStateGetAllAssetDataRequest>;
export const ZStateGetAllAssetDataResponse = z.record(ZPrincipalStrSanitized, z.optional(ZAssetDataExternal));
export type IStateGetAllAssetDataResponse = z.infer<typeof ZStateGetAllAssetDataResponse>;
// ----------- ICRC1 PROTOCOL RELATED TYPES -------------
export const ZICRC1Account = z.object({
owner: ZPrincipalStrSanitized,
subaccount: z.optional(ZICRC1Subaccount),
});
export type IICRC1Account = z.infer<typeof ZICRC1Account>;
export const ZICRC1TransferRequest = z.object({
canisterId: ZPrincipalStrSanitized,
to: ZICRC1Account,
amount: z.bigint().nonnegative(),
memo: z.optional(z.instanceof(Uint8Array)),
createdAt: z.optional(z.bigint().nonnegative()),
});
export type IICRC1TransferRequest = z.infer<typeof ZICRC1TransferRequest>;
export const ZShowICRC1TransferConfirmRequest = z.object({
requestOrigin: ZOrigin,
from: ZPrincipalStrSanitized,
to: ZICRC1Account,
totalAmountStr: ZAmountStrSanitized,
totalAmount: z.bigint().nonnegative(),
ticker: ZTickerStrSanitized,
});
export type IShowICRC1TransferConfirmRequest = z.infer<typeof ZShowICRC1TransferConfirmRequest>;
export const ZICRC1AddAssetRequest = z.object({
assets: z.array(
z.object({
assetId: ZPrincipalStrSanitized,
name: ZAssetNameSanitized,
symbol: ZTickerStrSanitized,
}),
),
});
export type IICRC1AddAssetRequest = z.infer<typeof ZICRC1AddAssetRequest>;
export const ZICRC1AddAssetAccountRequest = z.object({
assetId: ZPrincipalStrSanitized,
});
export type IICRC1AddAssetAccountRequest = z.infer<typeof ZICRC1AddAssetAccountRequest>;
export const ZICRC1EditAssetAccountRequest = z.object({
assetId: ZPrincipalStrSanitized,
accountId: ZAccountId,
newName: ZNonEmptyStrSanitized,
});
export type IICRC1EditAssetAccountRequest = z.infer<typeof ZICRC1EditAssetAccountRequest>;
// ---------- MESSAGE TYPES ------------------------------
export const ZMsgDomain = z.literal("msq");
export const ZRequestReceivedMsg = z.object({
domain: ZMsgDomain,
type: z.literal("request_received"),
});
export type IRequestReceivedMsg = z.infer<typeof ZRequestReceivedMsg>;
export const ZLoginRequestMsg = z.object({
domain: ZMsgDomain,
origin: z.string().url(),
type: z.literal("login_request"),
});
export type ILoginRequestMsg = z.infer<typeof ZLoginRequestMsg>;
export const ZLoginResultMsg = z.object({
domain: ZMsgDomain,
type: z.literal("login_result"),
result: z.boolean(),
});
export type ILoginResultMsg = z.infer<typeof ZLoginResultMsg>;
export const ZICRC1TransferRequestMsg = z.object({
domain: ZMsgDomain,
origin: z.string().url(),
type: z.literal("transfer_icrc1_request"),
request: ZICRC1TransferRequest,
});
export type IICRC1TransferRequestMsg = z.infer<typeof ZICRC1TransferRequestMsg>;
export const ZICRC1TransferResultMsg = z.object({
domain: ZMsgDomain,
type: z.literal("transfer_icrc1_result"),
result: z.optional(z.bigint()),
});
export type IICRC1TransferResultMsg = z.infer<typeof ZICRC1TransferResultMsg>;