@abtnode/auth 1.8.35 → 1.8.37

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/auth.js CHANGED
@@ -48,6 +48,10 @@ const messages = {
48
48
  en: 'Please provide passport',
49
49
  zh: '请提供通行证',
50
50
  },
51
+ requestOwnerPassport: {
52
+ en: 'Please provide owner passport',
53
+ zh: '请提供节点的所有者通行证',
54
+ },
51
55
  requestBlockletNft: {
52
56
  en: 'Please provide Blocklet Purchase NFT',
53
57
  zh: '请提供 Blocklet Purchase NFT',
@@ -225,6 +229,10 @@ const messages = {
225
229
  en: 'Not allowed to transfer the Server to yourself',
226
230
  zh: '不能将节点转移给自己',
227
231
  },
232
+ tagRequired: {
233
+ en: 'tag is required',
234
+ zh: 'tag 不能为空',
235
+ },
228
236
  };
229
237
 
230
238
  const PASSPORT_STATUS_KEY = 'passport-status';
package/lib/server.js CHANGED
@@ -11,8 +11,8 @@ const {
11
11
  VC_TYPE_GENERAL_PASSPORT,
12
12
  VC_TYPE_NODE_PASSPORT,
13
13
  NFT_TYPE_SERVER_OWNERSHIP,
14
- VC_TYPE_SERVER_SHARE,
15
14
  SERVER_ROLES,
15
+ NFT_TYPE_SERVER_USAGE_CREDENTIAL,
16
16
  } = require('@abtnode/constant');
17
17
  const { toExternalBlocklet } = require('@blocklet/meta/lib/did');
