@abtnode/util 1.16.47-beta-20250805-140707-3a4df7fd → 1.16.47-beta-20250808-102837-d10f3b40
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/did-document.js +26 -1
- package/lib/sanitize.js +5 -2
- package/lib/ssrf-protector.js +111 -0
- package/package.json +12 -11
package/lib/did-document.js
CHANGED
|
@@ -3,6 +3,8 @@ const { toBase64, toBase58, toDid } = require('@ocap/util');
|
|
|
3
3
|
const { joinURL } = require('ufo');
|
|
4
4
|
const pRetry = require('p-retry');
|
|
5
5
|
const debug = require('debug')('@abtnode/util:did-document');
|
|
6
|
+
|
|
7
|
+
const sleep = require('./sleep');
|
|
6
8
|
const axios = require('./axios');
|
|
7
9
|
const { encode: encodeBase32 } = require('./base32');
|
|
8
10
|
|
|
@@ -60,7 +62,27 @@ const update = ({ id, services, didRegistryUrl, wallet, alsoKnownAs = [], blockl
|
|
|
60
62
|
});
|
|
61
63
|
};
|
|
62
64
|
|
|
63
|
-
const
|
|
65
|
+
const DEFAULT_RETRY_COUNT = 6;
|
|
66
|
+
const getRetryCount = () => {
|
|
67
|
+
try {
|
|
68
|
+
let retryCount = parseInt(process.env.ABT_NODE_UPDATE_DID_DOCUMENT_RETRY_COUNT, 10);
|
|
69
|
+
retryCount = Number.isNaN(retryCount) ? DEFAULT_RETRY_COUNT : retryCount;
|
|
70
|
+
debug('get retry count', retryCount);
|
|
71
|
+
return retryCount;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
debug('get retry count error', error);
|
|
74
|
+
return DEFAULT_RETRY_COUNT;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const updateWithRetry = (...args) =>
|
|
79
|
+
pRetry(() => update(...args), {
|
|
80
|
+
retries: getRetryCount(),
|
|
81
|
+
onFailedAttempt: async (error) => {
|
|
82
|
+
debug('update did document failed', error);
|
|
83
|
+
await sleep(10 * 1000);
|
|
84
|
+
},
|
|
85
|
+
});
|
|
64
86
|
|
|
65
87
|
const getServerServices = ({ ips, wallet, domain }) => {
|
|
66
88
|
const records = ips.map((ip) => ({
|
|
@@ -148,9 +170,12 @@ const updateBlockletDocument = ({
|
|
|
148
170
|
};
|
|
149
171
|
|
|
150
172
|
module.exports = {
|
|
173
|
+
DEFAULT_RETRY_COUNT,
|
|
151
174
|
updateServerDocument,
|
|
152
175
|
updateBlockletDocument,
|
|
153
176
|
getDID,
|
|
154
177
|
getServerServices,
|
|
155
178
|
getBlockletServices,
|
|
179
|
+
updateWithRetry,
|
|
180
|
+
getRetryCount,
|
|
156
181
|
};
|
package/lib/sanitize.js
CHANGED
|
@@ -12,9 +12,12 @@ const sanitizeTag = (content) => {
|
|
|
12
12
|
|
|
13
13
|
const sanitize = initSanitize({
|
|
14
14
|
whiteList: {},
|
|
15
|
-
stripIgnoreTag:
|
|
16
|
-
onIgnoreTag: false,
|
|
15
|
+
stripIgnoreTag: false,
|
|
17
16
|
stripIgnoreTagBody: [],
|
|
17
|
+
onIgnoreTag: (tag, html) => html.replace(/</g, '<').replace(/>/g, '>'),
|
|
18
|
+
onIgnoreTagAttr: (tag, name, value) => `${name}="${value}"`,
|
|
19
|
+
onTag: (tag, html) => html.replace(/</g, '<').replace(/>/g, '>'),
|
|
20
|
+
escapeHtml: (html) => html.replace(/</g, '<').replace(/>/g, '>'),
|
|
18
21
|
});
|
|
19
22
|
return sanitize(content);
|
|
20
23
|
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSRF Protector
|
|
3
|
+
*/
|
|
4
|
+
const isPrivateIP = require('private-ip');
|
|
5
|
+
const isIP = require('is-ip');
|
|
6
|
+
const dns = require('dns');
|
|
7
|
+
|
|
8
|
+
// 允许的协议, 只允许 https
|
|
9
|
+
function isAllowedProtocol(protocol) {
|
|
10
|
+
if (!protocol) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const _protocol = protocol.toLowerCase().replace(':', '');
|
|
15
|
+
|
|
16
|
+
return ['https'].includes(_protocol);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 允许的 host, 只能是当前站点
|
|
20
|
+
function isAllowedReferer(referer, host) {
|
|
21
|
+
if (!referer || !host) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const refererUrl = new URL(referer);
|
|
27
|
+
|
|
28
|
+
// 检查referer是否来自当前站点
|
|
29
|
+
return refererUrl.hostname === host || refererUrl.hostname === host.split(':')[0]; // 处理端口号情况
|
|
30
|
+
} catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const resolveDomain = (domain) => {
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
dns.lookup(domain, { all: false }, (error, address) => {
|
|
38
|
+
if (!error) {
|
|
39
|
+
resolve(address);
|
|
40
|
+
} else {
|
|
41
|
+
reject(error);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 解析域名并验证是否为私有IP
|
|
49
|
+
* @param {string} hostname - 要解析的域名
|
|
50
|
+
* @returns {Promise<boolean>} - 如果解析到的IP不是私有IP则返回true,否则返回false
|
|
51
|
+
*/
|
|
52
|
+
async function resolveAndValidateHostname(hostname) {
|
|
53
|
+
if (!hostname) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
// 使用 lookup 方法解析域名
|
|
59
|
+
const address = await resolveDomain(hostname);
|
|
60
|
+
|
|
61
|
+
// 检查是否为私有IP,返回相反的结果
|
|
62
|
+
return !isPrivateIP(address);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
// DNS解析失败,拒绝访问
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 解析URL为IP地址并验证是否为私有IP
|
|
71
|
+
* @param {string} url - 要验证的URL
|
|
72
|
+
* @returns {Promise<boolean>} - 如果IP不是私有IP则返回true,否则返回false
|
|
73
|
+
*/
|
|
74
|
+
async function isAllowedURL(url) {
|
|
75
|
+
if (!url) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const { hostname, protocol } = new URL(url);
|
|
81
|
+
|
|
82
|
+
if (!isAllowedProtocol(protocol)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 如果是IP地址,直接验证
|
|
87
|
+
if (isIP(hostname)) {
|
|
88
|
+
return !isPrivateIP(hostname);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 测试和开发环境不进行 DNS 解析验证
|
|
92
|
+
if (process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'development') {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 如果是域名,进行DNS解析
|
|
97
|
+
const result = await resolveAndValidateHostname(hostname);
|
|
98
|
+
|
|
99
|
+
return result;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
// URL解析失败
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = {
|
|
107
|
+
isAllowedProtocol,
|
|
108
|
+
isAllowedReferer,
|
|
109
|
+
isAllowedURL,
|
|
110
|
+
resolveAndValidateHostname,
|
|
111
|
+
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.47-beta-
|
|
6
|
+
"version": "1.16.47-beta-20250808-102837-d10f3b40",
|
|
7
7
|
"description": "ArcBlock's JavaScript utility",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -18,18 +18,18 @@
|
|
|
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.47-beta-
|
|
22
|
-
"@abtnode/db-cache": "1.16.47-beta-
|
|
23
|
-
"@arcblock/did": "1.21.
|
|
21
|
+
"@abtnode/constant": "1.16.47-beta-20250808-102837-d10f3b40",
|
|
22
|
+
"@abtnode/db-cache": "1.16.47-beta-20250808-102837-d10f3b40",
|
|
23
|
+
"@arcblock/did": "1.21.2",
|
|
24
24
|
"@arcblock/pm2": "^6.0.12",
|
|
25
|
-
"@blocklet/constant": "1.16.47-beta-
|
|
25
|
+
"@blocklet/constant": "1.16.47-beta-20250808-102837-d10f3b40",
|
|
26
26
|
"@blocklet/error": "^0.2.5",
|
|
27
|
-
"@blocklet/meta": "1.16.47-beta-
|
|
27
|
+
"@blocklet/meta": "1.16.47-beta-20250808-102837-d10f3b40",
|
|
28
28
|
"@blocklet/xss": "^0.2.3",
|
|
29
|
-
"@ocap/client": "1.21.
|
|
30
|
-
"@ocap/mcrypto": "1.21.
|
|
31
|
-
"@ocap/util": "1.21.
|
|
32
|
-
"@ocap/wallet": "1.21.
|
|
29
|
+
"@ocap/client": "1.21.2",
|
|
30
|
+
"@ocap/mcrypto": "1.21.2",
|
|
31
|
+
"@ocap/util": "1.21.2",
|
|
32
|
+
"@ocap/wallet": "1.21.2",
|
|
33
33
|
"archiver": "^7.0.1",
|
|
34
34
|
"axios": "^1.7.9",
|
|
35
35
|
"axios-mock-adapter": "^2.1.0",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"p-retry": "^4.6.2",
|
|
64
64
|
"p-wait-for": "^3.2.0",
|
|
65
65
|
"parallel-transform": "^1.2.0",
|
|
66
|
+
"private-ip": "^2.3.4",
|
|
66
67
|
"public-ip": "^4.0.4",
|
|
67
68
|
"pump": "^3.0.0",
|
|
68
69
|
"request-ip": "^3.3.0",
|
|
@@ -89,5 +90,5 @@
|
|
|
89
90
|
"fs-extra": "^11.2.0",
|
|
90
91
|
"jest": "^29.7.0"
|
|
91
92
|
},
|
|
92
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "545f4b619e4e872f3cb6645aa95a0c22c06b58d0"
|
|
93
94
|
}
|