@blocklet/meta 1.7.6 → 1.7.9
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 +1 -1
- package/lib/parse-navigation.js +78 -0
- package/lib/parse.js +2 -2
- package/lib/schema.js +29 -2
- package/lib/util.js +13 -5
- package/lib/verify-multi-sig.js +49 -4
- package/package.json +14 -12
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.
|
|
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.
|
|
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.
|
|
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
|
|
207
|
+
const getWhoCanAccess = (blocklet) => {
|
|
208
208
|
if (!blocklet) {
|
|
209
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
239
|
+
getWhoCanAccess,
|
|
232
240
|
replaceSlotToIp,
|
|
233
241
|
};
|
package/lib/verify-multi-sig.js
CHANGED
|
@@ -1,9 +1,42 @@
|
|
|
1
|
-
const
|
|
2
|
-
const stableStringify = require('json-stable-stringify');
|
|
3
|
-
const cloneDeep = require('lodash/cloneDeep');
|
|
1
|
+
const get = require('lodash/get');
|
|
4
2
|
const omit = require('lodash/omit');
|
|
3
|
+
const cloneDeep = require('lodash/cloneDeep');
|
|
4
|
+
const stableStringify = require('json-stable-stringify');
|
|
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
|
+
const debug = require('debug')('@blocklet/meta:verifyMultiSig');
|
|
11
|
+
|
|
12
|
+
function verifyDelegationToken(signature) {
|
|
13
|
+
if (signature.delegation) {
|
|
14
|
+
const payload = JSON.parse(fromBase64(signature.delegation.split('.')[1]));
|
|
15
|
+
|
|
16
|
+
if (payload.from !== signature.signer) {
|
|
17
|
+
debug('verify payload.from failed', { payload, signature });
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (payload.to !== signature.delegatee) {
|
|
22
|
+
debug('verify payload.to failed', { payload, signature });
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!get(payload, 'permissions', []).includes('publish_blocklet')) {
|
|
27
|
+
debug('verify payload.permissions failed', payload);
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 验证一下delegation token
|
|
32
|
+
if (!verify(signature.delegation, signature.pk)) {
|
|
33
|
+
debug('verify delegation token failed', signature);
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
7
40
|
|
|
8
41
|
module.exports = (blockletMeta) => {
|
|
9
42
|
const { signatures: tmpSignatures, ...meta } = blockletMeta;
|
|
@@ -22,7 +55,19 @@ module.exports = (blockletMeta) => {
|
|
|
22
55
|
|
|
23
56
|
for (let i = 0; i < length; i++) {
|
|
24
57
|
const signature = signatures.shift();
|
|
25
|
-
|
|
58
|
+
|
|
59
|
+
// 验证delegation token
|
|
60
|
+
if (!verifyDelegationToken(signature)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const { sig, signer, pk } = signature.delegation
|
|
65
|
+
? {
|
|
66
|
+
sig: signature.sig,
|
|
67
|
+
signer: signature.delegatee,
|
|
68
|
+
pk: signature.delegateePk,
|
|
69
|
+
}
|
|
70
|
+
: signature;
|
|
26
71
|
delete signature.sig;
|
|
27
72
|
debug('verify', { signer });
|
|
28
73
|
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.7.
|
|
6
|
+
"version": "1.7.9",
|
|
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.
|
|
22
|
-
"@
|
|
23
|
-
"@arcblock/did
|
|
24
|
-
"@arcblock/did-
|
|
25
|
-
"@arcblock/
|
|
26
|
-
"@
|
|
27
|
-
"@
|
|
28
|
-
"@ocap/
|
|
29
|
-
"@ocap/
|
|
21
|
+
"@abtnode/constant": "1.7.9",
|
|
22
|
+
"@abtnode/util": "1.7.9",
|
|
23
|
+
"@arcblock/did": "^1.16.4",
|
|
24
|
+
"@arcblock/did-ext": "^1.16.4",
|
|
25
|
+
"@arcblock/did-util": "^1.16.4",
|
|
26
|
+
"@arcblock/jwt": "^1.16.4",
|
|
27
|
+
"@arcblock/nft": "^1.16.4",
|
|
28
|
+
"@ocap/asset": "^1.16.4",
|
|
29
|
+
"@ocap/mcrypto": "^1.16.4",
|
|
30
|
+
"@ocap/util": "^1.16.4",
|
|
31
|
+
"@ocap/wallet": "^1.16.4",
|
|
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": "^
|
|
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": "
|
|
49
|
+
"gitHead": "285f4fedd41fcb8e1814ce5d8250ac10616e67e0"
|
|
48
50
|
}
|