@abtnode/core 1.17.8-beta-20260109-075740-5f484e08 → 1.17.8-beta-20260111-112953-aed5ff39

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.
Files changed (65) hide show
  1. package/lib/api/team/access-key-manager.js +104 -0
  2. package/lib/api/team/invitation-manager.js +461 -0
  3. package/lib/api/team/notification-manager.js +189 -0
  4. package/lib/api/team/oauth-manager.js +60 -0
  5. package/lib/api/team/org-crud-manager.js +202 -0
  6. package/lib/api/team/org-manager.js +56 -0
  7. package/lib/api/team/org-member-manager.js +403 -0
  8. package/lib/api/team/org-query-manager.js +126 -0
  9. package/lib/api/team/org-resource-manager.js +186 -0
  10. package/lib/api/team/passport-manager.js +670 -0
  11. package/lib/api/team/rbac-manager.js +335 -0
  12. package/lib/api/team/session-manager.js +540 -0
  13. package/lib/api/team/store-manager.js +198 -0
  14. package/lib/api/team/tag-manager.js +230 -0
  15. package/lib/api/team/user-auth-manager.js +132 -0
  16. package/lib/api/team/user-manager.js +78 -0
  17. package/lib/api/team/user-query-manager.js +299 -0
  18. package/lib/api/team/user-social-manager.js +354 -0
  19. package/lib/api/team/user-update-manager.js +224 -0
  20. package/lib/api/team/verify-code-manager.js +161 -0
  21. package/lib/api/team.js +439 -3287
  22. package/lib/blocklet/manager/disk/auth-manager.js +68 -0
  23. package/lib/blocklet/manager/disk/backup-manager.js +288 -0
  24. package/lib/blocklet/manager/disk/cleanup-manager.js +157 -0
  25. package/lib/blocklet/manager/disk/component-manager.js +83 -0
  26. package/lib/blocklet/manager/disk/config-manager.js +191 -0
  27. package/lib/blocklet/manager/disk/controller-manager.js +64 -0
  28. package/lib/blocklet/manager/disk/delete-reset-manager.js +328 -0
  29. package/lib/blocklet/manager/disk/download-manager.js +96 -0
  30. package/lib/blocklet/manager/disk/env-config-manager.js +311 -0
  31. package/lib/blocklet/manager/disk/federated-manager.js +651 -0
  32. package/lib/blocklet/manager/disk/hook-manager.js +124 -0
  33. package/lib/blocklet/manager/disk/install-component-manager.js +95 -0
  34. package/lib/blocklet/manager/disk/install-core-manager.js +448 -0
  35. package/lib/blocklet/manager/disk/install-download-manager.js +313 -0
  36. package/lib/blocklet/manager/disk/install-manager.js +36 -0
  37. package/lib/blocklet/manager/disk/install-upgrade-manager.js +340 -0
  38. package/lib/blocklet/manager/disk/job-manager.js +467 -0
  39. package/lib/blocklet/manager/disk/lifecycle-manager.js +26 -0
  40. package/lib/blocklet/manager/disk/notification-manager.js +343 -0
  41. package/lib/blocklet/manager/disk/query-manager.js +562 -0
  42. package/lib/blocklet/manager/disk/settings-manager.js +507 -0
  43. package/lib/blocklet/manager/disk/start-manager.js +611 -0
  44. package/lib/blocklet/manager/disk/stop-restart-manager.js +292 -0
  45. package/lib/blocklet/manager/disk/update-manager.js +153 -0
  46. package/lib/blocklet/manager/disk.js +669 -5796
  47. package/lib/blocklet/manager/helper/blue-green-start-blocklet.js +5 -0
  48. package/lib/blocklet/manager/lock.js +18 -0
  49. package/lib/event/index.js +28 -24
  50. package/lib/util/blocklet/app-utils.js +192 -0
  51. package/lib/util/blocklet/blocklet-loader.js +258 -0
  52. package/lib/util/blocklet/config-manager.js +232 -0
  53. package/lib/util/blocklet/did-document.js +240 -0
  54. package/lib/util/blocklet/environment.js +555 -0
  55. package/lib/util/blocklet/health-check.js +449 -0
  56. package/lib/util/blocklet/install-utils.js +365 -0
  57. package/lib/util/blocklet/logo.js +57 -0
  58. package/lib/util/blocklet/meta-utils.js +269 -0
  59. package/lib/util/blocklet/port-manager.js +141 -0
  60. package/lib/util/blocklet/process-manager.js +504 -0
  61. package/lib/util/blocklet/runtime-info.js +105 -0
  62. package/lib/util/blocklet/validation.js +418 -0
  63. package/lib/util/blocklet.js +98 -3066
  64. package/lib/util/wallet-app-notification.js +40 -0
  65. package/package.json +22 -22
