@abtnode/util 1.16.43-beta-20250422-042711-c40bec75 → 1.16.43-beta-20250424-125523-08a65a5c
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-simple-access-key.js +90 -0
- package/lib/check-file.js +57 -0
- package/lib/ensure-server-endpoint.js +59 -0
- package/lib/make-from-data.js +62 -0
- package/package.json +12 -10
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const { fromPublicKey } = require('@ocap/wallet');
|
|
2
|
+
const { fromBase58 } = require('@ocap/util');
|
|
3
|
+
const { isSystemRole } = require('@abtnode/constant');
|
|
4
|
+
|
|
5
|
+
const checkAccessKeySource = async ({ node, keyId, info, blockletDid }) => {
|
|
6
|
+
let teamDid = info.did;
|
|
7
|
+
let accessKey = await node.getAccessKey({ teamDid, accessKeyId: keyId }).catch(() => null);
|
|
8
|
+
let isFromBlocklet;
|
|
9
|
+
|
|
10
|
+
if (blockletDid && !accessKey) {
|
|
11
|
+
isFromBlocklet = true;
|
|
12
|
+
teamDid = blockletDid;
|
|
13
|
+
accessKey = await node.getAccessKey({ teamDid, accessKeyId: keyId }).catch(() => null);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return { teamDid, isFromBlocklet, accessKey };
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const isLoginToken = (token) => {
|
|
20
|
+
return !!token && typeof token === 'string' && token.split('.').length === 3;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const isAccessKey = (token) => {
|
|
24
|
+
return !!token && typeof token === 'string' && token.split('.').length === 1 && token.startsWith('blocklet-');
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const authBySimpleAccessKey = async (token, node, blockletDid = '') => {
|
|
28
|
+
const info = await node.getNodeInfo({ useCache: true });
|
|
29
|
+
|
|
30
|
+
const secret = token.replace('blocklet-', '');
|
|
31
|
+
|
|
32
|
+
let publicKey = '';
|
|
33
|
+
try {
|
|
34
|
+
publicKey = fromBase58(secret);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
publicKey = '';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!publicKey) {
|
|
40
|
+
throw new Error('Invalid access key secret');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const wallet = fromPublicKey(publicKey);
|
|
44
|
+
if (!wallet) {
|
|
45
|
+
throw new Error('Invalid access key secret');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const accessKeyId = wallet.address;
|
|
49
|
+
|
|
50
|
+
const { teamDid, isFromBlocklet, accessKey } = await checkAccessKeySource({
|
|
51
|
+
node,
|
|
52
|
+
keyId: accessKeyId,
|
|
53
|
+
info,
|
|
54
|
+
blockletDid,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const { passport, remark, expireAt, authType } = accessKey;
|
|
58
|
+
|
|
59
|
+
if (authType !== 'simple') {
|
|
60
|
+
throw new Error(`Access Key ${accessKeyId} is not a simple type`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (expireAt && new Date(expireAt).getTime() < new Date().getTime()) {
|
|
64
|
+
throw new Error(`Access Key ${accessKeyId} has expired`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!accessKey.createdBy) {
|
|
68
|
+
throw new Error(`Access Key ${accessKeyId} is not created by a user`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
await node.refreshLastUsed({ teamDid, accessKeyId });
|
|
72
|
+
|
|
73
|
+
const role = passport;
|
|
74
|
+
const blockletRole = isSystemRole(role) ? `blocklet-${role}` : role;
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
did: accessKey.createdBy,
|
|
78
|
+
role: isFromBlocklet ? blockletRole : role,
|
|
79
|
+
elevated: true,
|
|
80
|
+
blockletDid: teamDid,
|
|
81
|
+
fullName: remark || accessKeyId,
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
module.exports = {
|
|
86
|
+
checkAccessKeySource,
|
|
87
|
+
authBySimpleAccessKey,
|
|
88
|
+
isLoginToken,
|
|
89
|
+
isAccessKey,
|
|
90
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const { minimatch } = require('minimatch');
|
|
2
|
+
|
|
3
|
+
const checkMatch = (file, match) => {
|
|
4
|
+
let m = match;
|
|
5
|
+
if (!m.includes('*')) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
if (!m.endsWith('*')) {
|
|
9
|
+
return minimatch(file, m);
|
|
10
|
+
}
|
|
11
|
+
if (!m.endsWith('**')) {
|
|
12
|
+
m = `${m}*`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return minimatch(file, m);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const checkInclude = (list, f) =>
|
|
19
|
+
f === '.' ||
|
|
20
|
+
f === '' || // root folder maybe '.' and ''
|
|
21
|
+
list.some(
|
|
22
|
+
(x) =>
|
|
23
|
+
x.indexOf(f) === 0 || // f is 'website' && x is 'website/public'
|
|
24
|
+
f.indexOf(x) === 0 || // f is website/public/index.html && x is website/public
|
|
25
|
+
checkMatch(f, x) // f is hooks/pre-start.js && x is hooks/*
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Whether a file should be deployed
|
|
30
|
+
* @param {string} file a file will be deployed
|
|
31
|
+
* @param {object} opts
|
|
32
|
+
* @param {array<string>} opts.diffList
|
|
33
|
+
* @param {BundleType} opts.bundleType
|
|
34
|
+
* @param {array<string>} opts.staticList
|
|
35
|
+
* @return {boolean} Should this file be deployed
|
|
36
|
+
*/
|
|
37
|
+
const fileFilter = (file, opts = {}) => {
|
|
38
|
+
const { diffList, bundleType, staticList } = opts;
|
|
39
|
+
// only include diffList if has one
|
|
40
|
+
if (diffList) {
|
|
41
|
+
return checkInclude(diffList, file);
|
|
42
|
+
}
|
|
43
|
+
// only include staticList if bundleType is static
|
|
44
|
+
if (bundleType === 'static') {
|
|
45
|
+
if (!staticList) {
|
|
46
|
+
throw new Error('staticList should not be empty when bundleType is static');
|
|
47
|
+
}
|
|
48
|
+
return checkInclude(staticList, file);
|
|
49
|
+
}
|
|
50
|
+
// include all files
|
|
51
|
+
return true;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
module.exports = {
|
|
55
|
+
fileFilter,
|
|
56
|
+
checkMatch,
|
|
57
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const { joinURL } = require('ufo');
|
|
2
|
+
const { default: axios } = require('axios');
|
|
3
|
+
const { WELLKNOWN_DID_RESOLVER_PREFIX } = require('@abtnode/constant');
|
|
4
|
+
const { getDidDomainForBlocklet } = require('./get-domain-for-blocklet');
|
|
5
|
+
|
|
6
|
+
const BLOCKLET_JSON_PATH = '__blocklet__.js?type=json';
|
|
7
|
+
|
|
8
|
+
const ensureServerEndpoint = async (endpoint) => {
|
|
9
|
+
let serverBaseUrl;
|
|
10
|
+
let appPid;
|
|
11
|
+
let appName;
|
|
12
|
+
let appDescription;
|
|
13
|
+
|
|
14
|
+
const jsonPathUrl = joinURL(new URL(endpoint).origin, BLOCKLET_JSON_PATH);
|
|
15
|
+
|
|
16
|
+
const checkEndpoint = await axios(jsonPathUrl).catch(() => null);
|
|
17
|
+
const contentType = checkEndpoint && checkEndpoint.headers['content-type'];
|
|
18
|
+
if (contentType?.includes('application/json')) {
|
|
19
|
+
const url = getDidDomainForBlocklet({ did: checkEndpoint.data.serverDid });
|
|
20
|
+
// service endpoint
|
|
21
|
+
serverBaseUrl = new URL(`https://${url}`).origin;
|
|
22
|
+
appPid = checkEndpoint.data.appPid;
|
|
23
|
+
appName = checkEndpoint.data.appName;
|
|
24
|
+
appDescription = checkEndpoint.data.appDescription;
|
|
25
|
+
} else {
|
|
26
|
+
// maybe server endpoint
|
|
27
|
+
serverBaseUrl = new URL(endpoint).origin;
|
|
28
|
+
appPid = '';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!serverBaseUrl) {
|
|
32
|
+
throw new Error('Invalid endpoint');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// local debug
|
|
36
|
+
if (serverBaseUrl.includes('localhost:3000')) {
|
|
37
|
+
return {
|
|
38
|
+
endpoint: serverBaseUrl,
|
|
39
|
+
appPid,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const didJsonUrl = joinURL(serverBaseUrl, WELLKNOWN_DID_RESOLVER_PREFIX);
|
|
44
|
+
const didJson = await axios(didJsonUrl);
|
|
45
|
+
|
|
46
|
+
const didJsonContentType = didJson.headers['content-type'];
|
|
47
|
+
if (!didJsonContentType.includes('application/json')) {
|
|
48
|
+
throw new Error('Invalid endpoint');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
endpoint: joinURL(serverBaseUrl, didJson?.data?.services?.[0]?.path),
|
|
53
|
+
appPid,
|
|
54
|
+
appName,
|
|
55
|
+
appDescription,
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
module.exports = ensureServerEndpoint;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const FormData = require('form-data');
|
|
3
|
+
|
|
4
|
+
const makeFormData = ({ tarFile: file, hasDiff, did, serverVersion, deleteSet, rootDid, mountPoint }) => {
|
|
5
|
+
let varFields = hasDiff
|
|
6
|
+
? '$file: Upload!, $did: String, $diffVersion: String, $deleteSet: [String!]'
|
|
7
|
+
: '$file: Upload!';
|
|
8
|
+
let inputFields = hasDiff
|
|
9
|
+
? 'file: $file, did: $did, diffVersion: $diffVersion, deleteSet: $deleteSet'
|
|
10
|
+
: 'file: $file';
|
|
11
|
+
|
|
12
|
+
varFields = `${varFields}, $rootDid: String, $mountPoint: String`;
|
|
13
|
+
inputFields = `${inputFields}, rootDid: $rootDid, mountPoint: $mountPoint`;
|
|
14
|
+
|
|
15
|
+
const variables = hasDiff
|
|
16
|
+
? {
|
|
17
|
+
file: null,
|
|
18
|
+
did,
|
|
19
|
+
diffVersion: serverVersion,
|
|
20
|
+
deleteSet,
|
|
21
|
+
}
|
|
22
|
+
: {
|
|
23
|
+
file: null,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
variables.rootDid = rootDid;
|
|
27
|
+
variables.mountPoint = mountPoint;
|
|
28
|
+
|
|
29
|
+
const apiName = 'installComponent';
|
|
30
|
+
const query = `
|
|
31
|
+
mutation (${varFields}) {
|
|
32
|
+
${apiName}(input: { ${inputFields} } ) {
|
|
33
|
+
code
|
|
34
|
+
blocklet {
|
|
35
|
+
meta {
|
|
36
|
+
did
|
|
37
|
+
name
|
|
38
|
+
title
|
|
39
|
+
version
|
|
40
|
+
description
|
|
41
|
+
}
|
|
42
|
+
status
|
|
43
|
+
source
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
48
|
+
const gql = {
|
|
49
|
+
query,
|
|
50
|
+
variables,
|
|
51
|
+
};
|
|
52
|
+
const map = {
|
|
53
|
+
file0: ['variables.file'],
|
|
54
|
+
};
|
|
55
|
+
const form = new FormData();
|
|
56
|
+
form.append('operations', JSON.stringify(gql));
|
|
57
|
+
form.append('map', JSON.stringify(map));
|
|
58
|
+
form.append('file0', fs.createReadStream(file));
|
|
59
|
+
return { form, apiName };
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
module.exports = makeFormData;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.43-beta-
|
|
6
|
+
"version": "1.16.43-beta-20250424-125523-08a65a5c",
|
|
7
7
|
"description": "ArcBlock's JavaScript utility",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -18,15 +18,15 @@
|
|
|
18
18
|
"author": "polunzh <polunzh@gmail.com> (http://github.com/polunzh)",
|
|
19
19
|
"license": "Apache-2.0",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@abtnode/constant": "1.16.43-beta-
|
|
22
|
-
"@arcblock/did": "^1.20.
|
|
21
|
+
"@abtnode/constant": "1.16.43-beta-20250424-125523-08a65a5c",
|
|
22
|
+
"@arcblock/did": "^1.20.2",
|
|
23
23
|
"@arcblock/pm2": "^5.4.0",
|
|
24
|
-
"@blocklet/constant": "1.16.43-beta-
|
|
25
|
-
"@blocklet/meta": "1.16.43-beta-
|
|
26
|
-
"@ocap/client": "1.20.
|
|
27
|
-
"@ocap/mcrypto": "1.20.
|
|
28
|
-
"@ocap/util": "1.20.
|
|
29
|
-
"@ocap/wallet": "1.20.
|
|
24
|
+
"@blocklet/constant": "1.16.43-beta-20250424-125523-08a65a5c",
|
|
25
|
+
"@blocklet/meta": "1.16.43-beta-20250424-125523-08a65a5c",
|
|
26
|
+
"@ocap/client": "1.20.2",
|
|
27
|
+
"@ocap/mcrypto": "1.20.2",
|
|
28
|
+
"@ocap/util": "1.20.2",
|
|
29
|
+
"@ocap/wallet": "1.20.2",
|
|
30
30
|
"archiver": "^7.0.1",
|
|
31
31
|
"axios": "^1.7.9",
|
|
32
32
|
"axios-mock-adapter": "^2.1.0",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"fkill": "^7.2.1",
|
|
44
44
|
"flush-write-stream": "^2.0.0",
|
|
45
45
|
"folder-walker": "^3.2.0",
|
|
46
|
+
"form-data": "^4.0.2",
|
|
46
47
|
"get-folder-size": "^2.0.1",
|
|
47
48
|
"hasha": "^5.2.2",
|
|
48
49
|
"hpagent": "^1.1.0",
|
|
@@ -52,6 +53,7 @@
|
|
|
52
53
|
"is-url": "^1.2.4",
|
|
53
54
|
"json-stable-stringify": "^1.0.1",
|
|
54
55
|
"lodash": "^4.17.21",
|
|
56
|
+
"minimatch": "^10.0.1",
|
|
55
57
|
"multiformats": "9.9.0",
|
|
56
58
|
"npm-packlist": "^7.0.4",
|
|
57
59
|
"p-retry": "^4.6.2",
|
|
@@ -82,5 +84,5 @@
|
|
|
82
84
|
"fs-extra": "^11.2.0",
|
|
83
85
|
"jest": "^29.7.0"
|
|
84
86
|
},
|
|
85
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "499de9f28770298a819122ba16a7f2b3cc78c7ee"
|
|
86
88
|
}
|