@blocklet/meta 1.7.7 → 1.7.10
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 +1 -1
- package/lib/parse.js +2 -2
- package/lib/schema.js +6 -0
- package/lib/service.js +102 -0
- package/lib/util.js +13 -5
- package/lib/validate.js +3 -29
- package/lib/verify-multi-sig.js +49 -4
- package/package.json +15 -14
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 };
|
package/lib/parse-navigation.js
CHANGED
|
@@ -17,7 +17,7 @@ const parseNavigation = (navigation, blocklet, prefix = '/', level = 1) => {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
if (nav.link) {
|
|
20
|
-
item.link = normalizePathPrefix(`${prefix}${nav.link || '/'}`);
|
|
20
|
+
item.link = nav.link.startsWith('/') ? normalizePathPrefix(`${prefix}${nav.link || '/'}`) : nav.link;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
if (level === 1) {
|
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({
|
|
@@ -181,6 +183,10 @@ const signatureSchema = Joi.object({
|
|
|
181
183
|
sig: Joi.string().required(),
|
|
182
184
|
excludes: Joi.array().items(Joi.string()).optional(),
|
|
183
185
|
appended: Joi.array().items(Joi.string()).optional(),
|
|
186
|
+
// delegation token 校验所需字段
|
|
187
|
+
delegatee: Joi.string(),
|
|
188
|
+
delegateePk: Joi.string(),
|
|
189
|
+
delegation: Joi.string(),
|
|
184
190
|
});
|
|
185
191
|
|
|
186
192
|
const titleSchema = Joi.string()
|
package/lib/service.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const cloneDeep = require('lodash/cloneDeep');
|
|
3
|
+
const Ajv = require('ajv').default;
|
|
4
|
+
|
|
5
|
+
const { NODE_SERVICES } = require('@abtnode/constant');
|
|
6
|
+
|
|
7
|
+
const ajv = new Ajv({
|
|
8
|
+
useDefaults: true,
|
|
9
|
+
removeAdditional: 'all',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const SERVICES = {};
|
|
13
|
+
|
|
14
|
+
const setService = (meta) => {
|
|
15
|
+
const validate = ajv.compile(meta.schema.JSONSchema);
|
|
16
|
+
|
|
17
|
+
// parse empty custom config to get default config
|
|
18
|
+
const defaultConfig = {};
|
|
19
|
+
validate(defaultConfig);
|
|
20
|
+
|
|
21
|
+
SERVICES[meta.name] = {
|
|
22
|
+
meta,
|
|
23
|
+
validate,
|
|
24
|
+
defaultConfig,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
setService(fs.readJSONSync(require.resolve('@abtnode/blocklet-services/configs/auth.json')));
|
|
29
|
+
|
|
30
|
+
// backward compatible
|
|
31
|
+
SERVICES[NODE_SERVICES.AUTH_SERVICE] = {
|
|
32
|
+
...SERVICES[NODE_SERVICES.AUTH],
|
|
33
|
+
meta: {
|
|
34
|
+
...SERVICES[NODE_SERVICES.AUTH].meta,
|
|
35
|
+
name: NODE_SERVICES.AUTH_SERVICE,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const getServiceMetas = ({ stringifySchema = false } = {}) => {
|
|
40
|
+
const list = Object.values(SERVICES).map(({ meta }) => {
|
|
41
|
+
const data = cloneDeep(meta);
|
|
42
|
+
if (stringifySchema) {
|
|
43
|
+
data.schema = JSON.stringify(meta.schema);
|
|
44
|
+
}
|
|
45
|
+
return data;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return list;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const getService = (serviceName) => {
|
|
52
|
+
if (!serviceName) {
|
|
53
|
+
throw new Error('service name should not be empty');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const service = SERVICES[serviceName];
|
|
57
|
+
if (!service) {
|
|
58
|
+
throw new Error(`service ${serviceName} does not exist`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return service;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const getServiceConfig = (serviceName, customConfig, { validate } = {}) => {
|
|
65
|
+
const service = getService(serviceName);
|
|
66
|
+
|
|
67
|
+
const data = cloneDeep(customConfig || {});
|
|
68
|
+
// this method may have side effect thar will fill default value to customConfig
|
|
69
|
+
const valid = service.validate(data || {});
|
|
70
|
+
|
|
71
|
+
if (validate && !valid) {
|
|
72
|
+
const message = service.validate.errors.map((x) => `${x.instancePath} ${x.message}`).join(', ');
|
|
73
|
+
throw new Error(`Invalid blocklet service config: ${message}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return data;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const getDefaultServiceConfig = (serviceName) => {
|
|
80
|
+
const { defaultConfig } = getService(serviceName);
|
|
81
|
+
|
|
82
|
+
return defaultConfig;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const findService = (services, name) => {
|
|
86
|
+
const names = [name];
|
|
87
|
+
|
|
88
|
+
// backward compatible
|
|
89
|
+
if (name === NODE_SERVICES.AUTH) {
|
|
90
|
+
names.push(NODE_SERVICES.AUTH_SERVICE);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return (services || []).find((x) => names.includes(x.name));
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
module.exports = {
|
|
97
|
+
getServiceMetas,
|
|
98
|
+
getServiceConfig,
|
|
99
|
+
getDefaultServiceConfig,
|
|
100
|
+
findService,
|
|
101
|
+
setService,
|
|
102
|
+
};
|
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/validate.js
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
const Ajv = require('ajv').default;
|
|
2
|
-
const cloneDeep = require('lodash/cloneDeep');
|
|
3
|
-
|
|
4
1
|
const { createBlockletSchema } = require('./schema');
|
|
2
|
+
const { getServiceConfig } = require('./service');
|
|
5
3
|
|
|
6
|
-
const fixAndValidateService = (meta
|
|
7
|
-
const ajv = new Ajv({
|
|
8
|
-
useDefaults: true,
|
|
9
|
-
removeAdditional: 'all',
|
|
10
|
-
});
|
|
11
|
-
|
|
4
|
+
const fixAndValidateService = (meta) => {
|
|
12
5
|
if (!meta.interfaces) {
|
|
13
6
|
return meta;
|
|
14
7
|
}
|
|
@@ -19,26 +12,7 @@ const fixAndValidateService = (meta, serviceMetas) => {
|
|
|
19
12
|
meta.interfaces.forEach((d) => {
|
|
20
13
|
if (d.services && d.services.length) {
|
|
21
14
|
d.services.forEach((s) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// validate service.config if serviceMetaList is exist
|
|
25
|
-
if (serviceMetas) {
|
|
26
|
-
const serviceMeta = serviceMetas.find((x) => x.name === s.name);
|
|
27
|
-
if (!serviceMeta) {
|
|
28
|
-
throw new Error(`Invalid blocklet service: ${s.name} does not exist`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const validate = ajv.compile(serviceMeta.schema.JSONSchema);
|
|
32
|
-
// this method may have side effect thar will fill default value to config
|
|
33
|
-
const valid = validate(config);
|
|
34
|
-
|
|
35
|
-
if (!valid) {
|
|
36
|
-
const message = validate.errors.map((x) => `${x.dataPath} ${x.message}`).join(', ');
|
|
37
|
-
throw new Error(`Invalid blocklet service config: ${message}`);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
s.config = config;
|
|
15
|
+
s.config = getServiceConfig(s.name, s.config, { validate: true });
|
|
42
16
|
});
|
|
43
17
|
}
|
|
44
18
|
});
|
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.10",
|
|
7
7
|
"description": "Library to parse/validate/fix blocklet meta",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -18,17 +18,18 @@
|
|
|
18
18
|
"author": "wangshijun <wangshijun2020@gmail.com> (http://github.com/wangshijun)",
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@abtnode/constant": "1.7.
|
|
22
|
-
"@abtnode/util": "1.7.
|
|
23
|
-
"@arcblock/did": "^1.16.
|
|
24
|
-
"@arcblock/did-ext": "^1.16.
|
|
25
|
-
"@arcblock/did-util": "^1.16.
|
|
26
|
-
"@arcblock/
|
|
27
|
-
"@
|
|
28
|
-
"@ocap/
|
|
29
|
-
"@ocap/
|
|
30
|
-
"@ocap/
|
|
31
|
-
"
|
|
21
|
+
"@abtnode/constant": "1.7.10",
|
|
22
|
+
"@abtnode/util": "1.7.10",
|
|
23
|
+
"@arcblock/did": "^1.16.5",
|
|
24
|
+
"@arcblock/did-ext": "^1.16.5",
|
|
25
|
+
"@arcblock/did-util": "^1.16.5",
|
|
26
|
+
"@arcblock/jwt": "^1.16.5",
|
|
27
|
+
"@arcblock/nft": "^1.16.5",
|
|
28
|
+
"@ocap/asset": "^1.16.5",
|
|
29
|
+
"@ocap/mcrypto": "^1.16.5",
|
|
30
|
+
"@ocap/util": "^1.16.5",
|
|
31
|
+
"@ocap/wallet": "^1.16.5",
|
|
32
|
+
"ajv": "^8.11.0",
|
|
32
33
|
"cjk-length": "^1.0.0",
|
|
33
34
|
"debug": "^4.3.3",
|
|
34
35
|
"fs-extra": "^10.0.1",
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
"is-glob": "^4.0.3",
|
|
37
38
|
"joi": "^17.6.0",
|
|
38
39
|
"joi-extension-semver": "^5.0.0",
|
|
39
|
-
"js-yaml": "^
|
|
40
|
+
"js-yaml": "^4.1.0",
|
|
40
41
|
"json-stable-stringify": "^1.0.1",
|
|
41
42
|
"lodash": "^4.17.21",
|
|
42
43
|
"url-join": "^4.0.1",
|
|
@@ -45,5 +46,5 @@
|
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"jest": "^27.4.5"
|
|
47
48
|
},
|
|
48
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "8eab10fd39b6183a2fa4d2706f52e8b2ecaa059a"
|
|
49
50
|
}
|