@abtnode/core 1.16.6-beta-4ea1eb90 → 1.16.6-beta-7c9b42cc
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/lib/api/team.js +38 -2
- package/lib/blocklet/manager/disk.js +15 -21
- package/lib/index.js +1 -0
- package/lib/router/helper.js +4 -7
- package/lib/states/user.js +237 -8
- package/lib/util/blocklet.js +28 -10
- package/lib/validators/user.js +44 -0
- package/package.json +28 -27
package/lib/api/team.js
CHANGED
|
@@ -110,6 +110,42 @@ class TeamAPI extends EventEmitter {
|
|
|
110
110
|
|
|
111
111
|
// User && Invitation
|
|
112
112
|
|
|
113
|
+
async loginUser({ teamDid, user }) {
|
|
114
|
+
const state = await this.getUserState(teamDid);
|
|
115
|
+
const nodeInfo = await this.node.read();
|
|
116
|
+
|
|
117
|
+
if (user.role === ROLES.OWNER) {
|
|
118
|
+
if (teamDid !== nodeInfo.did) {
|
|
119
|
+
throw new Error('Cannot add user of owner role');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (await state.count({ role: ROLES.OWNER })) {
|
|
123
|
+
throw new Error('The owner already exists');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const { _action, ...doc } = await state.login(user);
|
|
128
|
+
if (_action === 'update') {
|
|
129
|
+
logger.info('user updated successfully', { teamDid, userDid: user.did });
|
|
130
|
+
this.emit(EVENTS.USER_UPDATED, { teamDid, user: doc });
|
|
131
|
+
} else if (_action === 'add') {
|
|
132
|
+
if (teamDid === nodeInfo.did && nodeInfo.nodeOwner && user.did !== nodeInfo.nodeOwner.did) {
|
|
133
|
+
await this.notification.create({
|
|
134
|
+
title: 'New member join',
|
|
135
|
+
description: `User with Name (${user.fullName}) and DID (${user.did}) has joined this server`,
|
|
136
|
+
entityType: 'node',
|
|
137
|
+
action: '/team/members',
|
|
138
|
+
entityId: user.did,
|
|
139
|
+
severity: 'success',
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
logger.info('user added successfully', { teamDid, userDid: user.did, userPk: user.pk, userName: user.fullName });
|
|
144
|
+
this.emit(EVENTS.USER_ADDED, { teamDid, user: doc });
|
|
145
|
+
}
|
|
146
|
+
return doc;
|
|
147
|
+
}
|
|
148
|
+
|
|
113
149
|
async addUser({ teamDid, user }) {
|
|
114
150
|
const state = await this.getUserState(teamDid);
|
|
115
151
|
|
|
@@ -239,10 +275,10 @@ class TeamAPI extends EventEmitter {
|
|
|
239
275
|
return res;
|
|
240
276
|
}
|
|
241
277
|
|
|
242
|
-
async getUser({ teamDid, user }) {
|
|
278
|
+
async getUser({ teamDid, user, options = {} }) {
|
|
243
279
|
const state = await this.getUserState(teamDid);
|
|
244
280
|
|
|
245
|
-
return state.getUser(user.did);
|
|
281
|
+
return state.getUser(user.did, options);
|
|
246
282
|
}
|
|
247
283
|
|
|
248
284
|
async getOwner({ teamDid }) {
|
|
@@ -103,6 +103,7 @@ const {
|
|
|
103
103
|
getBlockletKnownAs,
|
|
104
104
|
updateBlockletFallbackLogo,
|
|
105
105
|
ensureAppLogo,
|
|
106
|
+
getBlockletDidDomainList,
|
|
106
107
|
} = require('../../util/blocklet');
|
|
107
108
|
const states = require('../../states');
|
|
108
109
|
const BaseBlockletManager = require('./base');
|
|
@@ -110,7 +111,6 @@ const { get: getEngine } = require('./engine');
|
|
|
110
111
|
const blockletPm2Events = require('./pm2-events');
|
|
111
112
|
const runMigrationScripts = require('../migration');
|
|
112
113
|
const hooks = require('../hooks');
|
|
113
|
-
const { getDidDomainForBlocklet } = require('../../util/get-domain-for-blocklet');
|
|
114
114
|
const handleInstanceInStore = require('../../util/public-to-store');
|
|
115
115
|
const { BlockletRuntimeMonitor } = require('../../monitor/blocklet-runtime-monitor');
|
|
116
116
|
const getHistoryList = require('../../monitor/get-history-list');
|
|
@@ -1095,10 +1095,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1095
1095
|
this.emit(BlockletEvents.spaceConnected, blocklet);
|
|
1096
1096
|
}
|
|
1097
1097
|
|
|
1098
|
-
if (willAppDidChange && !skipDidDocument) {
|
|
1099
|
-
await this._updateDidDocument(blocklet);
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
1098
|
// update blocklet meta
|
|
1103
1099
|
if (blocklet.structVersion && !childDids.length) {
|
|
1104
1100
|
const changedTitle = newConfigs.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_NAME)?.value;
|
|
@@ -1124,7 +1120,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1124
1120
|
|
|
1125
1121
|
// response
|
|
1126
1122
|
const newState = await this.getBlocklet(rootDid);
|
|
1123
|
+
|
|
1124
|
+
if (willAppDidChange && !skipDidDocument) {
|
|
1125
|
+
await this._updateDidDocument(newState);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1127
1128
|
this.emit(BlockletEvents.updated, newState);
|
|
1129
|
+
|
|
1128
1130
|
return newState;
|
|
1129
1131
|
}
|
|
1130
1132
|
|
|
@@ -2276,12 +2278,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2276
2278
|
const nodeInfo = await states.node.read();
|
|
2277
2279
|
const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
2278
2280
|
didDocument
|
|
2279
|
-
.
|
|
2281
|
+
.disableBlockletDNS({ appPid: blocklet.appPid, wallet, didRegistryUrl: nodeInfo.didRegistry })
|
|
2280
2282
|
.then(() => {
|
|
2281
|
-
logger.info(`disabled blocklet ${blocklet.
|
|
2283
|
+
logger.info(`disabled blocklet ${blocklet.appPid} dns`);
|
|
2282
2284
|
})
|
|
2283
2285
|
.catch((err) => {
|
|
2284
|
-
logger.error(`disable blocklet ${blocklet.
|
|
2286
|
+
logger.error(`disable blocklet ${blocklet.appPid} dns failed`, { error: err });
|
|
2285
2287
|
});
|
|
2286
2288
|
}
|
|
2287
2289
|
|
|
@@ -2547,32 +2549,24 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2547
2549
|
async _updateDidDocument(blocklet) {
|
|
2548
2550
|
const nodeInfo = await states.node.read();
|
|
2549
2551
|
|
|
2550
|
-
const { wallet } = getBlockletInfo(
|
|
2551
|
-
{
|
|
2552
|
-
meta: blocklet.meta,
|
|
2553
|
-
environments: [BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK, BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_WALLET_TYPE]
|
|
2554
|
-
.map((key) => ({ key, value: blocklet.configObj[key] }))
|
|
2555
|
-
.filter((x) => x.value),
|
|
2556
|
-
},
|
|
2557
|
-
nodeInfo.sk
|
|
2558
|
-
);
|
|
2559
|
-
const didDomain = getDidDomainForBlocklet({ appPid: blocklet.appPid, didDomain: nodeInfo.didDomain });
|
|
2560
|
-
|
|
2561
2552
|
const domainAliases = (get(blocklet, 'site.domainAliases') || []).filter(
|
|
2562
2553
|
(item) => !item.value.endsWith(nodeInfo.didDomain) && !item.value.endsWith('did.staging.arcblock.io') // did.staging.arcblock.io 是旧 did domain, 但主要存在于比较旧的节点中, 需要做兼容
|
|
2563
2554
|
);
|
|
2564
2555
|
|
|
2565
|
-
|
|
2556
|
+
const didDomainList = getBlockletDidDomainList(blocklet, nodeInfo);
|
|
2557
|
+
domainAliases.push(...didDomainList);
|
|
2566
2558
|
|
|
2567
2559
|
// 先更新 routing rule db 中的 domain aliases, 这一步的目的是为了后面用
|
|
2568
2560
|
await states.site.updateDomainAliasList(blocklet.site.id, domainAliases);
|
|
2569
2561
|
|
|
2570
2562
|
this.emit(BlockletEvents.appDidChanged, blocklet);
|
|
2571
2563
|
|
|
2564
|
+
const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
2565
|
+
const alsoKnownAs = getBlockletKnownAs(blocklet);
|
|
2572
2566
|
await didDocument.updateBlockletDocument({
|
|
2573
2567
|
wallet,
|
|
2574
2568
|
appPid: blocklet.appPid,
|
|
2575
|
-
alsoKnownAs
|
|
2569
|
+
alsoKnownAs,
|
|
2576
2570
|
daemonDidDomain: util.getServerDidDomain(nodeInfo),
|
|
2577
2571
|
didRegistryUrl: nodeInfo.didRegistry,
|
|
2578
2572
|
domain: nodeInfo.didDomain,
|
package/lib/index.js
CHANGED
|
@@ -303,6 +303,7 @@ function ABTNode(options) {
|
|
|
303
303
|
getNodeUsers: () => teamAPI.getUsers({ teamDid: options.nodeDid }),
|
|
304
304
|
getNodeUser: (user) => teamAPI.getUser({ teamDid: options.nodeDid, user }),
|
|
305
305
|
addUser: teamAPI.addUser.bind(teamAPI),
|
|
306
|
+
loginUser: teamAPI.loginUser.bind(teamAPI),
|
|
306
307
|
removeUser: teamAPI.removeUser.bind(teamAPI),
|
|
307
308
|
updateUser: teamAPI.updateUser.bind(teamAPI),
|
|
308
309
|
updateUserApproval: teamAPI.updateUserApproval.bind(teamAPI),
|
package/lib/router/helper.js
CHANGED
|
@@ -61,13 +61,13 @@ const {
|
|
|
61
61
|
isGatewayCacheEnabled,
|
|
62
62
|
isBlockletSite,
|
|
63
63
|
} = require('../util');
|
|
64
|
-
const { getIpDnsDomainForBlocklet
|
|
64
|
+
const { getIpDnsDomainForBlocklet } = require('../util/get-domain-for-blocklet');
|
|
65
65
|
const { getFromCache: getAccessibleExternalNodeIp } = require('../util/get-accessible-external-node-ip');
|
|
66
66
|
|
|
67
67
|
const Router = require('./index');
|
|
68
68
|
const states = require('../states');
|
|
69
69
|
const { getBlockletDomainGroupName, getDidFromDomainGroupName } = require('../util/router');
|
|
70
|
-
const { getBlockletKnownAs } = require('../util/blocklet');
|
|
70
|
+
const { getBlockletKnownAs, getBlockletDidDomainList } = require('../util/blocklet');
|
|
71
71
|
|
|
72
72
|
const isServiceFeDevelopment = process.env.ABT_NODE_SERVICE_FE_PORT;
|
|
73
73
|
|
|
@@ -839,13 +839,10 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
839
839
|
});
|
|
840
840
|
|
|
841
841
|
if (!existSite) {
|
|
842
|
-
const domainAliases =
|
|
843
|
-
|
|
844
|
-
const didDomain = getDidDomainForBlocklet({ appPid: blocklet.appPid, didDomain: nodeInfo.didDomain });
|
|
845
|
-
const ipEchoDnsDomain = getIpDnsDomainForBlocklet(blocklet);
|
|
842
|
+
const domainAliases = getBlockletDidDomainList(blocklet, nodeInfo);
|
|
846
843
|
|
|
847
844
|
// let didDomain in front of ipEchoDnsDomain
|
|
848
|
-
domainAliases.push({ value:
|
|
845
|
+
domainAliases.push({ value: getIpDnsDomainForBlocklet(blocklet), isProtected: true });
|
|
849
846
|
|
|
850
847
|
await routerManager.addRoutingSite(
|
|
851
848
|
{
|
package/lib/states/user.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
const pickBy = require('lodash/pickBy');
|
|
2
2
|
const escapeStringRegexp = require('escape-string-regexp');
|
|
3
|
-
|
|
3
|
+
const pick = require('lodash/pick');
|
|
4
|
+
const cloneDeep = require('lodash/cloneDeep');
|
|
4
5
|
const logger = require('@abtnode/logger')('@abtnode/core:states:user');
|
|
5
6
|
const { isValid } = require('@arcblock/did');
|
|
6
7
|
const { PASSPORT_STATUS } = require('@abtnode/constant');
|
|
8
|
+
const { upsertToPassports } = require('@abtnode/auth/lib/passport');
|
|
9
|
+
const { fromAppDid } = require('@arcblock/did-ext');
|
|
10
|
+
const { types } = require('@arcblock/did');
|
|
11
|
+
|
|
7
12
|
const BaseState = require('./base');
|
|
8
13
|
const { validateOwner } = require('../util');
|
|
14
|
+
const { loginSchema } = require('../validators/user');
|
|
9
15
|
|
|
10
16
|
const isNullOrUndefined = (x) => x === undefined || x === null;
|
|
11
17
|
|
|
@@ -39,15 +45,25 @@ const isNullOrUndefined = (x) => x === undefined || x === null;
|
|
|
39
45
|
* WalletAccount
|
|
40
46
|
* @typedef {Object} WalletAccount
|
|
41
47
|
* @property {'wallet'} provider
|
|
42
|
-
* @property {string} did - did for
|
|
43
|
-
* @property {string} pk - pk for
|
|
48
|
+
* @property {string} did - did for wallet account
|
|
49
|
+
* @property {string} pk - pk for wallet account
|
|
50
|
+
* @property {string} lastLoginAt - Last login time new Date().toISOString()
|
|
51
|
+
* @property {string} firstLoginAt - First login time new Date().toISOString()
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* NFTAccount
|
|
56
|
+
* @typedef {Object} NFTAccount
|
|
57
|
+
* @property {'nft'} provider
|
|
58
|
+
* @property {string} did - did for nft account
|
|
59
|
+
* @property {string} owner - owner for nft account
|
|
44
60
|
* @property {string} lastLoginAt - Last login time new Date().toISOString()
|
|
45
61
|
* @property {string} firstLoginAt - First login time new Date().toISOString()
|
|
46
62
|
*/
|
|
47
63
|
|
|
48
64
|
/**
|
|
49
65
|
* ConnectedAccount
|
|
50
|
-
* @typedef {(Auth0Account|WalletAccount)} ConnectedAccount
|
|
66
|
+
* @typedef {(Auth0Account|WalletAccount|NFTAccount)} ConnectedAccount
|
|
51
67
|
*/
|
|
52
68
|
|
|
53
69
|
/**
|
|
@@ -59,7 +75,6 @@ const isNullOrUndefined = (x) => x === undefined || x === null;
|
|
|
59
75
|
* @property {string} avatar - url of user's avatar, eg: bn://avatar/7f8848569405f8cdf8b1b2788ebf7d0f.jpg
|
|
60
76
|
* @property {string} did - user's did -> 实际上变为 uid, 是不可变的;真正的 wallet-did 转移到 extraConfigs 中去了
|
|
61
77
|
* @property {string} pk - user's publicKey
|
|
62
|
-
* @property {('owner'|'admin'|'member'|'guest'|string)} role - user's role
|
|
63
78
|
* @property {UserPassport[]} passports - user's passport list
|
|
64
79
|
* @property {boolean} approved - enable user to login
|
|
65
80
|
* @property {string} locale - locale
|
|
@@ -72,8 +87,36 @@ const isNullOrUndefined = (x) => x === undefined || x === null;
|
|
|
72
87
|
* @property {string} lastLoginIp - lastLoginIp
|
|
73
88
|
* @property {Date} createdAt - createdAt
|
|
74
89
|
* @property {Date} updatedAt - updatedAt
|
|
90
|
+
* @property {('owner'|'admin'|'member'|'guest'|string)} role - user's role deprecated
|
|
75
91
|
*/
|
|
76
92
|
|
|
93
|
+
function updateConnectedAccount(connectedAccounts = [], connectedAccount = {}) {
|
|
94
|
+
const now = new Date().toISOString();
|
|
95
|
+
const filterAccounts = connectedAccounts.filter(Boolean);
|
|
96
|
+
const updated = cloneDeep(filterAccounts);
|
|
97
|
+
const updates = Array.isArray(connectedAccount) ? connectedAccount : [connectedAccount];
|
|
98
|
+
updates.filter(Boolean).forEach((x) => {
|
|
99
|
+
if (x.provider && x.did) {
|
|
100
|
+
const findAccountIndex = updated.findIndex((item) => item.provider === x.provider && item.did === x.did);
|
|
101
|
+
if (findAccountIndex > -1) {
|
|
102
|
+
updated[findAccountIndex] = {
|
|
103
|
+
...filterAccounts[findAccountIndex],
|
|
104
|
+
...x,
|
|
105
|
+
lastLoginAt: now,
|
|
106
|
+
};
|
|
107
|
+
} else {
|
|
108
|
+
updated.push({
|
|
109
|
+
...x,
|
|
110
|
+
firstLoginAt: now,
|
|
111
|
+
lastLoginAt: now,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return updated;
|
|
118
|
+
}
|
|
119
|
+
|
|
77
120
|
class User extends BaseState {
|
|
78
121
|
constructor(baseDir, config = {}) {
|
|
79
122
|
super(baseDir, { filename: 'user.db', ...config });
|
|
@@ -296,14 +339,124 @@ class User extends BaseState {
|
|
|
296
339
|
return this.find(queryParam);
|
|
297
340
|
}
|
|
298
341
|
|
|
342
|
+
/**
|
|
343
|
+
* user 版本标准化,统一将 user 转换为最新的结构,结构参考 core/state/lib/states/user.js L12-L75
|
|
344
|
+
*/
|
|
345
|
+
// 1: 没有 extraConfigs 字段
|
|
346
|
+
// 2: 有 source 和 extraConfigs 字段,oauth 账号的 extraConfigs 中包含 sourceId 和 sourceProvider 字段
|
|
347
|
+
// 3: 只有 extraConfigs 字段,且 extraConfigs.connectedAccounts 中包含 extraConfigs.sourceProvider 的 account
|
|
348
|
+
async normalize(user, { blockletSk }) {
|
|
349
|
+
if (!user) {
|
|
350
|
+
return user;
|
|
351
|
+
}
|
|
352
|
+
let version = 1;
|
|
353
|
+
if (user.extraConfigs) {
|
|
354
|
+
version = 2;
|
|
355
|
+
|
|
356
|
+
const connectedAccounts = user.extraConfigs?.connectedAccounts || [];
|
|
357
|
+
const sourceProvider = user.extraConfigs?.sourceProvider || '';
|
|
358
|
+
if (connectedAccounts.some((item) => item.provider === sourceProvider)) {
|
|
359
|
+
version = 3;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const versionMap = {
|
|
364
|
+
1: async () => {
|
|
365
|
+
const connectedAccounts = [
|
|
366
|
+
{
|
|
367
|
+
provider: 'wallet',
|
|
368
|
+
did: user.did,
|
|
369
|
+
pk: user.pk,
|
|
370
|
+
firstLoginAt: user.firstLoginAt,
|
|
371
|
+
lastLoginAt: user.lastLoginAt,
|
|
372
|
+
},
|
|
373
|
+
];
|
|
374
|
+
const sourceProvider = 'wallet';
|
|
375
|
+
const updatedUser = await this.update({
|
|
376
|
+
did: user.did,
|
|
377
|
+
pk: user.pk,
|
|
378
|
+
extraConfigs: {
|
|
379
|
+
sourceProvider,
|
|
380
|
+
connectedAccounts,
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
return updatedUser;
|
|
384
|
+
},
|
|
385
|
+
2: async () => {
|
|
386
|
+
// eslint-disable-next-line prefer-const
|
|
387
|
+
let { sourceId, sourceProvider, connectedAccounts = [] } = user.extraConfigs || {};
|
|
388
|
+
if (sourceId && sourceProvider) {
|
|
389
|
+
connectedAccounts = [
|
|
390
|
+
{
|
|
391
|
+
provider: sourceProvider,
|
|
392
|
+
id: sourceId,
|
|
393
|
+
did: user.did,
|
|
394
|
+
pk: user.pk,
|
|
395
|
+
firstLoginAt: user.firstLoginAt,
|
|
396
|
+
lastLoginAt: user.lastLoginAt,
|
|
397
|
+
},
|
|
398
|
+
];
|
|
399
|
+
} else {
|
|
400
|
+
sourceProvider = 'wallet';
|
|
401
|
+
connectedAccounts.forEach((account) => {
|
|
402
|
+
if (account.id && blockletSk) {
|
|
403
|
+
const accountWallet = fromAppDid(account.id, blockletSk, types.RoleType.ROLE_ACCOUNT);
|
|
404
|
+
account.did = accountWallet.address;
|
|
405
|
+
account.pk = accountWallet.publicKey;
|
|
406
|
+
account.firstLoginAt = account.firstLoginAt || new Date().toISOString();
|
|
407
|
+
account.lastLoginAt = account.lastLoginAt || new Date().toISOString();
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
connectedAccounts.unshift({
|
|
411
|
+
provider: 'wallet',
|
|
412
|
+
did: user.did,
|
|
413
|
+
pk: user.pk,
|
|
414
|
+
firstLoginAt: user.firstLoginAt,
|
|
415
|
+
lastLoginAt: user.lastLoginAt,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
const updatedUser = await this.update({
|
|
419
|
+
did: user.did,
|
|
420
|
+
pk: user.pk,
|
|
421
|
+
extraConfigs: {
|
|
422
|
+
sourceProvider,
|
|
423
|
+
connectedAccounts,
|
|
424
|
+
},
|
|
425
|
+
source: undefined,
|
|
426
|
+
});
|
|
427
|
+
return updatedUser;
|
|
428
|
+
},
|
|
429
|
+
3: () => {
|
|
430
|
+
return user;
|
|
431
|
+
},
|
|
432
|
+
};
|
|
433
|
+
return versionMap[version]();
|
|
434
|
+
}
|
|
435
|
+
|
|
299
436
|
/**
|
|
300
437
|
* get user by did
|
|
301
438
|
* @param {string} did user's did
|
|
302
439
|
* @returns {BlockletUser}
|
|
303
440
|
*/
|
|
304
|
-
async getUser(did) {
|
|
305
|
-
|
|
306
|
-
|
|
441
|
+
async getUser(did, { enableConnectedAccout = false, enableNormalize = false, blockletSk } = {}) {
|
|
442
|
+
let user = await this.findOne({ did });
|
|
443
|
+
if (enableConnectedAccout) {
|
|
444
|
+
if (!user) {
|
|
445
|
+
user = await this.findOne({
|
|
446
|
+
'extraConfigs.connectedAccounts.did': did,
|
|
447
|
+
});
|
|
448
|
+
} else if (user.extraConfig?.bindDid) {
|
|
449
|
+
// @deprecated 已经不存在 bindDid 字段
|
|
450
|
+
({ user } = await this.findOne({ did: user.extraConfig.bindDid }));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (enableNormalize) {
|
|
454
|
+
if (!blockletSk) {
|
|
455
|
+
throw new Error('Normalize user must provide blockletSk params');
|
|
456
|
+
}
|
|
457
|
+
return this.normalize(user, { blockletSk });
|
|
458
|
+
}
|
|
459
|
+
return user;
|
|
307
460
|
}
|
|
308
461
|
|
|
309
462
|
/**
|
|
@@ -335,6 +488,82 @@ class User extends BaseState {
|
|
|
335
488
|
|
|
336
489
|
return doc;
|
|
337
490
|
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* 用户登录
|
|
494
|
+
* @param {Object} user
|
|
495
|
+
* @param {string} user.did
|
|
496
|
+
* @param {string} user.pk
|
|
497
|
+
* @param {ConnectedAccount} user.connectedAccount
|
|
498
|
+
* @param {passport} user.passport
|
|
499
|
+
* @param {string} user.fullName - user profile's name
|
|
500
|
+
* @param {string} user.avatar - url of user's avatar, eg: bn://avatar/7f8848569405f8cdf8b1b2788ebf7d0f.jpg
|
|
501
|
+
* @param {string} user.locale - locale
|
|
502
|
+
* @param {Object} [user.extra] - extra data of user
|
|
503
|
+
* @param {string} user.lastLoginIp - lastLoginIp
|
|
504
|
+
* @param {('owner'|'admin'|'member'|'guest'|string)} user.role - deprecated user's role
|
|
505
|
+
*/
|
|
506
|
+
async login(_user) {
|
|
507
|
+
const { error, value: user } = loginSchema.validate(_user);
|
|
508
|
+
if (error) {
|
|
509
|
+
throw new Error(error);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
let updatedUser;
|
|
513
|
+
let action = '';
|
|
514
|
+
const now = new Date().toISOString();
|
|
515
|
+
const oldUser = await this.getUser(user.did, {
|
|
516
|
+
enableConnectedAccout: true,
|
|
517
|
+
});
|
|
518
|
+
const cloneData = cloneDeep(user);
|
|
519
|
+
const passports = upsertToPassports(
|
|
520
|
+
oldUser?.passports || [],
|
|
521
|
+
cloneData.passport && {
|
|
522
|
+
...cloneData.passport,
|
|
523
|
+
lastLoginAt: now,
|
|
524
|
+
}
|
|
525
|
+
);
|
|
526
|
+
const mergeData = {
|
|
527
|
+
...pick(cloneData, ['type', 'fullName', 'email', 'avatar', 'role', 'locale', 'extra', 'lastLoginIp', 'remark']),
|
|
528
|
+
did: user.did,
|
|
529
|
+
pk: user.pk,
|
|
530
|
+
passports,
|
|
531
|
+
lastLoginAt: now,
|
|
532
|
+
extraConfigs: {
|
|
533
|
+
sourceProvider: 'wallet',
|
|
534
|
+
connectedAccounts: [],
|
|
535
|
+
},
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
if (oldUser) {
|
|
539
|
+
// update
|
|
540
|
+
action = 'update';
|
|
541
|
+
const extraConfigs = {
|
|
542
|
+
sourceProvider: oldUser?.extraConfigs?.sourceProvider || 'wallet',
|
|
543
|
+
connectedAccounts: updateConnectedAccount(
|
|
544
|
+
oldUser?.extraConfigs?.connectedAccounts || [],
|
|
545
|
+
cloneData.connectedAccount
|
|
546
|
+
),
|
|
547
|
+
};
|
|
548
|
+
mergeData.extraConfigs = extraConfigs;
|
|
549
|
+
updatedUser = await this.update(mergeData);
|
|
550
|
+
} else {
|
|
551
|
+
// insert
|
|
552
|
+
action = 'add';
|
|
553
|
+
mergeData.firstLoginAt = now;
|
|
554
|
+
mergeData.approved = true;
|
|
555
|
+
const connectedAccount = Array.isArray(cloneData.connectedAccount)
|
|
556
|
+
? cloneData.connectedAccount.filter(Boolean)[0]
|
|
557
|
+
: cloneData.connectedAccount;
|
|
558
|
+
|
|
559
|
+
mergeData.extraConfigs = {
|
|
560
|
+
sourceProvider: connectedAccount.provider,
|
|
561
|
+
connectedAccounts: updateConnectedAccount([], cloneData.connectedAccount),
|
|
562
|
+
};
|
|
563
|
+
updatedUser = await this.add(mergeData);
|
|
564
|
+
}
|
|
565
|
+
return { ...updatedUser, _action: action };
|
|
566
|
+
}
|
|
338
567
|
}
|
|
339
568
|
|
|
340
569
|
module.exports = User;
|
package/lib/util/blocklet.js
CHANGED
|
@@ -8,6 +8,8 @@ const os = require('os');
|
|
|
8
8
|
const pRetry = require('p-retry');
|
|
9
9
|
const tar = require('tar');
|
|
10
10
|
const get = require('lodash/get');
|
|
11
|
+
const uniq = require('lodash/uniq');
|
|
12
|
+
const toLower = require('lodash/toLower');
|
|
11
13
|
const isEmpty = require('lodash/isEmpty');
|
|
12
14
|
const streamToPromise = require('stream-to-promise');
|
|
13
15
|
const { Throttle } = require('stream-throttle');
|
|
@@ -21,7 +23,7 @@ const { stableStringify } = require('@arcblock/vc');
|
|
|
21
23
|
const { chainInfo: chainInfoSchema } = require('@arcblock/did-auth/lib/schema');
|
|
22
24
|
|
|
23
25
|
const { fromSecretKey } = require('@ocap/wallet');
|
|
24
|
-
const { toHex, toBase58, isHex, toDid } = require('@ocap/util');
|
|
26
|
+
const { toHex, toBase58, isHex, toDid, toAddress } = require('@ocap/util');
|
|
25
27
|
const { isValid: isValidDid, isEthereumDid } = require('@arcblock/did');
|
|
26
28
|
const logger = require('@abtnode/logger')('@abtnode/core:util:blocklet');
|
|
27
29
|
const pm2 = require('@abtnode/util/lib/async-pm2');
|
|
@@ -296,19 +298,19 @@ const getAppSystemEnvironments = (blocklet, nodeInfo) => {
|
|
|
296
298
|
* 2. 如果没有,再拼接
|
|
297
299
|
*/
|
|
298
300
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
+
const pidDomain = getDidDomainForBlocklet({ appPid, didDomain: nodeInfo.didDomain });
|
|
301
302
|
const domainAliases = get(blocklet, 'site.domainAliases') || [];
|
|
302
|
-
const didDomainAlias = domainAliases.find(
|
|
303
|
-
(item) => item.value.endsWith(nodeInfo.didDomain) || item.value.endsWith('did.staging.arcblock.io') // did.staging.arcblock.io 是旧 did domain, 但主要存在于比较旧的节点中, 需要做兼容
|
|
304
|
-
);
|
|
305
303
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
304
|
+
let didDomain = domainAliases.find((item) => toLower(item.value) === toLower(pidDomain));
|
|
305
|
+
|
|
306
|
+
if (!didDomain) {
|
|
307
|
+
didDomain = domainAliases.find(
|
|
308
|
+
(item) => item.value.endsWith(nodeInfo.didDomain) || item.value.endsWith('did.staging.arcblock.io') // did.staging.arcblock.io 是旧 did domain, 但主要存在于比较旧的节点中, 需要做兼容
|
|
309
|
+
);
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
+
const appUrl = didDomain ? prettyURL(didDomain.value, true) : `https://${pidDomain}`;
|
|
313
|
+
|
|
312
314
|
return {
|
|
313
315
|
BLOCKLET_DID: did, // BLOCKLET_DID is always same as BLOCKLET_APP_PID in structV2 application
|
|
314
316
|
BLOCKLET_APP_SK: appSk,
|
|
@@ -1922,6 +1924,21 @@ const ensureAppLogo = async (blocklet, blockletsDir) => {
|
|
|
1922
1924
|
}
|
|
1923
1925
|
};
|
|
1924
1926
|
|
|
1927
|
+
const getBlockletDidDomainList = (blocklet, nodeInfo) => {
|
|
1928
|
+
const domainAliases = [];
|
|
1929
|
+
const alsoKnownAs = getBlockletKnownAs(blocklet);
|
|
1930
|
+
|
|
1931
|
+
const dids = [blocklet.appPid, blocklet.appDid, ...alsoKnownAs].filter(Boolean).map((did) => toAddress(did));
|
|
1932
|
+
|
|
1933
|
+
uniq(dids).forEach((did) => {
|
|
1934
|
+
const domain = getDidDomainForBlocklet({ appPid: did, didDomain: nodeInfo.didDomain });
|
|
1935
|
+
|
|
1936
|
+
domainAliases.push({ value: domain, isProtected: true });
|
|
1937
|
+
});
|
|
1938
|
+
|
|
1939
|
+
return domainAliases;
|
|
1940
|
+
};
|
|
1941
|
+
|
|
1925
1942
|
module.exports = {
|
|
1926
1943
|
updateBlockletFallbackLogo,
|
|
1927
1944
|
consumeServerlessNFT,
|
|
@@ -1980,4 +1997,5 @@ module.exports = {
|
|
|
1980
1997
|
getBlockletKnownAs,
|
|
1981
1998
|
getFixedBundleSource,
|
|
1982
1999
|
ensureAppLogo,
|
|
2000
|
+
getBlockletDidDomainList,
|
|
1983
2001
|
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const JOI = require('joi');
|
|
2
|
+
const { didExtension } = require('@blocklet/meta/lib/extension');
|
|
3
|
+
|
|
4
|
+
const Joi = JOI.extend(didExtension);
|
|
5
|
+
|
|
6
|
+
// TODO: @zhanghan 这里目前仅包含必填的字段,后续需要增加其他字段
|
|
7
|
+
const passportSchema = Joi.object({
|
|
8
|
+
id: Joi.string().required(),
|
|
9
|
+
role: Joi.string().required(),
|
|
10
|
+
name: Joi.string().required(),
|
|
11
|
+
})
|
|
12
|
+
.unknown()
|
|
13
|
+
.empty(null);
|
|
14
|
+
|
|
15
|
+
// TODO: @zhanghan 这里目前仅包含必填的字段,后续需要增加其他字段
|
|
16
|
+
const connectedAccountSchema = Joi.object({
|
|
17
|
+
provider: Joi.string().required(),
|
|
18
|
+
did: Joi.DID().trim().required(),
|
|
19
|
+
pk: Joi.string().optional(),
|
|
20
|
+
id: Joi.string().optional(),
|
|
21
|
+
firstLoginAt: Joi.string().optional(),
|
|
22
|
+
lastLoginAt: Joi.string().optional(),
|
|
23
|
+
})
|
|
24
|
+
.unknown()
|
|
25
|
+
.empty(null);
|
|
26
|
+
|
|
27
|
+
const loginSchema = Joi.object({
|
|
28
|
+
did: Joi.DID().trim().required(),
|
|
29
|
+
pk: Joi.string().required(),
|
|
30
|
+
fullName: Joi.string().empty(''),
|
|
31
|
+
avatar: Joi.string().empty(''),
|
|
32
|
+
email: Joi.string().empty(''),
|
|
33
|
+
role: Joi.string().empty(''),
|
|
34
|
+
locale: Joi.string().empty(''),
|
|
35
|
+
extra: Joi.object(),
|
|
36
|
+
remark: Joi.string().empty(''),
|
|
37
|
+
lastLoginIp: Joi.string().empty(''),
|
|
38
|
+
passport: passportSchema.optional(),
|
|
39
|
+
connectedAccount: Joi.alternatives()
|
|
40
|
+
.try(connectedAccountSchema.required(), Joi.array().items(connectedAccountSchema).min(1).sparse(true))
|
|
41
|
+
.required(),
|
|
42
|
+
}).unknown();
|
|
43
|
+
|
|
44
|
+
exports.loginSchema = loginSchema;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.6-beta-
|
|
6
|
+
"version": "1.16.6-beta-7c9b42cc",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,35 +19,36 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/auth": "1.16.6-beta-
|
|
23
|
-
"@abtnode/certificate-manager": "1.16.6-beta-
|
|
24
|
-
"@abtnode/constant": "1.16.6-beta-
|
|
25
|
-
"@abtnode/cron": "1.16.6-beta-
|
|
26
|
-
"@abtnode/db": "1.16.6-beta-
|
|
27
|
-
"@abtnode/logger": "1.16.6-beta-
|
|
28
|
-
"@abtnode/queue": "1.16.6-beta-
|
|
29
|
-
"@abtnode/rbac": "1.16.6-beta-
|
|
30
|
-
"@abtnode/router-provider": "1.16.6-beta-
|
|
31
|
-
"@abtnode/static-server": "1.16.6-beta-
|
|
32
|
-
"@abtnode/timemachine": "1.16.6-beta-
|
|
33
|
-
"@abtnode/util": "1.16.6-beta-
|
|
34
|
-
"@arcblock/did": "1.18.
|
|
35
|
-
"@arcblock/did-auth": "1.18.
|
|
22
|
+
"@abtnode/auth": "1.16.6-beta-7c9b42cc",
|
|
23
|
+
"@abtnode/certificate-manager": "1.16.6-beta-7c9b42cc",
|
|
24
|
+
"@abtnode/constant": "1.16.6-beta-7c9b42cc",
|
|
25
|
+
"@abtnode/cron": "1.16.6-beta-7c9b42cc",
|
|
26
|
+
"@abtnode/db": "1.16.6-beta-7c9b42cc",
|
|
27
|
+
"@abtnode/logger": "1.16.6-beta-7c9b42cc",
|
|
28
|
+
"@abtnode/queue": "1.16.6-beta-7c9b42cc",
|
|
29
|
+
"@abtnode/rbac": "1.16.6-beta-7c9b42cc",
|
|
30
|
+
"@abtnode/router-provider": "1.16.6-beta-7c9b42cc",
|
|
31
|
+
"@abtnode/static-server": "1.16.6-beta-7c9b42cc",
|
|
32
|
+
"@abtnode/timemachine": "1.16.6-beta-7c9b42cc",
|
|
33
|
+
"@abtnode/util": "1.16.6-beta-7c9b42cc",
|
|
34
|
+
"@arcblock/did": "1.18.75",
|
|
35
|
+
"@arcblock/did-auth": "1.18.75",
|
|
36
|
+
"@arcblock/did-ext": "^1.18.75",
|
|
36
37
|
"@arcblock/did-motif": "^1.1.10",
|
|
37
|
-
"@arcblock/did-util": "1.18.
|
|
38
|
-
"@arcblock/event-hub": "1.18.
|
|
39
|
-
"@arcblock/jwt": "^1.18.
|
|
38
|
+
"@arcblock/did-util": "1.18.75",
|
|
39
|
+
"@arcblock/event-hub": "1.18.75",
|
|
40
|
+
"@arcblock/jwt": "^1.18.75",
|
|
40
41
|
"@arcblock/pm2-events": "^0.0.5",
|
|
41
|
-
"@arcblock/vc": "1.18.
|
|
42
|
-
"@blocklet/constant": "1.16.6-beta-
|
|
43
|
-
"@blocklet/meta": "1.16.6-beta-
|
|
44
|
-
"@blocklet/sdk": "1.16.6-beta-
|
|
42
|
+
"@arcblock/vc": "1.18.75",
|
|
43
|
+
"@blocklet/constant": "1.16.6-beta-7c9b42cc",
|
|
44
|
+
"@blocklet/meta": "1.16.6-beta-7c9b42cc",
|
|
45
|
+
"@blocklet/sdk": "1.16.6-beta-7c9b42cc",
|
|
45
46
|
"@did-space/client": "^0.2.80",
|
|
46
47
|
"@fidm/x509": "^1.2.1",
|
|
47
|
-
"@ocap/client": "1.18.
|
|
48
|
-
"@ocap/mcrypto": "1.18.
|
|
49
|
-
"@ocap/util": "1.18.
|
|
50
|
-
"@ocap/wallet": "1.18.
|
|
48
|
+
"@ocap/client": "1.18.75",
|
|
49
|
+
"@ocap/mcrypto": "1.18.75",
|
|
50
|
+
"@ocap/util": "1.18.75",
|
|
51
|
+
"@ocap/wallet": "1.18.75",
|
|
51
52
|
"@slack/webhook": "^5.0.4",
|
|
52
53
|
"archiver": "^5.3.1",
|
|
53
54
|
"axios": "^0.27.2",
|
|
@@ -97,5 +98,5 @@
|
|
|
97
98
|
"express": "^4.18.2",
|
|
98
99
|
"jest": "^27.5.1"
|
|
99
100
|
},
|
|
100
|
-
"gitHead": "
|
|
101
|
+
"gitHead": "113a82e948a779a050f1b06f5667c43c96315054"
|
|
101
102
|
}
|