@abtnode/core 1.16.31-beta-4246ab25 → 1.16.31-beta-a0cc72cf

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.
@@ -32,7 +32,6 @@ const runUserHook = async (label, hookName, args) => {
32
32
  logger.info(`run hook:${hookName}:`, { label, hook });
33
33
 
34
34
  const nodeInfo = await states.node.read();
35
- // FIXME @linchen timeout 应该动态设置或不设置
36
35
  await runScript(hook, [label, hookName].join(':'), {
37
36
  cwd: appDir,
38
37
  env: {
@@ -1,3 +1,4 @@
1
+ const cloneDeep = require('lodash/cloneDeep');
1
2
  const pickBy = require('lodash/pickBy');
2
3
  const get = require('lodash/get');
3
4
  const pick = require('lodash/pick');
@@ -73,7 +74,7 @@ class User extends ExtendBase {
73
74
  // create user
74
75
  await this.insert({
75
76
  ...user,
76
- ...(await this._prepareInviteInfo(user)),
77
+ ...(await this._extractInviteInfo(user)),
77
78
  sourceProvider: user.sourceProvider || LOGIN_PROVIDER.WALLET,
78
79
  approved: !!user.approved,
79
80
  });
@@ -96,12 +97,20 @@ class User extends ExtendBase {
96
97
 
97
98
  // FIXME: @wangshijun wrap these in a transaction
98
99
  async updateUser(did, updates) {
99
- const exist = await super.count({ did });
100
+ const exist = await super.findOne({ did });
100
101
  if (!exist) {
101
102
  throw new Error(`user does not exist: ${did}`);
102
103
  }
103
104
 
104
- await super.update({ did }, { $set: updates });
105
+ // Allow to update inviter only when inviter is not set
106
+ const pending = cloneDeep(updates);
107
+ if (exist.inviter) {
108
+ delete pending.inviter;
109
+ } else {
110
+ Object.assign(pending, await this._extractInviteInfo({ did, ...pending }));
111
+ }
112
+
113
+ await super.update({ did }, { $set: pending });
105
114
  await Promise.all(
106
115
  (get(updates, 'passports') || [])
107
116
  .filter((x) => x.id)
@@ -187,9 +196,10 @@ class User extends ExtendBase {
187
196
  /**
188
197
  * Get blocklet service user list
189
198
  */
190
- // eslint-disable-next-line require-await
191
199
  async getUsers({ query, sort, paging } = {}) {
192
200
  const where = {};
201
+ const replacements = {};
202
+
193
203
  const {
194
204
  approved,
195
205
  role,
@@ -208,6 +218,11 @@ class User extends ExtendBase {
208
218
  where.approved = approved;
209
219
  }
210
220
 
221
+ const sorting = pickBy(sort, (x) => !isNullOrUndefined(x));
222
+ if (!Object.keys(sorting).length) {
223
+ sorting.createdAt = -1;
224
+ }
225
+
211
226
  if (search) {
212
227
  if (search.length > 50) {
213
228
  throw new Error('the length of search text should not more than 50');
@@ -223,44 +238,51 @@ class User extends ExtendBase {
223
238
  throw new Error('You can not query by inviter and invitee at the same time');
224
239
  }
225
240
 
226
- // handle descendant query
227
- if (inviter) {
228
- if (isValid(inviter) === false) {
229
- throw new Error('inviter did invalid');
230
- }
231
- const exist = await this.model.findByPk(toAddress(inviter), { attributes: ['did', 'generation'] });
232
- if (!exist) {
233
- throw new Error(`inviter not found: ${inviter}`);
234
- }
241
+ let total = 0;
242
+ if (!where.did) {
243
+ // handle descendant query
244
+ if (inviter) {
245
+ if (isValid(inviter) === false) {
246
+ throw new Error('inviter did invalid');
247
+ }
248
+ const exist = await this.model.findByPk(toAddress(inviter), { attributes: ['did', 'generation'] });
249
+ if (!exist) {
250
+ throw new Error(`inviter not found: ${inviter}`);
251
+ }
235
252
 
236
- try {
237
- const subQuery = `
238
- WITH RECURSIVE UserTree(did,inviter,generation) AS (
239
- SELECT did,inviter,generation FROM users WHERE inviter="${exist.did}"
253
+ try {
254
+ const { pageSize: size = 20, page = 1 } = paging || {};
255
+ const pageSize = Math.min(100, size);
256
+ const offset = (page - 1) * pageSize;
257
+ // LIMIT ${pageSize} OFFSET ${offset}
258
+ const subQuery = `
259
+ WITH RECURSIVE UserTree(did,inviter,generation,createdAt) AS (
260
+ SELECT did,inviter,generation,createdAt FROM users WHERE inviter="${exist.did}"
240
261
  UNION ALL
241
- SELECT child.did,child.inviter,child.generation FROM users AS child INNER JOIN UserTree AS parent ON (child.inviter=parent.did)
262
+ SELECT child.did,child.inviter,child.generation,child.createdAt FROM users AS child INNER JOIN UserTree AS parent ON (child.inviter=parent.did) ORDER BY child.createdAt DESC
242
263
  )
243
- SELECT did,inviter,generation FROM UserTree ${generation > 0 ? `WHERE generation=${(exist.generation > 0 ? exist.generation : 0) + generation}` : ''} LIMIT ${USER_MAX_INVITE_DEPTH}`.trim();
244
- const children = await this.query(subQuery);
245
- where.did = children.map((x) => x.did);
246
- } catch (err) {
247
- console.error('Failed to get descendants', err);
248
- where.did = [];
264
+ SELECT did,inviter,generation FROM UserTree ${generation > 0 ? `WHERE generation=${(exist.generation > 0 ? exist.generation : 0) + generation}` : ''}`.trim();
265
+ const children = await this.query(subQuery);
266
+ total = children.length;
267
+ where.did = children.slice(offset, offset + pageSize).map((x) => x.did);
268
+ } catch (err) {
269
+ console.error('Failed to get descendants', err);
270
+ where.did = [];
271
+ }
249
272
  }
250
- }
251
273
 
252
- // handle ancestor query
253
- if (invitee) {
254
- if (isValid(invitee) === false) {
255
- throw new Error('invitee did invalid');
256
- }
257
- const exist = await this.model.findByPk(toAddress(invitee), { attributes: ['did', 'generation'] });
258
- if (!exist) {
259
- throw new Error(`invitee not found: ${invitee}`);
260
- }
274
+ // handle ancestor query
275
+ if (invitee) {
276
+ if (isValid(invitee) === false) {
277
+ throw new Error('invitee did invalid');
278
+ }
279
+ const exist = await this.model.findByPk(toAddress(invitee), { attributes: ['did', 'generation'] });
280
+ if (!exist) {
281
+ throw new Error(`invitee not found: ${invitee}`);
282
+ }
261
283
 
262
- try {
263
- const subQuery = `
284
+ try {
285
+ const subQuery = `
264
286
  WITH RECURSIVE UserTree(did,inviter,generation) AS (
265
287
  SELECT did,inviter,generation FROM users WHERE did="${exist.did}"
266
288
  UNION ALL
@@ -270,39 +292,34 @@ WITH RECURSIVE UserTree(did,inviter,generation) AS (
270
292
  (SELECT generation FROM users AS parent WHERE parent.did=child.inviter)
271
293
  FROM UserTree AS child
272
294
  WHERE inviter IS NOT NULL
273
- LIMIT ${USER_MAX_INVITE_DEPTH}
274
295
  )
275
296
  SELECT did,inviter,generation FROM UserTree`.trim();
276
- const children = await this.query(subQuery);
277
- where.did = children.map((x) => x.did).filter((x) => x !== exist.did);
278
- } catch (err) {
279
- console.error('Failed to get ancestors', err);
280
- where.did = [];
297
+ const children = await this.query(subQuery);
298
+ where.did = children.map((x) => x.did).filter((x) => x !== exist.did);
299
+ } catch (err) {
300
+ console.error('Failed to get ancestors', err);
301
+ where.did = [];
302
+ }
281
303
  }
282
- }
283
-
284
- const replacements = {};
285
304
 
286
- if (role && role !== '$all' && !where.did) {
287
- replacements.status = PASSPORT_STATUS.VALID;
288
- if (role === '$none') {
289
- where.did = {
290
- [Op.notIn]: Sequelize.literal('(SELECT DISTINCT userDid FROM passports WHERE status = :status)'),
291
- };
292
- } else {
293
- replacements.role = role;
294
- where.did = {
295
- [Op.in]: Sequelize.literal(
296
- '(SELECT DISTINCT userDid FROM passports WHERE name = :role AND status = :status)'
297
- ),
298
- };
305
+ // handle role/status query
306
+ if (role && role !== '$all') {
307
+ replacements.status = PASSPORT_STATUS.VALID;
308
+ if (role === '$none') {
309
+ where.did = {
310
+ [Op.notIn]: Sequelize.literal('(SELECT DISTINCT userDid FROM passports WHERE status = :status)'),
311
+ };
312
+ } else {
313
+ replacements.role = role;
314
+ where.did = {
315
+ [Op.in]: Sequelize.literal(
316
+ '(SELECT DISTINCT userDid FROM passports WHERE name = :role AND status = :status)'
317
+ ),
318
+ };
319
+ }
299
320
  }
300
321
  }
301
322
 
302
- const sorting = pickBy(sort, (x) => !isNullOrUndefined(x));
303
- if (!Object.keys(sorting).length) {
304
- sorting.createdAt = -1;
305
- }
306
323
  const include = [];
307
324
  if (shouldIncludeTag) {
308
325
  include.push(this.getTagInclude(tags));
@@ -325,7 +342,7 @@ SELECT did,inviter,generation FROM UserTree`.trim();
325
342
  }
326
343
 
327
344
  const result = await this.paginate({ where, include, replacements }, sorting, paging);
328
- return result;
345
+ return { list: result.list, paging: { ...result.paging, total: total || result.paging.total } };
329
346
  }
330
347
 
331
348
  // eslint-disable-next-line require-await
@@ -490,19 +507,15 @@ SELECT did,inviter,generation FROM UserTree`.trim();
490
507
  updates.sourceAppPid = null;
491
508
  }
492
509
 
493
- Object.assign(updates, await this._prepareInviteInfo(raw));
510
+ Object.assign(updates, await this._extractInviteInfo(raw));
494
511
 
495
512
  if (exist) {
496
- // immutable
497
- if (updates.sourceAppPid) {
498
- delete updates.sourceAppPid;
499
- }
500
- if (updates.inviter) {
501
- delete updates.inviter;
502
- delete updates.generation;
503
- }
504
- // 登录不再更新 locale
513
+ // immutable fields
505
514
  delete updates.locale;
515
+ delete updates.sourceAppPid;
516
+ delete updates.inviter;
517
+ delete updates.generation;
518
+
506
519
  // update user, connectedAccount, passport
507
520
  updates.connectedAccounts = updateConnectedAccount(exist.connectedAccounts, user.connectedAccount);
508
521
  updated = await this.updateUser(exist.did, updates);
@@ -520,18 +533,25 @@ SELECT did,inviter,generation FROM UserTree`.trim();
520
533
  return { ...updated, _action: exist ? 'update' : 'add' };
521
534
  }
522
535
 
523
- async _prepareInviteInfo(raw) {
536
+ async _extractInviteInfo(raw) {
524
537
  const info = {};
525
538
 
526
- // set inviter and generation
527
539
  if (raw.inviter) {
528
540
  // sybil-attack
529
541
  if (isValid(raw.inviter)) {
530
542
  const inviterId = toAddress(raw.inviter);
531
543
  const inviter = await this.model.findByPk(inviterId, { attributes: ['did', 'generation'] });
532
544
  if (inviter) {
533
- info.inviter = inviterId;
534
- info.generation = inviter.generation + 1;
545
+ // circle preventing
546
+ const { list: ancestors } = await this.getUsers({ query: { invitee: inviterId } });
547
+ const hasCircle = ancestors.some((x) => x.did === raw.did);
548
+ if (hasCircle) {
549
+ logger.warn('Set inviter result in cycle is not allowed', raw);
550
+ info.inviter = null;
551
+ } else {
552
+ info.inviter = inviterId;
553
+ info.generation = inviter.generation + 1;
554
+ }
535
555
  } else {
536
556
  logger.warn('Set inviter to non-exist user is not allowed', raw);
537
557
  }
@@ -357,9 +357,13 @@ const setupAppOwner = async ({ node, sessionId, justCreate = false, context }) =
357
357
  };
358
358
  };
359
359
 
360
- const getLauncherSession = async ({ launcherUrl, launcherSessionId, external = true }) => {
360
+ const getLauncherSession = async ({ launcherUrl, launcherSessionId, external = true }, context) => {
361
361
  const info = await states.node.read();
362
- const result = await getLauncherSessionRaw(info.sk, { launcherUrl, launcherSessionId });
362
+ const result = await getLauncherSessionRaw(info.sk, {
363
+ launcherUrl,
364
+ launcherSessionId,
365
+ locale: context?.query?.locale,
366
+ });
363
367
 
364
368
  // strip sensitive data if call from external
365
369
  if (external && result.launcherSession) {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.31-beta-4246ab25",
6
+ "version": "1.16.31-beta-a0cc72cf",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,19 +19,19 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "Apache-2.0",
21
21
  "dependencies": {
22
- "@abtnode/analytics": "1.16.31-beta-4246ab25",
23
- "@abtnode/auth": "1.16.31-beta-4246ab25",
24
- "@abtnode/certificate-manager": "1.16.31-beta-4246ab25",
25
- "@abtnode/constant": "1.16.31-beta-4246ab25",
26
- "@abtnode/cron": "1.16.31-beta-4246ab25",
27
- "@abtnode/logger": "1.16.31-beta-4246ab25",
28
- "@abtnode/models": "1.16.31-beta-4246ab25",
29
- "@abtnode/queue": "1.16.31-beta-4246ab25",
30
- "@abtnode/rbac": "1.16.31-beta-4246ab25",
31
- "@abtnode/router-provider": "1.16.31-beta-4246ab25",
32
- "@abtnode/static-server": "1.16.31-beta-4246ab25",
33
- "@abtnode/timemachine": "1.16.31-beta-4246ab25",
34
- "@abtnode/util": "1.16.31-beta-4246ab25",
22
+ "@abtnode/analytics": "1.16.31-beta-a0cc72cf",
23
+ "@abtnode/auth": "1.16.31-beta-a0cc72cf",
24
+ "@abtnode/certificate-manager": "1.16.31-beta-a0cc72cf",
25
+ "@abtnode/constant": "1.16.31-beta-a0cc72cf",
26
+ "@abtnode/cron": "1.16.31-beta-a0cc72cf",
27
+ "@abtnode/logger": "1.16.31-beta-a0cc72cf",
28
+ "@abtnode/models": "1.16.31-beta-a0cc72cf",
29
+ "@abtnode/queue": "1.16.31-beta-a0cc72cf",
30
+ "@abtnode/rbac": "1.16.31-beta-a0cc72cf",
31
+ "@abtnode/router-provider": "1.16.31-beta-a0cc72cf",
32
+ "@abtnode/static-server": "1.16.31-beta-a0cc72cf",
33
+ "@abtnode/timemachine": "1.16.31-beta-a0cc72cf",
34
+ "@abtnode/util": "1.16.31-beta-a0cc72cf",
35
35
  "@arcblock/did": "1.18.135",
36
36
  "@arcblock/did-auth": "1.18.135",
37
37
  "@arcblock/did-ext": "^1.18.135",
@@ -42,12 +42,12 @@
42
42
  "@arcblock/pm2-events": "^0.0.5",
43
43
  "@arcblock/validator": "^1.18.135",
44
44
  "@arcblock/vc": "1.18.135",
45
- "@blocklet/constant": "1.16.31-beta-4246ab25",
46
- "@blocklet/env": "1.16.31-beta-4246ab25",
47
- "@blocklet/meta": "1.16.31-beta-4246ab25",
48
- "@blocklet/resolver": "1.16.31-beta-4246ab25",
49
- "@blocklet/sdk": "1.16.31-beta-4246ab25",
50
- "@blocklet/store": "1.16.31-beta-4246ab25",
45
+ "@blocklet/constant": "1.16.31-beta-a0cc72cf",
46
+ "@blocklet/env": "1.16.31-beta-a0cc72cf",
47
+ "@blocklet/meta": "1.16.31-beta-a0cc72cf",
48
+ "@blocklet/resolver": "1.16.31-beta-a0cc72cf",
49
+ "@blocklet/sdk": "1.16.31-beta-a0cc72cf",
50
+ "@blocklet/store": "1.16.31-beta-a0cc72cf",
51
51
  "@did-space/client": "^0.5.31",
52
52
  "@fidm/x509": "^1.2.1",
53
53
  "@ocap/mcrypto": "1.18.135",
@@ -103,5 +103,5 @@
103
103
  "jest": "^29.7.0",
104
104
  "unzipper": "^0.10.11"
105
105
  },
106
- "gitHead": "ef93705b89033e4cd5fed458b64521d0a994a1d0"
106
+ "gitHead": "d1eec814979a4086fc5efd7c719687b76c972ec6"
107
107
  }