@abtnode/blocklet-services 1.8.3 → 1.8.4
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/api/index.js +3 -1
- package/api/libs/connect/session.js +456 -0
- package/api/libs/connect/v2.js +3 -0
- package/api/routes/{connect-relay.js → connect/relay.js} +3 -3
- package/api/routes/connect/session.js +120 -0
- package/api/services/auth/connect/login.js +17 -292
- package/api/services/auth/connect/switch-passport.js +18 -103
- package/api/services/auth/connect/switch-profile.js +17 -63
- package/api/services/notification/channel/app-channel.js +4 -1
- package/build/asset-manifest.json +7 -7
- package/build/index.html +1 -1
- package/build/static/js/{12.a879bfa6.chunk.js → 12.0e874475.chunk.js} +2 -2
- package/build/static/js/12.0e874475.chunk.js.map +1 -0
- package/build/static/js/{7.96fdf7e5.chunk.js → 7.b2428475.chunk.js} +2 -2
- package/build/static/js/7.b2428475.chunk.js.map +1 -0
- package/build/static/js/{runtime-main.7fadd252.js → runtime-main.2227285f.js} +2 -2
- package/build/static/js/{runtime-main.7fadd252.js.map → runtime-main.2227285f.js.map} +1 -1
- package/package.json +21 -21
- package/build/static/js/12.a879bfa6.chunk.js.map +0 -1
- package/build/static/js/7.96fdf7e5.chunk.js.map +0 -1
|
@@ -1,308 +1,33 @@
|
|
|
1
|
-
/* eslint-disable arrow-parens */
|
|
2
|
-
const get = require('lodash/get');
|
|
3
|
-
const joinUrl = require('url-join');
|
|
4
|
-
|
|
5
|
-
const { extractUserAvatar } = require('@abtnode/util/lib/user-avatar');
|
|
6
|
-
const formatContext = require('@abtnode/util/lib/format-context');
|
|
7
|
-
const {
|
|
8
|
-
messages,
|
|
9
|
-
getVCFromClaims,
|
|
10
|
-
checkWalletVersion,
|
|
11
|
-
getUser,
|
|
12
|
-
getPassportStatusEndpoint,
|
|
13
|
-
validatePassportStatus,
|
|
14
|
-
} = require('@abtnode/auth/lib/auth');
|
|
15
|
-
const {
|
|
16
|
-
ROLES,
|
|
17
|
-
VC_TYPE_GENERAL_PASSPORT,
|
|
18
|
-
VC_TYPE_NODE_PASSPORT,
|
|
19
|
-
NODE_SERVICES,
|
|
20
|
-
WELLKNOWN_SERVICE_PATH_PREFIX,
|
|
21
|
-
WHO_CAN_ACCESS,
|
|
22
|
-
} = require('@abtnode/constant');
|
|
23
|
-
const {
|
|
24
|
-
createPassportVC,
|
|
25
|
-
createPassport,
|
|
26
|
-
validatePassport,
|
|
27
|
-
isUserPassportRevoked,
|
|
28
|
-
upsertToPassports,
|
|
29
|
-
getRoleFromLocalPassport,
|
|
30
|
-
getRoleFromExternalPassport,
|
|
31
|
-
createUserPassport,
|
|
32
|
-
} = require('@abtnode/auth/lib/passport');
|
|
33
1
|
const logger = require('@abtnode/logger')(require('../../../../package.json').name);
|
|
34
2
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @returns {Array} config
|
|
39
|
-
* @returns {Boolean} config[0] is invited user only
|
|
40
|
-
* @returns {String} config[1] default role
|
|
41
|
-
* @returns {Boolean} config[2] issue passport
|
|
42
|
-
*/
|
|
43
|
-
const isInvitedUserOnly = async (config, node, teamDid) => {
|
|
44
|
-
const count = await node.getUsersCount({ teamDid });
|
|
45
|
-
|
|
46
|
-
// issue owner passport for first login user
|
|
47
|
-
if (count === 0) {
|
|
48
|
-
return [false, ROLES.OWNER, true];
|
|
49
|
-
}
|
|
3
|
+
const { login } = require('../../../libs/connect/session');
|
|
50
4
|
|
|
51
|
-
|
|
52
|
-
return [true];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if ([WHO_CAN_ACCESS.ALL].includes(config.whoCanAccess)) {
|
|
56
|
-
return [false, ROLES.GUEST];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return [false, ROLES.GUEST];
|
|
60
|
-
};
|
|
5
|
+
const { onConnect, onApprove } = login;
|
|
61
6
|
|
|
62
7
|
module.exports = function createRoutes(node, authenticator, createSessionToken) {
|
|
63
8
|
return {
|
|
64
9
|
action: 'login',
|
|
65
|
-
onConnect: async ({ req, userDid }) => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const claims = {
|
|
69
|
-
profile: async ({ extraParams, context }) => {
|
|
70
|
-
const { locale } = extraParams;
|
|
71
|
-
|
|
72
|
-
const config = await context.request.getServiceConfig(NODE_SERVICES.AUTH);
|
|
73
|
-
const profileFields = get(config, 'profileFields');
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
fields: profileFields || ['fullName', 'avatar'],
|
|
77
|
-
description: messages.description[locale],
|
|
78
|
-
};
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
verifiableCredential: async ({ context, extraParams: { locale, passportId = '' } }) => {
|
|
82
|
-
const { request, didwallet } = context;
|
|
83
|
-
const { wallet, did: teamDid } = await request.getBlockletInfo();
|
|
84
|
-
|
|
85
|
-
checkWalletVersion({ didwallet, locale });
|
|
86
|
-
|
|
87
|
-
const trustedPassports = (blocklet.trustedPassports || []).map((x) => x.issuerDid);
|
|
88
|
-
const trustedIssuers = [wallet.address, ...trustedPassports].filter(Boolean);
|
|
89
|
-
|
|
90
|
-
const config = (await request.getServiceConfig(NODE_SERVICES.AUTH)) || {};
|
|
91
|
-
const [invitedUserOnly] = await isInvitedUserOnly(config, node, teamDid);
|
|
92
|
-
|
|
93
|
-
const claim = {
|
|
94
|
-
description: messages.requestPassport[locale],
|
|
95
|
-
item: vcTypes,
|
|
96
|
-
trustedIssuers,
|
|
97
|
-
optional: !invitedUserOnly,
|
|
98
|
-
};
|
|
99
|
-
if (passportId) {
|
|
100
|
-
claim.target = passportId;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return claim;
|
|
104
|
-
},
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const user = await node.getUser({ teamDid: blocklet.meta.did, user: { did: userDid } });
|
|
108
|
-
if (user) {
|
|
109
|
-
delete claims.profile;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return claims;
|
|
10
|
+
onConnect: async ({ req, userDid, extraParams: { locale, passportId = '' } }) => {
|
|
11
|
+
return onConnect({ node, request: req, userDid, locale, passportId });
|
|
113
12
|
},
|
|
114
13
|
|
|
115
|
-
// eslint-disable-next-line consistent-return
|
|
116
14
|
onAuth: async ({ claims, challenge, userDid, userPk, updateSession, extraParams, req, baseUrl }) => {
|
|
117
|
-
const { locale } = extraParams;
|
|
118
|
-
const blocklet = await req.getBlocklet();
|
|
119
|
-
const { wallet, name, passportColor, did: teamDid } = await req.getBlockletInfo();
|
|
120
|
-
const teamAppDid = wallet.address;
|
|
121
|
-
|
|
122
|
-
// check user approved
|
|
123
|
-
const user = await getUser(node, teamDid, userDid);
|
|
124
|
-
if (user && !user.approved) {
|
|
125
|
-
throw new Error(messages.notAllowed[locale]);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Get passport
|
|
129
|
-
const trustedPassports = (blocklet.trustedPassports || []).map((x) => x.issuerDid);
|
|
130
|
-
const trustedIssuers = [teamAppDid, ...trustedPassports].filter(Boolean);
|
|
131
|
-
const { vc: inputVC } = await getVCFromClaims({
|
|
132
|
-
claims,
|
|
133
|
-
challenge,
|
|
134
|
-
trustedIssuers,
|
|
135
|
-
vcTypes,
|
|
136
|
-
locale,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
let vc = inputVC;
|
|
140
|
-
|
|
141
|
-
const config = (await req.getServiceConfig(NODE_SERVICES.AUTH)) || {};
|
|
142
|
-
const [invitedUserOnly, defaultRole, issuePassport] = await isInvitedUserOnly(config, node, teamDid);
|
|
143
|
-
|
|
144
|
-
if (invitedUserOnly && !vc) {
|
|
145
|
-
throw new Error(messages.missingCredentialClaim[locale]);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// issue passport for the first login user in a invite-only team
|
|
149
|
-
if (issuePassport) {
|
|
150
|
-
logger.info('issue passport to user at the login workflow', { role: defaultRole });
|
|
151
|
-
const profile = claims.find((x) => x.type === 'profile');
|
|
152
|
-
vc = createPassportVC({
|
|
153
|
-
issuerName: name,
|
|
154
|
-
issuerWallet: wallet,
|
|
155
|
-
ownerDid: userDid,
|
|
156
|
-
passport: await createPassport({
|
|
157
|
-
name: defaultRole,
|
|
158
|
-
node,
|
|
159
|
-
teamDid,
|
|
160
|
-
locale,
|
|
161
|
-
endpoint: baseUrl,
|
|
162
|
-
}),
|
|
163
|
-
endpoint: getPassportStatusEndpoint({
|
|
164
|
-
baseUrl: joinUrl(baseUrl, WELLKNOWN_SERVICE_PATH_PREFIX),
|
|
165
|
-
userDid,
|
|
166
|
-
teamDid,
|
|
167
|
-
}),
|
|
168
|
-
ownerProfile: profile,
|
|
169
|
-
preferredColor: passportColor,
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Get user passport from vc
|
|
174
|
-
let passport = vc ? createUserPassport(vc) : null;
|
|
175
|
-
if (user && passport && isUserPassportRevoked(user, passport)) {
|
|
176
|
-
throw new Error(messages.passportRevoked[locale](name));
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Get role
|
|
180
|
-
let role = ROLES.GUEST;
|
|
181
|
-
if (vc) {
|
|
182
|
-
await validatePassport(get(vc, 'credentialSubject.passport'));
|
|
183
|
-
const issuerId = get(vc, 'issuer.id');
|
|
184
|
-
if (issuerId === teamAppDid) {
|
|
185
|
-
role = getRoleFromLocalPassport(get(vc, 'credentialSubject.passport'));
|
|
186
|
-
} else {
|
|
187
|
-
// map external passport to local role
|
|
188
|
-
const { mappings = [] } = (blocklet.trustedPassports || []).find((x) => x.issuerDid === issuerId) || {};
|
|
189
|
-
role = await getRoleFromExternalPassport({
|
|
190
|
-
passport: get(vc, 'credentialSubject.passport'),
|
|
191
|
-
node,
|
|
192
|
-
teamDid,
|
|
193
|
-
locale,
|
|
194
|
-
mappings,
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
// check status of external passport if passport has an endpoint
|
|
198
|
-
const endpoint = get(vc, 'credentialStatus.id');
|
|
199
|
-
if (endpoint) {
|
|
200
|
-
await validatePassportStatus({ vcId: vc.id, endpoint, locale });
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (config.whoCanAccess === WHO_CAN_ACCESS.OWNER && role !== ROLES.OWNER) {
|
|
206
|
-
throw new Error(
|
|
207
|
-
{
|
|
208
|
-
zh: '你不是该应用的所有者',
|
|
209
|
-
en: 'You are not the owner of this application',
|
|
210
|
-
}[locale]
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Recreate passport with correct role
|
|
215
|
-
passport = vc ? createUserPassport(vc, { role }) : null;
|
|
216
|
-
|
|
217
|
-
// Update profile
|
|
218
15
|
try {
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
},
|
|
231
|
-
});
|
|
232
|
-
await node.createAuditLog(
|
|
233
|
-
{
|
|
234
|
-
action: 'login',
|
|
235
|
-
args: { teamDid, userDid, passport: passportForLog },
|
|
236
|
-
context: formatContext(Object.assign(req, { user: doc })),
|
|
237
|
-
result: doc,
|
|
238
|
-
},
|
|
239
|
-
node
|
|
240
|
-
);
|
|
241
|
-
} else {
|
|
242
|
-
// Create user
|
|
243
|
-
const profile = claims.find((x) => x.type === 'profile');
|
|
244
|
-
|
|
245
|
-
const doc = await node.addUser({
|
|
246
|
-
teamDid,
|
|
247
|
-
user: {
|
|
248
|
-
...profile,
|
|
249
|
-
avatar: await extractUserAvatar(get(profile, 'avatar'), {
|
|
250
|
-
dataDir: blocklet.env.dataDir,
|
|
251
|
-
}),
|
|
252
|
-
did: userDid,
|
|
253
|
-
pk: userPk,
|
|
254
|
-
approved: true,
|
|
255
|
-
locale,
|
|
256
|
-
passports: [passport].filter(Boolean),
|
|
257
|
-
firstLoginAt: new Date().toISOString(),
|
|
258
|
-
lastLoginAt: new Date().toISOString(),
|
|
259
|
-
},
|
|
260
|
-
});
|
|
261
|
-
await node.createAuditLog(
|
|
262
|
-
{
|
|
263
|
-
action: 'addUser',
|
|
264
|
-
args: { teamDid, userDid, reason: `first login as ${passportForLog.role}` },
|
|
265
|
-
context: formatContext(Object.assign(req, { user: doc })),
|
|
266
|
-
result: doc,
|
|
267
|
-
},
|
|
268
|
-
node
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Generate new session token that client can save to localStorage
|
|
273
|
-
const sessionToken = await createSessionToken(userDid, { passport, role });
|
|
274
|
-
await updateSession({ sessionToken }, true);
|
|
275
|
-
logger.info('login.success', { userDid, role });
|
|
276
|
-
|
|
277
|
-
if (
|
|
278
|
-
// if user provides owner passport AND app does not have owner, set this user to owner
|
|
279
|
-
(inputVC && role === ROLES.OWNER && !blocklet.settings?.owner) ||
|
|
280
|
-
// if the user will receive a owner passport AND app does not have owner, set this user to owner
|
|
281
|
-
(issuePassport && defaultRole === ROLES.OWNER && !blocklet.settings?.owner)
|
|
282
|
-
) {
|
|
283
|
-
logger.info('Bind owner for blocklet', { teamDid, userDid });
|
|
284
|
-
await node.setBlockletInitialized({ did: teamDid, owner: { did: userDid, pk: userPk } });
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// issue passport for the first login user in a invite-only team
|
|
288
|
-
if (issuePassport) {
|
|
289
|
-
return {
|
|
290
|
-
disposition: 'attachment',
|
|
291
|
-
type: 'VerifiableCredential',
|
|
292
|
-
data: vc,
|
|
293
|
-
nextWorkflowData: {
|
|
294
|
-
userDid,
|
|
295
|
-
},
|
|
296
|
-
};
|
|
297
|
-
}
|
|
16
|
+
const result = await onApprove({
|
|
17
|
+
node,
|
|
18
|
+
request: req,
|
|
19
|
+
locale: extraParams.locale,
|
|
20
|
+
challenge,
|
|
21
|
+
userDid,
|
|
22
|
+
userPk,
|
|
23
|
+
baseUrl,
|
|
24
|
+
claims,
|
|
25
|
+
createSessionToken,
|
|
26
|
+
});
|
|
298
27
|
|
|
299
|
-
|
|
28
|
+
await updateSession({ sessionToken: result.sessionToken }, true);
|
|
300
29
|
|
|
301
|
-
return
|
|
302
|
-
nextWorkflowData: {
|
|
303
|
-
userDid,
|
|
304
|
-
},
|
|
305
|
-
};
|
|
30
|
+
return result;
|
|
306
31
|
} catch (err) {
|
|
307
32
|
logger.error('login.error', { error: err, userDid });
|
|
308
33
|
throw new Error(err.message);
|
|
@@ -1,116 +1,31 @@
|
|
|
1
|
-
const
|
|
2
|
-
const formatContext = require('@abtnode/util/lib/format-context');
|
|
3
|
-
const { messages, getVCFromClaims, getUser, validatePassportStatus } = require('@abtnode/auth/lib/auth');
|
|
4
|
-
const { ROLES, VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT } = require('@abtnode/constant');
|
|
5
|
-
const {
|
|
6
|
-
validatePassport,
|
|
7
|
-
isUserPassportRevoked,
|
|
8
|
-
getRoleFromLocalPassport,
|
|
9
|
-
getRoleFromExternalPassport,
|
|
10
|
-
createUserPassport,
|
|
11
|
-
} = require('@abtnode/auth/lib/passport');
|
|
1
|
+
const { switchPassport } = require('../../../libs/connect/session');
|
|
12
2
|
|
|
13
|
-
const
|
|
3
|
+
const { onConnect, onApprove } = switchPassport;
|
|
14
4
|
|
|
15
5
|
module.exports = function createRoutes(node, authenticator, createSessionToken) {
|
|
16
6
|
return {
|
|
17
7
|
action: 'switch-passport',
|
|
18
8
|
onConnect: async ({ req, userDid, extraParams: { locale, connectedDid } }) => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (!user) {
|
|
27
|
-
throw new Error(messages.userNotFound[locale]);
|
|
28
|
-
}
|
|
29
|
-
if (!user.approved) {
|
|
30
|
-
throw new Error(messages.notAuthorized[locale]);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
verifiableCredential: async ({ context }) => {
|
|
35
|
-
const { request } = context;
|
|
36
|
-
const blocklet = await request.getBlocklet();
|
|
37
|
-
|
|
38
|
-
const trustedPassports = (blocklet.trustedPassports || []).map((x) => x.issuerDid);
|
|
39
|
-
const trustedIssuers = [wallet.address, ...trustedPassports].filter(Boolean);
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
description: messages.requestPassport[locale],
|
|
43
|
-
item: vcTypes,
|
|
44
|
-
trustedIssuers,
|
|
45
|
-
optional: false,
|
|
46
|
-
};
|
|
47
|
-
},
|
|
48
|
-
};
|
|
9
|
+
return onConnect({
|
|
10
|
+
node,
|
|
11
|
+
request: req,
|
|
12
|
+
locale,
|
|
13
|
+
userDid,
|
|
14
|
+
previousUserDid: connectedDid,
|
|
15
|
+
});
|
|
49
16
|
},
|
|
50
17
|
|
|
51
18
|
onAuth: async ({ claims, challenge, userDid, updateSession, extraParams, req }) => {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
if (!user.approved) {
|
|
62
|
-
throw new Error(messages.notAuthorized[locale]);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Get passport
|
|
66
|
-
const trustedPassports = (blocklet.trustedPassports || []).map((x) => x.issuerDid);
|
|
67
|
-
const trustedIssuers = [wallet.address, ...trustedPassports].filter(Boolean);
|
|
68
|
-
const { vc } = await getVCFromClaims({ claims, challenge, trustedIssuers, vcTypes, locale });
|
|
69
|
-
|
|
70
|
-
// Get user passport from vc
|
|
71
|
-
let passport = createUserPassport(vc);
|
|
72
|
-
if (passport && isUserPassportRevoked(user, passport)) {
|
|
73
|
-
throw new Error(messages.passportRevoked[locale](name));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Get role
|
|
77
|
-
let role = ROLES.GUEST;
|
|
78
|
-
await validatePassport(get(vc, 'credentialSubject.passport'));
|
|
79
|
-
const issuerId = get(vc, 'issuer.id');
|
|
80
|
-
if (issuerId === wallet.address) {
|
|
81
|
-
role = getRoleFromLocalPassport(get(vc, 'credentialSubject.passport'));
|
|
82
|
-
} else {
|
|
83
|
-
// map external passport to local role
|
|
84
|
-
const { mappings = [] } = (blocklet.trustedPassports || []).find((x) => x.issuerDid === issuerId) || {};
|
|
85
|
-
role = await getRoleFromExternalPassport({
|
|
86
|
-
passport: get(vc, 'credentialSubject.passport'),
|
|
87
|
-
node,
|
|
88
|
-
teamDid,
|
|
89
|
-
locale,
|
|
90
|
-
mappings,
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// check status of external passport if passport has an endpoint
|
|
94
|
-
const endpoint = get(vc, 'credentialStatus.id');
|
|
95
|
-
if (endpoint) {
|
|
96
|
-
await validatePassportStatus({ vcId: vc.id, endpoint, locale });
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Recreate passport with correct role
|
|
101
|
-
passport = createUserPassport(vc, { role });
|
|
102
|
-
await node.createAuditLog(
|
|
103
|
-
{
|
|
104
|
-
action: 'switchPassport',
|
|
105
|
-
args: { teamDid, userDid, passport },
|
|
106
|
-
context: formatContext(Object.assign(req, { user })),
|
|
107
|
-
result: {},
|
|
108
|
-
},
|
|
109
|
-
node
|
|
110
|
-
);
|
|
19
|
+
const sessionToken = await onApprove({
|
|
20
|
+
node,
|
|
21
|
+
request: req,
|
|
22
|
+
challenge,
|
|
23
|
+
locale: extraParams.locale,
|
|
24
|
+
verifiableCredential: claims.find((x) => x.type === 'verifiableCredential'),
|
|
25
|
+
userDid,
|
|
26
|
+
createSessionToken,
|
|
27
|
+
});
|
|
111
28
|
|
|
112
|
-
// Generate new session token that client can save to localStorage
|
|
113
|
-
const sessionToken = await createSessionToken(userDid, { passport, role });
|
|
114
29
|
await updateSession({ sessionToken }, true);
|
|
115
30
|
},
|
|
116
31
|
};
|
|
@@ -1,75 +1,29 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
const {
|
|
4
|
-
const { NODE_SERVICES } = require('@abtnode/constant');
|
|
5
|
-
const { extractUserAvatar } = require('@abtnode/util/lib/user-avatar');
|
|
1
|
+
const { switchProfile } = require('../../../libs/connect/session');
|
|
2
|
+
|
|
3
|
+
const { onConnect, onApprove } = switchProfile;
|
|
6
4
|
|
|
7
5
|
module.exports = function createRoutes(node) {
|
|
8
6
|
return {
|
|
9
7
|
action: 'switch-profile',
|
|
10
|
-
onConnect:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const { did: teamDid } = await req.getBlockletInfo();
|
|
21
|
-
const user = await getUser(node, teamDid, userDid);
|
|
22
|
-
|
|
23
|
-
if (!user) {
|
|
24
|
-
throw new Error(messages.userNotFound[locale]);
|
|
25
|
-
}
|
|
26
|
-
if (!user.approved) {
|
|
27
|
-
throw new Error(messages.notAuthorized[locale]);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return {
|
|
31
|
-
profile: {
|
|
32
|
-
fields: get(config, 'profileFields') || ['fullName', 'avatar'],
|
|
33
|
-
description: messages.description[locale],
|
|
34
|
-
},
|
|
35
|
-
};
|
|
8
|
+
onConnect: ({ req, userDid, extraParams: { locale, connectedDid } }) => {
|
|
9
|
+
return onConnect({
|
|
10
|
+
node,
|
|
11
|
+
request: req,
|
|
12
|
+
locale,
|
|
13
|
+
userDid,
|
|
14
|
+
previousUserDid: connectedDid,
|
|
15
|
+
});
|
|
36
16
|
},
|
|
37
17
|
|
|
38
18
|
onAuth: async ({ req, claims, userDid, extraParams: { locale } }) => {
|
|
39
|
-
const blocklet = await req.getBlocklet();
|
|
40
|
-
const teamDid = blocklet.meta.did;
|
|
41
|
-
|
|
42
|
-
// check user approved
|
|
43
|
-
const user = await getUser(node, teamDid, userDid);
|
|
44
|
-
if (!user) {
|
|
45
|
-
throw new Error(messages.userNotFound[locale]);
|
|
46
|
-
}
|
|
47
|
-
if (!user.approved) {
|
|
48
|
-
throw new Error(messages.notAuthorized[locale]);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Update user
|
|
52
19
|
const profile = claims.find((x) => x.type === 'profile');
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
dataDir: blocklet.env.dataDir,
|
|
60
|
-
}),
|
|
61
|
-
locale,
|
|
62
|
-
},
|
|
20
|
+
return onApprove({
|
|
21
|
+
node,
|
|
22
|
+
request: req,
|
|
23
|
+
locale,
|
|
24
|
+
profile,
|
|
25
|
+
userDid,
|
|
63
26
|
});
|
|
64
|
-
await node.createAuditLog(
|
|
65
|
-
{
|
|
66
|
-
action: 'switchProfile',
|
|
67
|
-
args: { teamDid, userDid, profile },
|
|
68
|
-
context: formatContext(Object.assign(req, { user })),
|
|
69
|
-
result: doc,
|
|
70
|
-
},
|
|
71
|
-
node
|
|
72
|
-
);
|
|
73
27
|
},
|
|
74
28
|
};
|
|
75
29
|
};
|
|
@@ -78,7 +78,10 @@ const onAuthenticate = async ({ channel, node }) => {
|
|
|
78
78
|
|
|
79
79
|
const exist = await node.hasBlocklet({ did: appDid });
|
|
80
80
|
if (!exist) {
|
|
81
|
-
|
|
81
|
+
const nodeInfo = await node.getNodeInfo();
|
|
82
|
+
if (nodeInfo.did !== appDid) {
|
|
83
|
+
throw new Error(`App does not exist: ${appDid}`);
|
|
84
|
+
}
|
|
82
85
|
}
|
|
83
86
|
};
|
|
84
87
|
|
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
"static/js/2.dc4d44c3.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/2.dc4d44c3.chunk.js.map",
|
|
9
9
|
"main.js": "/.blocklet/proxy/blocklet-service/static/js/main.67b92d1a.chunk.js",
|
|
10
10
|
"main.js.map": "/.blocklet/proxy/blocklet-service/static/js/main.67b92d1a.chunk.js.map",
|
|
11
|
-
"runtime-main.js": "/.blocklet/proxy/blocklet-service/static/js/runtime-main.
|
|
12
|
-
"runtime-main.js.map": "/.blocklet/proxy/blocklet-service/static/js/runtime-main.
|
|
11
|
+
"runtime-main.js": "/.blocklet/proxy/blocklet-service/static/js/runtime-main.2227285f.js",
|
|
12
|
+
"runtime-main.js.map": "/.blocklet/proxy/blocklet-service/static/js/runtime-main.2227285f.js.map",
|
|
13
13
|
"static/css/5.4db48a1d.chunk.css": "/.blocklet/proxy/blocklet-service/static/css/5.4db48a1d.chunk.css",
|
|
14
14
|
"static/js/5.40b9123f.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/5.40b9123f.chunk.js",
|
|
15
15
|
"static/js/5.40b9123f.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/5.40b9123f.chunk.js.map",
|
|
16
16
|
"static/js/6.d8cacc55.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/6.d8cacc55.chunk.js",
|
|
17
17
|
"static/js/6.d8cacc55.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/6.d8cacc55.chunk.js.map",
|
|
18
|
-
"static/js/7.
|
|
19
|
-
"static/js/7.
|
|
18
|
+
"static/js/7.b2428475.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/7.b2428475.chunk.js",
|
|
19
|
+
"static/js/7.b2428475.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/7.b2428475.chunk.js.map",
|
|
20
20
|
"static/js/8.512a38a3.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/8.512a38a3.chunk.js",
|
|
21
21
|
"static/js/8.512a38a3.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/8.512a38a3.chunk.js.map",
|
|
22
22
|
"static/js/9.c10d6f6d.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/9.c10d6f6d.chunk.js",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"static/js/10.7cdccc61.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/10.7cdccc61.chunk.js.map",
|
|
26
26
|
"static/js/11.4647209f.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/11.4647209f.chunk.js",
|
|
27
27
|
"static/js/11.4647209f.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/11.4647209f.chunk.js.map",
|
|
28
|
-
"static/js/12.
|
|
29
|
-
"static/js/12.
|
|
28
|
+
"static/js/12.0e874475.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/12.0e874475.chunk.js",
|
|
29
|
+
"static/js/12.0e874475.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/12.0e874475.chunk.js.map",
|
|
30
30
|
"static/js/13.14a45622.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/13.14a45622.chunk.js",
|
|
31
31
|
"static/js/13.14a45622.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/13.14a45622.chunk.js.map",
|
|
32
32
|
"index.html": "/.blocklet/proxy/blocklet-service/index.html",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"static/media/700.css": "/.blocklet/proxy/blocklet-service/static/media/lato-latin-ext-700-normal.9c8812ea.woff2"
|
|
39
39
|
},
|
|
40
40
|
"entrypoints": [
|
|
41
|
-
"static/js/runtime-main.
|
|
41
|
+
"static/js/runtime-main.2227285f.js",
|
|
42
42
|
"static/css/5.4db48a1d.chunk.css",
|
|
43
43
|
"static/js/5.40b9123f.chunk.js",
|
|
44
44
|
"static/js/main.67b92d1a.chunk.js"
|
package/build/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/.well-known/service/static/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#000000"/><title>Blocklet Service</title><script src=".well-known/service/api/env"></script><link href="/.blocklet/proxy/blocklet-service/static/css/5.4db48a1d.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,u,i=t[0],l=t[1],f=t[2],s=t[3]||[],d=0,h=[];d<i.length;d++)u=i[d],Object.prototype.hasOwnProperty.call(o,u)&&o[u]&&h.push(o[u][0]),o[u]=0;for(n in l)Object.prototype.hasOwnProperty.call(l,n)&&(e[n]=l[n]);for(p&&p(t),a.push.apply(a,s);h.length;)h.shift()();return c.push.apply(c,f||[]),r()}function r(){for(var e,t=0;t<c.length;t++){for(var r=c[t],n=!0,l=1;l<r.length;l++){var f=r[l];0!==o[f]&&(n=!1)}n&&(c.splice(t--,1),e=i(i.s=r[0]))}return 0===c.length&&(a.forEach((function(e){if(void 0===o[e]){o[e]=null;var t=document.createElement("link");i.nc&&t.setAttribute("nonce",i.nc),t.rel="prefetch",t.as="script",t.href=u(e),document.head.appendChild(t)}})),a.length=0),e}var n={},o={4:0},c=[],a=[];function u(e){return i.p+"static/js/"+({}[e]||e)+"."+{0:"125a8c91",1:"19473290",2:"dc4d44c3",6:"d8cacc55",7:"
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/.well-known/service/static/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#000000"/><title>Blocklet Service</title><script src=".well-known/service/api/env"></script><link href="/.blocklet/proxy/blocklet-service/static/css/5.4db48a1d.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,u,i=t[0],l=t[1],f=t[2],s=t[3]||[],d=0,h=[];d<i.length;d++)u=i[d],Object.prototype.hasOwnProperty.call(o,u)&&o[u]&&h.push(o[u][0]),o[u]=0;for(n in l)Object.prototype.hasOwnProperty.call(l,n)&&(e[n]=l[n]);for(p&&p(t),a.push.apply(a,s);h.length;)h.shift()();return c.push.apply(c,f||[]),r()}function r(){for(var e,t=0;t<c.length;t++){for(var r=c[t],n=!0,l=1;l<r.length;l++){var f=r[l];0!==o[f]&&(n=!1)}n&&(c.splice(t--,1),e=i(i.s=r[0]))}return 0===c.length&&(a.forEach((function(e){if(void 0===o[e]){o[e]=null;var t=document.createElement("link");i.nc&&t.setAttribute("nonce",i.nc),t.rel="prefetch",t.as="script",t.href=u(e),document.head.appendChild(t)}})),a.length=0),e}var n={},o={4:0},c=[],a=[];function u(e){return i.p+"static/js/"+({}[e]||e)+"."+{0:"125a8c91",1:"19473290",2:"dc4d44c3",6:"d8cacc55",7:"b2428475",8:"512a38a3",9:"c10d6f6d",10:"7cdccc61",11:"4647209f",12:"0e874475",13:"14a45622"}[e]+".chunk.js"}function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r=o[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=o[e]=[t,n]}));t.push(r[2]=n);var c,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=u(e);var l=new Error;c=function(t){a.onerror=a.onload=null,clearTimeout(f);var r=o[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),c=t&&t.target&&t.target.src;l.message="Loading chunk "+e+" failed.\n("+n+": "+c+")",l.name="ChunkLoadError",l.type=n,l.request=c,r[1](l)}o[e]=void 0}};var f=setTimeout((function(){c({type:"timeout",target:a})}),12e4);a.onerror=a.onload=c,document.head.appendChild(a)}return Promise.all(t)},i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/.blocklet/proxy/blocklet-service/",i.oe=function(e){throw console.error(e),e};var l=this["webpackJsonp@abtnode/blocklet-services"]=this["webpackJsonp@abtnode/blocklet-services"]||[],f=l.push.bind(l);l.push=t,l=l.slice();for(var s=0;s<l.length;s++)t(l[s]);var p=f;r()}([])</script><script src="/.blocklet/proxy/blocklet-service/static/js/5.40b9123f.chunk.js"></script><script src="/.blocklet/proxy/blocklet-service/static/js/main.67b92d1a.chunk.js"></script></body></html>
|