@prosopo/provider 3.3.0 → 3.12.3
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/CHANGELOG.md +545 -0
- package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js +7 -4
- package/dist/api/blacklistRequestInspector.js +11 -9
- package/dist/api/captcha.js +121 -33
- package/dist/api/domainMiddleware.js +8 -8
- package/dist/api/headerCheckMiddleware.js +4 -0
- package/dist/api/ignoreMiddleware.js +4 -1
- package/dist/api/ja4Middleware.js +5 -23
- package/dist/api/public.js +26 -3
- package/dist/api/verify.js +4 -2
- package/dist/cjs/api/admin/apiRemoveDetectorKeyEndpoint.cjs +6 -3
- package/dist/cjs/api/blacklistRequestInspector.cjs +11 -9
- package/dist/cjs/api/captcha.cjs +121 -33
- package/dist/cjs/api/domainMiddleware.cjs +8 -8
- package/dist/cjs/api/headerCheckMiddleware.cjs +4 -0
- package/dist/cjs/api/ignoreMiddleware.cjs +3 -0
- package/dist/cjs/api/ja4Middleware.cjs +4 -22
- package/dist/cjs/api/public.cjs +26 -3
- package/dist/cjs/api/verify.cjs +4 -2
- package/dist/cjs/compositeIpAddress.cjs +53 -0
- package/dist/cjs/index.cjs +7 -0
- package/dist/cjs/pairs.cjs +27 -0
- package/dist/cjs/services/ipComparison.cjs +123 -0
- package/dist/cjs/services/ipInfo.cjs +87 -0
- package/dist/cjs/tasks/captchaManager.cjs +49 -2
- package/dist/cjs/tasks/client/clientTasks.cjs +33 -12
- package/dist/cjs/tasks/detection/decodePayload.cjs +712 -278
- package/dist/cjs/tasks/detection/getBotScore.cjs +14 -3
- package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +128 -24
- package/dist/cjs/tasks/frictionless/frictionlessTasksUtils.cjs +17 -0
- package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +62 -20
- package/dist/cjs/tasks/powCaptcha/powTasks.cjs +43 -15
- package/dist/cjs/util.cjs +248 -16
- package/dist/cjs/utils/hashUserAgent.cjs +10 -0
- package/dist/compositeIpAddress.js +53 -0
- package/dist/index.js +8 -1
- package/dist/pairs.js +27 -0
- package/dist/services/ipComparison.js +123 -0
- package/dist/services/ipInfo.js +87 -0
- package/dist/tasks/captchaManager.js +49 -2
- package/dist/tasks/client/clientTasks.js +33 -12
- package/dist/tasks/detection/decodePayload.js +712 -278
- package/dist/tasks/detection/getBotScore.js +15 -4
- package/dist/tasks/frictionless/frictionlessTasks.js +128 -24
- package/dist/tasks/frictionless/frictionlessTasksUtils.js +18 -1
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +64 -22
- package/dist/tasks/powCaptcha/powTasks.js +44 -16
- package/dist/util.js +249 -17
- package/dist/utils/hashUserAgent.js +10 -0
- package/package.json +26 -23
- package/vite.test.config.ts +3 -2
- package/vite.threads.test.config.ts +33 -0
package/dist/util.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { hexToU8a } from "@polkadot/util/hex";
|
|
2
2
|
import { isHex } from "@polkadot/util/is";
|
|
3
3
|
import { ProsopoContractError, ProsopoEnvError } from "@prosopo/common";
|
|
4
|
-
import { ScheduledTaskStatus } from "@prosopo/types";
|
|
4
|
+
import { ScheduledTaskStatus, IPValidationAction } from "@prosopo/types";
|
|
5
5
|
import { at } from "@prosopo/util";
|
|
6
6
|
import { encodeAddress, decodeAddress } from "@prosopo/util-crypto";
|
|
7
7
|
import { Address4, Address6 } from "ip-address";
|
|
8
|
+
import { compareIPs } from "./services/ipComparison.js";
|
|
8
9
|
function encodeStringAddress(address) {
|
|
9
10
|
try {
|
|
10
11
|
return encodeAddress(
|
|
@@ -61,7 +62,7 @@ const getIPAddressFromBigInt = (ipAddressBigInt) => {
|
|
|
61
62
|
throw new ProsopoEnvError("API.INVALID_IP");
|
|
62
63
|
}
|
|
63
64
|
};
|
|
64
|
-
const validateIpAddress = (ip,
|
|
65
|
+
const validateIpAddress = (ip, challengeIpAddress, logger) => {
|
|
65
66
|
if (!ip) {
|
|
66
67
|
return { isValid: true };
|
|
67
68
|
}
|
|
@@ -74,27 +75,19 @@ const validateIpAddress = (ip, challengeRecordIpAddress, logger) => {
|
|
|
74
75
|
logger.info(() => ({ msg: errorMessage }));
|
|
75
76
|
return { isValid: false, errorMessage };
|
|
76
77
|
}
|
|
77
|
-
let challengeIpV4orV6Address = getIPAddressFromBigInt(
|
|
78
|
-
challengeRecordIpAddress
|
|
79
|
-
);
|
|
80
78
|
ipV4orV6Address = "address4" in ipV4orV6Address && ipV4orV6Address.address4 ? ipV4orV6Address.address4 : ipV4orV6Address;
|
|
81
|
-
|
|
82
|
-
if (ipV4orV6Address.v4 && !
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
if (!ipV4orV6Address.v4 && challengeIpV4orV6Address.v4) {
|
|
88
|
-
ipV4orV6Address = new Address6(
|
|
89
|
-
ipV4orV6Address.to4().correctForm()
|
|
79
|
+
challengeIpAddress = "address4" in challengeIpAddress && challengeIpAddress.address4 ? challengeIpAddress.address4 : challengeIpAddress;
|
|
80
|
+
if (ipV4orV6Address.v4 && !challengeIpAddress.v4) {
|
|
81
|
+
challengeIpAddress = new Address4(
|
|
82
|
+
challengeIpAddress.to4().correctForm()
|
|
90
83
|
);
|
|
91
84
|
}
|
|
92
|
-
if (
|
|
93
|
-
const errorMessage = `IP address mismatch: ${
|
|
85
|
+
if (challengeIpAddress.bigInt() - ipV4orV6Address.bigInt() !== 0n) {
|
|
86
|
+
const errorMessage = `IP address mismatch: ${challengeIpAddress.address} !== ${ipV4orV6Address.address}`;
|
|
94
87
|
logger.info(() => ({
|
|
95
88
|
msg: errorMessage,
|
|
96
89
|
data: {
|
|
97
|
-
challengeIp:
|
|
90
|
+
challengeIp: challengeIpAddress.address,
|
|
98
91
|
providedIp: ipV4orV6Address.address
|
|
99
92
|
}
|
|
100
93
|
}));
|
|
@@ -102,9 +95,248 @@ const validateIpAddress = (ip, challengeRecordIpAddress, logger) => {
|
|
|
102
95
|
}
|
|
103
96
|
return { isValid: true };
|
|
104
97
|
};
|
|
98
|
+
const evaluateIpValidationRules = (comparison, rules, logger) => {
|
|
99
|
+
if (!comparison.comparison) {
|
|
100
|
+
return { action: IPValidationAction.Allow };
|
|
101
|
+
}
|
|
102
|
+
const conditions = [];
|
|
103
|
+
const rejectActions = Object.values(rules.actions).filter(
|
|
104
|
+
(action) => action === IPValidationAction.Reject
|
|
105
|
+
);
|
|
106
|
+
const ip1Country = comparison.comparison.ip1Details?.country;
|
|
107
|
+
const ip2Country = comparison.comparison.ip2Details?.country;
|
|
108
|
+
const ip1CountryCode = comparison.comparison.ip1Details?.countryCode;
|
|
109
|
+
const ip2CountryCode = comparison.comparison.ip2Details?.countryCode;
|
|
110
|
+
let effectiveRules = rules;
|
|
111
|
+
let countryOverride = void 0;
|
|
112
|
+
if (ip1CountryCode && rules.countryOverrides?.[ip1CountryCode]) {
|
|
113
|
+
countryOverride = rules.countryOverrides[ip1CountryCode];
|
|
114
|
+
}
|
|
115
|
+
if (ip2CountryCode && rules.countryOverrides?.[ip2CountryCode]) {
|
|
116
|
+
countryOverride = rules.countryOverrides[ip2CountryCode];
|
|
117
|
+
}
|
|
118
|
+
if (countryOverride) {
|
|
119
|
+
effectiveRules = {
|
|
120
|
+
...rules,
|
|
121
|
+
actions: {
|
|
122
|
+
...rules.actions,
|
|
123
|
+
...countryOverride.actions
|
|
124
|
+
},
|
|
125
|
+
distanceThresholdKm: countryOverride.distanceThresholdKm ?? rules.distanceThresholdKm,
|
|
126
|
+
abuseScoreThreshold: countryOverride.abuseScoreThreshold ?? rules.abuseScoreThreshold,
|
|
127
|
+
requireAllConditions: countryOverride.requireAllConditions ?? rules.requireAllConditions
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (ip1Country !== ip2Country) {
|
|
131
|
+
conditions.push({
|
|
132
|
+
met: true,
|
|
133
|
+
action: effectiveRules.actions.countryChangeAction,
|
|
134
|
+
message: `Country changed from ${ip1Country} to ${ip2Country}`
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
const ip1City = comparison.comparison.ip1Details?.city;
|
|
138
|
+
const ip2City = comparison.comparison.ip2Details?.city;
|
|
139
|
+
if (ip1City !== ip2City) {
|
|
140
|
+
conditions.push({
|
|
141
|
+
met: true,
|
|
142
|
+
action: effectiveRules.actions.cityChangeAction,
|
|
143
|
+
message: `City changed from ${ip1City} to ${ip2City}`
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
if (comparison.comparison.differentProviders) {
|
|
147
|
+
const ip1Provider = comparison.comparison.ip1Details?.provider;
|
|
148
|
+
const ip2Provider = comparison.comparison.ip2Details?.provider;
|
|
149
|
+
conditions.push({
|
|
150
|
+
met: true,
|
|
151
|
+
action: effectiveRules.actions.ispChangeAction,
|
|
152
|
+
message: `ISP changed from ${ip1Provider} to ${ip2Provider}`
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
const distanceKm = comparison.comparison.distanceKm;
|
|
156
|
+
if (distanceKm !== void 0 && distanceKm > effectiveRules.distanceThresholdKm) {
|
|
157
|
+
conditions.push({
|
|
158
|
+
met: true,
|
|
159
|
+
action: effectiveRules.actions.distanceExceedAction,
|
|
160
|
+
message: `IP addresses are ${distanceKm.toFixed(2)}km apart (>${effectiveRules.distanceThresholdKm}km limit)`
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
console.log(JSON.stringify(effectiveRules, null, 2));
|
|
164
|
+
const ip2AbuseScore = comparison.comparison.ip2Details?.abuserScore;
|
|
165
|
+
if (ip2AbuseScore !== void 0 && ip2AbuseScore > effectiveRules.abuseScoreThreshold) {
|
|
166
|
+
conditions.push({
|
|
167
|
+
met: true,
|
|
168
|
+
action: effectiveRules.actions.abuseScoreExceedAction,
|
|
169
|
+
message: `Abuse score ${ip2AbuseScore.toFixed(4)} exceeds threshold ${effectiveRules.abuseScoreThreshold}`
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
const ip1AbuseScore = comparison.comparison.ip1Details?.abuserScore;
|
|
173
|
+
if (ip1AbuseScore !== void 0 && ip1AbuseScore > effectiveRules.abuseScoreThreshold) {
|
|
174
|
+
conditions.push({
|
|
175
|
+
met: true,
|
|
176
|
+
action: effectiveRules.actions.abuseScoreExceedAction,
|
|
177
|
+
message: `Abuse score ${ip1AbuseScore.toFixed(4)} exceeds threshold ${effectiveRules.abuseScoreThreshold}`
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (conditions.length === 0) {
|
|
181
|
+
return { action: IPValidationAction.Allow };
|
|
182
|
+
}
|
|
183
|
+
const errorMessages = [];
|
|
184
|
+
let finalAction = IPValidationAction.Allow;
|
|
185
|
+
let shouldFlag = false;
|
|
186
|
+
if (effectiveRules.requireAllConditions) {
|
|
187
|
+
const rejectConditions = conditions.filter(
|
|
188
|
+
(c) => c.action === IPValidationAction.Reject
|
|
189
|
+
);
|
|
190
|
+
if (rejectConditions.length > 0 && rejectConditions.length >= rejectActions.length) {
|
|
191
|
+
finalAction = IPValidationAction.Reject;
|
|
192
|
+
}
|
|
193
|
+
for (const condition of conditions) {
|
|
194
|
+
if (condition.action === IPValidationAction.Reject || condition.action === IPValidationAction.Flag) {
|
|
195
|
+
errorMessages.push(condition.message);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
for (const condition of conditions) {
|
|
200
|
+
if (condition.action === IPValidationAction.Reject) {
|
|
201
|
+
finalAction = IPValidationAction.Reject;
|
|
202
|
+
errorMessages.push(condition.message);
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
if (condition.action === IPValidationAction.Flag) {
|
|
206
|
+
finalAction = IPValidationAction.Flag;
|
|
207
|
+
shouldFlag = true;
|
|
208
|
+
}
|
|
209
|
+
errorMessages.push(condition.message);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
logger.info(() => ({
|
|
213
|
+
msg: `IP validation rules evaluated: ${finalAction}`,
|
|
214
|
+
data: {
|
|
215
|
+
conditions,
|
|
216
|
+
finalAction,
|
|
217
|
+
requireAllConditions: effectiveRules.requireAllConditions
|
|
218
|
+
}
|
|
219
|
+
}));
|
|
220
|
+
return {
|
|
221
|
+
action: finalAction,
|
|
222
|
+
errorMessage: errorMessages.length > 0 ? errorMessages.join("; ") : void 0,
|
|
223
|
+
shouldFlag
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
const deepValidateIpAddress = async (ip, challengeIpAddress, logger, apiKey, apiUrl, ipValidationRules) => {
|
|
227
|
+
const standardValidation = validateIpAddress(ip, challengeIpAddress, logger);
|
|
228
|
+
if (!standardValidation.isValid) {
|
|
229
|
+
if (standardValidation.errorMessage?.includes("Invalid IP address")) {
|
|
230
|
+
return standardValidation;
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
return { isValid: true };
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
const challengeIpString = challengeIpAddress.address;
|
|
237
|
+
const comparison = await compareIPs(challengeIpString, ip, apiKey, apiUrl);
|
|
238
|
+
if ("error" in comparison) {
|
|
239
|
+
logger.error(() => ({
|
|
240
|
+
msg: "Failed to get IP distance comparison",
|
|
241
|
+
data: {
|
|
242
|
+
error: comparison.error,
|
|
243
|
+
challengeIp: challengeIpString,
|
|
244
|
+
providedIp: ip
|
|
245
|
+
}
|
|
246
|
+
}));
|
|
247
|
+
return {
|
|
248
|
+
isValid: false,
|
|
249
|
+
errorMessage: "Could not determine IP distance"
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
if (comparison.ipsMatch) {
|
|
253
|
+
return { isValid: true };
|
|
254
|
+
}
|
|
255
|
+
const distanceKm = comparison.comparison?.distanceKm;
|
|
256
|
+
if (!ipValidationRules) {
|
|
257
|
+
logger.info(() => ({
|
|
258
|
+
msg: "No IP validation rules provided, using legacy logic",
|
|
259
|
+
data: {
|
|
260
|
+
challengeIp: challengeIpString,
|
|
261
|
+
providedIp: ip,
|
|
262
|
+
distanceKm
|
|
263
|
+
}
|
|
264
|
+
}));
|
|
265
|
+
if (distanceKm !== void 0 && distanceKm > 1e3) {
|
|
266
|
+
const errorMessage = `IP addresses are too far apart: ${distanceKm.toFixed(2)}km (>1000km limit)`;
|
|
267
|
+
logger.info(() => ({
|
|
268
|
+
msg: "IP validation failed - distance too great",
|
|
269
|
+
data: {
|
|
270
|
+
challengeIp: challengeIpString,
|
|
271
|
+
providedIp: ip,
|
|
272
|
+
distanceKm,
|
|
273
|
+
comparison: comparison.comparison
|
|
274
|
+
}
|
|
275
|
+
}));
|
|
276
|
+
return {
|
|
277
|
+
isValid: false,
|
|
278
|
+
errorMessage,
|
|
279
|
+
distanceKm
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
logger.info(() => ({
|
|
283
|
+
msg: "IP addresses differ but within acceptable distance",
|
|
284
|
+
data: {
|
|
285
|
+
challengeIp: challengeIpString,
|
|
286
|
+
providedIp: ip,
|
|
287
|
+
distanceKm,
|
|
288
|
+
comparison: comparison.comparison
|
|
289
|
+
}
|
|
290
|
+
}));
|
|
291
|
+
return {
|
|
292
|
+
isValid: true,
|
|
293
|
+
distanceKm,
|
|
294
|
+
shouldFlag: true
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
const ruleEvaluation = evaluateIpValidationRules(
|
|
298
|
+
comparison,
|
|
299
|
+
ipValidationRules,
|
|
300
|
+
logger
|
|
301
|
+
);
|
|
302
|
+
switch (ruleEvaluation.action) {
|
|
303
|
+
case IPValidationAction.Reject:
|
|
304
|
+
return {
|
|
305
|
+
isValid: false,
|
|
306
|
+
errorMessage: ruleEvaluation.errorMessage,
|
|
307
|
+
distanceKm
|
|
308
|
+
};
|
|
309
|
+
case IPValidationAction.Flag:
|
|
310
|
+
return {
|
|
311
|
+
isValid: true,
|
|
312
|
+
distanceKm,
|
|
313
|
+
shouldFlag: true,
|
|
314
|
+
errorMessage: ruleEvaluation.errorMessage
|
|
315
|
+
};
|
|
316
|
+
default:
|
|
317
|
+
return {
|
|
318
|
+
isValid: true,
|
|
319
|
+
distanceKm
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
} catch (error) {
|
|
323
|
+
logger.error(() => ({
|
|
324
|
+
msg: "Error during IP distance validation",
|
|
325
|
+
err: error,
|
|
326
|
+
data: { challengeIp: challengeIpAddress.address, providedIp: ip }
|
|
327
|
+
}));
|
|
328
|
+
return {
|
|
329
|
+
isValid: true,
|
|
330
|
+
shouldFlag: true,
|
|
331
|
+
errorMessage: "IP distance validation error"
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
};
|
|
105
335
|
export {
|
|
106
336
|
checkIfTaskIsRunning,
|
|
337
|
+
deepValidateIpAddress,
|
|
107
338
|
encodeStringAddress,
|
|
339
|
+
evaluateIpValidationRules,
|
|
108
340
|
getIPAddress,
|
|
109
341
|
getIPAddressFromBigInt,
|
|
110
342
|
shuffleArray,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosopo/provider",
|
|
3
|
-
"version": "3.3
|
|
3
|
+
"version": "3.12.3",
|
|
4
4
|
"author": "PROSOPO LIMITED <info@prosopo.io>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -13,38 +13,41 @@
|
|
|
13
13
|
"build": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.esm.config.ts --mode $NODE_ENV",
|
|
14
14
|
"build:tsc": "tsc --build --verbose",
|
|
15
15
|
"build:cjs": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV",
|
|
16
|
-
"typecheck": "tsc --
|
|
17
|
-
"test": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --config ./vite.test.config.ts",
|
|
16
|
+
"typecheck": "tsc --project tsconfig.types.json",
|
|
17
|
+
"test:unit": "NODE_ENV=${NODE_ENV:-test}; TEST_TYPE=unit npx vitest run --config ./vite.test.config.ts",
|
|
18
|
+
"test:integration": "NODE_ENV=${NODE_ENV:-test}; NX_PARALLEL=1 TEST_TYPE=integration npx vitest run --config ./vite.threads.test.config.ts",
|
|
19
|
+
"test": "npm run test:unit && npm run test:integration",
|
|
18
20
|
"mnemonic": "tsx ./scripts/generateMnemonic.ts"
|
|
19
21
|
},
|
|
20
22
|
"dependencies": {
|
|
21
23
|
"@noble/hashes": "1.8.0",
|
|
22
24
|
"@polkadot/util": "12.6.2",
|
|
23
|
-
"@prosopo/api
|
|
24
|
-
"@prosopo/api-
|
|
25
|
-
"@prosopo/
|
|
26
|
-
"@prosopo/
|
|
27
|
-
"@prosopo/
|
|
28
|
-
"@prosopo/
|
|
29
|
-
"@prosopo/
|
|
30
|
-
"@prosopo/
|
|
31
|
-
"@prosopo/
|
|
32
|
-
"@prosopo/
|
|
33
|
-
"@prosopo/
|
|
34
|
-
"@prosopo/
|
|
35
|
-
"@prosopo/
|
|
36
|
-
"@prosopo/
|
|
37
|
-
"@
|
|
38
|
-
"
|
|
25
|
+
"@prosopo/api": "3.1.24",
|
|
26
|
+
"@prosopo/api-express-router": "3.0.25",
|
|
27
|
+
"@prosopo/api-route": "2.6.28",
|
|
28
|
+
"@prosopo/common": "3.1.20",
|
|
29
|
+
"@prosopo/config": "3.1.20",
|
|
30
|
+
"@prosopo/database": "3.4.5",
|
|
31
|
+
"@prosopo/datasets": "3.0.34",
|
|
32
|
+
"@prosopo/env": "3.2.13",
|
|
33
|
+
"@prosopo/keyring": "2.8.27",
|
|
34
|
+
"@prosopo/load-balancer": "2.8.0",
|
|
35
|
+
"@prosopo/locale": "3.1.20",
|
|
36
|
+
"@prosopo/types": "3.5.3",
|
|
37
|
+
"@prosopo/types-database": "3.3.5",
|
|
38
|
+
"@prosopo/types-env": "2.7.38",
|
|
39
|
+
"@prosopo/user-access-policy": "3.5.19",
|
|
40
|
+
"@prosopo/util": "3.1.5",
|
|
41
|
+
"@prosopo/util-crypto": "13.5.22",
|
|
39
42
|
"cron": "3.1.7",
|
|
40
|
-
"esbuild": "0.25.6",
|
|
41
43
|
"express": "4.21.2",
|
|
44
|
+
"geolib": "3.3.4",
|
|
45
|
+
"i18next": "24.1.0",
|
|
42
46
|
"ip-address": "10.0.1",
|
|
43
|
-
"
|
|
44
|
-
"
|
|
47
|
+
"mongodb": "6.15.0",
|
|
48
|
+
"mongoose": "8.13.0",
|
|
45
49
|
"read-tls-client-hello": "1.1.0",
|
|
46
50
|
"uuid": "11.1.0",
|
|
47
|
-
"webpack-dev-server": "5.2.2",
|
|
48
51
|
"zod": "3.23.8"
|
|
49
52
|
},
|
|
50
53
|
"devDependencies": {
|
package/vite.test.config.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
1
|
// Copyright 2021-2025 Prosopo (UK) Ltd.
|
|
4
2
|
//
|
|
5
3
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -13,6 +11,9 @@ import path from "node:path";
|
|
|
13
11
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
12
|
// See the License for the specific language governing permissions and
|
|
15
13
|
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import fs from "node:fs";
|
|
16
|
+
import path from "node:path";
|
|
16
17
|
import { ViteTestConfig } from "@prosopo/config";
|
|
17
18
|
import dotenv from "dotenv";
|
|
18
19
|
process.env.NODE_ENV = "test";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright 2021-2025 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import fs from "node:fs";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import { ViteThreadsTestConfig } from "@prosopo/config";
|
|
18
|
+
import dotenv from "dotenv";
|
|
19
|
+
process.env.NODE_ENV = "test";
|
|
20
|
+
// if .env.test exists at this level, use it, otherwise use the one at the root
|
|
21
|
+
const envFile = `.env.${process.env.NODE_ENV || "development"}`;
|
|
22
|
+
let envPath = envFile;
|
|
23
|
+
if (fs.existsSync(envFile)) {
|
|
24
|
+
envPath = path.resolve(envFile);
|
|
25
|
+
} else if (fs.existsSync(`../../${envFile}`)) {
|
|
26
|
+
envPath = path.resolve(`../../${envFile}`);
|
|
27
|
+
} else {
|
|
28
|
+
throw new Error(`No ${envFile} file found`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
dotenv.config({ path: envPath });
|
|
32
|
+
|
|
33
|
+
export default ViteThreadsTestConfig();
|