@abtnode/core 1.16.17-beta-3232a7af → 1.16.17-beta-703fb879
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 +187 -12
- package/lib/blocklet/manager/disk.js +79 -70
- package/lib/event/auto-backup-handler.js +4 -2
- package/lib/index.js +9 -0
- package/lib/states/blocklet.js +5 -5
- package/lib/states/user-session.js +8 -0
- package/lib/states/user.js +10 -0
- package/lib/team/manager.js +9 -1
- package/lib/util/blocklet.js +3 -0
- package/lib/util/federated.js +24 -0
- package/lib/util/router.js +2 -2
- package/lib/util/spaces.js +10 -0
- package/lib/validators/role.js +28 -6
- package/package.json +20 -20
package/lib/api/team.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const { EventEmitter } = require('events');
|
|
2
2
|
const pick = require('lodash/pick');
|
|
3
|
+
const defaults = require('lodash/defaults');
|
|
4
|
+
const cloneDeep = require('lodash/cloneDeep');
|
|
3
5
|
const joinUrl = require('url-join');
|
|
4
6
|
|
|
5
7
|
const logger = require('@abtnode/logger')('@abtnode/core:api:team');
|
|
@@ -40,6 +42,7 @@ const { validateCreatePermission, validateUpdatePermission } = require('../valid
|
|
|
40
42
|
const { getBlocklet } = require('../util/blocklet');
|
|
41
43
|
const StoreUtil = require('../util/store');
|
|
42
44
|
const { profileSchema } = require('../validators/user');
|
|
45
|
+
const { callFederated } = require('../util/federated');
|
|
43
46
|
|
|
44
47
|
const sanitizeUrl = (url) => {
|
|
45
48
|
if (!url) {
|
|
@@ -1000,6 +1003,7 @@ class TeamAPI extends EventEmitter {
|
|
|
1000
1003
|
async getPassportIssuance({ teamDid, sessionId }) {
|
|
1001
1004
|
const state = await this.getSessionState(teamDid);
|
|
1002
1005
|
const doc = await state.read(sessionId);
|
|
1006
|
+
// FIXME: @zhanghan 指定被邀请者的邀请需要查询被邀请者的详细信息
|
|
1003
1007
|
return doc;
|
|
1004
1008
|
}
|
|
1005
1009
|
|
|
@@ -1096,10 +1100,28 @@ class TeamAPI extends EventEmitter {
|
|
|
1096
1100
|
return this.teamManager.getRoles(teamDid);
|
|
1097
1101
|
}
|
|
1098
1102
|
|
|
1099
|
-
async
|
|
1100
|
-
|
|
1103
|
+
async getRole({ teamDid, role: { name } = {} }) {
|
|
1104
|
+
if (!name) {
|
|
1105
|
+
throw new Error('role name is invalid');
|
|
1106
|
+
}
|
|
1107
|
+
const rbac = await this.getRBAC(teamDid);
|
|
1108
|
+
const role = await rbac.getRole(name);
|
|
1109
|
+
return role ? pick(role, ['name', 'grants', 'title', 'description', 'extra']) : null;
|
|
1110
|
+
}
|
|
1101
1111
|
|
|
1102
|
-
|
|
1112
|
+
async createRole({ teamDid, name, description, title, childName, permissions = [], extra: raw }) {
|
|
1113
|
+
logger.info('create role', { teamDid, name, description, childName, permissions, raw });
|
|
1114
|
+
const attrs = { name, title, description, childName, permissions };
|
|
1115
|
+
|
|
1116
|
+
if (raw) {
|
|
1117
|
+
try {
|
|
1118
|
+
attrs.extra = JSON.parse(raw);
|
|
1119
|
+
} catch (err) {
|
|
1120
|
+
throw new Error('extra should be a valid json string');
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
await validateCreateRole(pick(attrs, ['name', 'title', 'description', 'extra']));
|
|
1103
1125
|
|
|
1104
1126
|
validateReservedRole(name);
|
|
1105
1127
|
|
|
@@ -1107,8 +1129,8 @@ class TeamAPI extends EventEmitter {
|
|
|
1107
1129
|
|
|
1108
1130
|
let role;
|
|
1109
1131
|
try {
|
|
1110
|
-
role = await rbac.createRole(
|
|
1111
|
-
return pick(role, ['name', '
|
|
1132
|
+
role = await rbac.createRole(attrs);
|
|
1133
|
+
return pick(role, ['name', 'title', 'grants', 'description', 'extra']);
|
|
1112
1134
|
} catch (err) {
|
|
1113
1135
|
if (new RegExp(`Item ${name} already exists`).test(err.message)) {
|
|
1114
1136
|
throw new Error(`Id ${name} already exists`);
|
|
@@ -1117,16 +1139,23 @@ class TeamAPI extends EventEmitter {
|
|
|
1117
1139
|
}
|
|
1118
1140
|
}
|
|
1119
1141
|
|
|
1120
|
-
async updateRole({ teamDid, role: { name, title, description } = {} }) {
|
|
1121
|
-
logger.info('update role', { teamDid, name, title, description });
|
|
1142
|
+
async updateRole({ teamDid, role: { name, title, description, extra: raw } = {} }) {
|
|
1143
|
+
logger.info('update role', { teamDid, name, title, description, raw });
|
|
1122
1144
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
const rbac = await this.getRBAC(teamDid);
|
|
1145
|
+
const attrs = { name, title, description };
|
|
1126
1146
|
|
|
1127
|
-
|
|
1147
|
+
if (raw) {
|
|
1148
|
+
try {
|
|
1149
|
+
attrs.extra = JSON.parse(raw);
|
|
1150
|
+
} catch (err) {
|
|
1151
|
+
throw new Error('extra should be a valid json string');
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1128
1154
|
|
|
1129
|
-
|
|
1155
|
+
await validateUpdateRole(attrs);
|
|
1156
|
+
const rbac = await this.getRBAC(teamDid);
|
|
1157
|
+
const state = await rbac.updateRole(attrs);
|
|
1158
|
+
return pick(state, ['name', 'title', 'grants', 'description', 'extra']);
|
|
1130
1159
|
}
|
|
1131
1160
|
|
|
1132
1161
|
async getPermissions({ teamDid }) {
|
|
@@ -1315,6 +1344,10 @@ class TeamAPI extends EventEmitter {
|
|
|
1315
1344
|
return this.teamManager.getUserState(did);
|
|
1316
1345
|
}
|
|
1317
1346
|
|
|
1347
|
+
getUserSessionState(did) {
|
|
1348
|
+
return this.teamManager.getUserSessionState(did);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1318
1351
|
getTagState(did) {
|
|
1319
1352
|
return this.teamManager.getTagState(did);
|
|
1320
1353
|
}
|
|
@@ -1329,6 +1362,148 @@ class TeamAPI extends EventEmitter {
|
|
|
1329
1362
|
setInviteExpireTime(ms) {
|
|
1330
1363
|
this.memberInviteExpireTime = ms;
|
|
1331
1364
|
}
|
|
1365
|
+
|
|
1366
|
+
// user-session management
|
|
1367
|
+
async getUserSession({ teamDid, userDid, visitorId }) {
|
|
1368
|
+
const state = await this.getUserSessionState(teamDid);
|
|
1369
|
+
const userState = await this.getUserState(teamDid);
|
|
1370
|
+
|
|
1371
|
+
const where = {
|
|
1372
|
+
status: 'online',
|
|
1373
|
+
};
|
|
1374
|
+
if (userDid) where.userDid = userDid;
|
|
1375
|
+
if (visitorId) where.visitorId = visitorId;
|
|
1376
|
+
|
|
1377
|
+
const userSessions = await state.model.findAll({
|
|
1378
|
+
where,
|
|
1379
|
+
attributes: ['id', 'appPid', 'userDid', 'visitorId', 'passportId'],
|
|
1380
|
+
include: {
|
|
1381
|
+
model: userState.model,
|
|
1382
|
+
as: 'user',
|
|
1383
|
+
attributes: ['did', 'sourceProvider', 'fullName', 'email', 'avatar', 'remark', 'sourceAppPid'],
|
|
1384
|
+
},
|
|
1385
|
+
});
|
|
1386
|
+
return userSessions.map((x) => x.toJSON());
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
async getPassportById({ teamDid, passportId }) {
|
|
1390
|
+
const userState = await this.getUserState(teamDid);
|
|
1391
|
+
const passport = await userState.getPassportById(passportId);
|
|
1392
|
+
return passport;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
async getPassportFromFederated({ site, passportId, teamDid }) {
|
|
1396
|
+
const blocklet = await getBlocklet({ did: teamDid, states: this.states, dataDirs: this.dataDirs });
|
|
1397
|
+
const nodeInfo = await this.node.read();
|
|
1398
|
+
const { permanentWallet } = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
1399
|
+
|
|
1400
|
+
const result = await callFederated({
|
|
1401
|
+
action: 'getPassport',
|
|
1402
|
+
data: {
|
|
1403
|
+
passportId,
|
|
1404
|
+
},
|
|
1405
|
+
permanentWallet,
|
|
1406
|
+
site,
|
|
1407
|
+
});
|
|
1408
|
+
|
|
1409
|
+
return result;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
async upsertUserSession({ teamDid, appPid, userDid, visitorId, ua, lastLoginIp, sourceAppPid, passportId, status }) {
|
|
1413
|
+
if (!userDid) {
|
|
1414
|
+
throw new Error('userDid are required');
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
const state = await this.getUserSessionState(teamDid);
|
|
1418
|
+
let data;
|
|
1419
|
+
if (!visitorId) {
|
|
1420
|
+
data = await state.insert({
|
|
1421
|
+
userDid,
|
|
1422
|
+
ua,
|
|
1423
|
+
lastLoginIp,
|
|
1424
|
+
appPid,
|
|
1425
|
+
passportId,
|
|
1426
|
+
});
|
|
1427
|
+
} else {
|
|
1428
|
+
const exist = await state.findOne({ userDid, visitorId, appPid });
|
|
1429
|
+
if (exist) {
|
|
1430
|
+
[, [data]] = await state.update(exist.id, { ua, lastLoginIp, passportId, status });
|
|
1431
|
+
} else {
|
|
1432
|
+
data = await state.insert({
|
|
1433
|
+
visitorId,
|
|
1434
|
+
userDid,
|
|
1435
|
+
ua,
|
|
1436
|
+
lastLoginIp,
|
|
1437
|
+
appPid,
|
|
1438
|
+
passportId,
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
if (sourceAppPid) {
|
|
1444
|
+
const blocklet = await getBlocklet({ did: teamDid, states: this.states, dataDirs: this.dataDirs });
|
|
1445
|
+
const nodeInfo = await this.node.read();
|
|
1446
|
+
const { permanentWallet } = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
1447
|
+
const federated = defaults(cloneDeep(blocklet.settings.federated || {}), {
|
|
1448
|
+
config: {},
|
|
1449
|
+
sites: [],
|
|
1450
|
+
});
|
|
1451
|
+
const masterSite = federated.sites[0];
|
|
1452
|
+
if (masterSite && masterSite.isMaster !== false && masterSite.appPid === sourceAppPid) {
|
|
1453
|
+
await callFederated({
|
|
1454
|
+
action: 'sync',
|
|
1455
|
+
permanentWallet,
|
|
1456
|
+
site: masterSite,
|
|
1457
|
+
data: {
|
|
1458
|
+
userSessions: [
|
|
1459
|
+
{
|
|
1460
|
+
action: 'login',
|
|
1461
|
+
userDid,
|
|
1462
|
+
visitorId: data.visitorId,
|
|
1463
|
+
ua,
|
|
1464
|
+
lastLoginIp,
|
|
1465
|
+
appPid: teamDid,
|
|
1466
|
+
passportId,
|
|
1467
|
+
},
|
|
1468
|
+
],
|
|
1469
|
+
},
|
|
1470
|
+
});
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
return data;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
async logoutUser({ teamDid, userDid, visitorId, appPid }) {
|
|
1478
|
+
const state = await this.getUserSessionState(teamDid);
|
|
1479
|
+
const data = await state.update({ userDid, visitorId, appPid }, { status: 'offline' });
|
|
1480
|
+
const nodeInfo = await this.node.read();
|
|
1481
|
+
const blocklet = await getBlocklet({ did: teamDid, states: this.states, dataDirs: this.dataDirs });
|
|
1482
|
+
const { permanentWallet } = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
1483
|
+
const federated = defaults(cloneDeep(blocklet.settings.federated || {}), {
|
|
1484
|
+
config: {},
|
|
1485
|
+
sites: [],
|
|
1486
|
+
});
|
|
1487
|
+
const masterSite = federated.sites[0];
|
|
1488
|
+
if (masterSite && masterSite.isMaster !== false && masterSite.appPid !== teamDid) {
|
|
1489
|
+
callFederated({
|
|
1490
|
+
action: 'sync',
|
|
1491
|
+
permanentWallet,
|
|
1492
|
+
site: masterSite,
|
|
1493
|
+
data: {
|
|
1494
|
+
userSessions: [
|
|
1495
|
+
{
|
|
1496
|
+
action: 'logout',
|
|
1497
|
+
userDid,
|
|
1498
|
+
visitorId,
|
|
1499
|
+
appPid: teamDid,
|
|
1500
|
+
},
|
|
1501
|
+
],
|
|
1502
|
+
},
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
return data;
|
|
1506
|
+
}
|
|
1332
1507
|
}
|
|
1333
1508
|
|
|
1334
1509
|
module.exports = TeamAPI;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/* eslint-disable max-classes-per-file */
|
|
2
|
-
/* eslint-disable no-underscore-dangle */
|
|
3
2
|
/* eslint-disable no-await-in-loop */
|
|
4
3
|
const fs = require('fs-extra');
|
|
5
4
|
const path = require('path');
|
|
@@ -163,7 +162,12 @@ const UpgradeComponents = require('./helper/upgrade-components');
|
|
|
163
162
|
const BlockletDownloader = require('../downloader/blocklet-downloader');
|
|
164
163
|
const RollbackCache = require('./helper/rollback-cache');
|
|
165
164
|
const { migrateApplicationToStructV2 } = require('./helper/migrate-application-to-struct-v2');
|
|
166
|
-
const {
|
|
165
|
+
const {
|
|
166
|
+
getBackupFilesUrlFromEndpoint,
|
|
167
|
+
getBackupEndpoint,
|
|
168
|
+
getSpaceNameByEndpoint,
|
|
169
|
+
getBackupJobId,
|
|
170
|
+
} = require('../../util/spaces');
|
|
167
171
|
const { validateAddSpaceGateway, validateUpdateSpaceGateway } = require('../../validators/space-gateway');
|
|
168
172
|
const { sessionConfigSchema } = require('../../validators/util');
|
|
169
173
|
|
|
@@ -182,6 +186,7 @@ const {
|
|
|
182
186
|
getSelectedResources,
|
|
183
187
|
updateSelectedResources,
|
|
184
188
|
} = require('../project');
|
|
189
|
+
const { callFederated } = require('../../util/federated');
|
|
185
190
|
|
|
186
191
|
const { formatEnvironments, getBlockletMeta, validateOwner, isCLI } = util;
|
|
187
192
|
|
|
@@ -221,12 +226,19 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
221
226
|
this.teamManager = teamManager;
|
|
222
227
|
|
|
223
228
|
if (isFunction(this.backupQueue.on)) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
229
|
+
/**
|
|
230
|
+
*
|
|
231
|
+
* @param {{
|
|
232
|
+
* id: string,
|
|
233
|
+
* job: { blocklet: import('@abtnode/client').BlockletState }
|
|
234
|
+
* }} param0
|
|
235
|
+
*/
|
|
236
|
+
const handleBackupComplete = async ({ id: jobId, job }) => {
|
|
237
|
+
await this.backupQueue.delete(jobId);
|
|
238
|
+
|
|
239
|
+
const autoBackup = await this.getAutoBackup({ did: job.blocklet.meta.did });
|
|
228
240
|
if (autoBackup?.enabled) {
|
|
229
|
-
this.backupQueue.push(job,
|
|
241
|
+
this.backupQueue.push(job, jobId, true, BACKUPS.JOB.INTERVAL);
|
|
230
242
|
}
|
|
231
243
|
};
|
|
232
244
|
this.backupQueue.on('finished', handleBackupComplete).on('failed', handleBackupComplete);
|
|
@@ -1898,12 +1910,14 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
1898
1910
|
const value = { ...autoBackup };
|
|
1899
1911
|
await states.blockletExtras.setSettings(did, { autoBackup: value });
|
|
1900
1912
|
|
|
1901
|
-
|
|
1913
|
+
const jobId = getBackupJobId(did);
|
|
1914
|
+
await this.backupQueue.delete(jobId);
|
|
1902
1915
|
|
|
1903
1916
|
logger.info('updateAutoBackup.$value', value);
|
|
1904
1917
|
|
|
1905
1918
|
if (value.enabled) {
|
|
1906
1919
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1920
|
+
|
|
1907
1921
|
this.backupQueue.push(
|
|
1908
1922
|
{
|
|
1909
1923
|
entity: 'blocklet',
|
|
@@ -1911,7 +1925,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
1911
1925
|
blocklet,
|
|
1912
1926
|
context,
|
|
1913
1927
|
},
|
|
1914
|
-
|
|
1928
|
+
jobId,
|
|
1915
1929
|
true,
|
|
1916
1930
|
BACKUPS.JOB.INTERVAL
|
|
1917
1931
|
);
|
|
@@ -3568,7 +3582,8 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3568
3582
|
try {
|
|
3569
3583
|
const { did } = blocklet.meta;
|
|
3570
3584
|
|
|
3571
|
-
|
|
3585
|
+
const jobId = getBackupJobId(did);
|
|
3586
|
+
await this.backupQueue.delete(jobId);
|
|
3572
3587
|
|
|
3573
3588
|
this.backupQueue.push(
|
|
3574
3589
|
{
|
|
@@ -3580,7 +3595,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3580
3595
|
strategy: BACKUPS.STRATEGY.MANUAL,
|
|
3581
3596
|
},
|
|
3582
3597
|
},
|
|
3583
|
-
|
|
3598
|
+
jobId
|
|
3584
3599
|
);
|
|
3585
3600
|
|
|
3586
3601
|
return blocklet;
|
|
@@ -3744,7 +3759,7 @@ class FederatedBlockletManager extends DiskBlockletManager {
|
|
|
3744
3759
|
* @param {string} options.appUrl - 申请加入统一登录的 master appUrl
|
|
3745
3760
|
* @returns {Promise<any>} 更新后的 blocklet 数据
|
|
3746
3761
|
*/
|
|
3747
|
-
async joinFederatedLogin({ appUrl, did }) {
|
|
3762
|
+
async joinFederatedLogin({ appUrl, did }, context) {
|
|
3748
3763
|
const url = new URL(appUrl);
|
|
3749
3764
|
// master service api 的地址
|
|
3750
3765
|
url.pathname = joinUrl(WELLKNOWN_SERVICE_PATH_PREFIX, '/api/federated/join');
|
|
@@ -3818,7 +3833,7 @@ class FederatedBlockletManager extends DiskBlockletManager {
|
|
|
3818
3833
|
* @param {string} options.did - blocklet pid
|
|
3819
3834
|
* @returns {Promise<any>} 更新后的 blocklet 数据
|
|
3820
3835
|
*/
|
|
3821
|
-
async quitFederatedLogin({ did }) {
|
|
3836
|
+
async quitFederatedLogin({ did }, context) {
|
|
3822
3837
|
const blocklet = await this.getBlocklet(did);
|
|
3823
3838
|
const federated = defaults(cloneDeep(blocklet.settings.federated || {}), {
|
|
3824
3839
|
config: {},
|
|
@@ -3839,21 +3854,17 @@ class FederatedBlockletManager extends DiskBlockletManager {
|
|
|
3839
3854
|
},
|
|
3840
3855
|
masterAppUrl: masterSite.appUrl,
|
|
3841
3856
|
});
|
|
3842
|
-
const url = new URL(masterSite.appUrl);
|
|
3843
|
-
url.pathname = joinUrl(WELLKNOWN_SERVICE_PATH_PREFIX, '/api/federated/quit');
|
|
3844
3857
|
try {
|
|
3845
|
-
await
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
{ retries: 3 }
|
|
3854
|
-
);
|
|
3858
|
+
await callFederated({
|
|
3859
|
+
action: 'quit',
|
|
3860
|
+
site: masterSite,
|
|
3861
|
+
permanentWallet,
|
|
3862
|
+
data: {
|
|
3863
|
+
memberPid: blocklet.appPid,
|
|
3864
|
+
},
|
|
3865
|
+
});
|
|
3855
3866
|
} catch (error) {
|
|
3856
|
-
logger.error('Failed to quit blocklet, will still quit federated by itself', { error, did
|
|
3867
|
+
logger.error('Failed to quit blocklet, will still quit federated by itself', { error, did });
|
|
3857
3868
|
}
|
|
3858
3869
|
}
|
|
3859
3870
|
|
|
@@ -3872,7 +3883,7 @@ class FederatedBlockletManager extends DiskBlockletManager {
|
|
|
3872
3883
|
* @param {string} options.did - blocklet pid
|
|
3873
3884
|
* @returns {Promise<any>} 更新后的 blocklet 数据
|
|
3874
3885
|
*/
|
|
3875
|
-
async disbandFederatedLogin({ did }) {
|
|
3886
|
+
async disbandFederatedLogin({ did }, context) {
|
|
3876
3887
|
const blocklet = await this.getBlocklet(did);
|
|
3877
3888
|
const federated = defaults(cloneDeep(blocklet.settings.federated || {}), {
|
|
3878
3889
|
config: {},
|
|
@@ -3899,22 +3910,17 @@ class FederatedBlockletManager extends DiskBlockletManager {
|
|
|
3899
3910
|
.filter((item) => item.appPid !== did)
|
|
3900
3911
|
.map((item) => {
|
|
3901
3912
|
return limitSync(async () => {
|
|
3902
|
-
const url = new URL(item.appUrl);
|
|
3903
|
-
url.pathname = joinUrl(WELLKNOWN_SERVICE_PATH_PREFIX, '/api/federated/disband');
|
|
3904
3913
|
try {
|
|
3905
|
-
await
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
{ retries: 1 }
|
|
3912
|
-
);
|
|
3914
|
+
await callFederated({
|
|
3915
|
+
action: 'disband',
|
|
3916
|
+
permanentWallet,
|
|
3917
|
+
site: item,
|
|
3918
|
+
data: {},
|
|
3919
|
+
});
|
|
3913
3920
|
} catch (error) {
|
|
3914
3921
|
logger.error('Failed to disband blocklet, will still disband federated by itself', {
|
|
3915
3922
|
error,
|
|
3916
3923
|
did,
|
|
3917
|
-
url: url.href,
|
|
3918
3924
|
});
|
|
3919
3925
|
}
|
|
3920
3926
|
});
|
|
@@ -3937,7 +3943,7 @@ class FederatedBlockletManager extends DiskBlockletManager {
|
|
|
3937
3943
|
* @param {object} param.config federated 配置内容
|
|
3938
3944
|
* @returns {Promise<any>} 更新后的 blocklet 数据
|
|
3939
3945
|
*/
|
|
3940
|
-
async setFederated({ did, config }) {
|
|
3946
|
+
async setFederated({ did, config }, context) {
|
|
3941
3947
|
await states.blockletExtras.setSettings(did, { federated: config });
|
|
3942
3948
|
|
|
3943
3949
|
const newState = await this.getBlocklet(did);
|
|
@@ -3953,7 +3959,8 @@ class FederatedBlockletManager extends DiskBlockletManager {
|
|
|
3953
3959
|
* @param {boolean} param.autoLogin 是否自动登录
|
|
3954
3960
|
* @returns {Promise<any>} 更新后的 blocklet 数据
|
|
3955
3961
|
*/
|
|
3956
|
-
|
|
3962
|
+
// FIXME: @zhanghan deprecated 不再需要配置自动登录
|
|
3963
|
+
async configFederated({ did, autoLogin = false }, context) {
|
|
3957
3964
|
const blocklet = await this.getBlocklet(did);
|
|
3958
3965
|
const federated = cloneDeep(blocklet.settings.federated || {});
|
|
3959
3966
|
federated.config.autoLogin = autoLogin;
|
|
@@ -3970,7 +3977,6 @@ class FederatedBlockletManager extends DiskBlockletManager {
|
|
|
3970
3977
|
* @param {object} param
|
|
3971
3978
|
* @param {string} param.did master blocklet pid
|
|
3972
3979
|
* @param {string} param.memberPid member blocklet pid
|
|
3973
|
-
* @param {boolean} param.autoLogin 是否自动登录
|
|
3974
3980
|
* @returns {Promise<any>} 更新后的 blocklet 数据
|
|
3975
3981
|
*/
|
|
3976
3982
|
async auditFederatedLogin({ memberPid, did, status }) {
|
|
@@ -4028,31 +4034,24 @@ class FederatedBlockletManager extends DiskBlockletManager {
|
|
|
4028
4034
|
roles = await this.teamManager.getRoles(blocklet.appPid);
|
|
4029
4035
|
}
|
|
4030
4036
|
|
|
4031
|
-
const postUrl = joinUrl(memberSite.appUrl, WELLKNOWN_SERVICE_PATH_PREFIX, '/api/federated/audit-res');
|
|
4032
|
-
|
|
4033
4037
|
logger.info('Audit member join federated login', {
|
|
4034
4038
|
status,
|
|
4035
|
-
postUrl,
|
|
4036
4039
|
});
|
|
4037
4040
|
try {
|
|
4038
4041
|
const roleList = roles.map((item) => pick(item, ['name', 'title', 'description']));
|
|
4039
|
-
await
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
{
|
|
4051
|
-
retries: 3,
|
|
4052
|
-
}
|
|
4053
|
-
);
|
|
4042
|
+
await callFederated({
|
|
4043
|
+
action: 'audit-res',
|
|
4044
|
+
permanentWallet,
|
|
4045
|
+
site: memberSite,
|
|
4046
|
+
data: {
|
|
4047
|
+
masterPid: blocklet.appPid,
|
|
4048
|
+
status,
|
|
4049
|
+
delegation,
|
|
4050
|
+
roles: roleList,
|
|
4051
|
+
},
|
|
4052
|
+
});
|
|
4054
4053
|
} catch (error) {
|
|
4055
|
-
logger.error('Failed to post audit res to member-site', { error, did
|
|
4054
|
+
logger.error('Failed to post audit res to member-site', { error, did });
|
|
4056
4055
|
throw error;
|
|
4057
4056
|
}
|
|
4058
4057
|
await this.syncFederated({
|
|
@@ -4119,24 +4118,34 @@ class FederatedBlockletManager extends DiskBlockletManager {
|
|
|
4119
4118
|
.filter((item) => item.appId !== federated.config.appId)
|
|
4120
4119
|
.map((item) => {
|
|
4121
4120
|
return limitSync(async () => {
|
|
4122
|
-
const url = joinUrl(item.appUrl, WELLKNOWN_SERVICE_PATH_PREFIX, '/api/federated/sync');
|
|
4123
4121
|
try {
|
|
4124
4122
|
// NOTICE: 即使通知某个站点失败了,也不影响其他站点接收同步结果
|
|
4125
|
-
await
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
{ retries: 3 }
|
|
4132
|
-
);
|
|
4123
|
+
await callFederated({
|
|
4124
|
+
action: 'sync',
|
|
4125
|
+
permanentWallet,
|
|
4126
|
+
site: item,
|
|
4127
|
+
data: safeData,
|
|
4128
|
+
});
|
|
4133
4129
|
} catch (error) {
|
|
4134
|
-
logger.warn('Failed to sync federated sites', { error, did,
|
|
4130
|
+
logger.warn('Failed to sync federated sites', { error, did, action: 'sync' });
|
|
4135
4131
|
}
|
|
4136
4132
|
});
|
|
4137
4133
|
});
|
|
4138
4134
|
await Promise.all(waitingList);
|
|
4139
4135
|
}
|
|
4136
|
+
|
|
4137
|
+
async loginFederated({ did, site, data }) {
|
|
4138
|
+
const blocklet = await this.getBlocklet(did);
|
|
4139
|
+
const nodeInfo = await states.node.read();
|
|
4140
|
+
const { permanentWallet } = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
4141
|
+
const result = await callFederated({
|
|
4142
|
+
action: 'loginByMaster',
|
|
4143
|
+
data,
|
|
4144
|
+
permanentWallet,
|
|
4145
|
+
site,
|
|
4146
|
+
});
|
|
4147
|
+
return result;
|
|
4148
|
+
}
|
|
4140
4149
|
}
|
|
4141
4150
|
|
|
4142
4151
|
class BlockletManager extends FederatedBlockletManager {}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const debounce = require('lodash/debounce');
|
|
2
2
|
const logger = require('@abtnode/logger')('@abtnode/core:event/auto-backup-handler');
|
|
3
|
+
const { getBackupJobId } = require('../util/spaces');
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @description
|
|
@@ -15,7 +16,8 @@ async function autoBackupHandler(eventName, payload, blockletManager) {
|
|
|
15
16
|
logger.info('autoBackupHandler.$Boolean(payload.context)', Boolean(payload.context));
|
|
16
17
|
|
|
17
18
|
if (autoBackup.enabled && payload.context) {
|
|
18
|
-
|
|
19
|
+
const jobId = getBackupJobId(did);
|
|
20
|
+
await blockletManager.backupQueue.delete(jobId);
|
|
19
21
|
|
|
20
22
|
blockletManager.backupQueue.push(
|
|
21
23
|
{
|
|
@@ -24,7 +26,7 @@ async function autoBackupHandler(eventName, payload, blockletManager) {
|
|
|
24
26
|
blocklet: payload,
|
|
25
27
|
context: payload.context,
|
|
26
28
|
},
|
|
27
|
-
|
|
29
|
+
jobId
|
|
28
30
|
);
|
|
29
31
|
}
|
|
30
32
|
}
|
package/lib/index.js
CHANGED
|
@@ -269,6 +269,7 @@ function ABTNode(options) {
|
|
|
269
269
|
configFederated: blockletManager.configFederated.bind(blockletManager),
|
|
270
270
|
setFederated: blockletManager.setFederated.bind(blockletManager),
|
|
271
271
|
syncFederated: blockletManager.syncFederated.bind(blockletManager),
|
|
272
|
+
loginFederated: blockletManager.loginFederated.bind(blockletManager),
|
|
272
273
|
configNotification: blockletManager.configNotification.bind(blockletManager),
|
|
273
274
|
updateWhoCanAccess: blockletManager.updateWhoCanAccess.bind(blockletManager),
|
|
274
275
|
updateAppSessionConfig: blockletManager.updateAppSessionConfig.bind(blockletManager),
|
|
@@ -381,6 +382,13 @@ function ABTNode(options) {
|
|
|
381
382
|
isConnectedAccount: teamAPI.isConnectedAccount.bind(teamAPI),
|
|
382
383
|
switchProfile: teamAPI.switchProfile.bind(teamAPI),
|
|
383
384
|
|
|
385
|
+
// user-session
|
|
386
|
+
getUserSession: teamAPI.getUserSession.bind(teamAPI),
|
|
387
|
+
upsertUserSession: teamAPI.upsertUserSession.bind(teamAPI),
|
|
388
|
+
logoutUser: teamAPI.logoutUser.bind(teamAPI),
|
|
389
|
+
getPassportById: teamAPI.getPassportById.bind(teamAPI),
|
|
390
|
+
getPassportFromFederated: teamAPI.getPassportFromFederated.bind(teamAPI),
|
|
391
|
+
|
|
384
392
|
// Tagging
|
|
385
393
|
createTag: teamAPI.createTag.bind(teamAPI),
|
|
386
394
|
updateTag: teamAPI.updateTag.bind(teamAPI),
|
|
@@ -391,6 +399,7 @@ function ABTNode(options) {
|
|
|
391
399
|
getRBAC: (did = options.nodeDid) => teamManager.getRBAC(did),
|
|
392
400
|
|
|
393
401
|
getRoles: teamAPI.getRoles.bind(teamAPI),
|
|
402
|
+
getRole: teamAPI.getRole.bind(teamAPI),
|
|
394
403
|
createRole: teamAPI.createRole.bind(teamAPI),
|
|
395
404
|
updateRole: teamAPI.updateRole.bind(teamAPI),
|
|
396
405
|
deleteRole: teamAPI.deleteRole.bind(teamAPI),
|
package/lib/states/blocklet.js
CHANGED
|
@@ -234,7 +234,7 @@ class BlockletState extends BaseState {
|
|
|
234
234
|
} = {}) {
|
|
235
235
|
let doc = await this.getBlocklet(meta.did);
|
|
236
236
|
if (doc) {
|
|
237
|
-
throw new Error(
|
|
237
|
+
throw new Error(`Blocklet already added: ${meta.did}`);
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
try {
|
|
@@ -288,7 +288,7 @@ class BlockletState extends BaseState {
|
|
|
288
288
|
async updateBlocklet(did, updates) {
|
|
289
289
|
const doc = await this.getBlocklet(did);
|
|
290
290
|
if (!doc) {
|
|
291
|
-
throw new Error(
|
|
291
|
+
throw new Error(`Blocklet does not exist on update: ${did}`);
|
|
292
292
|
}
|
|
293
293
|
|
|
294
294
|
const formatted = formatBlocklet(cloneDeep(updates), 'onUpdate', this.config.dek);
|
|
@@ -302,7 +302,7 @@ class BlockletState extends BaseState {
|
|
|
302
302
|
async upgradeBlocklet({ meta, source, deployedFrom = '', children } = {}) {
|
|
303
303
|
const doc = await this.getBlocklet(meta.did);
|
|
304
304
|
if (!doc) {
|
|
305
|
-
throw new Error(
|
|
305
|
+
throw new Error(`Blocklet does not exist on upgrade: ${meta.did}`);
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
try {
|
|
@@ -427,7 +427,7 @@ class BlockletState extends BaseState {
|
|
|
427
427
|
async refreshBlockletPorts(did, componentDids = []) {
|
|
428
428
|
const blocklet = await this.getBlocklet(did);
|
|
429
429
|
if (!blocklet) {
|
|
430
|
-
throw new Error(
|
|
430
|
+
throw new Error(`Blocklet does not exist on refresh: ${did}`);
|
|
431
431
|
}
|
|
432
432
|
|
|
433
433
|
const { occupiedExternalPorts, occupiedInternalPorts } = await this._getOccupiedPorts();
|
|
@@ -626,7 +626,7 @@ class BlockletState extends BaseState {
|
|
|
626
626
|
async addChildren(did, children) {
|
|
627
627
|
const parent = await this.getBlocklet(did);
|
|
628
628
|
if (!parent) {
|
|
629
|
-
throw new Error(
|
|
629
|
+
throw new Error(`Blocklet does not exist on addChildren: ${did}`);
|
|
630
630
|
}
|
|
631
631
|
|
|
632
632
|
const oldChildren = parent.children || [];
|
package/lib/states/user.js
CHANGED
|
@@ -423,6 +423,16 @@ class User extends ExtendBase {
|
|
|
423
423
|
|
|
424
424
|
return result;
|
|
425
425
|
}
|
|
426
|
+
|
|
427
|
+
async getPassports(did) {
|
|
428
|
+
const passports = await this.passport.find({ userDid: did });
|
|
429
|
+
return passports;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
async getPassportById(passportId) {
|
|
433
|
+
const passport = await this.passport.findOne({ id: passportId });
|
|
434
|
+
return passport;
|
|
435
|
+
}
|
|
426
436
|
}
|
|
427
437
|
|
|
428
438
|
module.exports = User;
|
package/lib/team/manager.js
CHANGED
|
@@ -28,6 +28,7 @@ const rbacCreationLock = new Lock('rbac-creation-lock');
|
|
|
28
28
|
|
|
29
29
|
const States = {
|
|
30
30
|
User: require('../states/user'),
|
|
31
|
+
UserSession: require('../states/user-session'),
|
|
31
32
|
Passport: require('../states/passport'),
|
|
32
33
|
ConnectedAccount: require('../states/connect-account'),
|
|
33
34
|
Session: require('../states/session'),
|
|
@@ -96,6 +97,7 @@ class TeamManager extends EventEmitter {
|
|
|
96
97
|
this.cache[this.nodeDid] = {
|
|
97
98
|
rbac: await createRBAC({ storage: new MemoryStorage(), data: RBAC_CONFIG }),
|
|
98
99
|
user: await this.createState(this.nodeDid, 'User'),
|
|
100
|
+
userSession: await this.createState(this.nodeDid, 'UserSession'),
|
|
99
101
|
tag: await this.createState(this.nodeDid, 'Tag'),
|
|
100
102
|
passport: await this.createState(this.nodeDid, 'Passport'),
|
|
101
103
|
connectedAccount: await this.createState(this.nodeDid, 'ConnectedAccount'),
|
|
@@ -107,6 +109,10 @@ class TeamManager extends EventEmitter {
|
|
|
107
109
|
return this.getState(teamDid, 'user');
|
|
108
110
|
}
|
|
109
111
|
|
|
112
|
+
getUserSessionState(teamDid) {
|
|
113
|
+
return this.getState(teamDid, 'userSession');
|
|
114
|
+
}
|
|
115
|
+
|
|
110
116
|
getTagState(teamDid) {
|
|
111
117
|
return this.getState(teamDid, 'tag');
|
|
112
118
|
}
|
|
@@ -320,7 +326,7 @@ class TeamManager extends EventEmitter {
|
|
|
320
326
|
async getRoles(did) {
|
|
321
327
|
const rbac = await this.getRBAC(did);
|
|
322
328
|
const roles = await rbac.getRoles();
|
|
323
|
-
return roles.map((d) => pick(d, ['name', 'grants', 'title', 'description']));
|
|
329
|
+
return roles.map((d) => pick(d, ['name', 'grants', 'title', 'description', 'extra']));
|
|
324
330
|
}
|
|
325
331
|
|
|
326
332
|
async initTeam(did) {
|
|
@@ -339,10 +345,12 @@ class TeamManager extends EventEmitter {
|
|
|
339
345
|
const passport = await this.createState(did, 'Passport');
|
|
340
346
|
const connectedAccount = await this.createState(did, 'ConnectedAccount');
|
|
341
347
|
const session = await this.createState(did, 'Session');
|
|
348
|
+
const userSession = await this.createState(did, 'UserSession');
|
|
342
349
|
|
|
343
350
|
this.cache[did] = {
|
|
344
351
|
rbac,
|
|
345
352
|
user,
|
|
353
|
+
userSession,
|
|
346
354
|
tag,
|
|
347
355
|
session,
|
|
348
356
|
passport,
|
package/lib/util/blocklet.js
CHANGED
|
@@ -12,6 +12,7 @@ const toLower = require('lodash/toLower');
|
|
|
12
12
|
const isEmpty = require('lodash/isEmpty');
|
|
13
13
|
const streamToPromise = require('stream-to-promise');
|
|
14
14
|
const { Throttle } = require('stream-throttle');
|
|
15
|
+
const { slugify } = require('transliteration');
|
|
15
16
|
const ssri = require('ssri');
|
|
16
17
|
const diff = require('deep-diff');
|
|
17
18
|
const createArchive = require('archiver');
|
|
@@ -19,6 +20,7 @@ const isUrl = require('is-url');
|
|
|
19
20
|
const semver = require('semver');
|
|
20
21
|
const { chainInfo: chainInfoSchema } = require('@arcblock/did-auth/lib/schema');
|
|
21
22
|
|
|
23
|
+
const urlPathFriendly = require('@blocklet/meta/lib/url-path-friendly').default;
|
|
22
24
|
const { fromSecretKey, fromPublicKey } = require('@ocap/wallet');
|
|
23
25
|
const { toHex, isHex, toDid, toAddress, toBuffer } = require('@ocap/util');
|
|
24
26
|
const { isValid: isValidDid, isEthereumDid } = require('@arcblock/did');
|
|
@@ -309,6 +311,7 @@ const getAppSystemEnvironments = (blocklet, nodeInfo, dataDirs) => {
|
|
|
309
311
|
BLOCKLET_APP_PSK: appPsk, // permanent sk even the blocklet has been migrated
|
|
310
312
|
BLOCKLET_APP_PID: appPid, // permanent did even the blocklet has been migrated
|
|
311
313
|
BLOCKLET_APP_NAME: appName,
|
|
314
|
+
BLOCKLET_APP_NAME_SLUG: urlPathFriendly(slugify(appName)),
|
|
312
315
|
BLOCKLET_APP_DESCRIPTION: appDescription,
|
|
313
316
|
BLOCKLET_APP_URL: appUrl,
|
|
314
317
|
BLOCKLET_APP_DATA_DIR: path.join(dataDirs.data, blocklet.meta.name),
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
|
|
2
|
+
const pRetry = require('p-retry');
|
|
3
|
+
const { signV2 } = require('@arcblock/jwt');
|
|
4
|
+
const joinUrl = require('url-join');
|
|
5
|
+
|
|
6
|
+
const request = require('./request');
|
|
7
|
+
|
|
8
|
+
async function callFederated({ site, permanentWallet, data, action }) {
|
|
9
|
+
const url = new URL(site.appUrl);
|
|
10
|
+
url.pathname = joinUrl(WELLKNOWN_SERVICE_PATH_PREFIX, `/api/federated/${action}`);
|
|
11
|
+
const result = await pRetry(
|
|
12
|
+
() =>
|
|
13
|
+
request.post(url.href, {
|
|
14
|
+
signer: permanentWallet.address,
|
|
15
|
+
data: signV2(permanentWallet.address, permanentWallet.secretKey, data),
|
|
16
|
+
}),
|
|
17
|
+
{ retries: 3 }
|
|
18
|
+
);
|
|
19
|
+
return result.data;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
callFederated,
|
|
24
|
+
};
|
package/lib/util/router.js
CHANGED
|
@@ -21,7 +21,7 @@ const updateNFTDomainRecord = async ({ name, value, blocklet, nodeInfo }) => {
|
|
|
21
21
|
const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
22
22
|
|
|
23
23
|
const payload = {
|
|
24
|
-
delegatee:
|
|
24
|
+
delegatee: blocklet.appPid,
|
|
25
25
|
domain: name,
|
|
26
26
|
record: {
|
|
27
27
|
name,
|
|
@@ -43,7 +43,7 @@ const updateNFTDomainRecord = async ({ name, value, blocklet, nodeInfo }) => {
|
|
|
43
43
|
error,
|
|
44
44
|
name,
|
|
45
45
|
value,
|
|
46
|
-
delegatee:
|
|
46
|
+
delegatee: blocklet.appPid,
|
|
47
47
|
appPid: blocklet.appPid,
|
|
48
48
|
resp: error.response?.data,
|
|
49
49
|
});
|
package/lib/util/spaces.js
CHANGED
|
@@ -72,9 +72,19 @@ async function getSpaceNameByEndpoint(endpoint, defaultValue = '') {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* @description
|
|
77
|
+
* @param {string} did
|
|
78
|
+
* @return {string}
|
|
79
|
+
*/
|
|
80
|
+
function getBackupJobId(did) {
|
|
81
|
+
return `${did}.backupToSpaces`;
|
|
82
|
+
}
|
|
83
|
+
|
|
75
84
|
module.exports = {
|
|
76
85
|
getBackupEndpoint,
|
|
77
86
|
getBackupFilesUrlFromEndpoint,
|
|
78
87
|
getDIDSpacesUrlFromEndpoint,
|
|
79
88
|
getSpaceNameByEndpoint,
|
|
89
|
+
getBackupJobId,
|
|
80
90
|
};
|
package/lib/validators/role.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/* eslint-disable newline-per-chained-call */
|
|
2
|
-
const
|
|
2
|
+
const Joi = require('joi');
|
|
3
3
|
const { getMultipleLangParams } = require('./util');
|
|
4
4
|
|
|
5
|
-
const roleNameSchema =
|
|
5
|
+
const roleNameSchema = Joi.string()
|
|
6
6
|
.trim()
|
|
7
7
|
.max(64)
|
|
8
8
|
.custom((value) => {
|
|
@@ -17,19 +17,41 @@ const roleNameSchema = JOI.string()
|
|
|
17
17
|
return value;
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
const
|
|
21
|
-
|
|
20
|
+
const roleAcquireSchema = Joi.object({
|
|
21
|
+
pay: Joi.string().optional().allow(''),
|
|
22
|
+
exchange: Joi.string().optional().allow(''),
|
|
23
|
+
invite: Joi.boolean().optional(),
|
|
24
|
+
transfer: Joi.boolean().optional(),
|
|
25
|
+
request: Joi.boolean().optional(),
|
|
26
|
+
}).default({
|
|
27
|
+
pay: '',
|
|
28
|
+
exchange: '',
|
|
29
|
+
invite: true,
|
|
30
|
+
transfer: false,
|
|
31
|
+
request: false,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const titleSchema = Joi.string().trim().max(25);
|
|
35
|
+
const descriptionSchema = Joi.string().trim().max(600);
|
|
22
36
|
|
|
23
|
-
const createRoleSchema =
|
|
37
|
+
const createRoleSchema = Joi.object({
|
|
24
38
|
name: roleNameSchema.required(),
|
|
25
39
|
title: titleSchema.required(),
|
|
26
40
|
description: descriptionSchema.required(),
|
|
41
|
+
extra: Joi.object({
|
|
42
|
+
acquire: roleAcquireSchema,
|
|
43
|
+
payment: Joi.any().optional(),
|
|
44
|
+
}).optional(),
|
|
27
45
|
});
|
|
28
46
|
|
|
29
|
-
const updateRoleSchema =
|
|
47
|
+
const updateRoleSchema = Joi.object({
|
|
30
48
|
name: roleNameSchema.required(),
|
|
31
49
|
title: titleSchema,
|
|
32
50
|
description: descriptionSchema,
|
|
51
|
+
extra: Joi.object({
|
|
52
|
+
acquire: roleAcquireSchema,
|
|
53
|
+
payment: Joi.any().optional(),
|
|
54
|
+
}).optional(),
|
|
33
55
|
});
|
|
34
56
|
|
|
35
57
|
module.exports = {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.17-beta-
|
|
6
|
+
"version": "1.16.17-beta-703fb879",
|
|
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.17-beta-
|
|
23
|
-
"@abtnode/auth": "1.16.17-beta-
|
|
24
|
-
"@abtnode/certificate-manager": "1.16.17-beta-
|
|
25
|
-
"@abtnode/constant": "1.16.17-beta-
|
|
26
|
-
"@abtnode/cron": "1.16.17-beta-
|
|
27
|
-
"@abtnode/logger": "1.16.17-beta-
|
|
28
|
-
"@abtnode/models": "1.16.17-beta-
|
|
29
|
-
"@abtnode/queue": "1.16.17-beta-
|
|
30
|
-
"@abtnode/rbac": "1.16.17-beta-
|
|
31
|
-
"@abtnode/router-provider": "1.16.17-beta-
|
|
32
|
-
"@abtnode/static-server": "1.16.17-beta-
|
|
33
|
-
"@abtnode/timemachine": "1.16.17-beta-
|
|
34
|
-
"@abtnode/util": "1.16.17-beta-
|
|
22
|
+
"@abtnode/analytics": "1.16.17-beta-703fb879",
|
|
23
|
+
"@abtnode/auth": "1.16.17-beta-703fb879",
|
|
24
|
+
"@abtnode/certificate-manager": "1.16.17-beta-703fb879",
|
|
25
|
+
"@abtnode/constant": "1.16.17-beta-703fb879",
|
|
26
|
+
"@abtnode/cron": "1.16.17-beta-703fb879",
|
|
27
|
+
"@abtnode/logger": "1.16.17-beta-703fb879",
|
|
28
|
+
"@abtnode/models": "1.16.17-beta-703fb879",
|
|
29
|
+
"@abtnode/queue": "1.16.17-beta-703fb879",
|
|
30
|
+
"@abtnode/rbac": "1.16.17-beta-703fb879",
|
|
31
|
+
"@abtnode/router-provider": "1.16.17-beta-703fb879",
|
|
32
|
+
"@abtnode/static-server": "1.16.17-beta-703fb879",
|
|
33
|
+
"@abtnode/timemachine": "1.16.17-beta-703fb879",
|
|
34
|
+
"@abtnode/util": "1.16.17-beta-703fb879",
|
|
35
35
|
"@arcblock/did": "1.18.92",
|
|
36
36
|
"@arcblock/did-auth": "1.18.92",
|
|
37
37
|
"@arcblock/did-ext": "^1.18.92",
|
|
@@ -42,11 +42,11 @@
|
|
|
42
42
|
"@arcblock/pm2-events": "^0.0.5",
|
|
43
43
|
"@arcblock/validator": "^1.18.92",
|
|
44
44
|
"@arcblock/vc": "1.18.92",
|
|
45
|
-
"@blocklet/constant": "1.16.17-beta-
|
|
46
|
-
"@blocklet/env": "1.16.17-beta-
|
|
47
|
-
"@blocklet/meta": "1.16.17-beta-
|
|
48
|
-
"@blocklet/resolver": "1.16.17-beta-
|
|
49
|
-
"@blocklet/sdk": "1.16.17-beta-
|
|
45
|
+
"@blocklet/constant": "1.16.17-beta-703fb879",
|
|
46
|
+
"@blocklet/env": "1.16.17-beta-703fb879",
|
|
47
|
+
"@blocklet/meta": "1.16.17-beta-703fb879",
|
|
48
|
+
"@blocklet/resolver": "1.16.17-beta-703fb879",
|
|
49
|
+
"@blocklet/sdk": "1.16.17-beta-703fb879",
|
|
50
50
|
"@did-space/client": "^0.3.11",
|
|
51
51
|
"@fidm/x509": "^1.2.1",
|
|
52
52
|
"@ocap/mcrypto": "1.18.92",
|
|
@@ -101,5 +101,5 @@
|
|
|
101
101
|
"jest": "^27.5.1",
|
|
102
102
|
"unzipper": "^0.10.11"
|
|
103
103
|
},
|
|
104
|
-
"gitHead": "
|
|
104
|
+
"gitHead": "97d63c671d823076e58b994107e10866367edd5d"
|
|
105
105
|
}
|