@wbce-d9/api 11.0.5 → 11.1.0
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/dist/constants.js +13 -5
- package/dist/middleware/extract-token.js +3 -1
- package/dist/request/validate-ip.js +55 -5
- package/package.json +12 -12
package/dist/constants.js
CHANGED
|
@@ -56,8 +56,12 @@ export const REFRESH_COOKIE_OPTIONS = {
|
|
|
56
56
|
sameSite: env['REFRESH_TOKEN_COOKIE_SAME_SITE'] || 'strict',
|
|
57
57
|
path: '/auth',
|
|
58
58
|
};
|
|
59
|
-
const
|
|
60
|
-
|
|
59
|
+
export const REFRESH_COOKIE_CLEAR_OPTIONS = (() => {
|
|
60
|
+
const { ...rest } = REFRESH_COOKIE_OPTIONS;
|
|
61
|
+
delete rest.maxAge;
|
|
62
|
+
delete rest.expires;
|
|
63
|
+
return rest;
|
|
64
|
+
})();
|
|
61
65
|
export const GET_SET_HEADER = (cookieValue) => {
|
|
62
66
|
const domainHeader = env['REFRESH_TOKEN_COOKIE_DOMAIN'] ? ` Domain=${env['REFRESH_TOKEN_COOKIE_DOMAIN']};` : '';
|
|
63
67
|
const partitionedHeader = env['REFRESH_TOKEN_COOKIE_PARTITIONED'] == true ? ' Partitioned;' : '';
|
|
@@ -70,10 +74,14 @@ export const ACCESS_COOKIE_OPTIONS = {
|
|
|
70
74
|
maxAge: getMilliseconds(env['ACCESS_TOKEN_TTL']),
|
|
71
75
|
secure: env['ACCESS_TOKEN_COOKIE_SECURE'] ?? false,
|
|
72
76
|
sameSite: env['ACCESS_TOKEN_COOKIE_SAME_SITE'] || 'strict',
|
|
73
|
-
path: '/',
|
|
77
|
+
path: '/assets',
|
|
74
78
|
};
|
|
75
|
-
const
|
|
76
|
-
|
|
79
|
+
export const ACCESS_COOKIE_CLEAR_OPTIONS = (() => {
|
|
80
|
+
const { ...rest } = ACCESS_COOKIE_OPTIONS;
|
|
81
|
+
delete rest.maxAge;
|
|
82
|
+
delete rest.expires;
|
|
83
|
+
return rest;
|
|
84
|
+
})();
|
|
77
85
|
export const OAS_REQUIRED_SCHEMAS = ['Diff', 'Schema', 'Query', 'x-metadata'];
|
|
78
86
|
/** Formats from which transformation is supported */
|
|
79
87
|
export const SUPPORTED_IMAGE_TRANSFORM_FORMATS = ['image/jpeg', 'image/png', 'image/webp', 'image/tiff', 'image/avif'];
|
|
@@ -22,7 +22,9 @@ const extractToken = (req, _res, next) => {
|
|
|
22
22
|
/**
|
|
23
23
|
* Check if there is an access token stored in the cookies
|
|
24
24
|
*/
|
|
25
|
-
if (req?.cookies?.[env['ACCESS_TOKEN_COOKIE_NAME']]
|
|
25
|
+
if (req?.cookies?.[env['ACCESS_TOKEN_COOKIE_NAME']] &&
|
|
26
|
+
req.path.startsWith('/assets/') &&
|
|
27
|
+
req.method === 'GET') {
|
|
26
28
|
token = req.cookies[env['ACCESS_TOKEN_COOKIE_NAME']];
|
|
27
29
|
}
|
|
28
30
|
/**
|
|
@@ -1,20 +1,70 @@
|
|
|
1
|
+
import { BlockList } from 'net';
|
|
1
2
|
import os from 'node:os';
|
|
2
3
|
import { getEnv } from '../env.js';
|
|
4
|
+
import logger from '../logger.js';
|
|
3
5
|
export const validateIP = async (ip, url) => {
|
|
4
6
|
const env = getEnv();
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
const ipDenyList = env['IMPORT_IP_DENY_LIST'] || [];
|
|
8
|
+
// Create a BlockList for efficient IP range checking
|
|
9
|
+
const blockList = new BlockList();
|
|
10
|
+
// Add all denied ranges to the block list
|
|
11
|
+
for (const deniedRange of ipDenyList) {
|
|
12
|
+
if (deniedRange.includes('/')) {
|
|
13
|
+
// CIDR notation
|
|
14
|
+
const parts = deniedRange.split('/');
|
|
15
|
+
const network = parts[0];
|
|
16
|
+
const prefixLengthStr = parts[1];
|
|
17
|
+
if (!network || !prefixLengthStr) {
|
|
18
|
+
throw new Error('Invalid CIDR format: missing network or prefix');
|
|
19
|
+
}
|
|
20
|
+
const prefixLength = parseInt(prefixLengthStr, 10);
|
|
21
|
+
if (isNaN(prefixLength)) {
|
|
22
|
+
throw new Error('Invalid CIDR format: prefix length must be a number');
|
|
23
|
+
}
|
|
24
|
+
blockList.addSubnet(network, prefixLength);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// Single IP address
|
|
28
|
+
blockList.addAddress(deniedRange);
|
|
29
|
+
}
|
|
7
30
|
}
|
|
8
|
-
|
|
31
|
+
// Special case: "0.0.0.0" blocks all local interfaces AND loopback addresses
|
|
32
|
+
if (ipDenyList.includes('0.0.0.0')) {
|
|
33
|
+
// Add the entire loopback range (127.0.0.0/8) to fix the vulnerability
|
|
34
|
+
// This blocks all 127.x.x.x addresses, not just 127.0.0.1
|
|
35
|
+
blockList.addSubnet('127.0.0.0', 8);
|
|
36
|
+
// Add local network interfaces
|
|
9
37
|
const networkInterfaces = os.networkInterfaces();
|
|
10
38
|
for (const networkInfo of Object.values(networkInterfaces)) {
|
|
11
39
|
if (!networkInfo)
|
|
12
40
|
continue;
|
|
13
41
|
for (const info of networkInfo) {
|
|
14
|
-
if (info.
|
|
15
|
-
|
|
42
|
+
if (info.internal && info.cidr) {
|
|
43
|
+
try {
|
|
44
|
+
const parts = info.cidr.split('/');
|
|
45
|
+
const network = parts[0];
|
|
46
|
+
const prefixLengthStr = parts[1];
|
|
47
|
+
if (!network || !prefixLengthStr) {
|
|
48
|
+
logger.warn(`Warning: Invalid local interface CIDR format "${info.cidr}": missing network or prefix`);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const prefixLength = parseInt(prefixLengthStr, 10);
|
|
52
|
+
if (isNaN(prefixLength)) {
|
|
53
|
+
logger.warn(`Warning: Invalid prefix length in CIDR "${info.cidr}"`);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
blockList.addSubnet(network, prefixLength);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
// Log but don't fail for invalid local interface CIDR
|
|
60
|
+
logger.warn(`Warning: Invalid local interface CIDR "${info.cidr}": ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
61
|
+
}
|
|
16
62
|
}
|
|
17
63
|
}
|
|
18
64
|
}
|
|
19
65
|
}
|
|
66
|
+
// Check if the IP is blocked
|
|
67
|
+
if (blockList.check(ip)) {
|
|
68
|
+
throw new Error(`Requested URL "${url}" resolves to a denied IP address`);
|
|
69
|
+
}
|
|
20
70
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wbce-d9/api",
|
|
3
|
-
"version": "11.0
|
|
3
|
+
"version": "11.1.0",
|
|
4
4
|
"description": "Directus is a real-time API and App dashboard for managing SQL database content",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -143,20 +143,20 @@
|
|
|
143
143
|
"uuid": "9.0.0",
|
|
144
144
|
"uuid-validate": "0.0.3",
|
|
145
145
|
"wellknown": "0.5.0",
|
|
146
|
-
"@wbce-d9/
|
|
147
|
-
"@wbce-d9/extensions-sdk": "9.27.1",
|
|
146
|
+
"@wbce-d9/app": "9.33.2",
|
|
148
147
|
"@wbce-d9/constants": "9.28.0",
|
|
148
|
+
"@wbce-d9/schema": "9.26.4",
|
|
149
149
|
"@wbce-d9/specs": "9.26.5",
|
|
150
|
+
"@wbce-d9/exceptions": "9.26.4",
|
|
150
151
|
"@wbce-d9/storage": "9.26.4",
|
|
151
|
-
"@wbce-d9/
|
|
152
|
-
"@wbce-d9/
|
|
153
|
-
"@wbce-d9/storage-driver-
|
|
154
|
-
"@wbce-d9/storage-driver-
|
|
155
|
-
"@wbce-d9/storage-driver-
|
|
156
|
-
"@wbce-d9/storage-driver-local": "9.26.8",
|
|
157
|
-
"@wbce-d9/storage-driver-s3": "9.26.10",
|
|
152
|
+
"@wbce-d9/storage-driver-azure": "9.26.9",
|
|
153
|
+
"@wbce-d9/extensions-sdk": "9.27.2",
|
|
154
|
+
"@wbce-d9/storage-driver-gcs": "9.26.9",
|
|
155
|
+
"@wbce-d9/storage-driver-s3": "9.26.11",
|
|
156
|
+
"@wbce-d9/storage-driver-local": "9.26.9",
|
|
158
157
|
"@wbce-d9/update-check": "9.28.0",
|
|
159
|
-
"@wbce-d9/
|
|
158
|
+
"@wbce-d9/storage-driver-cloudinary": "9.27.2",
|
|
159
|
+
"@wbce-d9/utils": "9.29.2"
|
|
160
160
|
},
|
|
161
161
|
"devDependencies": {
|
|
162
162
|
"@ngneat/falso": "6.4.0",
|
|
@@ -199,7 +199,7 @@
|
|
|
199
199
|
"@vitest/coverage-c8": "0.30.1",
|
|
200
200
|
"@wbce-d9/tsconfig": "0.0.7",
|
|
201
201
|
"copyfiles": "2.4.1",
|
|
202
|
-
"form-data": "4.0.
|
|
202
|
+
"form-data": "4.0.4",
|
|
203
203
|
"knex-mock-client": "3.0.2",
|
|
204
204
|
"supertest": "6.3.3",
|
|
205
205
|
"typescript": "5.0.4",
|