@@ -0,0 +1,224 @@
1
+ const pick = require('lodash/pick');
2
+ const isUrl = require('is-url');
3
+ const logger = require('@abtnode/logger')('@abtnode/core:api:team:user-update');
4
+ const { ROLES, USER_AVATAR_URL_PREFIX } = require('@abtnode/constant');
5
+ const { TeamEvents } = require('@blocklet/constant');
6
+ const { hasActiveOwnerPassport } = require('@abtnode/util/lib/passport');
7
+ const { getAvatarByUrl, extractUserAvatar } = require('@abtnode/util/lib/user');
8
+ const { syncFederated } = require('@abtnode/auth/lib/util/federated');
9
+
10
+ const { getBlocklet } = require('../../util/blocklet');
11
+ const { profileSchema } = require('../../validators/user');
12
+
13
+ /**
14
+ * Update user
15
+ * @param {Object} api - TeamAPI instance
16
+ * @param {Object} params
17
+ * @param {string} params.teamDid - Team DID
18
+ * @param {Object} params.user - User
19
+ * @returns {Promise<Object>}
20
+ */
21
+ async function updateUser(api, { teamDid, user }) {
22
+ const state = await api.getUserState(teamDid);
23
+ const exist = await state.getUserByDid(user.did);
24
+ const updated = await state.updateUser(user.did, user);
25
+ logger.info('user updated successfully', { teamDid, userDid: user.did });
26
+
27
+ api.emit(TeamEvents.userUpdated, { teamDid, user: updated });
28
+ const kycChanged =
29
+ (typeof user.emailVerified === 'boolean' && user.emailVerified !== exist.emailVerified) ||
30
+ (typeof user.phoneVerified === 'boolean' && user.phoneVerified !== exist.phoneVerified);
31
+ if (kycChanged) {
32
+ logger.info('user updated with kycChanged', { teamDid, userDid: user.did });
33
+ api.emit(TeamEvents.userPermissionUpdated, { teamDid, user: updated });
34
+ }
35
+
36
+ return updated;
37
+ }
38
+
39
+ /**
40
+ * Update user address
41
+ * @param {Object} api - TeamAPI instance
42
+ * @param {Object} args
43
+ * @returns {Promise<Object>}
44
+ */
45
+ function updateUserAddress(api, args) {
46
+ if (!args.address) {
47
+ throw new Error('address should not be empty');
48
+ }
49
+
50
+ return updateUser(api, { teamDid: args.teamDid, user: pick(args, ['did', 'address']) });
51
+ }
52
+
53
+ /**
54
+ * Update user tags
55
+ * @param {Object} api - TeamAPI instance
56
+ * @param {Object} params
57
+ * @param {string} params.teamDid - Team DID
58
+ * @param {string} params.did - User DID
59
+ * @param {Array} params.tags - Tags
60
+ * @returns {Promise<Object>}
61
+ */
62
+ async function updateUserTags(api, { teamDid, did, tags }) {
63
+ const state = await api.getUserState(teamDid);
64
+ const doc = await state.updateTags(did, tags);
65
+ logger.info('user tags updated successfully', { teamDid, userDid: did, tags });
66
+ api.emit(TeamEvents.userUpdated, { teamDid, user: doc });
67
+ return doc;
68
+ }
69
+
70
+ /**
71
+ * Remove user
72
+ * @param {Object} api - TeamAPI instance
73
+ * @param {Object} params
74
+ * @param {string} params.teamDid - Team DID
75
+ * @param {Object} params.user - User
76
+ * @returns {Promise<Object>}
77
+ */
78
+ async function removeUser(api, { teamDid, user }) {
79
+ const { did } = user;
80
+
81
+ if (!did) {
82
+ throw new Error('did does not exist');
83
+ }
84
+
85
+ if (user.role === ROLES.OWNER) {
86
+ throw new Error('Cannot delete owner');
87
+ }
88
+
89
+ const state = await api.getUserState(teamDid);
90
+ await state.remove({ did });
91
+ logger.info('user removed successfully', { teamDid, userDid: did });
92
+ api.emit(TeamEvents.userRemoved, { teamDid, user: { did } });
93
+
94
+ return { did };
95
+ }
96
+
97
+ /**
98
+ * Update user approval
99
+ * @param {Object} api - TeamAPI instance
100
+ * @param {Object} params
101
+ * @param {string} params.teamDid - Team DID
102
+ * @param {Object} params.user - User
103
+ * @param {Object} params.options - Options
104
+ * @returns {Promise<Object>}
105
+ */
106
+ async function updateUserApproval(api, { teamDid, user, options: { includeFederated = true } = {} }) {
107
+ const state = await api.getUserState(teamDid);
108
+ const userDoc = await state.getUser(user.did);
109
+
110
+ if (!userDoc) {
111
+ throw new Error('User does not exist');
112
+ }
113
+
114
+ if (hasActiveOwnerPassport(userDoc)) {
115
+ throw new Error('Cannot update owner\'s approval'); // prettier-ignore
116
+ }
117
+
118
+ const changeData = pick(user, ['did', 'approved']);
119
+
120
+ const result = await state.updateApproved(changeData);
121
+
122
+ logger.info('user approval updated successfully', { teamDid, userDid: user.did, approved: user.approved });
123
+
124
+ if (changeData?.approved === false) {
125
+ // 需要注销指定 userDid 在当前 member 和 master 中的所有 userSession
126
+ await api.logoutUser({ teamDid, userDid: user.did });
127
+
128
+ // 需要禁用用户的所有 passport
129
+ await state.revokePassportByUserDid({ did: user.did });
130
+ }
131
+ if (includeFederated) {
132
+ const nodeInfo = await api.node.read();
133
+ // 只有 blocklet 需要执行这个操作
134
+ if (nodeInfo.did !== teamDid) {
135
+ const blocklet = await getBlocklet({
136
+ did: teamDid,
137
+ states: api.states,
138
+ dataDirs: api.dataDirs,
139
+ useCache: true,
140
+ });
141
+ syncFederated({
142
+ nodeInfo,
143
+ blocklet,
144
+ data: {
145
+ users: [
146
+ {
147
+ action: user.approved ? 'unban' : 'ban',
148
+ did: user.did,
149
+ sourceAppPid: userDoc.sourceAppPid,
150
+ },
151
+ ],
152
+ },
153
+ });
154
+ }
155
+ }
156
+ api.emit(TeamEvents.userUpdated, { teamDid, user: result });
157
+ api.emit(TeamEvents.userPermissionUpdated, { teamDid, user: result });
158
+
159
+ return result;
160
+ }
161
+
162
+ /**
163
+ * Switch profile
164
+ * @param {Object} api - TeamAPI instance
165
+ * @param {Object} params
166
+ * @param {string} params.teamDid - Team DID
167
+ * @param {string} params.userDid - User DID
168
+ * @param {Object} params.profile - Profile
169
+ * @returns {Promise<Object>}
170
+ */
171
+ async function switchProfile(api, { teamDid, userDid, profile }) {
172
+ const state = await api.getUserState(teamDid);
173
+ // NOTICE: 这个 schema 没有对数据做任何 default 操作,所以没必要用 validate 之后的值
174
+ const { error } = profileSchema.validate({ ...profile, did: userDid });
175
+ if (error) {
176
+ throw new Error(error);
177
+ }
178
+ const oldUser = await state.getUser(userDid);
179
+ if (!oldUser) {
180
+ throw new Error('User is not exist', { userDid, teamDid });
181
+ }
182
+
183
+ const mergeData = { ...profile };
184
+
185
+ if (mergeData.avatar) {
186
+ if (mergeData.avatar.startsWith(USER_AVATAR_URL_PREFIX)) {
187
+ // pass
188
+ } else if (isUrl(mergeData.avatar)) {
189
+ try {
190
+ mergeData.avatar = await getAvatarByUrl(mergeData.avatar);
191
+ const blocklet = await getBlocklet({ did: teamDid, states: api.states, dataDirs: api.dataDirs });
192
+ mergeData.avatar = await extractUserAvatar(mergeData.avatar, { dataDir: blocklet.env.dataDir });
193
+ } catch {
194
+ logger.error('Failed to convert external avatar', { teamDid, userDid, avatar: mergeData.avatar });
195
+ throw new Error('Failed to convert external avatar');
196
+ }
197
+ } else {
198
+ // 仅当 avatar 是 base64 时,对 avatar 进行处理
199
+ const regex = /^data:image\/(\w+);base64,/;
200
+ const match = regex.exec(mergeData.avatar);
201
+ if (match) {
202
+ const blocklet = await getBlocklet({ did: teamDid, states: api.states, dataDirs: api.dataDirs });
203
+ mergeData.avatar = await extractUserAvatar(mergeData.avatar, { dataDir: blocklet.env.dataDir });
204
+ } else {
205
+ logger.error('Profile avatar is invalid', { teamDid, userDid, profile });
206
+ throw new Error('Profile avatar is invalid');
207
+ }
208
+ }
209
+ }
210
+ const doc = await state.updateUser(userDid, mergeData);
211
+ logger.info('User switch-profile successfully', { teamDid, userDid });
212
+ api.emit(TeamEvents.userUpdated, { teamDid, user: doc });
213
+ api.emit(TeamEvents.userProfileUpdated, { teamDid, user: doc });
214
+ return doc;
215
+ }
216
+
217
+ module.exports = {
218
+ updateUser,
219
+ updateUserAddress,
220
+ updateUserTags,
221
+ removeUser,
222
+ updateUserApproval,
223
+ switchProfile,
224
+ };
@@ -0,0 +1,161 @@
1
+ const cloneDeep = require('@abtnode/util/lib/deep-clone');
2
+ const { generateRandomString } = require('@abtnode/models/lib/util');
3
+ const { BlockletEvents, BlockletInternalEvents } = require('@blocklet/constant');
4
+
5
+ const { getBlocklet } = require('../../util/blocklet');
6
+
7
+ /**
8
+ * Create verify code
9
+ * @param {Object} api - TeamAPI instance
10
+ * @param {Object} params
11
+ * @param {string} params.teamDid - Team DID
12
+ * @param {string} params.subject - Subject
13
+ * @param {string} params.scope - Scope
14
+ * @param {string} params.purpose - Purpose
15
+ * @returns {Promise<Object>}
16
+ */
17
+ async function createVerifyCode(api, { teamDid, subject, scope = 'email', purpose = 'kyc' }) {
18
+ const state = await api.getVerifyCodeState(teamDid);
19
+ return state.create(subject, scope, purpose);
20
+ }
21
+
22
+ /**
23
+ * Consume verify code
24
+ * @param {Object} api - TeamAPI instance
25
+ * @param {Object} params
26
+ * @param {string} params.teamDid - Team DID
27
+ * @param {string} params.code - Verify code
28
+ * @returns {Promise<Object>}
29
+ */
30
+ async function consumeVerifyCode(api, { teamDid, code }) {
31
+ const state = await api.getVerifyCodeState(teamDid);
32
+ return state.verify(code);
33
+ }
34
+
35
+ /**
36
+ * Issue verify code
37
+ * @param {Object} api - TeamAPI instance
38
+ * @param {Object} params
39
+ * @param {string} params.teamDid - Team DID
40
+ * @param {string} params.code - Verify code
41
+ * @returns {Promise<Object>}
42
+ */
43
+ async function issueVerifyCode(api, { teamDid, code }) {
44
+ const state = await api.getVerifyCodeState(teamDid);
45
+ return state.issue(code);
46
+ }
47
+
48
+ /**
49
+ * Send verify code
50
+ * @param {Object} api - TeamAPI instance
51
+ * @param {Object} params
52
+ * @param {string} params.teamDid - Team DID
53
+ * @param {string} params.code - Verify code
54
+ * @returns {Promise<Object>}
55
+ */
56
+ async function sendVerifyCode(api, { teamDid, code }) {
57
+ const state = await api.getVerifyCodeState(teamDid);
58
+ return state.send(code);
59
+ }
60
+
61
+ /**
62
+ * Check if subject is verified
63
+ * @param {Object} api - TeamAPI instance
64
+ * @param {Object} params
65
+ * @param {string} params.teamDid - Team DID
66
+ * @param {string} params.subject - Subject
67
+ * @returns {Promise<boolean>}
68
+ */
69
+ async function isSubjectVerified(api, { teamDid, subject }) {
70
+ const state = await api.getVerifyCodeState(teamDid);
71
+ return state.isVerified(subject);
72
+ }
73
+
74
+ /**
75
+ * Check if subject is issued
76
+ * @param {Object} api - TeamAPI instance
77
+ * @param {Object} params
78
+ * @param {string} params.teamDid - Team DID
79
+ * @param {string} params.userDid - User DID
80
+ * @param {string} params.subject - Subject
81
+ * @returns {Promise<boolean>}
82
+ */
83
+ async function isSubjectIssued(api, { teamDid, userDid, subject }) {
84
+ const state = await api.getUserState(teamDid);
85
+ return state.isSubjectIssued(userDid, subject);
86
+ }
87
+
88
+ /**
89
+ * Check if subject is sent
90
+ * @param {Object} api - TeamAPI instance
91
+ * @param {Object} params
92
+ * @param {string} params.teamDid - Team DID
93
+ * @param {string} params.subject - Subject
94
+ * @returns {Promise<boolean>}
95
+ */
96
+ async function isSubjectSent(api, { teamDid, subject }) {
97
+ const state = await api.getVerifyCodeState(teamDid);
98
+ return state.isSent(subject);
99
+ }
100
+
101
+ /**
102
+ * Get verify code
103
+ * @param {Object} api - TeamAPI instance
104
+ * @param {Object} params
105
+ * @param {string} params.teamDid - Team DID
106
+ * @param {string} params.code - Verify code
107
+ * @param {string} params.id - Verify code ID
108
+ * @returns {Promise<Object>}
109
+ */
110
+ async function getVerifyCode(api, { teamDid, code, id }) {
111
+ const state = await api.getVerifyCodeState(teamDid);
112
+ const where = {};
113
+ if (code) where.code = code;
114
+ if (id) where.id = id;
115
+ return state.findOne(where);
116
+ }
117
+
118
+ /**
119
+ * Rotate session key
120
+ * @param {Object} api - TeamAPI instance
121
+ * @param {Object} params
122
+ * @param {string} params.teamDid - Team DID
123
+ * @returns {Promise<number>}
124
+ */
125
+ async function rotateSessionKey(api, { teamDid }) {
126
+ if (!teamDid) {
127
+ throw new Error('teamDid is required');
128
+ }
129
+
130
+ const info = await api.node.read();
131
+ if (info.did === teamDid) {
132
+ await api.node.updateNodeInfo({ sessionSalt: generateRandomString(16) });
133
+ return 0;
134
+ }
135
+
136
+ const blocklet = await getBlocklet({ did: teamDid, states: api.states, dataDirs: api.dataDirs, useCache: true });
137
+ const sessionConfig = cloneDeep(blocklet.settings.session || {});
138
+ sessionConfig.salt = generateRandomString(16);
139
+ await api.states.blockletExtras.setSettings(blocklet.meta.did, { session: sessionConfig });
140
+ api.emit(BlockletEvents.updated, { meta: { did: teamDid } });
141
+
142
+ // NOTE: we need emit appConfigChanged event to update sessionSalt in blocklet-sdk
143
+ api.emit(BlockletInternalEvents.appConfigChanged, {
144
+ appDid: teamDid,
145
+ configs: [{ key: 'BLOCKLET_APP_SALT', value: sessionConfig.salt }],
146
+ });
147
+
148
+ return 1;
149
+ }
150
+
151
+ module.exports = {
152
+ createVerifyCode,
153
+ consumeVerifyCode,
154
+ issueVerifyCode,
155
+ sendVerifyCode,
156
+ isSubjectVerified,
157
+ isSubjectIssued,
158
+ isSubjectSent,
159
+ getVerifyCode,
160
+ rotateSessionKey,
161
+ };