@blocklet/meta 1.7.5 → 1.7.8

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/file.js CHANGED
@@ -34,7 +34,7 @@ const update = (file, meta) => {
34
34
  meta.specVersion = '1.0.0';
35
35
  }
36
36
 
37
- fs.writeFileSync(file, yaml.safeDump(meta, { sortKeys: false, skipInvalid: true }));
37
+ fs.writeFileSync(file, yaml.dump(meta, { sortKeys: false, skipInvalid: true }));
38
38
  };
39
39
 
40
40
  module.exports = { list, select, update };
@@ -0,0 +1,78 @@
1
+ const get = require('lodash/get');
2
+ const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
3
+
4
+ /**
5
+ * @param {*} navigation src
6
+ * @param {*} blocklet
7
+ * @param {*} prefix prefix of link
8
+ * @param {*} level 1 or 2. primary menu or secondary menu
9
+ */
10
+ const parseNavigation = (navigation, blocklet, prefix = '/', level = 1) => {
11
+ const result = [];
12
+
13
+ (navigation || []).forEach((nav) => {
14
+ if (!nav.child) {
15
+ const item = {
16
+ title: nav.title,
17
+ };
18
+
19
+ if (nav.link) {
20
+ item.link = normalizePathPrefix(`${prefix}${nav.link || '/'}`);
21
+ }
22
+
23
+ if (level === 1) {
24
+ const list = parseNavigation(nav.items, blocklet, prefix, 2);
25
+ if (list.length) {
26
+ item.items = list;
27
+ }
28
+ }
29
+
30
+ result.push(item);
31
+ return;
32
+ }
33
+
34
+ if (!blocklet) {
35
+ return;
36
+ }
37
+
38
+ // parse child
39
+ const child = (blocklet.children || []).find((x) => [x.meta.name, x.meta.did].includes(nav.child));
40
+ if (!child) {
41
+ return;
42
+ }
43
+ const childTitle = child.meta.title || child.meta.name;
44
+
45
+ const childNavigation = get(child, 'meta.navigation', []);
46
+ if (!childNavigation.length) {
47
+ // child does not declares menu
48
+ result.push({
49
+ title: nav.title || childTitle,
50
+ link: normalizePathPrefix(`${prefix}${child.mountPoint || '/'}`),
51
+ });
52
+ } else if (childNavigation.length === 1) {
53
+ // child declares one menu
54
+ result.push({
55
+ title: nav.title || childNavigation[0].title || childTitle,
56
+ link: normalizePathPrefix(`${prefix}${child.mountPoint}${childNavigation[0].link || '/'}`),
57
+ });
58
+ } else {
59
+ // child declares multiple menus
60
+ if (level === 1) { // eslint-disable-line
61
+ // primary menu
62
+ const item = {
63
+ title: nav.title || child.meta.title || child.meta.name,
64
+ items: parseNavigation(childNavigation, null, normalizePathPrefix(`${prefix}${child.mountPoint}`), 2),
65
+ };
66
+ result.push(item);
67
+ } else {
68
+ // secondary menu
69
+ const list = parseNavigation(childNavigation, null, normalizePathPrefix(`${prefix}${child.mountPoint}`), 2);
70
+ result.push(...list);
71
+ }
72
+ }
73
+ });
74
+
75
+ return result;
76
+ };
77
+
78
+ module.exports = parseNavigation;
package/lib/parse.js CHANGED
@@ -50,14 +50,14 @@ const parse = (
50
50
  const blockletMetaFileAlt = path.join(dir, BLOCKLET_META_FILE_ALT);
51
51
  if (fs.existsSync(blockletMetaFile)) {
52
52
  try {
53
- result = Object.assign(result, yaml.safeLoad(fs.readFileSync(blockletMetaFile).toString(), { json: true }));
53
+ result = Object.assign(result, yaml.load(fs.readFileSync(blockletMetaFile).toString(), { json: true }));
54
54
  debug(`parse ${blockletMetaFile}`, result);
55
55
  } catch (err) {
56
56
  console.error(`parse_blocklet_meta from ${BLOCKLET_META_FILE} failed`, err);
57
57
  }
58
58
  } else if (fs.existsSync(blockletMetaFileAlt)) {
59
59
  try {
60
- result = Object.assign(result, yaml.safeLoad(fs.readFileSync(blockletMetaFileAlt).toString(), { json: true }));
60
+ result = Object.assign(result, yaml.load(fs.readFileSync(blockletMetaFileAlt).toString(), { json: true }));
61
61
  debug(`parse ${blockletMetaFileAlt}`, result);
62
62
  } catch (err) {
63
63
  console.error(`parse_blocklet_meta from ${BLOCKLET_META_FILE_ALT} failed`, err);
package/lib/schema.js CHANGED
@@ -47,6 +47,7 @@ const environmentSchema = Joi.object({
47
47
 
48
48
  const scriptsSchema = Joi.object({
49
49
  dev: Joi.string().trim().min(1),
50
+ e2eDev: Joi.string().trim().min(1),
50
51
  preInstall: Joi.string().trim().min(1),
51
52
  postInstall: Joi.string().trim().min(1),
52
53
  preDeploy: Joi.string().trim().min(1),
@@ -137,6 +138,7 @@ const personSchema = Joi.object({
137
138
  const distSchema = Joi.object({
138
139
  tarball: Joi.alternatives().try(Joi.string().uri(), Joi.string()).required(),
139
140
  integrity: Joi.string().required(),
141
+ size: Joi.number().optional(),
140
142
  });
141
143
 
142
144
  const statsSchema = Joi.object({
@@ -161,8 +163,7 @@ const childrenSchema = Joi.object({
161
163
  services: Joi.array().items(serviceSchema).unique('name'),
162
164
  })
163
165
  )
164
- .optional()
165
- .default([]),
166
+ .optional(),
166
167
  mountPoint: Joi.string().trim().min(1), // added in 1.2.3
167
168
  services: Joi.array().items(serviceSchema).unique('name'), // added in 1.2.3
168
169
  }).custom((value) => {
@@ -182,6 +183,10 @@ const signatureSchema = Joi.object({
182
183
  sig: Joi.string().required(),
183
184
  excludes: Joi.array().items(Joi.string()).optional(),
184
185
  appended: Joi.array().items(Joi.string()).optional(),
186
+ // delegation token 校验所需字段
187
+ delegatee: Joi.string(),
188
+ delegateePk: Joi.string(),
189
+ delegation: Joi.string(),
185
190
  });
186
191
 
187
192
  const titleSchema = Joi.string()
@@ -196,6 +201,22 @@ const titleSchema = Joi.string()
196
201
  });
197
202
  const descriptionSchema = Joi.string().trim().min(3).max(160);
198
203
 
204
+ const navigationItemSchema = Joi.object({
205
+ title: Joi.string().required(),
206
+ link: Joi.string(),
207
+ child: Joi.string(), // child name or child did
208
+ });
209
+
210
+ const navigationSchema = Joi.array().items(
211
+ navigationItemSchema.append({
212
+ items: Joi.array().items(navigationItemSchema),
213
+ })
214
+ );
215
+
216
+ const themeSchema = Joi.object({
217
+ background: Joi.string(),
218
+ });
219
+
199
220
  const createBlockletSchema = (
200
221
  baseDir,
201
222
  { ensureMain = false, ensureFiles = false, ensureDist = false, ...schemaOptions } = {}
@@ -397,6 +418,10 @@ const createBlockletSchema = (
397
418
 
398
419
  // blocklet component support
399
420
  children: Joi.array().items(childrenSchema).optional().default([]),
421
+
422
+ // navigation & theme
423
+ navigation: navigationSchema,
424
+ theme: themeSchema,
400
425
  })
401
426
  .rename('public_url', 'publicUrl', { ignoreUndefined: true, override: true })
402
427
  .rename('admin_url', 'adminUrl', { ignoreUndefined: true, override: true })
@@ -415,4 +440,6 @@ module.exports = {
415
440
  distSchema,
416
441
  titleSchema,
417
442
  descriptionSchema,
443
+ navigationSchema,
444
+ themeSchema,
418
445
  };
package/lib/util.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable no-await-in-loop */
2
2
  const get = require('lodash/get');
3
3
 
4
- const { NODE_SERVICES, SLOT_FOR_IP_DNS_SITE } = require('@abtnode/constant');
4
+ const { NODE_SERVICES, SLOT_FOR_IP_DNS_SITE, WHO_CAN_ACCESS } = require('@abtnode/constant');
5
5
 
6
6
  const { BlockletGroup, fromBlockletStatus, fromBlockletSource, BLOCKLET_INTERFACE_TYPE_WEB } = require('./constants');
7
7
 
@@ -204,13 +204,21 @@ const findServiceFromMeta = (meta, ServiceName) => {
204
204
  return (webInterface.services || []).find((x) => names.includes(x.name));
205
205
  };
206
206
 
207
- const isInvitedUserOnlyInMeta = (blocklet) => {
207
+ const getWhoCanAccess = (blocklet) => {
208
208
  if (!blocklet) {
209
- return false;
209
+ return WHO_CAN_ACCESS.ALL;
210
+ }
211
+
212
+ if (get(blocklet, 'settings.whoCanAccess')) {
213
+ return blocklet.settings.whoCanAccess;
210
214
  }
211
215
 
212
216
  const service = findServiceFromMeta(blocklet.meta, NODE_SERVICES.AUTH);
213
- return service && service.config && ['yes', 'not-first'].includes(service.config.invitedUserOnly);
217
+ if (get(service, 'config.whoCanAccess')) {
218
+ return service.config.whoCanAccess;
219
+ }
220
+
221
+ return WHO_CAN_ACCESS.ALL;
214
222
  };
215
223
 
216
224
  const replaceSlotToIp = (url, ip) => (url || '').replace(SLOT_FOR_IP_DNS_SITE, (ip || '').replace(/\./g, '-'));
@@ -228,6 +236,6 @@ module.exports = {
228
236
  fixBlockletStatus,
229
237
  findWebInterface,
230
238
  findServiceFromMeta,
231
- isInvitedUserOnlyInMeta,
239
+ getWhoCanAccess,
232
240
  replaceSlotToIp,
233
241
  };
@@ -4,6 +4,37 @@ const cloneDeep = require('lodash/cloneDeep');
4
4
  const omit = require('lodash/omit');
5
5
  const { toTypeInfo } = require('@arcblock/did');
6
6
  const { fromPublicKey } = require('@ocap/wallet');
7
+ const { verify } = require('@arcblock/jwt');
8
+ const { fromBase64 } = require('@ocap/util');
9
+
10
+ function verifyDelegationToken(signature) {
11
+ if (signature.delegation) {
12
+ const payload = JSON.parse(fromBase64(signature.delegation.split('.')[1]));
13
+
14
+ if (payload.from !== signature.signer) {
15
+ debug('verify payload.from failed', { payload, signature });
16
+ return false;
17
+ }
18
+
19
+ if (payload.to !== signature.delegatee) {
20
+ debug('verify payload.to failed', { payload, signature });
21
+ return false;
22
+ }
23
+
24
+ if (!payload?.permissions?.includes('publish_blocklet')) {
25
+ debug('verify payload.permissions failed', payload);
26
+ return false;
27
+ }
28
+
29
+ // 验证一下delegation token
30
+ if (!verify(signature.delegation, signature.pk)) {
31
+ debug('verify delegation token failed', signature);
32
+ return false;
33
+ }
34
+ }
35
+
36
+ return true;
37
+ }
7
38
 
8
39
  module.exports = (blockletMeta) => {
9
40
  const { signatures: tmpSignatures, ...meta } = blockletMeta;
@@ -22,7 +53,19 @@ module.exports = (blockletMeta) => {
22
53
 
23
54
  for (let i = 0; i < length; i++) {
24
55
  const signature = signatures.shift();
25
- const { sig, signer, pk } = signature;
56
+
57
+ // 验证delegation token
58
+ if (!verifyDelegationToken(signature)) {
59
+ return false;
60
+ }
61
+
62
+ const { sig, signer, pk } = signature.delegation
63
+ ? {
64
+ sig: signature.sig,
65
+ signer: signature.delegatee,
66
+ pk: signature.delegateePk,
67
+ }
68
+ : signature;
26
69
  delete signature.sig;
27
70
  debug('verify', { signer });
28
71
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.7.5",
6
+ "version": "1.7.8",
7
7
  "description": "Library to parse/validate/fix blocklet meta",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -18,15 +18,17 @@
18
18
  "author": "wangshijun <wangshijun2020@gmail.com> (http://github.com/wangshijun)",
19
19
  "license": "MIT",
20
20
  "dependencies": {
21
- "@abtnode/constant": "1.7.5",
22
- "@arcblock/did": "^1.15.7",
23
- "@arcblock/did-ext": "^1.15.7",
24
- "@arcblock/did-util": "^1.15.7",
25
- "@arcblock/nft": "^1.15.7",
26
- "@ocap/asset": "^1.15.7",
27
- "@ocap/mcrypto": "^1.15.7",
28
- "@ocap/util": "^1.15.7",
29
- "@ocap/wallet": "^1.15.7",
21
+ "@abtnode/constant": "1.7.8",
22
+ "@abtnode/util": "1.7.8",
23
+ "@arcblock/did": "^1.16.3",
24
+ "@arcblock/did-ext": "^1.16.3",
25
+ "@arcblock/did-util": "^1.16.3",
26
+ "@arcblock/jwt": "^1.16.3",
27
+ "@arcblock/nft": "^1.16.3",
28
+ "@ocap/asset": "^1.16.3",
29
+ "@ocap/mcrypto": "^1.16.3",
30
+ "@ocap/util": "^1.16.3",
31
+ "@ocap/wallet": "^1.16.3",
30
32
  "ajv": "^7.0.3",
31
33
  "cjk-length": "^1.0.0",
32
34
  "debug": "^4.3.3",
@@ -35,7 +37,7 @@
35
37
  "is-glob": "^4.0.3",
36
38
  "joi": "^17.6.0",
37
39
  "joi-extension-semver": "^5.0.0",
38
- "js-yaml": "^3.14.0",
40
+ "js-yaml": "^4.1.0",
39
41
  "json-stable-stringify": "^1.0.1",
40
42
  "lodash": "^4.17.21",
41
43
  "url-join": "^4.0.1",
@@ -44,5 +46,5 @@
44
46
  "devDependencies": {
45
47
  "jest": "^27.4.5"
46
48
  },
47
- "gitHead": "b17d83773e5a4c06bae390fc70398d49d6dd86b3"
49
+ "gitHead": "ae75dd20b4750a31dc53c88b75ed1d95c8f15397"
48
50
  }