@session-foundation/qa-seeder 0.1.21
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/dist/index.d.mts +45 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +1043 -0
- package/dist/index.mjs +1012 -0
- package/package.json +34 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1043 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
USERNAME: () => USERNAME,
|
|
34
|
+
buildStateForTest: () => buildStateForTest,
|
|
35
|
+
usernames: () => usernames
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(index_exports);
|
|
38
|
+
var import_lodash5 = require("lodash");
|
|
39
|
+
|
|
40
|
+
// src/requests/seedRequest.ts
|
|
41
|
+
var import_lodash = require("lodash");
|
|
42
|
+
var fetchedSnodesFromSeed = {};
|
|
43
|
+
async function getAllSnodesFromSeed(seedNodeUrl) {
|
|
44
|
+
if (!seedNodeUrl.startsWith("http")) {
|
|
45
|
+
throw new Error("Invalid seed node URL, must start with http");
|
|
46
|
+
}
|
|
47
|
+
if (seedNodeUrl.endsWith("/json_rpc")) {
|
|
48
|
+
throw new Error("Invalid seed node URL, must NOT finish with /json_rpc");
|
|
49
|
+
}
|
|
50
|
+
if (fetchedSnodesFromSeed[seedNodeUrl]?.length) {
|
|
51
|
+
return fetchedSnodesFromSeed[seedNodeUrl];
|
|
52
|
+
}
|
|
53
|
+
const getAll = new GetSnodesFromSeed();
|
|
54
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
55
|
+
console.info(`Fetching snodes from seed node: "${seedNodeUrl}/json_rpc"`);
|
|
56
|
+
try {
|
|
57
|
+
const result = await fetch(`${seedNodeUrl}/json_rpc`, {
|
|
58
|
+
body: JSON.stringify(getAll.build()),
|
|
59
|
+
method: "POST"
|
|
60
|
+
});
|
|
61
|
+
console.info("snode from list result status:", result.status);
|
|
62
|
+
const json = await result.json();
|
|
63
|
+
fetchedSnodesFromSeed[seedNodeUrl] = json.result.service_node_states;
|
|
64
|
+
return fetchedSnodesFromSeed[seedNodeUrl];
|
|
65
|
+
} catch (e) {
|
|
66
|
+
console.warn(e);
|
|
67
|
+
throw e;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function randomSnodeFromNetwork(seedNodeUrl) {
|
|
71
|
+
const snodes = await getAllSnodesFromSeed(seedNodeUrl);
|
|
72
|
+
const snode = (0, import_lodash.sample)(snodes);
|
|
73
|
+
if (!snode) {
|
|
74
|
+
throw new Error(`No random snode found on seed node: ${seedNodeUrl}`);
|
|
75
|
+
}
|
|
76
|
+
return snode;
|
|
77
|
+
}
|
|
78
|
+
var GetSnodesFromSeed = class {
|
|
79
|
+
build() {
|
|
80
|
+
return {
|
|
81
|
+
jsonrpc: "2.0",
|
|
82
|
+
id: "0",
|
|
83
|
+
method: "get_n_service_nodes",
|
|
84
|
+
params: {
|
|
85
|
+
active_only: true,
|
|
86
|
+
limit: 20,
|
|
87
|
+
fields: {
|
|
88
|
+
public_ip: true,
|
|
89
|
+
storage_port: true,
|
|
90
|
+
pubkey_x25519: true,
|
|
91
|
+
pubkey_ed25519: true
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// src/sessionTools/index.ts
|
|
99
|
+
var import_libsession_wasm = __toESM(require("@session-foundation/libsession-wasm/"));
|
|
100
|
+
async function loadSessionTools() {
|
|
101
|
+
const loaded = await (0, import_libsession_wasm.default)();
|
|
102
|
+
return loaded;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/requests/snodeRequests.ts
|
|
106
|
+
var import_lodash2 = require("lodash");
|
|
107
|
+
var SwarmForSubRequest = class {
|
|
108
|
+
method = "get_swarm";
|
|
109
|
+
pubkey;
|
|
110
|
+
constructor(pubkey) {
|
|
111
|
+
this.pubkey = pubkey;
|
|
112
|
+
}
|
|
113
|
+
async build() {
|
|
114
|
+
return {
|
|
115
|
+
method: this.method,
|
|
116
|
+
params: {
|
|
117
|
+
pubkey: this.pubkey,
|
|
118
|
+
params: {
|
|
119
|
+
active_only: true,
|
|
120
|
+
fields: {
|
|
121
|
+
public_ip: true,
|
|
122
|
+
storage_port: true,
|
|
123
|
+
pubkey_x25519: true,
|
|
124
|
+
pubkey_ed25519: true
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
loggingId() {
|
|
131
|
+
return `${this.method}`;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
var StoreUserConfigSubRequest = class {
|
|
135
|
+
method = "store";
|
|
136
|
+
namespace;
|
|
137
|
+
ttlMs;
|
|
138
|
+
encryptedData;
|
|
139
|
+
destination;
|
|
140
|
+
userSigner;
|
|
141
|
+
constructor(args) {
|
|
142
|
+
this.namespace = args.namespace;
|
|
143
|
+
this.ttlMs = args.ttlMs;
|
|
144
|
+
this.encryptedData = args.encryptedData;
|
|
145
|
+
this.destination = args.sessionId;
|
|
146
|
+
this.userSigner = args.userSigner;
|
|
147
|
+
if ((0, import_lodash2.isEmpty)(this.encryptedData)) {
|
|
148
|
+
throw new Error("this.encryptedData cannot be empty");
|
|
149
|
+
}
|
|
150
|
+
if ((0, import_lodash2.isEmpty)(this.destination)) {
|
|
151
|
+
throw new Error("this.destination cannot be empty");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async build() {
|
|
155
|
+
const encryptedDataBase64 = this.userSigner.sodium.to_base64(
|
|
156
|
+
this.encryptedData,
|
|
157
|
+
this.userSigner.sodium.base64_variants.ORIGINAL
|
|
158
|
+
);
|
|
159
|
+
const signDetails = await this.userSigner.getSnodeSignatureParams({
|
|
160
|
+
getNow: () => Date.now(),
|
|
161
|
+
method: this.method,
|
|
162
|
+
namespace: this.namespace
|
|
163
|
+
});
|
|
164
|
+
if (!signDetails) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`[StoreUserConfigSubRequest] signing returned an empty result`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
const toRet = {
|
|
170
|
+
method: this.method,
|
|
171
|
+
params: {
|
|
172
|
+
namespace: this.namespace,
|
|
173
|
+
ttl: this.ttlMs,
|
|
174
|
+
data: encryptedDataBase64,
|
|
175
|
+
...signDetails
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
return toRet;
|
|
179
|
+
}
|
|
180
|
+
loggingId() {
|
|
181
|
+
return `${this.method}-${this.destination}-${this.namespace}`;
|
|
182
|
+
}
|
|
183
|
+
getDestination() {
|
|
184
|
+
return this.destination;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
var StoreGroupConfigSubRequest = class {
|
|
188
|
+
method = "store";
|
|
189
|
+
namespace;
|
|
190
|
+
ttlMs;
|
|
191
|
+
encryptedData;
|
|
192
|
+
destination;
|
|
193
|
+
adminGroupSigner;
|
|
194
|
+
constructor(args) {
|
|
195
|
+
this.namespace = args.namespace;
|
|
196
|
+
this.ttlMs = args.ttlMs;
|
|
197
|
+
this.encryptedData = args.encryptedData;
|
|
198
|
+
this.destination = args.groupPk;
|
|
199
|
+
this.adminGroupSigner = args.adminGroupSigner;
|
|
200
|
+
if ((0, import_lodash2.isEmpty)(this.encryptedData)) {
|
|
201
|
+
throw new Error("this.encryptedData cannot be empty");
|
|
202
|
+
}
|
|
203
|
+
if ((0, import_lodash2.isEmpty)(this.destination)) {
|
|
204
|
+
throw new Error("this.destination cannot be empty");
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async build() {
|
|
208
|
+
const encryptedDataBase64 = this.adminGroupSigner.sodium.to_base64(
|
|
209
|
+
this.encryptedData,
|
|
210
|
+
this.adminGroupSigner.sodium.base64_variants.ORIGINAL
|
|
211
|
+
);
|
|
212
|
+
const signDetails = await this.adminGroupSigner.getSnodeSignatureParams({
|
|
213
|
+
getNow: () => Date.now(),
|
|
214
|
+
method: this.method,
|
|
215
|
+
namespace: this.namespace
|
|
216
|
+
});
|
|
217
|
+
if (!signDetails) {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`[StoreGroupConfigSubRequest] signing returned an empty result`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
const toRet = {
|
|
223
|
+
method: this.method,
|
|
224
|
+
params: {
|
|
225
|
+
namespace: this.namespace,
|
|
226
|
+
ttl: this.ttlMs,
|
|
227
|
+
data: encryptedDataBase64,
|
|
228
|
+
...signDetails
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
return toRet;
|
|
232
|
+
}
|
|
233
|
+
loggingId() {
|
|
234
|
+
return `${this.method}-${this.destination}-${this.namespace}`;
|
|
235
|
+
}
|
|
236
|
+
getDestination() {
|
|
237
|
+
return this.destination;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// src/sessionUser.ts
|
|
242
|
+
var import_mnemonic = require("@session-foundation/mnemonic");
|
|
243
|
+
|
|
244
|
+
// src/signer/userSigner.ts
|
|
245
|
+
var import_sodium = require("@session-foundation/sodium");
|
|
246
|
+
function getVerificationDataForStoreRetrieve(params) {
|
|
247
|
+
const signatureTimestamp = params.getNow();
|
|
248
|
+
const verificationString = `${params.method}${params.namespace === 0 ? "" : params.namespace}${signatureTimestamp}`;
|
|
249
|
+
const verificationData = params.sodium.from_string(verificationString);
|
|
250
|
+
return {
|
|
251
|
+
toSign: new Uint8Array(verificationData),
|
|
252
|
+
signatureTimestamp
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
async function getSnodeSignatureShared(params) {
|
|
256
|
+
const { signatureTimestamp, toSign } = getVerificationDataForStoreRetrieve(params);
|
|
257
|
+
const sodium = await (0, import_sodium.getSodium)();
|
|
258
|
+
const signature = sodium.crypto_sign_detached(toSign, params.privKey);
|
|
259
|
+
const signatureBase64 = params.sodium.to_base64(
|
|
260
|
+
signature,
|
|
261
|
+
params.sodium.base64_variants.ORIGINAL
|
|
262
|
+
);
|
|
263
|
+
return {
|
|
264
|
+
timestamp: signatureTimestamp,
|
|
265
|
+
signature: signatureBase64
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
var UserSigner = class {
|
|
269
|
+
ed25519PubKey;
|
|
270
|
+
ed25519PrivKey;
|
|
271
|
+
sodium;
|
|
272
|
+
sessionId;
|
|
273
|
+
constructor({
|
|
274
|
+
ed25519PrivKey,
|
|
275
|
+
ed25519PubKey,
|
|
276
|
+
sessionId,
|
|
277
|
+
sodium
|
|
278
|
+
}) {
|
|
279
|
+
this.ed25519PubKey = ed25519PubKey;
|
|
280
|
+
if (this.ed25519PubKey.length !== 64) {
|
|
281
|
+
console.warn("ed25519PubKey length", ed25519PubKey.length);
|
|
282
|
+
throw new Error("ed25519PubKey not 64 long");
|
|
283
|
+
}
|
|
284
|
+
this.ed25519PrivKey = ed25519PrivKey;
|
|
285
|
+
if (this.ed25519PrivKey.length !== 64) {
|
|
286
|
+
console.warn("ed25519PrivKey length", ed25519PrivKey.length);
|
|
287
|
+
throw new Error("ed25519PrivKey not 64 long");
|
|
288
|
+
}
|
|
289
|
+
this.sessionId = sessionId;
|
|
290
|
+
this.sodium = sodium;
|
|
291
|
+
}
|
|
292
|
+
async getSnodeSignatureParams({
|
|
293
|
+
method,
|
|
294
|
+
namespace,
|
|
295
|
+
getNow
|
|
296
|
+
}) {
|
|
297
|
+
if (!this.ed25519PrivKey || !this.ed25519PubKey) {
|
|
298
|
+
const err = `getSnodeSignatureParams "${method}": User has no getUserED25519KeyPairBytes()`;
|
|
299
|
+
throw new Error(err);
|
|
300
|
+
}
|
|
301
|
+
const sigData = await getSnodeSignatureShared({
|
|
302
|
+
pubKey: this.sessionId,
|
|
303
|
+
method,
|
|
304
|
+
namespace,
|
|
305
|
+
privKey: this.ed25519PrivKey,
|
|
306
|
+
getNow,
|
|
307
|
+
sodium: this.sodium
|
|
308
|
+
});
|
|
309
|
+
return {
|
|
310
|
+
...sigData,
|
|
311
|
+
pubkey_ed25519: this.ed25519PubKey,
|
|
312
|
+
pubkey: this.sessionId
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
// src/sessionUser.ts
|
|
318
|
+
function buildUserSigner(user, sodium) {
|
|
319
|
+
const userSigner = new UserSigner({
|
|
320
|
+
sessionId: user.sessionId,
|
|
321
|
+
ed25519PrivKey: user.ed25519Sk,
|
|
322
|
+
ed25519PubKey: sodium.to_hex(user.ed25519Pk),
|
|
323
|
+
sodium
|
|
324
|
+
});
|
|
325
|
+
return userSigner;
|
|
326
|
+
}
|
|
327
|
+
function generateMnemonic(opts) {
|
|
328
|
+
const seedSize = 16;
|
|
329
|
+
const seed = opts.sodium.randombytes_buf(seedSize);
|
|
330
|
+
const hex = opts.sodium.to_hex(seed);
|
|
331
|
+
return (0, import_mnemonic.mnEncode)(hex);
|
|
332
|
+
}
|
|
333
|
+
function mnemonicToRawSeed(mnemonic, sodium) {
|
|
334
|
+
let seedHex = (0, import_mnemonic.mnDecode)(mnemonic);
|
|
335
|
+
const privKeyHexLength = 32 * 2;
|
|
336
|
+
if (seedHex.length !== privKeyHexLength) {
|
|
337
|
+
seedHex = seedHex.concat("0".repeat(32));
|
|
338
|
+
seedHex = seedHex.substring(0, privKeyHexLength);
|
|
339
|
+
}
|
|
340
|
+
const seed = sodium.from_hex(seedHex);
|
|
341
|
+
return seed;
|
|
342
|
+
}
|
|
343
|
+
function sessionGenerateKeyPair(opts) {
|
|
344
|
+
const ed25519KeyPair = opts.sodium.crypto_sign_seed_keypair(
|
|
345
|
+
new Uint8Array(opts.seed)
|
|
346
|
+
);
|
|
347
|
+
const x25519PublicKey = opts.sodium.crypto_sign_ed25519_pk_to_curve25519(
|
|
348
|
+
ed25519KeyPair.publicKey
|
|
349
|
+
);
|
|
350
|
+
const origPub = new Uint8Array(x25519PublicKey);
|
|
351
|
+
const prependedX25519PublicKey = new Uint8Array(33);
|
|
352
|
+
prependedX25519PublicKey.set(origPub, 1);
|
|
353
|
+
prependedX25519PublicKey[0] = 5;
|
|
354
|
+
const x25519SecretKey = opts.sodium.crypto_sign_ed25519_sk_to_curve25519(
|
|
355
|
+
ed25519KeyPair.privateKey
|
|
356
|
+
);
|
|
357
|
+
return {
|
|
358
|
+
x25519PublicKeyWith05: prependedX25519PublicKey,
|
|
359
|
+
x25519SecretKey: x25519SecretKey.buffer,
|
|
360
|
+
ed25519KeyPair
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
var SessionUser = class {
|
|
364
|
+
sessionId;
|
|
365
|
+
ed25519Pk;
|
|
366
|
+
ed25519Sk;
|
|
367
|
+
seed;
|
|
368
|
+
seedPhrase;
|
|
369
|
+
wrappers;
|
|
370
|
+
userProfile;
|
|
371
|
+
contacts;
|
|
372
|
+
userGroups;
|
|
373
|
+
userSigner;
|
|
374
|
+
sodium;
|
|
375
|
+
constructor({ sessionTools, sodium }) {
|
|
376
|
+
const mnemonic = generateMnemonic({ sodium });
|
|
377
|
+
const seed = mnemonicToRawSeed(mnemonic, sodium);
|
|
378
|
+
const userKeys = sessionGenerateKeyPair({ seed, sodium });
|
|
379
|
+
const userProfile = new sessionTools.UserProfileW(
|
|
380
|
+
userKeys.ed25519KeyPair.privateKey,
|
|
381
|
+
void 0
|
|
382
|
+
);
|
|
383
|
+
const contacts = new sessionTools.ContactsW(
|
|
384
|
+
userKeys.ed25519KeyPair.privateKey,
|
|
385
|
+
void 0
|
|
386
|
+
);
|
|
387
|
+
const userGroups = new sessionTools.UserGroupsW(
|
|
388
|
+
userKeys.ed25519KeyPair.privateKey,
|
|
389
|
+
void 0
|
|
390
|
+
);
|
|
391
|
+
const wrappers = [userProfile, contacts, userGroups];
|
|
392
|
+
this.sessionId = sodium.to_hex(
|
|
393
|
+
userKeys.x25519PublicKeyWith05
|
|
394
|
+
);
|
|
395
|
+
this.ed25519Pk = userKeys.ed25519KeyPair.publicKey;
|
|
396
|
+
this.ed25519Sk = userKeys.ed25519KeyPair.privateKey;
|
|
397
|
+
this.seed = seed;
|
|
398
|
+
this.seedPhrase = (0, import_mnemonic.mnEncode)(sodium.to_hex(seed).slice(0, 32));
|
|
399
|
+
this.wrappers = wrappers;
|
|
400
|
+
this.userProfile = userProfile;
|
|
401
|
+
this.contacts = contacts;
|
|
402
|
+
this.userGroups = userGroups;
|
|
403
|
+
this.sodium = sodium;
|
|
404
|
+
this.userSigner = buildUserSigner(this, this.sodium);
|
|
405
|
+
}
|
|
406
|
+
async pushChangesToSwarm(snode) {
|
|
407
|
+
const storeRequests = this.wrappers.map(
|
|
408
|
+
(wrapper) => new StoreUserConfigSubRequest({
|
|
409
|
+
namespace: wrapper.storageNamespace().value,
|
|
410
|
+
encryptedData: this.sodium.from_hex(
|
|
411
|
+
wrapper.makePushHex().get(0)?.toString() ?? ""
|
|
412
|
+
),
|
|
413
|
+
sessionId: this.sessionId,
|
|
414
|
+
ttlMs: 1e3 * 3600 * 24,
|
|
415
|
+
// 1 day should be enough for testing and debugging a test?
|
|
416
|
+
userSigner: this.userSigner
|
|
417
|
+
})
|
|
418
|
+
);
|
|
419
|
+
const storeResult = await Promise.all(
|
|
420
|
+
storeRequests.map(async (request) => {
|
|
421
|
+
const builtRequest = await request.build();
|
|
422
|
+
console.info(
|
|
423
|
+
"storing to snode",
|
|
424
|
+
`https://${snode.ip}:${snode.port}/storage_rpc/v1`
|
|
425
|
+
);
|
|
426
|
+
const ret = await fetch(
|
|
427
|
+
`https://${snode.ip}:${snode.port}/storage_rpc/v1`,
|
|
428
|
+
{
|
|
429
|
+
body: JSON.stringify(builtRequest),
|
|
430
|
+
method: "POST"
|
|
431
|
+
}
|
|
432
|
+
);
|
|
433
|
+
return ret.status;
|
|
434
|
+
})
|
|
435
|
+
);
|
|
436
|
+
console.log(`storeStatus for ${this.userProfile.getName()}:`, storeResult);
|
|
437
|
+
}
|
|
438
|
+
freeMemory() {
|
|
439
|
+
this.wrappers.map((wrapper) => wrapper.delete());
|
|
440
|
+
}
|
|
441
|
+
toString() {
|
|
442
|
+
const name = this.userProfile.getName();
|
|
443
|
+
const sessionId = this.sessionId;
|
|
444
|
+
const seedPhrase = this.seedPhrase;
|
|
445
|
+
return `SessionUser: ${JSON.stringify({ name, sessionId, seedPhrase })}`;
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
function createRandomUser(details) {
|
|
449
|
+
return new SessionUser(details);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// src/signer/groupSigner.ts
|
|
453
|
+
var import_sodium2 = require("@session-foundation/sodium");
|
|
454
|
+
function getVerificationDataForStoreRetrieve2(params) {
|
|
455
|
+
const signatureTimestamp = params.getNow();
|
|
456
|
+
const verificationString = `${params.method}${params.namespace === 0 ? "" : params.namespace}${signatureTimestamp}`;
|
|
457
|
+
const verificationData = params.sodium.from_string(verificationString);
|
|
458
|
+
return {
|
|
459
|
+
toSign: new Uint8Array(verificationData),
|
|
460
|
+
signatureTimestamp
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
async function getSnodeSignatureShared2(params) {
|
|
464
|
+
const { signatureTimestamp, toSign } = getVerificationDataForStoreRetrieve2(params);
|
|
465
|
+
const sodium = await (0, import_sodium2.getSodium)();
|
|
466
|
+
const signature = sodium.crypto_sign_detached(toSign, params.privKey);
|
|
467
|
+
const signatureBase64 = params.sodium.to_base64(
|
|
468
|
+
signature,
|
|
469
|
+
params.sodium.base64_variants.ORIGINAL
|
|
470
|
+
);
|
|
471
|
+
return {
|
|
472
|
+
timestamp: signatureTimestamp,
|
|
473
|
+
signature: signatureBase64
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
var GroupAdminSigner = class {
|
|
477
|
+
groupPk;
|
|
478
|
+
sodium;
|
|
479
|
+
groupSecretKey;
|
|
480
|
+
constructor({
|
|
481
|
+
groupSecretKey,
|
|
482
|
+
groupPk,
|
|
483
|
+
sodium
|
|
484
|
+
}) {
|
|
485
|
+
this.groupSecretKey = groupSecretKey;
|
|
486
|
+
if (this.groupSecretKey.length !== 64) {
|
|
487
|
+
console.warn("groupSecretKey length", groupSecretKey.length);
|
|
488
|
+
throw new Error("groupSecretKey not 64 long");
|
|
489
|
+
}
|
|
490
|
+
this.groupPk = groupPk;
|
|
491
|
+
this.sodium = sodium;
|
|
492
|
+
}
|
|
493
|
+
async getSnodeSignatureParams({
|
|
494
|
+
method,
|
|
495
|
+
namespace,
|
|
496
|
+
getNow
|
|
497
|
+
}) {
|
|
498
|
+
const sigData = await getSnodeSignatureShared2({
|
|
499
|
+
pubKey: this.groupPk,
|
|
500
|
+
method,
|
|
501
|
+
namespace,
|
|
502
|
+
privKey: this.groupSecretKey,
|
|
503
|
+
getNow,
|
|
504
|
+
sodium: this.sodium
|
|
505
|
+
});
|
|
506
|
+
return {
|
|
507
|
+
...sigData,
|
|
508
|
+
pubkey: this.groupPk
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
// src/sessionGroup.ts
|
|
514
|
+
var import_lodash3 = require("lodash");
|
|
515
|
+
function buildGroupSigner(group, sodium) {
|
|
516
|
+
if (!group.groupSecretKey) {
|
|
517
|
+
throw new Error(
|
|
518
|
+
"only group admin signer (with admin key) is supported currently"
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
return new GroupAdminSigner({
|
|
522
|
+
groupPk: group.groupPk,
|
|
523
|
+
groupSecretKey: group.groupSecretKey,
|
|
524
|
+
sodium
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
var SessionGroup = class {
|
|
528
|
+
groupPk;
|
|
529
|
+
groupSecretKey;
|
|
530
|
+
metagroupW;
|
|
531
|
+
adminGroupSigner;
|
|
532
|
+
groupName;
|
|
533
|
+
sodium;
|
|
534
|
+
constructor({
|
|
535
|
+
sessionTools,
|
|
536
|
+
groupName,
|
|
537
|
+
members,
|
|
538
|
+
sodium
|
|
539
|
+
}) {
|
|
540
|
+
if (!members.length) {
|
|
541
|
+
throw new Error("Excepted at least one creator/member");
|
|
542
|
+
}
|
|
543
|
+
this.groupName = groupName;
|
|
544
|
+
const [creator, ...otherMembers] = members;
|
|
545
|
+
if (!creator) {
|
|
546
|
+
throw new Error("Expected at least the creator");
|
|
547
|
+
}
|
|
548
|
+
const newGroup = creator.userGroups.createGroup();
|
|
549
|
+
newGroup.name = groupName;
|
|
550
|
+
newGroup.joinedAtSeconds = BigInt(Math.floor(Date.now() / 1e3));
|
|
551
|
+
this.groupSecretKey = sodium.from_hex(newGroup.adminSecretKey.toString());
|
|
552
|
+
this.metagroupW = new sessionTools.MetaGroupW(
|
|
553
|
+
creator.ed25519Sk,
|
|
554
|
+
sodium.from_hex(newGroup.groupPk.toString().slice(2)).buffer,
|
|
555
|
+
this.groupSecretKey,
|
|
556
|
+
void 0
|
|
557
|
+
);
|
|
558
|
+
[creator, ...otherMembers].forEach((member) => {
|
|
559
|
+
if (member.sessionId !== creator.sessionId) {
|
|
560
|
+
const authDataHex = this.metagroupW.makeSubaccountHex(
|
|
561
|
+
member.sessionId,
|
|
562
|
+
true,
|
|
563
|
+
false
|
|
564
|
+
);
|
|
565
|
+
const groupForUser = member.userGroups.getOrConstructGroup(
|
|
566
|
+
newGroup.groupPk
|
|
567
|
+
);
|
|
568
|
+
groupForUser.name = newGroup.name;
|
|
569
|
+
groupForUser.joinedAtSeconds = newGroup.joinedAtSeconds;
|
|
570
|
+
groupForUser.invited = false;
|
|
571
|
+
groupForUser.priority = 0;
|
|
572
|
+
groupForUser.authData = sodium.from_hex(authDataHex);
|
|
573
|
+
member.userGroups.setGroup(groupForUser);
|
|
574
|
+
} else {
|
|
575
|
+
member.userGroups.setGroup(newGroup);
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
this.metagroupW.setNameTruncated(groupName);
|
|
579
|
+
[creator, ...otherMembers].forEach((u) => {
|
|
580
|
+
const member = this.metagroupW.membersGetOrConstruct(u.sessionId);
|
|
581
|
+
if (u.sessionId === creator.sessionId) {
|
|
582
|
+
member.setPromotionAccepted();
|
|
583
|
+
} else {
|
|
584
|
+
member.setInviteAccepted();
|
|
585
|
+
}
|
|
586
|
+
member.setNameTruncated(u.userProfile.getName()?.toString() || "");
|
|
587
|
+
this.metagroupW.membersSet(member);
|
|
588
|
+
});
|
|
589
|
+
this.metagroupW.rekeyHex();
|
|
590
|
+
this.groupPk = newGroup.groupPk.toString();
|
|
591
|
+
this.sodium = sodium;
|
|
592
|
+
this.adminGroupSigner = buildGroupSigner(this, this.sodium);
|
|
593
|
+
}
|
|
594
|
+
async pushChangesToSwarm(snode) {
|
|
595
|
+
const pushHex = this.metagroupW.pushHex();
|
|
596
|
+
const toPush = (0, import_lodash3.compact)([
|
|
597
|
+
pushHex.keysPush,
|
|
598
|
+
pushHex.membersPush,
|
|
599
|
+
pushHex.infosPush
|
|
600
|
+
]);
|
|
601
|
+
const storeRequests = toPush.map((m) => {
|
|
602
|
+
return new StoreGroupConfigSubRequest({
|
|
603
|
+
namespace: m.storageNamespace.value,
|
|
604
|
+
encryptedData: this.sodium.from_hex(m.dataHex.toString()),
|
|
605
|
+
groupPk: this.groupPk,
|
|
606
|
+
ttlMs: 1e3 * 3600 * 24,
|
|
607
|
+
// 1 day should be enough for testing and debugging a test?
|
|
608
|
+
adminGroupSigner: this.adminGroupSigner
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
const storeResult = await Promise.all(
|
|
612
|
+
storeRequests.map(async (request) => {
|
|
613
|
+
const builtRequest = await request.build();
|
|
614
|
+
console.info(
|
|
615
|
+
"storing to snode",
|
|
616
|
+
`https://${snode.ip}:${snode.port}/storage_rpc/v1`
|
|
617
|
+
);
|
|
618
|
+
const ret = await fetch(
|
|
619
|
+
`https://${snode.ip}:${snode.port}/storage_rpc/v1`,
|
|
620
|
+
{
|
|
621
|
+
body: JSON.stringify(builtRequest),
|
|
622
|
+
method: "POST"
|
|
623
|
+
}
|
|
624
|
+
);
|
|
625
|
+
return ret.status;
|
|
626
|
+
})
|
|
627
|
+
);
|
|
628
|
+
console.log(`storeStatus for (group) ${this.groupPk}:`, storeResult);
|
|
629
|
+
}
|
|
630
|
+
freeMemory() {
|
|
631
|
+
this.metagroupW.delete();
|
|
632
|
+
}
|
|
633
|
+
toString() {
|
|
634
|
+
const groupName = this.groupName;
|
|
635
|
+
const groupPk = this.groupPk;
|
|
636
|
+
const groupSecretKeyHex = this.sodium.to_hex(this.groupSecretKey);
|
|
637
|
+
return `SessionGroup: ${JSON.stringify({ groupPk, groupName, groupSecretKeyHex })}`;
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
// src/index.ts
|
|
642
|
+
var import_basic_types = require("@session-foundation/basic-types");
|
|
643
|
+
var import_sodium3 = require("@session-foundation/sodium");
|
|
644
|
+
|
|
645
|
+
// src/actions/fetchSwarmOf.ts
|
|
646
|
+
var import_lodash4 = require("lodash");
|
|
647
|
+
var fetchedSwarms = {};
|
|
648
|
+
async function getSwarmOfUser(sessionId, snode) {
|
|
649
|
+
const swarmRequest = new SwarmForSubRequest(sessionId);
|
|
650
|
+
const swarmResult = await fetch(
|
|
651
|
+
`https://${snode.public_ip}:${snode.storage_port}/storage_rpc/v1`,
|
|
652
|
+
{
|
|
653
|
+
body: JSON.stringify(await swarmRequest.build()),
|
|
654
|
+
method: "POST"
|
|
655
|
+
}
|
|
656
|
+
);
|
|
657
|
+
const swarm = await swarmResult.json();
|
|
658
|
+
if ((0, import_lodash4.isEmpty)(fetchedSwarms[sessionId])) {
|
|
659
|
+
fetchedSwarms[sessionId] = swarm;
|
|
660
|
+
}
|
|
661
|
+
return swarm.snodes;
|
|
662
|
+
}
|
|
663
|
+
async function randomSnodeOnUserSwarm(sessionId, snode) {
|
|
664
|
+
const userSwarm = fetchedSwarms[sessionId] || await getSwarmOfUser(sessionId, snode);
|
|
665
|
+
const randomSnodeOnSwarm = (0, import_lodash4.sample)(userSwarm);
|
|
666
|
+
if (!randomSnodeOnSwarm) {
|
|
667
|
+
throw new Error(`did not find a snode for user: ${sessionId}`);
|
|
668
|
+
}
|
|
669
|
+
console.info(
|
|
670
|
+
`random snode for user: ${sessionId} is snode: ${randomSnodeOnSwarm.pubkey_ed25519}`
|
|
671
|
+
);
|
|
672
|
+
return randomSnodeOnSwarm;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// src/index.ts
|
|
676
|
+
var networks = {
|
|
677
|
+
mainnet: "https://seed2.getsession.org:4443",
|
|
678
|
+
testnet: "http://seed2.getsession.org:38157"
|
|
679
|
+
};
|
|
680
|
+
function getSeedNodeUrl(network) {
|
|
681
|
+
if (network === "mainnet" || network === "testnet") {
|
|
682
|
+
return networks[network];
|
|
683
|
+
}
|
|
684
|
+
return network;
|
|
685
|
+
}
|
|
686
|
+
function makeFriendsAndKnown(users) {
|
|
687
|
+
if (users.length < 2) {
|
|
688
|
+
throw new Error("needs at least two users to make them friends");
|
|
689
|
+
}
|
|
690
|
+
console.info(
|
|
691
|
+
`makeFriendsAndKnown: users: [${users.map((m) => m.toString()).join(",\n")}]`
|
|
692
|
+
);
|
|
693
|
+
users.forEach((user1) => {
|
|
694
|
+
users.forEach((user2) => {
|
|
695
|
+
if (user1.sessionId === user2.sessionId) {
|
|
696
|
+
console.info(
|
|
697
|
+
"makeFriendsAndKnown: user1 === user2. Skipping",
|
|
698
|
+
user1.toString()
|
|
699
|
+
);
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
console.info("makeFriendsAndKnown: user1", user1.toString());
|
|
703
|
+
if (user2) {
|
|
704
|
+
console.info("makeFriendsAndKnown: user2", user2.toString());
|
|
705
|
+
user1.contacts.setApproved(user2.sessionId, true);
|
|
706
|
+
user1.contacts.setApprovedMe(user2.sessionId, true);
|
|
707
|
+
user1.contacts.setName(
|
|
708
|
+
user2.sessionId,
|
|
709
|
+
user2.userProfile.getName() || ""
|
|
710
|
+
);
|
|
711
|
+
user2.contacts.setApproved(user1.sessionId, true);
|
|
712
|
+
user2.contacts.setApprovedMe(user1.sessionId, true);
|
|
713
|
+
user2.contacts.setName(
|
|
714
|
+
user1.sessionId,
|
|
715
|
+
user1.userProfile.getName() || ""
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
function makeGroupWithMembers({
|
|
722
|
+
members,
|
|
723
|
+
groupName,
|
|
724
|
+
sessionTools,
|
|
725
|
+
sodium
|
|
726
|
+
}) {
|
|
727
|
+
return new SessionGroup({ sessionTools, groupName, members, sodium });
|
|
728
|
+
}
|
|
729
|
+
var PrebuiltStateWithWrappers = class {
|
|
730
|
+
userWrappers;
|
|
731
|
+
groupWrapper;
|
|
732
|
+
constructor(args) {
|
|
733
|
+
this.userWrappers = args.users;
|
|
734
|
+
this.groupWrapper = args.group;
|
|
735
|
+
}
|
|
736
|
+
async pushChangesToSwarms({
|
|
737
|
+
seedNodeUrl
|
|
738
|
+
}) {
|
|
739
|
+
console.info(`Pushing changes to swarms on network "${seedNodeUrl}"`);
|
|
740
|
+
const promises = [];
|
|
741
|
+
if (this.userWrappers && (0, import_lodash5.isArray)(this.userWrappers) && this.userWrappers?.length) {
|
|
742
|
+
const users = this.userWrappers;
|
|
743
|
+
const userPromise = pushUsersChangesToSwarm({ seedNodeUrl, users });
|
|
744
|
+
promises.push(userPromise);
|
|
745
|
+
}
|
|
746
|
+
if (this.groupWrapper && this.groupWrapper instanceof SessionGroup) {
|
|
747
|
+
const randomNetworkSnode = await randomSnodeFromNetwork(seedNodeUrl);
|
|
748
|
+
const groupWrapper = this.groupWrapper;
|
|
749
|
+
const swarmSnode = await randomSnodeOnUserSwarm(
|
|
750
|
+
groupWrapper.groupPk,
|
|
751
|
+
randomNetworkSnode
|
|
752
|
+
);
|
|
753
|
+
const groupPromise = groupWrapper.pushChangesToSwarm(swarmSnode);
|
|
754
|
+
promises.push(groupPromise);
|
|
755
|
+
}
|
|
756
|
+
console.info(`promises`, promises);
|
|
757
|
+
await Promise.all(promises);
|
|
758
|
+
console.info(`Pushed changes to swarms on network "${seedNodeUrl}"`);
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
var usernames = ["Alice", "Bob", "Charlie", "Dracula"];
|
|
762
|
+
var USERNAME = {
|
|
763
|
+
ALICE: "Alice",
|
|
764
|
+
BOB: "Bob",
|
|
765
|
+
CHARLIE: "Charlie",
|
|
766
|
+
DRACULA: "Dracula"
|
|
767
|
+
};
|
|
768
|
+
function assertUserCountIsValid(count) {
|
|
769
|
+
if (count > usernames.length) {
|
|
770
|
+
throw new Error(`count should be less than ${usernames.length} currently`);
|
|
771
|
+
}
|
|
772
|
+
if (count < 1) {
|
|
773
|
+
throw new Error("count should be at least 1");
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
function createCountOfUsers({
|
|
777
|
+
count,
|
|
778
|
+
sessionTools,
|
|
779
|
+
sodium
|
|
780
|
+
}) {
|
|
781
|
+
return Array.from(
|
|
782
|
+
{ length: count },
|
|
783
|
+
() => createRandomUser({ sodium, sessionTools })
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
function assignNamesToUsers(users) {
|
|
787
|
+
users.forEach((user, index) => {
|
|
788
|
+
const name = usernames[index];
|
|
789
|
+
if (!name) {
|
|
790
|
+
throw new Error(
|
|
791
|
+
`assignNamesToUsers: username at index ${index} is empty`
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
user.userProfile.setName(name);
|
|
795
|
+
return user;
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
function createGroupWithMembers({
|
|
799
|
+
groupName,
|
|
800
|
+
users,
|
|
801
|
+
sodium,
|
|
802
|
+
sessionTools
|
|
803
|
+
}) {
|
|
804
|
+
if (!groupName) {
|
|
805
|
+
throw new Error("groupName should be provided");
|
|
806
|
+
}
|
|
807
|
+
const group = makeGroupWithMembers({
|
|
808
|
+
groupName,
|
|
809
|
+
members: users,
|
|
810
|
+
sessionTools,
|
|
811
|
+
sodium
|
|
812
|
+
});
|
|
813
|
+
console.log("creatorMetagroupW info:", group.metagroupW.makeInfoDumpHex());
|
|
814
|
+
console.log(
|
|
815
|
+
"creatorMetagroupW members:",
|
|
816
|
+
group.metagroupW.makeMembersDumpHex()
|
|
817
|
+
);
|
|
818
|
+
console.log("creatorMetagroupW keys:", group.metagroupW.makeKeysDumpHex());
|
|
819
|
+
return {
|
|
820
|
+
group
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
async function pushUsersChangesToSwarm({
|
|
824
|
+
users,
|
|
825
|
+
seedNodeUrl
|
|
826
|
+
}) {
|
|
827
|
+
await Promise.all(
|
|
828
|
+
users.map(async (user) => {
|
|
829
|
+
const randomNetworkSnode = await randomSnodeFromNetwork(seedNodeUrl);
|
|
830
|
+
const swarmSnode = await randomSnodeOnUserSwarm(
|
|
831
|
+
user.sessionId,
|
|
832
|
+
randomNetworkSnode
|
|
833
|
+
);
|
|
834
|
+
await user.pushChangesToSwarm(swarmSnode);
|
|
835
|
+
})
|
|
836
|
+
);
|
|
837
|
+
console.info(
|
|
838
|
+
`seed of users:
|
|
839
|
+
${users.map((u) => `"${u.userProfile.getName()}": "${u.seedPhrase}"`).join("\n ")} `
|
|
840
|
+
);
|
|
841
|
+
}
|
|
842
|
+
function toStateUsers(users) {
|
|
843
|
+
return users.map((user, index) => {
|
|
844
|
+
const userName = user.userProfile.getName()?.toString();
|
|
845
|
+
if (!userName) {
|
|
846
|
+
throw new Error(`userName should be defined for user at index: ${index}`);
|
|
847
|
+
}
|
|
848
|
+
return {
|
|
849
|
+
seed: user.seed,
|
|
850
|
+
seedPhrase: user.seedPhrase,
|
|
851
|
+
sessionId: user.sessionId,
|
|
852
|
+
userName
|
|
853
|
+
};
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
function toStateGroup(group) {
|
|
857
|
+
if (!group.groupSecretKey || (0, import_lodash5.isEmpty)(group.groupSecretKey)) {
|
|
858
|
+
throw new Error("groupSecretKey should be defined");
|
|
859
|
+
}
|
|
860
|
+
return {
|
|
861
|
+
groupPk: group.groupPk,
|
|
862
|
+
groupName: group.groupName,
|
|
863
|
+
adminSecretKey: group.groupSecretKey
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
function prepareUsers({
|
|
867
|
+
sessionTools,
|
|
868
|
+
sodium,
|
|
869
|
+
usersCount
|
|
870
|
+
}) {
|
|
871
|
+
const users = createCountOfUsers({
|
|
872
|
+
count: usersCount,
|
|
873
|
+
sodium,
|
|
874
|
+
sessionTools
|
|
875
|
+
});
|
|
876
|
+
assignNamesToUsers(users);
|
|
877
|
+
return users;
|
|
878
|
+
}
|
|
879
|
+
function prepareFriends({
|
|
880
|
+
friendsCount,
|
|
881
|
+
sessionTools,
|
|
882
|
+
sodium
|
|
883
|
+
}) {
|
|
884
|
+
assertUserCountIsValid(friendsCount);
|
|
885
|
+
const users = prepareUsers({
|
|
886
|
+
usersCount: friendsCount,
|
|
887
|
+
sessionTools,
|
|
888
|
+
sodium
|
|
889
|
+
});
|
|
890
|
+
makeFriendsAndKnown(users);
|
|
891
|
+
return {
|
|
892
|
+
stateUsers: toStateUsers(users),
|
|
893
|
+
usersWrapper: users
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
function prepareFriendsInGroup({
|
|
897
|
+
friendsCount,
|
|
898
|
+
groupName,
|
|
899
|
+
sessionTools,
|
|
900
|
+
sodium
|
|
901
|
+
}) {
|
|
902
|
+
if (!groupName) {
|
|
903
|
+
throw new Error("groupName should be provided");
|
|
904
|
+
}
|
|
905
|
+
const { stateUsers, usersWrapper } = prepareFriends({
|
|
906
|
+
friendsCount,
|
|
907
|
+
sessionTools,
|
|
908
|
+
sodium
|
|
909
|
+
});
|
|
910
|
+
const { group } = createGroupWithMembers({
|
|
911
|
+
groupName,
|
|
912
|
+
users: usersWrapper,
|
|
913
|
+
sodium,
|
|
914
|
+
sessionTools
|
|
915
|
+
});
|
|
916
|
+
return {
|
|
917
|
+
stateUsers,
|
|
918
|
+
usersWrapper,
|
|
919
|
+
stateGroup: toStateGroup(group),
|
|
920
|
+
groupWrapper: group
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
async function buildStateForTest(stateToBuild, groupName, network) {
|
|
924
|
+
const seedNodeUrl = getSeedNodeUrl(network);
|
|
925
|
+
console.info(
|
|
926
|
+
`[buildStateForTest] stateToBuild:"${stateToBuild}". seedNodeUrl: "${seedNodeUrl}" (${network})`
|
|
927
|
+
);
|
|
928
|
+
const sodium = await (0, import_sodium3.getSodium)();
|
|
929
|
+
const sessionTools = await loadSessionTools();
|
|
930
|
+
switch (stateToBuild) {
|
|
931
|
+
case "none": {
|
|
932
|
+
return { users: {} };
|
|
933
|
+
}
|
|
934
|
+
case "1user": {
|
|
935
|
+
const users = prepareUsers({ usersCount: 1, sessionTools, sodium });
|
|
936
|
+
await new PrebuiltStateWithWrappers({
|
|
937
|
+
users,
|
|
938
|
+
group: null
|
|
939
|
+
}).pushChangesToSwarms({ seedNodeUrl });
|
|
940
|
+
return {
|
|
941
|
+
users: toStateUsers(users)
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
case "2users": {
|
|
945
|
+
const users = prepareUsers({ usersCount: 2, sessionTools, sodium });
|
|
946
|
+
await new PrebuiltStateWithWrappers({
|
|
947
|
+
users,
|
|
948
|
+
group: null
|
|
949
|
+
}).pushChangesToSwarms({ seedNodeUrl });
|
|
950
|
+
return {
|
|
951
|
+
users: toStateUsers(users)
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
case "3users": {
|
|
955
|
+
const users = prepareUsers({ usersCount: 3, sessionTools, sodium });
|
|
956
|
+
await new PrebuiltStateWithWrappers({
|
|
957
|
+
users,
|
|
958
|
+
group: null
|
|
959
|
+
}).pushChangesToSwarms({ seedNodeUrl });
|
|
960
|
+
return {
|
|
961
|
+
users: toStateUsers(users)
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
case "2friends": {
|
|
965
|
+
const state = prepareFriends({
|
|
966
|
+
friendsCount: 2,
|
|
967
|
+
sessionTools,
|
|
968
|
+
sodium
|
|
969
|
+
});
|
|
970
|
+
await new PrebuiltStateWithWrappers({
|
|
971
|
+
users: state.usersWrapper,
|
|
972
|
+
group: null
|
|
973
|
+
}).pushChangesToSwarms({ seedNodeUrl });
|
|
974
|
+
return {
|
|
975
|
+
users: state.stateUsers
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
case "2friendsInGroup": {
|
|
979
|
+
if (!groupName) {
|
|
980
|
+
throw new Error("state 2friendsInGroup needs a groupName");
|
|
981
|
+
}
|
|
982
|
+
const state = prepareFriendsInGroup({
|
|
983
|
+
friendsCount: 2,
|
|
984
|
+
sessionTools,
|
|
985
|
+
sodium,
|
|
986
|
+
groupName
|
|
987
|
+
});
|
|
988
|
+
await new PrebuiltStateWithWrappers({
|
|
989
|
+
users: state.usersWrapper,
|
|
990
|
+
group: state.groupWrapper
|
|
991
|
+
}).pushChangesToSwarms({ seedNodeUrl });
|
|
992
|
+
return {
|
|
993
|
+
users: state.stateUsers,
|
|
994
|
+
group: state.stateGroup
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
case "3friends": {
|
|
998
|
+
const state = prepareFriends({
|
|
999
|
+
friendsCount: 3,
|
|
1000
|
+
sessionTools,
|
|
1001
|
+
sodium
|
|
1002
|
+
});
|
|
1003
|
+
await new PrebuiltStateWithWrappers({
|
|
1004
|
+
users: state.usersWrapper,
|
|
1005
|
+
group: null
|
|
1006
|
+
}).pushChangesToSwarms({ seedNodeUrl });
|
|
1007
|
+
return {
|
|
1008
|
+
users: state.stateUsers
|
|
1009
|
+
};
|
|
1010
|
+
}
|
|
1011
|
+
case "3friendsInGroup": {
|
|
1012
|
+
if (!groupName) {
|
|
1013
|
+
throw new Error("state 3friendsInGroup needs a groupName");
|
|
1014
|
+
}
|
|
1015
|
+
const state = prepareFriendsInGroup({
|
|
1016
|
+
friendsCount: 3,
|
|
1017
|
+
sessionTools,
|
|
1018
|
+
sodium,
|
|
1019
|
+
groupName
|
|
1020
|
+
});
|
|
1021
|
+
await new PrebuiltStateWithWrappers({
|
|
1022
|
+
users: state.usersWrapper,
|
|
1023
|
+
group: state.groupWrapper
|
|
1024
|
+
}).pushChangesToSwarms({ seedNodeUrl });
|
|
1025
|
+
return {
|
|
1026
|
+
users: state.stateUsers,
|
|
1027
|
+
group: state.stateGroup
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
default:
|
|
1031
|
+
(0, import_basic_types.assertUnreachable)(
|
|
1032
|
+
stateToBuild,
|
|
1033
|
+
`buildStateForTest of "${stateToBuild}" not implemented`
|
|
1034
|
+
);
|
|
1035
|
+
break;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1039
|
+
0 && (module.exports = {
|
|
1040
|
+
USERNAME,
|
|
1041
|
+
buildStateForTest,
|
|
1042
|
+
usernames
|
|
1043
|
+
});
|