18
18
  const {
@@ -41,46 +41,27 @@ const LAUNCH_BLOCKLET_TOKEN_EXPIRE = '1d';
41
41
  // Assuming the blocklet installation will take no more than 20 min
42
42
  const EXTERNAL_LAUNCH_BLOCKLET_TOKEN_EXPIRE = '20m';
43
43
 
44
- const abtnodeVcTypes = (launchBlocklet) =>
45
- launchBlocklet
46
- ? [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT, VC_TYPE_SERVER_SHARE]
47
- : [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
44
+ const BLOCKLET_SERVER_VC_TYPES = [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
48
45
 
49
46
  const ensureLauncherIssuer = (issuers, nodeInfo) => {
50
- // TODO: server 开启共享后, 才接收 launcher 颁发的 nft
51
-
52
47
  const launcherDid = get(nodeInfo, 'launcher.did');
53
48
  if (launcherDid) {
54
49
  issuers.push(launcherDid);
55
50
  }
56
51
  };
57
52
 
58
- const getExternalPassport = async (vc, nodeInfo) => {
59
- // TODO: server 开启共享后, 才接收 launcher 颁发的 nft
60
-
61
- const launcherDid = get(nodeInfo, 'launcher.did');
62
- if (!launcherDid) {
63
- return null;
64
- }
65
-
66
- if (vc.issuer.id !== launcherDid) {
67
- return null;
68
- }
69
-
70
- if (!vc.type.includes(VC_TYPE_SERVER_SHARE)) {
71
- throw new Error('Cannot get NFT issued by launcher: Invalid type');
72
- }
53
+ const getTrustedIssuers = (nodeInfo) => {
54
+ const trustedPassports = (nodeInfo.trustedPassports || []).map((x) => x.issuerDid);
55
+ return [nodeInfo.did, ...trustedPassports].filter(Boolean);
56
+ };
73
57
 
74
- if (vc.credentialSubject.serverDid !== nodeInfo.did) {
75
- throw new Error('Cannot get NFT issued by launcher: Invalid Server DID');
76
- }
58
+ const getExternalPassport = async (nft) => {
59
+ const data = JSON.parse(nft.data.value);
77
60
 
78
- // TODO more info from vc and launcher
79
- // FIXME expireDate 需要动态获取
80
61
  return {
81
62
  name: SERVER_ROLES.EXTERNAL_BLOCKLET_CONTROLLER,
82
- appMaxCount: vc.credentialSubject.appMaxCount || 1,
83
- expireDate: vc.credentialSubject.expireDate,
63
+ appMaxCount: data.appMaxCount || 1,
64
+ expireDate: last(data.expirationDate),
84
65
  };
85
66
  };
86
67
 
@@ -104,9 +85,7 @@ const authenticateByVc = async ({
104
85
  const teamDid = info.did;
105
86
  const { name } = info;
106
87
 
107
- // Get passport
108
- const trustedPassports = (info.trustedPassports || []).map((x) => x.issuerDid);
109
- const trustedIssuers = [info.did, ...trustedPassports].filter(Boolean);
88
+ const trustedIssuers = getTrustedIssuers(info);
110
89
 
111
90
  if (launchBlocklet) {
112
91
  ensureLauncherIssuer(trustedIssuers, info);
@@ -116,7 +95,7 @@ const authenticateByVc = async ({
116
95
  claims,
117
96
  challenge,
118
97
  trustedIssuers,
119
- vcTypes: abtnodeVcTypes(launchBlocklet),
98
+ vcTypes: BLOCKLET_SERVER_VC_TYPES,
120
99
  locale,
121
100
  vcId: blocklet?.controller?.vcId,
122
101
  });
@@ -125,27 +104,6 @@ const authenticateByVc = async ({
125
104
  throw new Error(messages.missingCredentialClaim[locale]);
126
105
  }
127
106
 
128
- // external user
129
- if (launchBlocklet) {
130
- const externalPassport = await getExternalPassport(vc, info);
131
- if (externalPassport) {
132
- return {
133
- role: externalPassport.name,
134
- extra: {
135
- controller: {
136
- vcId: vc.id,
137
- appMaxCount: externalPassport.appMaxCount,
138
- expireDate: externalPassport.expireDate,
139
- },
140
- },
141
- user: {
142
- did: userDid,
143
- },
144
- teamDid,
145
- };
146
- }
147
- }
148
-
149
107
  // check user approved
150
108
  const user = await getUser(node, teamDid, userDid);
151
109
  if (user && !user.approved) {
@@ -179,12 +137,10 @@ const authenticateByVc = async ({
179
137
  // check status of external passport if passport has an endpoint
180
138
  const endpoint = get(vc, 'credentialStatus.id');
181
139
  if (endpoint) {
182
- if (endpoint) {
183
- await validatePassportStatus({ vcId: vc.id, endpoint, locale });
184
- }
140
+ await validatePassportStatus({ vcId: vc.id, endpoint, locale });
185
141
  }
186
142
  }
187
- } else if (passportTypes.some((x) => [NFT_TYPE_SERVER_OWNERSHIP].includes(x))) {
143
+ } else if (passportTypes.includes(NFT_TYPE_SERVER_OWNERSHIP)) {
188
144
  role = ROLES.OWNER;
189
145
  } else {
190
146
  logger.error('cannot get role from passport, use "guest" for default', { passportTypes, vcId: vc.id });
@@ -237,6 +193,26 @@ const authenticateByNFT = async ({ node, claims, userDid, challenge, locale }) =
237
193
  throw new Error(messages.invalidNftIssuer[locale]);
238
194
  }
239
195
 
196
+ if (state.tags.includes(NFT_TYPE_SERVER_USAGE_CREDENTIAL) && state.tags.includes(info.did)) {
197
+ const passport = await getExternalPassport(state);
198
+
199
+ return {
200
+ role: SERVER_ROLES.EXTERNAL_BLOCKLET_CONTROLLER,
201
+ extra: {
202
+ controller: {
203
+ nftId: address,
204
+ nftOwner: state.owner,
205
+ appMaxCount: passport.appMaxCount,
206
+ expireDate: passport.expireDate,
207
+ },
208
+ },
209
+ user: {
210
+ did: userDid,
211
+ },
212
+ teamDid: info.did,
213
+ };
214
+ }
215
+
240
216
  // enforce tag match
241
217
  if (last(state.tags) !== info.launcher.tag) {
242
218
  throw new Error(messages.tagNotMatch[locale]);
@@ -247,14 +223,14 @@ const authenticateByNFT = async ({ node, claims, userDid, challenge, locale }) =
247
223
  };
248
224
 
249
225
  const getAuthVcClaim =
250
- ({ node, launchBlocklet, blocklet }) =>
226
+ ({ node, launchBlocklet, blocklet, options }) =>
251
227
  async ({ extraParams: { locale, passportId }, context: { didwallet } }) => {
252
228
  checkWalletVersion({ didwallet, locale });
253
229
 
254
230
  const baseClaim = {
255
231
  description: messages.requestPassport[locale],
256
232
  optional: false,
257
- item: abtnodeVcTypes(launchBlocklet),
233
+ item: BLOCKLET_SERVER_VC_TYPES,
258
234
  };
259
235
 
260
236
  if (blocklet && blocklet?.controller?.vcId) {
@@ -272,9 +248,7 @@ const getAuthVcClaim =
272
248
  }
273
249
 
274
250
  const info = await node.getNodeInfo();
275
- const trustedPassports = (info.trustedPassports || []).map((x) => x.issuerDid);
276
-
277
- const trustedIssuers = [info.did, ...trustedPassports].filter(Boolean);
251
+ const trustedIssuers = getTrustedIssuers(info);
278
252
 
279
253
  if (launchBlocklet) {
280
254
  ensureLauncherIssuer(trustedIssuers, info);
@@ -283,13 +257,18 @@ const getAuthVcClaim =
283
257
  return {
284
258
  ...baseClaim,
285
259
  trustedIssuers,
260
+ ...(options || {}),
286
261
  };
287
262
  };
288
263
 
289
264
  const getAuthNFTClaim =
290
265
  ({ node }) =>
291
- async ({ extraParams: { locale }, context: { didwallet } }) => {
266
+ async ({ extraParams: { locale, launchType }, context: { didwallet } }) => {
292
267
  checkWalletVersion({ didwallet, locale });
268
+ if (launchType === 'serverless') {
269
+ return getUsageCredentialNFTClaim(node, locale);
270
+ }
271
+
293
272
  return getOwnershipNFTClaim(node, locale);
294
273
  };
295
274
 
@@ -319,7 +298,7 @@ const getSetupBlockletClaims = (node, authMethod, blocklet) => {
319
298
 
320
299
  const getOwnershipNFTClaim = async (node, locale) => {
321
300
  const info = await node.getNodeInfo();
322
- if (!info.ownerNft && !info.ownerNft.issuer) {
301
+ if (!info.ownerNft || !info.ownerNft.issuer) {
323
302
  throw new Error(messages.noNft[locale]);
324
303
  }
325
304
 
@@ -339,6 +318,25 @@ const getOwnershipNFTClaim = async (node, locale) => {
339
318
  };
340
319
  };
341
320
 
321
+ const getUsageCredentialNFTClaim = async (node, locale) => {
322
+ const info = await node.getNodeInfo();
323
+ if (!info.ownerNft || !info.ownerNft.issuer) {
324
+ throw new Error(messages.noNft[locale]);
325
+ }
326
+
327
+ const chainHost = get(info, 'launcher.chainHost', '');
328
+
329
+ if (!chainHost) {
330
+ throw new Error(messages.noChainHost[locale]);
331
+ }
332
+
333
+ return {
334
+ description: messages.requestNft[locale],
335
+ trustedIssuers: [info.ownerNft.issuer],
336
+ tag: info.did,
337
+ };
338
+ };
339
+
342
340
  const ensureBlockletPermission = async ({ authMethod, node, userDid, claims, challenge, locale, blocklet }) => {
343
341
  let result;
344
342
  if (authMethod === 'vc') {
@@ -364,7 +362,7 @@ const ensureBlockletPermission = async ({ authMethod, node, userDid, claims, cha
364
362
  const { teamDid, role } = result;
365
363
 
366
364
  const permissions = await node.getPermissionsByRole({ teamDid, role: { name: role } });
367
- if (!permissions.some((item) => ['mutate_blockets'].includes(item.name))) {
365
+ if (!permissions.some((item) => ['mutate_blocklets'].includes(item.name))) {
368
366
  throw new Error(messages.notAuthorized[locale]);
369
367
  }
370
368
 
@@ -409,25 +407,22 @@ const createLaunchBlockletHandler =
409
407
 
410
408
  let sessionToken = '';
411
409
  if (authMethod === 'vc') {
412
- if (role === SERVER_ROLES.EXTERNAL_BLOCKLET_CONTROLLER) {
413
- // TODO get more info from vc and launcher
414
- controller = extra.controller;
415
- sessionToken = createBlockletControllerAuthToken({
416
- did: userDid,
417
- role,
418
- controller,
419
- secret,
420
- expiresIn: EXTERNAL_LAUNCH_BLOCKLET_TOKEN_EXPIRE,
421
- });
422
- } else {
423
- sessionToken = createAuthToken({
424
- did: userDid,
425
- passport,
426
- role,
427
- secret,
428
- expiresIn: LAUNCH_BLOCKLET_TOKEN_EXPIRE,
429
- });
430
- }
410
+ sessionToken = createAuthToken({
411
+ did: userDid,
412
+ passport,
413
+ role,
414
+ secret,
415
+ expiresIn: LAUNCH_BLOCKLET_TOKEN_EXPIRE,
416
+ });
417
+ } else if (role === SERVER_ROLES.EXTERNAL_BLOCKLET_CONTROLLER) {
418
+ controller = extra.controller;
419
+ sessionToken = createBlockletControllerAuthToken({
420
+ did: userDid,
421
+ role,
422
+ controller,
423
+ secret,
424
+ expiresIn: EXTERNAL_LAUNCH_BLOCKLET_TOKEN_EXPIRE,
425
+ });
431
426
  } else {
432
427
  sessionToken = createAuthTokenByOwnershipNFT({
433
428
  did: userDid,
@@ -491,4 +486,6 @@ module.exports = {
491
486
  createLaunchBlockletHandler,
492
487
  ensureBlockletPermission,
493
488
  getSetupBlockletClaims,
489
+ getTrustedIssuers,
490
+ getUsageCredentialNFTClaim,
494
491
  };
@@ -1,6 +1,10 @@
1
1
  const get = require('lodash/get');
2
2
 
3
- const getServerAuthMethod = (info) => {
3
+ const getServerAuthMethod = (info, type) => {
4
+ if (type === 'serverless') {
5
+ return 'nft';
6
+ }
7
+
4
8
  if (info.initialized) {
5
9
  return 'vc';
6
10
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.8.35",
6
+ "version": "1.8.37",
7
7
  "description": "Simple lib to manage auth in ABT Node",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -20,14 +20,14 @@
20
20
  "author": "linchen <linchen1987@foxmail.com> (http://github.com/linchen1987)",
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
- "@abtnode/constant": "1.8.35",
24
- "@abtnode/logger": "1.8.35",
25
- "@abtnode/util": "1.8.35",
23
+ "@abtnode/constant": "1.8.37",
24
+ "@abtnode/logger": "1.8.37",
25
+ "@abtnode/util": "1.8.37",
26
26
  "@arcblock/did": "1.18.15",
27
27
  "@arcblock/jwt": "^1.18.15",
28
28
  "@arcblock/vc": "1.18.15",
29
- "@blocklet/constant": "1.8.35",
30
- "@blocklet/meta": "1.8.35",
29
+ "@blocklet/constant": "1.8.37",
30
+ "@blocklet/meta": "1.8.37",
31
31
  "@ocap/client": "1.18.15",
32
32
  "@ocap/mcrypto": "1.18.15",
33
33
  "@ocap/util": "1.18.15",
@@ -42,5 +42,5 @@
42
42
  "devDependencies": {
43
43
  "jest": "^27.5.1"
44
44
  },
45
- "gitHead": "dd89e7a61dc8cff64302608ad5ab6545dd903daa"
45
+ "gitHead": "f26f451c6e2b1168b36f78269eafdf3f671236bf"
46
46
  }