@prosopo/user-access-policy 2.5.3 → 2.6.1
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 +21 -0
- package/dist/cjs/index.cjs +28 -0
- package/dist/cjs/rules/api/apiRulePaths.cjs +7 -0
- package/dist/cjs/rules/api/apiRuleRoutesProvider.cjs +23 -0
- package/dist/cjs/rules/api/deleteMany/apiDeleteManyRulesArgsSchema.cjs +13 -0
- package/dist/cjs/rules/api/deleteMany/apiDeleteManyRulesEndpoint.cjs +19 -0
- package/dist/cjs/rules/api/getExpressApiRuleRateLimits.cjs +18 -0
- package/dist/cjs/rules/api/insertMany/apiInsertManyRulesArgsSchema.cjs +39 -0
- package/dist/cjs/rules/api/insertMany/apiInsertManyRulesEndpoint.cjs +193 -0
- package/dist/cjs/rules/blacklistRulesInspector.cjs +44 -0
- package/dist/cjs/rules/imageCaptchaConfigRulesResolver.cjs +115 -0
- package/dist/cjs/rules/mongoose/indexes/rulePerformanceMongooseIndexes.cjs +75 -0
- package/dist/cjs/rules/mongoose/indexes/ruleUniqueMongooseIndexes.cjs +137 -0
- package/dist/cjs/rules/mongoose/rulesMongooseStorage.cjs +177 -0
- package/dist/cjs/rules/mongoose/schemas/config/configMongooseSchema.cjs +14 -0
- package/dist/cjs/rules/mongoose/schemas/config/imageCaptchaConfigMongooseSchema.cjs +17 -0
- package/dist/cjs/rules/mongoose/schemas/getRuleMongooseSchema.cjs +19 -0
- package/dist/cjs/rules/mongoose/schemas/ip/ipMongooseSchema.cjs +29 -0
- package/dist/cjs/rules/mongoose/schemas/ip/v4/ipV4MaskMongooseSchema.cjs +14 -0
- package/dist/cjs/rules/mongoose/schemas/ip/v4/ipV4MongooseSchema.cjs +18 -0
- package/dist/cjs/rules/mongoose/schemas/ip/v6/ipV6MaskMongooseSchema.cjs +34 -0
- package/dist/cjs/rules/mongoose/schemas/ip/v6/ipV6MongooseSchema.cjs +33 -0
- package/dist/cjs/rules/mongoose/schemas/ruleMongooseSchema.cjs +43 -0
- package/dist/cjs/rules/rule/config/imageCaptcha/imageCaptchaConfigSchema.cjs +8 -0
- package/dist/cjs/rules/rule/config/ruleConfigSchema.cjs +8 -0
- package/dist/cjs/rules/rule/ip/ruleIpSchema.cjs +10 -0
- package/dist/cjs/rules/rule/ip/ruleIpVersion.cjs +8 -0
- package/dist/cjs/rules/rule/ip/v4/mask/ruleIpV4MaskSchema.cjs +9 -0
- package/dist/cjs/rules/rule/ip/v4/ruleIpV4Schema.cjs +10 -0
- package/dist/cjs/rules/rule/ip/v6/mask/ruleIpV6MaskSchema.cjs +9 -0
- package/dist/cjs/rules/rule/ip/v6/ruleIpV6NumericMaxLength.cjs +4 -0
- package/dist/cjs/rules/rule/ip/v6/ruleIpV6Schema.cjs +10 -0
- package/package.json +12 -7
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# @prosopo/user-access-policy
|
|
2
|
+
|
|
3
|
+
## 2.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [52feffc]
|
|
8
|
+
- @prosopo/types@2.6.1
|
|
9
|
+
|
|
10
|
+
## 2.6.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- a0bfc8a: bump all pkg versions since independent versioning applied
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies [a0bfc8a]
|
|
19
|
+
- @prosopo/api-route@2.6.0
|
|
20
|
+
- @prosopo/common@2.6.0
|
|
21
|
+
- @prosopo/types@2.6.0
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const apiRulePaths = require("./rules/api/apiRulePaths.cjs");
|
|
4
|
+
const apiRuleRoutesProvider = require("./rules/api/apiRuleRoutesProvider.cjs");
|
|
5
|
+
const getExpressApiRuleRateLimits = require("./rules/api/getExpressApiRuleRateLimits.cjs");
|
|
6
|
+
const blacklistRulesInspector = require("./rules/blacklistRulesInspector.cjs");
|
|
7
|
+
const imageCaptchaConfigRulesResolver = require("./rules/imageCaptchaConfigRulesResolver.cjs");
|
|
8
|
+
const rulesMongooseStorage = require("./rules/mongoose/rulesMongooseStorage.cjs");
|
|
9
|
+
const getRuleMongooseSchema = require("./rules/mongoose/schemas/getRuleMongooseSchema.cjs");
|
|
10
|
+
const createBlacklistInspector = (rulesStorage, logger) => {
|
|
11
|
+
return new blacklistRulesInspector.BlacklistRulesInspector(rulesStorage, logger);
|
|
12
|
+
};
|
|
13
|
+
const createImageCaptchaConfigResolver = (rulesStorage, logger) => {
|
|
14
|
+
return new imageCaptchaConfigRulesResolver.ImageCaptchaConfigRulesResolver(rulesStorage, logger);
|
|
15
|
+
};
|
|
16
|
+
const createApiRuleRoutesProvider = (rulesStorage) => {
|
|
17
|
+
return new apiRuleRoutesProvider.ApiRuleRoutesProvider(rulesStorage);
|
|
18
|
+
};
|
|
19
|
+
const createMongooseRulesStorage = (logger, readingModel, writingModel = null) => {
|
|
20
|
+
return new rulesMongooseStorage.RulesMongooseStorage(logger, readingModel, writingModel);
|
|
21
|
+
};
|
|
22
|
+
exports.apiRulePaths = apiRulePaths.apiRulePaths;
|
|
23
|
+
exports.getExpressApiRuleRateLimits = getExpressApiRuleRateLimits.getExpressApiRuleRateLimits;
|
|
24
|
+
exports.getRuleMongooseSchema = getRuleMongooseSchema.getRuleMongooseSchema;
|
|
25
|
+
exports.createApiRuleRoutesProvider = createApiRuleRoutesProvider;
|
|
26
|
+
exports.createBlacklistInspector = createBlacklistInspector;
|
|
27
|
+
exports.createImageCaptchaConfigResolver = createImageCaptchaConfigResolver;
|
|
28
|
+
exports.createMongooseRulesStorage = createMongooseRulesStorage;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const apiRulePaths = {
|
|
4
|
+
INSERT_MANY: "/v1/prosopo/user-access-policy/rules/insert-many",
|
|
5
|
+
DELETE_MANY: "/v1/prosopo/user-access-policy/rules/delete-many"
|
|
6
|
+
};
|
|
7
|
+
exports.apiRulePaths = apiRulePaths;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const apiRulePaths = require("./apiRulePaths.cjs");
|
|
4
|
+
const apiDeleteManyRulesEndpoint = require("./deleteMany/apiDeleteManyRulesEndpoint.cjs");
|
|
5
|
+
const apiInsertManyRulesEndpoint = require("./insertMany/apiInsertManyRulesEndpoint.cjs");
|
|
6
|
+
class ApiRuleRoutesProvider {
|
|
7
|
+
constructor(rulesStorage) {
|
|
8
|
+
this.rulesStorage = rulesStorage;
|
|
9
|
+
}
|
|
10
|
+
getRoutes() {
|
|
11
|
+
return [
|
|
12
|
+
{
|
|
13
|
+
path: apiRulePaths.apiRulePaths.INSERT_MANY,
|
|
14
|
+
endpoint: new apiInsertManyRulesEndpoint.ApiInsertManyRulesEndpoint(this.rulesStorage)
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
path: apiRulePaths.apiRulePaths.DELETE_MANY,
|
|
18
|
+
endpoint: new apiDeleteManyRulesEndpoint.ApiDeleteManyRulesEndpoint(this.rulesStorage)
|
|
19
|
+
}
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.ApiRuleRoutesProvider = ApiRuleRoutesProvider;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const zod = require("zod");
|
|
4
|
+
const ruleIpSchema = require("../../rule/ip/ruleIpSchema.cjs");
|
|
5
|
+
const apiDeleteManyRulesArgsSchema = zod.array(
|
|
6
|
+
zod.object({
|
|
7
|
+
clientId: zod.string().optional(),
|
|
8
|
+
userIp: ruleIpSchema.ruleIpSchema.optional(),
|
|
9
|
+
userId: zod.string().optional(),
|
|
10
|
+
ja4: zod.string().optional()
|
|
11
|
+
})
|
|
12
|
+
);
|
|
13
|
+
exports.apiDeleteManyRulesArgsSchema = apiDeleteManyRulesArgsSchema;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const apiRoute = require("@prosopo/api-route");
|
|
4
|
+
const apiDeleteManyRulesArgsSchema = require("./apiDeleteManyRulesArgsSchema.cjs");
|
|
5
|
+
class ApiDeleteManyRulesEndpoint {
|
|
6
|
+
constructor(rulesStorage) {
|
|
7
|
+
this.rulesStorage = rulesStorage;
|
|
8
|
+
}
|
|
9
|
+
async processRequest(args) {
|
|
10
|
+
await this.rulesStorage.deleteMany(args);
|
|
11
|
+
return {
|
|
12
|
+
status: apiRoute.ApiEndpointResponseStatus.SUCCESS
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
getRequestArgsSchema() {
|
|
16
|
+
return apiDeleteManyRulesArgsSchema.apiDeleteManyRulesArgsSchema;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.ApiDeleteManyRulesEndpoint = ApiDeleteManyRulesEndpoint;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const apiRulePaths = require("./apiRulePaths.cjs");
|
|
4
|
+
const getExpressApiRuleRateLimits = () => {
|
|
5
|
+
const defaultWindowsMs = 6e4;
|
|
6
|
+
const defaultLimit = 5;
|
|
7
|
+
return {
|
|
8
|
+
[apiRulePaths.apiRulePaths.INSERT_MANY]: {
|
|
9
|
+
windowMs: process.env.PROSOPO_USER_ACCESS_POLICY_RULE_INSERT_MANY_WINDOW || defaultWindowsMs,
|
|
10
|
+
limit: process.env.PROSOPO_USER_ACCESS_POLICY_RULE_INSERT_MANY_LIMIT || defaultLimit
|
|
11
|
+
},
|
|
12
|
+
[apiRulePaths.apiRulePaths.DELETE_MANY]: {
|
|
13
|
+
windowMs: process.env.PROSOPO_USER_ACCESS_POLICY_RULE_DELETE_MANY_WINDOW || defaultWindowsMs,
|
|
14
|
+
limit: process.env.PROSOPO_USER_ACCESS_POLICY_RULE_DELETE_MANY_LIMIT || defaultLimit
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
exports.getExpressApiRuleRateLimits = getExpressApiRuleRateLimits;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const zod = require("zod");
|
|
4
|
+
const ruleConfigSchema = require("../../rule/config/ruleConfigSchema.cjs");
|
|
5
|
+
const apiInsertManyRulesArgsSchema = zod.object({
|
|
6
|
+
isUserBlocked: zod.boolean(),
|
|
7
|
+
clientId: zod.string().optional(),
|
|
8
|
+
description: zod.string().optional(),
|
|
9
|
+
userIps: zod.object({
|
|
10
|
+
v4: zod.string().array().optional(),
|
|
11
|
+
v6: zod.string().array().optional()
|
|
12
|
+
}),
|
|
13
|
+
// block multiple user ip ranges
|
|
14
|
+
userIpMasks: zod.object({
|
|
15
|
+
v4: zod.object({
|
|
16
|
+
min: zod.string(),
|
|
17
|
+
max: zod.string()
|
|
18
|
+
}).array().optional(),
|
|
19
|
+
v6: zod.object({
|
|
20
|
+
min: zod.string(),
|
|
21
|
+
max: zod.string()
|
|
22
|
+
}).array().optional()
|
|
23
|
+
}),
|
|
24
|
+
// block multiple user ip ranges
|
|
25
|
+
userIds: zod.string().array().optional(),
|
|
26
|
+
// block multiple user ids
|
|
27
|
+
ja4s: zod.string().array().optional(),
|
|
28
|
+
// block multiple ja4s
|
|
29
|
+
// setting individual rule values overrides any array values for the same type
|
|
30
|
+
userIp: zod.object({
|
|
31
|
+
v4: zod.string().optional(),
|
|
32
|
+
v6: zod.string().optional()
|
|
33
|
+
}).optional(),
|
|
34
|
+
userId: zod.string().optional(),
|
|
35
|
+
ja4: zod.string().optional(),
|
|
36
|
+
config: ruleConfigSchema.ruleConfigSchema.optional(),
|
|
37
|
+
score: zod.number().optional()
|
|
38
|
+
});
|
|
39
|
+
exports.apiInsertManyRulesArgsSchema = apiInsertManyRulesArgsSchema;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const apiRoute = require("@prosopo/api-route");
|
|
4
|
+
const ipAddress = require("ip-address");
|
|
5
|
+
const ruleIpSchema = require("../../rule/ip/ruleIpSchema.cjs");
|
|
6
|
+
const apiInsertManyRulesArgsSchema = require("./apiInsertManyRulesArgsSchema.cjs");
|
|
7
|
+
class ApiInsertManyRulesEndpoint {
|
|
8
|
+
constructor(rulesStorage) {
|
|
9
|
+
this.rulesStorage = rulesStorage;
|
|
10
|
+
}
|
|
11
|
+
async processRequest(args) {
|
|
12
|
+
const singleRule = this.getSingleRule(args);
|
|
13
|
+
const rules = [
|
|
14
|
+
...this.getUserIpRules(args),
|
|
15
|
+
...this.getUserIPMaskRules(args),
|
|
16
|
+
...this.getUserIdRules(args),
|
|
17
|
+
...this.getJa4Rules(args),
|
|
18
|
+
...singleRule ? [singleRule] : []
|
|
19
|
+
];
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
this.rulesStorage.insertMany(rules).then(() => {
|
|
22
|
+
resolve({
|
|
23
|
+
status: apiRoute.ApiEndpointResponseStatus.SUCCESS
|
|
24
|
+
});
|
|
25
|
+
}).catch((e) => {
|
|
26
|
+
resolve({
|
|
27
|
+
status: apiRoute.ApiEndpointResponseStatus.FAIL
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
setTimeout(() => {
|
|
31
|
+
resolve({
|
|
32
|
+
status: apiRoute.ApiEndpointResponseStatus.PROCESSING
|
|
33
|
+
});
|
|
34
|
+
}, 5e3);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
getRequestArgsSchema() {
|
|
38
|
+
return apiInsertManyRulesArgsSchema.apiInsertManyRulesArgsSchema;
|
|
39
|
+
}
|
|
40
|
+
getUserIpRules(args) {
|
|
41
|
+
const rules = [];
|
|
42
|
+
const userIps = args.userIps || [];
|
|
43
|
+
for (const userIp of userIps.v4 || []) {
|
|
44
|
+
const ipAddress$1 = new ipAddress.Address4(userIp);
|
|
45
|
+
rules.push({
|
|
46
|
+
userIp: ruleIpSchema.ruleIpSchema.parse({
|
|
47
|
+
v4: {
|
|
48
|
+
asNumeric: ipAddress$1.bigInt(),
|
|
49
|
+
asString: ipAddress$1.address
|
|
50
|
+
}
|
|
51
|
+
}),
|
|
52
|
+
isUserBlocked: args.isUserBlocked,
|
|
53
|
+
description: args.description,
|
|
54
|
+
clientId: args.clientId,
|
|
55
|
+
config: args.config,
|
|
56
|
+
score: args.score
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
for (const userIp of userIps.v6 || []) {
|
|
60
|
+
const ipAddress$1 = new ipAddress.Address6(userIp);
|
|
61
|
+
rules.push({
|
|
62
|
+
userIp: ruleIpSchema.ruleIpSchema.parse({
|
|
63
|
+
v4: {
|
|
64
|
+
asNumeric: ipAddress$1.bigInt(),
|
|
65
|
+
asString: ipAddress$1.address
|
|
66
|
+
}
|
|
67
|
+
}),
|
|
68
|
+
isUserBlocked: args.isUserBlocked,
|
|
69
|
+
description: args.description,
|
|
70
|
+
clientId: args.clientId,
|
|
71
|
+
config: args.config,
|
|
72
|
+
score: args.score
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return rules;
|
|
76
|
+
}
|
|
77
|
+
getUserIPMaskRules(args) {
|
|
78
|
+
const rules = [];
|
|
79
|
+
const userIpMasks = args.userIpMasks || [];
|
|
80
|
+
for (const userMask of userIpMasks.v4 || []) {
|
|
81
|
+
const min = new ipAddress.Address4(userMask.min);
|
|
82
|
+
const max = new ipAddress.Address4(userMask.max);
|
|
83
|
+
rules.push({
|
|
84
|
+
userIp: ruleIpSchema.ruleIpSchema.parse({
|
|
85
|
+
v4: {
|
|
86
|
+
asNumeric: min.bigInt(),
|
|
87
|
+
asString: min.address,
|
|
88
|
+
mask: {
|
|
89
|
+
rangeMinAsNumeric: min.bigInt(),
|
|
90
|
+
rangeMaxAsNumeric: max.bigInt(),
|
|
91
|
+
asNumeric: Number(min.bigInt())
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}),
|
|
95
|
+
isUserBlocked: args.isUserBlocked,
|
|
96
|
+
description: args.description,
|
|
97
|
+
clientId: args.clientId,
|
|
98
|
+
config: args.config,
|
|
99
|
+
score: args.score
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
for (const userMask of userIpMasks.v6 || []) {
|
|
103
|
+
const min = new ipAddress.Address6(userMask.min);
|
|
104
|
+
const max = new ipAddress.Address6(userMask.max);
|
|
105
|
+
rules.push({
|
|
106
|
+
userIp: ruleIpSchema.ruleIpSchema.parse({
|
|
107
|
+
v6: {
|
|
108
|
+
asNumeric: min.bigInt(),
|
|
109
|
+
asString: min.address,
|
|
110
|
+
mask: {
|
|
111
|
+
rangeMinAsNumeric: min.bigInt(),
|
|
112
|
+
rangeMaxAsNumeric: max.bigInt(),
|
|
113
|
+
asNumeric: Number(min.bigInt())
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}),
|
|
117
|
+
isUserBlocked: args.isUserBlocked,
|
|
118
|
+
description: args.description,
|
|
119
|
+
clientId: args.clientId,
|
|
120
|
+
config: args.config,
|
|
121
|
+
score: args.score
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return rules;
|
|
125
|
+
}
|
|
126
|
+
getUserIdRules(args) {
|
|
127
|
+
const rules = [];
|
|
128
|
+
const userIds = args.userIds || [];
|
|
129
|
+
for (const userId of userIds) {
|
|
130
|
+
rules.push({
|
|
131
|
+
userId,
|
|
132
|
+
isUserBlocked: args.isUserBlocked,
|
|
133
|
+
description: args.description,
|
|
134
|
+
clientId: args.clientId,
|
|
135
|
+
config: args.config,
|
|
136
|
+
score: args.score
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return rules;
|
|
140
|
+
}
|
|
141
|
+
getJa4Rules(args) {
|
|
142
|
+
const rules = [];
|
|
143
|
+
const ja4s = args.ja4s || [];
|
|
144
|
+
for (const ja4 of ja4s) {
|
|
145
|
+
rules.push({
|
|
146
|
+
ja4,
|
|
147
|
+
isUserBlocked: args.isUserBlocked,
|
|
148
|
+
description: args.description,
|
|
149
|
+
clientId: args.clientId,
|
|
150
|
+
config: args.config,
|
|
151
|
+
score: args.score
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return rules;
|
|
155
|
+
}
|
|
156
|
+
getSingleRule(args) {
|
|
157
|
+
if (!args.userIp && !args.userId && !args.ja4) {
|
|
158
|
+
return void 0;
|
|
159
|
+
}
|
|
160
|
+
const rule = {
|
|
161
|
+
isUserBlocked: args.isUserBlocked,
|
|
162
|
+
...args.description && { description: args.description },
|
|
163
|
+
...args.clientId && { clientId: args.clientId },
|
|
164
|
+
...args.config && { config: args.config },
|
|
165
|
+
...args.score && { score: args.score },
|
|
166
|
+
...args.ja4 && { ja4: args.ja4 },
|
|
167
|
+
...args.userId && { userId: args.userId }
|
|
168
|
+
};
|
|
169
|
+
if (args.userIp) {
|
|
170
|
+
const userIp = args.userIp;
|
|
171
|
+
if (userIp.v4) {
|
|
172
|
+
const ipAddress$1 = new ipAddress.Address4(userIp.v4);
|
|
173
|
+
rule.userIp = ruleIpSchema.ruleIpSchema.parse({
|
|
174
|
+
v4: {
|
|
175
|
+
asNumeric: ipAddress$1.bigInt(),
|
|
176
|
+
asString: ipAddress$1.address
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (userIp.v6) {
|
|
181
|
+
const ipAddress$1 = new ipAddress.Address6(userIp.v6);
|
|
182
|
+
rule.userIp = ruleIpSchema.ruleIpSchema.parse({
|
|
183
|
+
v6: {
|
|
184
|
+
asNumeric: ipAddress$1.bigInt(),
|
|
185
|
+
asString: ipAddress$1.address
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return rule;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
exports.ApiInsertManyRulesEndpoint = ApiInsertManyRulesEndpoint;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
class BlacklistRulesInspector {
|
|
4
|
+
constructor(rulesStorage, logger) {
|
|
5
|
+
this.rulesStorage = rulesStorage;
|
|
6
|
+
this.logger = logger;
|
|
7
|
+
}
|
|
8
|
+
async isUserBlacklisted(clientId, userIpAddress, ja4, userId) {
|
|
9
|
+
this.logger.debug({
|
|
10
|
+
clientId,
|
|
11
|
+
userIpAddress,
|
|
12
|
+
ja4,
|
|
13
|
+
userId
|
|
14
|
+
});
|
|
15
|
+
const accessRules = await this.rulesStorage.find(
|
|
16
|
+
{
|
|
17
|
+
clientId,
|
|
18
|
+
userIpAddress,
|
|
19
|
+
ja4,
|
|
20
|
+
userId
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
includeRecordsWithPartialFilterMatches: true,
|
|
24
|
+
includeRecordsWithoutClientId: true
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
const blockingRules = accessRules.filter(
|
|
28
|
+
(accessRule) => accessRule.isUserBlocked
|
|
29
|
+
);
|
|
30
|
+
const userBlacklisted = blockingRules.length > 0;
|
|
31
|
+
if (userBlacklisted) {
|
|
32
|
+
this.logger.info({
|
|
33
|
+
userBlacklisted,
|
|
34
|
+
clientId,
|
|
35
|
+
userIpAddress: userIpAddress.address.toString(),
|
|
36
|
+
userId,
|
|
37
|
+
accessRules: accessRules.length,
|
|
38
|
+
blockingRules: blockingRules.length
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return userBlacklisted;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.BlacklistRulesInspector = BlacklistRulesInspector;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
class ImageCaptchaConfigRulesResolver {
|
|
4
|
+
constructor(rulesStorage, logger, _accessRule = null) {
|
|
5
|
+
this.rulesStorage = rulesStorage;
|
|
6
|
+
this.logger = logger;
|
|
7
|
+
this._accessRule = _accessRule;
|
|
8
|
+
}
|
|
9
|
+
get accessRule() {
|
|
10
|
+
return this._accessRule;
|
|
11
|
+
}
|
|
12
|
+
async isConfigDefined(clientId, userIpAddress, ja4, userId) {
|
|
13
|
+
const accessRule = await this.fetchUserAccessRule(
|
|
14
|
+
userIpAddress,
|
|
15
|
+
ja4,
|
|
16
|
+
userId,
|
|
17
|
+
clientId
|
|
18
|
+
);
|
|
19
|
+
const imageCaptchaConfig = accessRule?.config?.imageCaptcha || null;
|
|
20
|
+
const configDefined = null !== imageCaptchaConfig;
|
|
21
|
+
if (configDefined) {
|
|
22
|
+
this.logger.info({
|
|
23
|
+
configDefined,
|
|
24
|
+
clientId,
|
|
25
|
+
userIpAddress: userIpAddress.toString(),
|
|
26
|
+
userId,
|
|
27
|
+
imageCaptchaConfig,
|
|
28
|
+
ja4
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return configDefined;
|
|
32
|
+
}
|
|
33
|
+
async resolveConfig(defaults, userIpAddress, ja4, userId, clientId) {
|
|
34
|
+
const logArgs = {
|
|
35
|
+
userIpAddress: userIpAddress.address.toString(),
|
|
36
|
+
userId,
|
|
37
|
+
clientId,
|
|
38
|
+
defaults,
|
|
39
|
+
ja4
|
|
40
|
+
};
|
|
41
|
+
this._accessRule = await this.fetchUserAccessRule(
|
|
42
|
+
userIpAddress,
|
|
43
|
+
ja4,
|
|
44
|
+
userId,
|
|
45
|
+
clientId
|
|
46
|
+
);
|
|
47
|
+
if (null === this.accessRule) {
|
|
48
|
+
this.logger.debug("ImageCaptchaConfigRulesResolver.resolveConfig", {
|
|
49
|
+
configDefined: false,
|
|
50
|
+
...logArgs
|
|
51
|
+
});
|
|
52
|
+
return defaults;
|
|
53
|
+
}
|
|
54
|
+
const imageCaptchaConfig = this.accessRule.config?.imageCaptcha || {};
|
|
55
|
+
const config = this.getImageCaptchaConfig(defaults, imageCaptchaConfig);
|
|
56
|
+
this.logger.info("ImageCaptchaConfigRulesResolver.resolveConfig", {
|
|
57
|
+
configDefined: true,
|
|
58
|
+
imageCaptchaConfig,
|
|
59
|
+
config,
|
|
60
|
+
...logArgs
|
|
61
|
+
});
|
|
62
|
+
return config;
|
|
63
|
+
}
|
|
64
|
+
async fetchUserAccessRule(userIpAddress, ja4, userId, clientId) {
|
|
65
|
+
const accessRules = await this.queryUserAccessRules(
|
|
66
|
+
userIpAddress,
|
|
67
|
+
ja4,
|
|
68
|
+
userId,
|
|
69
|
+
clientId
|
|
70
|
+
);
|
|
71
|
+
this.logger.debug("ImageCaptchaConfigRulesResolver.fetchUserAccessRule", {
|
|
72
|
+
accessRules: accessRules.length,
|
|
73
|
+
userIpAddress: userIpAddress.address.toString(),
|
|
74
|
+
userId,
|
|
75
|
+
clientId,
|
|
76
|
+
ja4
|
|
77
|
+
});
|
|
78
|
+
return this.selectPrimaryUserAccessRule(accessRules);
|
|
79
|
+
}
|
|
80
|
+
async queryUserAccessRules(ipAddress, ja4, user, clientId) {
|
|
81
|
+
return await this.rulesStorage.find(
|
|
82
|
+
{
|
|
83
|
+
clientId,
|
|
84
|
+
userId: user,
|
|
85
|
+
userIpAddress: ipAddress,
|
|
86
|
+
ja4
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
includeRecordsWithoutClientId: true,
|
|
90
|
+
includeRecordsWithPartialFilterMatches: true
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
selectPrimaryUserAccessRule(accessRules) {
|
|
95
|
+
const clientRules = accessRules.filter(
|
|
96
|
+
(accessRule2) => "string" === typeof accessRule2.clientId
|
|
97
|
+
);
|
|
98
|
+
const globalRules = accessRules.filter(
|
|
99
|
+
(accessRule2) => void 0 === accessRule2.clientId
|
|
100
|
+
);
|
|
101
|
+
const accessRule = clientRules.length > 0 ? clientRules.shift() : globalRules.shift();
|
|
102
|
+
return void 0 === accessRule ? null : accessRule;
|
|
103
|
+
}
|
|
104
|
+
getImageCaptchaConfig(defaults, imageCaptchaConfig) {
|
|
105
|
+
return {
|
|
106
|
+
solved: {
|
|
107
|
+
count: imageCaptchaConfig.solvedCount || defaults.solved.count
|
|
108
|
+
},
|
|
109
|
+
unsolved: {
|
|
110
|
+
count: imageCaptchaConfig.unsolvedCount || defaults.unsolved.count
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.ImageCaptchaConfigRulesResolver = ImageCaptchaConfigRulesResolver;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const userIpIndexes = [
|
|
4
|
+
{
|
|
5
|
+
definition: {
|
|
6
|
+
"userIp.v4.asNumeric": 1
|
|
7
|
+
},
|
|
8
|
+
options: {
|
|
9
|
+
partialFilterExpression: {
|
|
10
|
+
"userIp.v4.asNumeric": { $exists: true }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
definition: {
|
|
16
|
+
"userIp.v6.asNumericString": 1
|
|
17
|
+
},
|
|
18
|
+
options: {
|
|
19
|
+
partialFilterExpression: {
|
|
20
|
+
"userIp.v6.asNumericString": { $exists: true }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
const userIpMaskIndexes = [
|
|
26
|
+
{
|
|
27
|
+
definition: {
|
|
28
|
+
"userIp.v4.mask.rangeMinAsNumeric": 1,
|
|
29
|
+
"userIp.v4.mask.rangeMaxAsNumeric": 1,
|
|
30
|
+
"userIp.v4.asNumeric": 1
|
|
31
|
+
},
|
|
32
|
+
options: {
|
|
33
|
+
partialFilterExpression: {
|
|
34
|
+
"userIp.v4.mask.asNumeric": { $exists: true }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
definition: {
|
|
40
|
+
"userIp.v6.mask.rangeMinAsNumericString": 1,
|
|
41
|
+
"userIp.v6.mask.rangeMaxAsNumericString": 1
|
|
42
|
+
},
|
|
43
|
+
options: {
|
|
44
|
+
partialFilterExpression: {
|
|
45
|
+
"userIp.v6.mask.asNumeric": { $exists: true }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
];
|
|
50
|
+
const otherIndexes = [
|
|
51
|
+
{
|
|
52
|
+
definition: {
|
|
53
|
+
userId: 1
|
|
54
|
+
},
|
|
55
|
+
options: {
|
|
56
|
+
unique: true,
|
|
57
|
+
sparse: true
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
definition: {
|
|
62
|
+
ja4: 1
|
|
63
|
+
},
|
|
64
|
+
options: {
|
|
65
|
+
unique: true,
|
|
66
|
+
sparse: true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
const rulePerformanceMongooseIndexes = [
|
|
71
|
+
...userIpIndexes,
|
|
72
|
+
...userIpMaskIndexes,
|
|
73
|
+
...otherIndexes
|
|
74
|
+
];
|
|
75
|
+
exports.rulePerformanceMongooseIndexes = rulePerformanceMongooseIndexes;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const globalIpIndexes = [
|
|
4
|
+
{
|
|
5
|
+
definition: {
|
|
6
|
+
"userIp.v4.asNumeric": 1
|
|
7
|
+
},
|
|
8
|
+
options: {
|
|
9
|
+
name: "globalIpV4",
|
|
10
|
+
unique: true,
|
|
11
|
+
partialFilterExpression: {
|
|
12
|
+
clientId: null,
|
|
13
|
+
"userIp.v4.asNumeric": { $exists: true },
|
|
14
|
+
"userIp.v4.mask.asNumeric": null
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
definition: {
|
|
20
|
+
"userIp.v6.asNumericString": 1
|
|
21
|
+
},
|
|
22
|
+
options: {
|
|
23
|
+
name: "globalIpV6",
|
|
24
|
+
unique: true,
|
|
25
|
+
partialFilterExpression: {
|
|
26
|
+
clientId: null,
|
|
27
|
+
"userIp.v6.asNumericString": { $exists: true },
|
|
28
|
+
"userIp.v6.mask.asNumeric": null
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
const globalIpMaskIndexes = [
|
|
34
|
+
{
|
|
35
|
+
definition: {
|
|
36
|
+
"userIp.v4.asNumeric": 1,
|
|
37
|
+
"userIp.v4.mask.asNumeric": 1
|
|
38
|
+
},
|
|
39
|
+
options: {
|
|
40
|
+
name: "globalIpMaskV4",
|
|
41
|
+
unique: true,
|
|
42
|
+
partialFilterExpression: {
|
|
43
|
+
clientId: null,
|
|
44
|
+
"userIp.v4.asNumeric": { $exists: true },
|
|
45
|
+
"userIp.v4.mask.asNumeric": { $exists: true }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
definition: {
|
|
51
|
+
"userIp.v6.asNumericString": 1,
|
|
52
|
+
"userIp.v6.mask.asNumeric": 1
|
|
53
|
+
},
|
|
54
|
+
options: {
|
|
55
|
+
name: "globalIpMaskV6",
|
|
56
|
+
unique: true,
|
|
57
|
+
partialFilterExpression: {
|
|
58
|
+
clientId: null,
|
|
59
|
+
"userIp.v6.asNumericString": { $exists: true },
|
|
60
|
+
"userIp.v6.mask.asNumeric": { $exists: true }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
const ipPerClientIndexes = [
|
|
66
|
+
{
|
|
67
|
+
definition: {
|
|
68
|
+
clientId: 1,
|
|
69
|
+
"userIp.v4.asNumeric": 1
|
|
70
|
+
},
|
|
71
|
+
options: {
|
|
72
|
+
name: "clientIpV4",
|
|
73
|
+
unique: true,
|
|
74
|
+
partialFilterExpression: {
|
|
75
|
+
clientId: { $exists: true },
|
|
76
|
+
"userIp.v4.asNumeric": { $exists: true },
|
|
77
|
+
"userIp.v4.mask.asNumeric": null
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
definition: {
|
|
83
|
+
clientId: 1,
|
|
84
|
+
"userIp.v6.asNumericString": 1
|
|
85
|
+
},
|
|
86
|
+
options: {
|
|
87
|
+
name: "clientIpV6",
|
|
88
|
+
unique: true,
|
|
89
|
+
partialFilterExpression: {
|
|
90
|
+
clientId: { $exists: true },
|
|
91
|
+
"userIp.v6.asNumericString": { $exists: true },
|
|
92
|
+
"userIp.v6.mask.asNumeric": null
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
];
|
|
97
|
+
const ipMaskPerClientIndexes = [
|
|
98
|
+
{
|
|
99
|
+
definition: {
|
|
100
|
+
clientId: 1,
|
|
101
|
+
"userIp.v4.asNumeric": 1,
|
|
102
|
+
"userIp.v4.mask.asNumeric": 1
|
|
103
|
+
},
|
|
104
|
+
options: {
|
|
105
|
+
name: "clientIpV4Mask",
|
|
106
|
+
unique: true,
|
|
107
|
+
partialFilterExpression: {
|
|
108
|
+
clientId: { $exists: true },
|
|
109
|
+
"userIp.v4.asNumeric": { $exists: true },
|
|
110
|
+
"userIp.v4.mask.asNumeric": { $exists: true }
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
definition: {
|
|
116
|
+
clientId: 1,
|
|
117
|
+
"userIp.v6.asNumericString": 1,
|
|
118
|
+
"userIp.v6.mask.asNumeric": 1
|
|
119
|
+
},
|
|
120
|
+
options: {
|
|
121
|
+
name: "clientIpV6Mask",
|
|
122
|
+
unique: true,
|
|
123
|
+
partialFilterExpression: {
|
|
124
|
+
clientId: { $exists: true },
|
|
125
|
+
"userIp.v6.asNumericString": { $exists: true },
|
|
126
|
+
"userIp.v6.mask.asNumeric": { $exists: true }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
];
|
|
131
|
+
const ruleUniqueMongooseIndexes = [
|
|
132
|
+
...globalIpIndexes,
|
|
133
|
+
...globalIpMaskIndexes,
|
|
134
|
+
...ipMaskPerClientIndexes,
|
|
135
|
+
...ipPerClientIndexes
|
|
136
|
+
];
|
|
137
|
+
exports.ruleUniqueMongooseIndexes = ruleUniqueMongooseIndexes;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const common = require("@prosopo/common");
|
|
4
|
+
const ipAddress = require("ip-address");
|
|
5
|
+
const ruleIpVersion = require("../rule/ip/ruleIpVersion.cjs");
|
|
6
|
+
const ruleIpV6NumericMaxLength = require("../rule/ip/v6/ruleIpV6NumericMaxLength.cjs");
|
|
7
|
+
class RulesMongooseStorage {
|
|
8
|
+
constructor(logger, readingModel, writingModel = null) {
|
|
9
|
+
this.logger = logger;
|
|
10
|
+
this.readingModel = readingModel;
|
|
11
|
+
this.writingModel = writingModel;
|
|
12
|
+
if (null === this.writingModel) {
|
|
13
|
+
this.writingModel = this.readingModel;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async insert(record) {
|
|
17
|
+
if (!this.writingModel) {
|
|
18
|
+
throw this.modelNotSetProsopoError();
|
|
19
|
+
}
|
|
20
|
+
const filter = {
|
|
21
|
+
...record.clientId && { clientId: record.clientId },
|
|
22
|
+
...record.userIp && { userIp: record.userIp },
|
|
23
|
+
...record.userId && { userId: record.userId },
|
|
24
|
+
...record.ja4 && { ja4: record.ja4 }
|
|
25
|
+
};
|
|
26
|
+
const validationError = new this.writingModel(record).validateSync();
|
|
27
|
+
if (validationError) {
|
|
28
|
+
throw validationError;
|
|
29
|
+
}
|
|
30
|
+
const document = await this.writingModel.findOneAndUpdate(
|
|
31
|
+
filter,
|
|
32
|
+
record,
|
|
33
|
+
{ new: true, upsert: true, runValidators: true }
|
|
34
|
+
// 🔥 Enforce schema validation!
|
|
35
|
+
);
|
|
36
|
+
const ruleRecord = this.convertMongooseRecordToRuleRecord(
|
|
37
|
+
document.toObject()
|
|
38
|
+
);
|
|
39
|
+
return ruleRecord;
|
|
40
|
+
}
|
|
41
|
+
async insertMany(records) {
|
|
42
|
+
if (!this.writingModel) {
|
|
43
|
+
throw this.modelNotSetProsopoError();
|
|
44
|
+
}
|
|
45
|
+
if (!this.readingModel) {
|
|
46
|
+
throw this.modelNotSetProsopoError();
|
|
47
|
+
}
|
|
48
|
+
const beforeDelete = await this.writingModel.find({});
|
|
49
|
+
this.logger.debug("Before deletion, DB records:", beforeDelete.length);
|
|
50
|
+
await this.writingModel.bulkWrite(
|
|
51
|
+
records.map((record) => {
|
|
52
|
+
const filter = {
|
|
53
|
+
...record.clientId && { clientId: record.clientId },
|
|
54
|
+
...record.userIp && { userIp: record.userIp },
|
|
55
|
+
...record.userId && { userId: record.userId },
|
|
56
|
+
...record.ja4 && { ja4: record.ja4 }
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
deleteOne: {
|
|
60
|
+
filter
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
})
|
|
64
|
+
);
|
|
65
|
+
this.logger.debug("After deletion");
|
|
66
|
+
const afterDelete = await this.readingModel.find({});
|
|
67
|
+
this.logger.debug("After deletion, DB records:", afterDelete.length);
|
|
68
|
+
const documents = await this.writingModel.insertMany(records);
|
|
69
|
+
const objectDocuments = documents.map((document) => document.toObject());
|
|
70
|
+
const ruleRecords = this.convertMongooseRecordsToRuleRecords(objectDocuments);
|
|
71
|
+
return ruleRecords;
|
|
72
|
+
}
|
|
73
|
+
async find(filters, filterSettings) {
|
|
74
|
+
if (!this.readingModel) {
|
|
75
|
+
throw this.modelNotSetProsopoError();
|
|
76
|
+
}
|
|
77
|
+
const query = this.createSearchQuery(filters, filterSettings);
|
|
78
|
+
const mongooseRecords = await this.readingModel.find(query).lean().exec();
|
|
79
|
+
const ruleRecords = this.convertMongooseRecordsToRuleRecords(mongooseRecords);
|
|
80
|
+
return ruleRecords;
|
|
81
|
+
}
|
|
82
|
+
async deleteMany(recordFilters) {
|
|
83
|
+
if (!this.writingModel) {
|
|
84
|
+
throw this.modelNotSetProsopoError();
|
|
85
|
+
}
|
|
86
|
+
for (const recordFilter of recordFilters) {
|
|
87
|
+
await this.writingModel.deleteOne(recordFilter).exec();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async countRecords() {
|
|
91
|
+
if (!this.readingModel) {
|
|
92
|
+
throw this.modelNotSetProsopoError();
|
|
93
|
+
}
|
|
94
|
+
const count = await this.readingModel.countDocuments().exec();
|
|
95
|
+
return count;
|
|
96
|
+
}
|
|
97
|
+
modelNotSetProsopoError() {
|
|
98
|
+
return new common.ProsopoError("USER_ACCESS_POLICY.MONGOOSE_RULE_MODEL_NOT_SET");
|
|
99
|
+
}
|
|
100
|
+
createSearchQuery(filters, filterSettings) {
|
|
101
|
+
const includeRecordsWithoutClientId = filterSettings?.includeRecordsWithoutClientId || false;
|
|
102
|
+
const includeRecordsWithPartialFilterMatches = filterSettings?.includeRecordsWithPartialFilterMatches || false;
|
|
103
|
+
const queryParts = [
|
|
104
|
+
this.getFilterByClientId(includeRecordsWithoutClientId, filters.clientId)
|
|
105
|
+
];
|
|
106
|
+
const queryFilters = this.getSearchQueryFilters(
|
|
107
|
+
filters,
|
|
108
|
+
includeRecordsWithPartialFilterMatches
|
|
109
|
+
);
|
|
110
|
+
return {
|
|
111
|
+
$and: queryParts.concat(queryFilters)
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
getSearchQueryFilters(filters, includeRecordsWithPartialFilterMatches) {
|
|
115
|
+
const queryFilters = [];
|
|
116
|
+
if (filters.userId) {
|
|
117
|
+
queryFilters.push({ userId: filters.userId });
|
|
118
|
+
}
|
|
119
|
+
if (filters.userIpAddress) {
|
|
120
|
+
queryFilters.push(this.getFilterByUserIp(filters.userIpAddress));
|
|
121
|
+
}
|
|
122
|
+
if (filters.ja4) {
|
|
123
|
+
queryFilters.push({ ja4: filters.ja4 });
|
|
124
|
+
}
|
|
125
|
+
return includeRecordsWithPartialFilterMatches && queryFilters.length > 1 ? [{ $or: queryFilters }] : queryFilters;
|
|
126
|
+
}
|
|
127
|
+
getFilterByClientId(includeRecordsWithoutClientId, clientId) {
|
|
128
|
+
const clientIdValue = void 0 === clientId ? { $exists: false } : clientId;
|
|
129
|
+
const clientIdFilter = {
|
|
130
|
+
clientId: clientIdValue
|
|
131
|
+
};
|
|
132
|
+
return includeRecordsWithoutClientId ? {
|
|
133
|
+
$or: [clientIdFilter, { clientId: { $exists: false } }]
|
|
134
|
+
} : clientIdFilter;
|
|
135
|
+
}
|
|
136
|
+
getFilterByUserIp(userIpAddress) {
|
|
137
|
+
return null !== userIpAddress ? this.getFilterByUserIpAddress(userIpAddress) : { userIp: null };
|
|
138
|
+
}
|
|
139
|
+
getFilterByUserIpAddress(userIpAddress) {
|
|
140
|
+
const isIpV4 = userIpAddress instanceof ipAddress.Address4;
|
|
141
|
+
const userIpVersion = isIpV4 ? ruleIpVersion.RuleIpVersion.v4 : ruleIpVersion.RuleIpVersion.v6;
|
|
142
|
+
const userIpAsNumeric = isIpV4 ? userIpAddress.bigInt() : (
|
|
143
|
+
// we must have the exact same string length to guarantee the right comparison.
|
|
144
|
+
userIpAddress.bigInt().toString().padStart(ruleIpV6NumericMaxLength.RULE_IPV6_NUMERIC_MAX_LENGTH, "0")
|
|
145
|
+
);
|
|
146
|
+
const userIpKey = userIpVersion === ruleIpVersion.RuleIpVersion.v4 ? "userIp.v4.asNumeric" : "userIp.v6.asNumericString";
|
|
147
|
+
const rangeMinKey = userIpVersion === ruleIpVersion.RuleIpVersion.v4 ? "userIp.v4.mask.rangeMinAsNumeric" : "userIp.v6.mask.rangeMinAsNumericString";
|
|
148
|
+
const rangeMaxKey = userIpVersion === ruleIpVersion.RuleIpVersion.v4 ? "userIp.v4.mask.rangeMaxAsNumeric" : "userIp.v6.mask.rangeMaxAsNumericString";
|
|
149
|
+
return {
|
|
150
|
+
$or: [
|
|
151
|
+
{ [userIpKey]: userIpAsNumeric },
|
|
152
|
+
{
|
|
153
|
+
[rangeMinKey]: {
|
|
154
|
+
$lte: userIpAsNumeric
|
|
155
|
+
},
|
|
156
|
+
[rangeMaxKey]: {
|
|
157
|
+
$gte: userIpAsNumeric
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
convertMongooseRecordsToRuleRecords(mongooseRecords) {
|
|
164
|
+
const ruleRecords = mongooseRecords.map(
|
|
165
|
+
(mongooseRecord) => this.convertMongooseRecordToRuleRecord(mongooseRecord)
|
|
166
|
+
);
|
|
167
|
+
return ruleRecords;
|
|
168
|
+
}
|
|
169
|
+
convertMongooseRecordToRuleRecord(mongooseRecord) {
|
|
170
|
+
const ruleRecord = {
|
|
171
|
+
...mongooseRecord,
|
|
172
|
+
_id: mongooseRecord._id.toString()
|
|
173
|
+
};
|
|
174
|
+
return ruleRecord;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
exports.RulesMongooseStorage = RulesMongooseStorage;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const mongoose = require("mongoose");
|
|
4
|
+
const imageCaptchaConfigMongooseSchema = require("./imageCaptchaConfigMongooseSchema.cjs");
|
|
5
|
+
const configMongooseSchema = new mongoose.Schema(
|
|
6
|
+
{
|
|
7
|
+
imageCaptcha: {
|
|
8
|
+
type: imageCaptchaConfigMongooseSchema.imageCaptchaConfigMongooseSchema,
|
|
9
|
+
required: false
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
{ _id: false }
|
|
13
|
+
);
|
|
14
|
+
exports.configMongooseSchema = configMongooseSchema;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const mongoose = require("mongoose");
|
|
4
|
+
const imageCaptchaConfigMongooseSchema = new mongoose.Schema(
|
|
5
|
+
{
|
|
6
|
+
solvedCount: {
|
|
7
|
+
type: Number,
|
|
8
|
+
required: false
|
|
9
|
+
},
|
|
10
|
+
unsolvedCount: {
|
|
11
|
+
type: Number,
|
|
12
|
+
required: false
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
{ _id: false }
|
|
16
|
+
);
|
|
17
|
+
exports.imageCaptchaConfigMongooseSchema = imageCaptchaConfigMongooseSchema;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const rulePerformanceMongooseIndexes = require("../indexes/rulePerformanceMongooseIndexes.cjs");
|
|
4
|
+
const ruleUniqueMongooseIndexes = require("../indexes/ruleUniqueMongooseIndexes.cjs");
|
|
5
|
+
const ruleMongooseSchema = require("./ruleMongooseSchema.cjs");
|
|
6
|
+
const getRuleMongooseSchema = () => {
|
|
7
|
+
const ruleMongooseIndexes = [
|
|
8
|
+
...rulePerformanceMongooseIndexes.rulePerformanceMongooseIndexes,
|
|
9
|
+
...ruleUniqueMongooseIndexes.ruleUniqueMongooseIndexes
|
|
10
|
+
];
|
|
11
|
+
for (const ruleMongooseIndex of ruleMongooseIndexes) {
|
|
12
|
+
ruleMongooseSchema.ruleMongooseSchema.index(
|
|
13
|
+
ruleMongooseIndex.definition,
|
|
14
|
+
ruleMongooseIndex.options
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
return ruleMongooseSchema.ruleMongooseSchema;
|
|
18
|
+
};
|
|
19
|
+
exports.getRuleMongooseSchema = getRuleMongooseSchema;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const mongoose = require("mongoose");
|
|
4
|
+
const ipV4MongooseSchema = require("./v4/ipV4MongooseSchema.cjs");
|
|
5
|
+
const ipV6MongooseSchema = require("./v6/ipV6MongooseSchema.cjs");
|
|
6
|
+
const ipMongooseSchema = new mongoose.Schema(
|
|
7
|
+
{
|
|
8
|
+
v4: {
|
|
9
|
+
type: ipV4MongooseSchema.ipV4MongooseSchema,
|
|
10
|
+
required: [
|
|
11
|
+
function() {
|
|
12
|
+
return !this.v6;
|
|
13
|
+
},
|
|
14
|
+
"v4 is required when v6 is not set"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
v6: {
|
|
18
|
+
type: ipV6MongooseSchema.ipV6MongooseSchema,
|
|
19
|
+
required: [
|
|
20
|
+
function() {
|
|
21
|
+
return !this.v4;
|
|
22
|
+
},
|
|
23
|
+
"v6 is required when v4 is not set"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{ _id: false }
|
|
28
|
+
);
|
|
29
|
+
exports.ipMongooseSchema = ipMongooseSchema;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const mongoose = require("mongoose");
|
|
4
|
+
const ipV4MaskMongooseSchema = new mongoose.Schema(
|
|
5
|
+
{
|
|
6
|
+
// Type choice note: Int32 can't store 10 digits of the numeric presentation of ipV4,
|
|
7
|
+
// so we use BigInt, which is supported by Mongoose and turned into Mongo's Long (Int64)
|
|
8
|
+
rangeMinAsNumeric: { type: BigInt, required: true },
|
|
9
|
+
rangeMaxAsNumeric: { type: BigInt, required: true },
|
|
10
|
+
asNumeric: { type: Number, required: true }
|
|
11
|
+
},
|
|
12
|
+
{ _id: false }
|
|
13
|
+
);
|
|
14
|
+
exports.ipV4MaskMongooseSchema = ipV4MaskMongooseSchema;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const mongoose = require("mongoose");
|
|
4
|
+
const ipV4MaskMongooseSchema = require("./ipV4MaskMongooseSchema.cjs");
|
|
5
|
+
const ipV4MongooseSchema = new mongoose.Schema(
|
|
6
|
+
{
|
|
7
|
+
// Type choice note: Int32 can't store 10 digits of the numeric presentation of ipV4,
|
|
8
|
+
// so we use BigInt, which is supported by Mongoose and turned into Mongo's Long (Int64)
|
|
9
|
+
asNumeric: { type: BigInt, required: true },
|
|
10
|
+
asString: { type: String, required: true },
|
|
11
|
+
mask: {
|
|
12
|
+
type: ipV4MaskMongooseSchema.ipV4MaskMongooseSchema,
|
|
13
|
+
required: false
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{ _id: false }
|
|
17
|
+
);
|
|
18
|
+
exports.ipV4MongooseSchema = ipV4MongooseSchema;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const mongoose = require("mongoose");
|
|
4
|
+
const ruleIpV6NumericMaxLength = require("../../../../rule/ip/v6/ruleIpV6NumericMaxLength.cjs");
|
|
5
|
+
const ipV6MaskMongooseSchema = new mongoose.Schema(
|
|
6
|
+
{
|
|
7
|
+
// 1. Type choice note:
|
|
8
|
+
/**
|
|
9
|
+
* ipV6 takes 128bits (38 digits), so we can't use Mongo's Long (Int64), and can't even Decimal128,
|
|
10
|
+
* cause it supports only 34 digits https://www.mongodb.com/docs/manual/reference/bson-types/
|
|
11
|
+
*/
|
|
12
|
+
// 2. String comparison note
|
|
13
|
+
/**
|
|
14
|
+
* Mongo compares strings by unicode codes of each letter, so it works for us,
|
|
15
|
+
* as long we make sure both strings have the exact same length:
|
|
16
|
+
* so '10' and '02', never '10' and '2'.
|
|
17
|
+
*/
|
|
18
|
+
rangeMinAsNumericString: {
|
|
19
|
+
type: String,
|
|
20
|
+
required: true,
|
|
21
|
+
// we must have the exact same string length to guarantee the right comparison.
|
|
22
|
+
set: (value) => value.padStart(ruleIpV6NumericMaxLength.RULE_IPV6_NUMERIC_MAX_LENGTH, "0")
|
|
23
|
+
},
|
|
24
|
+
rangeMaxAsNumericString: {
|
|
25
|
+
type: String,
|
|
26
|
+
required: true,
|
|
27
|
+
// we must have the exact same string length to guarantee the right comparison.
|
|
28
|
+
set: (value) => value.padStart(ruleIpV6NumericMaxLength.RULE_IPV6_NUMERIC_MAX_LENGTH, "0")
|
|
29
|
+
},
|
|
30
|
+
asNumeric: { type: Number, required: true }
|
|
31
|
+
},
|
|
32
|
+
{ _id: false }
|
|
33
|
+
);
|
|
34
|
+
exports.ipV6MaskMongooseSchema = ipV6MaskMongooseSchema;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const mongoose = require("mongoose");
|
|
4
|
+
const ruleIpV6NumericMaxLength = require("../../../../rule/ip/v6/ruleIpV6NumericMaxLength.cjs");
|
|
5
|
+
const ipV6MaskMongooseSchema = require("./ipV6MaskMongooseSchema.cjs");
|
|
6
|
+
const ipV6MongooseSchema = new mongoose.Schema(
|
|
7
|
+
{
|
|
8
|
+
// 1. Type choice note:
|
|
9
|
+
/**
|
|
10
|
+
* ipV6 takes 128bits (38 digits), so we can't use Mongo's Long (Int64), and can't even Decimal128,
|
|
11
|
+
* cause it supports only 34 digits https://www.mongodb.com/docs/manual/reference/bson-types/
|
|
12
|
+
*/
|
|
13
|
+
// 2. String comparison note
|
|
14
|
+
/**
|
|
15
|
+
* Mongo compares strings by unicode codes of each letter, so it works for us,
|
|
16
|
+
* as long we make sure both strings have the exact same length:
|
|
17
|
+
* so '10' and '02', never '10' and '2'.
|
|
18
|
+
*/
|
|
19
|
+
asNumericString: {
|
|
20
|
+
type: String,
|
|
21
|
+
required: true,
|
|
22
|
+
// we must have the exact same string length to guarantee the right comparison.
|
|
23
|
+
set: (value) => value.padStart(ruleIpV6NumericMaxLength.RULE_IPV6_NUMERIC_MAX_LENGTH, "0")
|
|
24
|
+
},
|
|
25
|
+
asString: { type: String, required: true },
|
|
26
|
+
mask: {
|
|
27
|
+
type: ipV6MaskMongooseSchema.ipV6MaskMongooseSchema,
|
|
28
|
+
required: false
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{ _id: false }
|
|
32
|
+
);
|
|
33
|
+
exports.ipV6MongooseSchema = ipV6MongooseSchema;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const mongoose = require("mongoose");
|
|
4
|
+
const configMongooseSchema = require("./config/configMongooseSchema.cjs");
|
|
5
|
+
const ipMongooseSchema = require("./ip/ipMongooseSchema.cjs");
|
|
6
|
+
const ruleMongooseSchema = new mongoose.Schema({
|
|
7
|
+
isUserBlocked: { type: Boolean, required: true },
|
|
8
|
+
clientId: { type: String, required: false },
|
|
9
|
+
description: { type: String, required: false },
|
|
10
|
+
userIp: {
|
|
11
|
+
type: ipMongooseSchema.ipMongooseSchema,
|
|
12
|
+
required: [
|
|
13
|
+
function() {
|
|
14
|
+
return !this.userId && !this.ja4;
|
|
15
|
+
},
|
|
16
|
+
"userIp is required when userId is not set and ja4 is not set"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
userId: {
|
|
20
|
+
type: String,
|
|
21
|
+
required: [
|
|
22
|
+
function() {
|
|
23
|
+
return !this.userIp && !this.ja4;
|
|
24
|
+
},
|
|
25
|
+
"userId is required when userIp is not set and ja4 is not set"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
ja4: {
|
|
29
|
+
type: String,
|
|
30
|
+
required: [
|
|
31
|
+
function() {
|
|
32
|
+
return !this.userIp && !this.userId;
|
|
33
|
+
},
|
|
34
|
+
"ja4 is required when userIp is not set and userId is not set"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
config: {
|
|
38
|
+
type: configMongooseSchema.configMongooseSchema,
|
|
39
|
+
required: false
|
|
40
|
+
},
|
|
41
|
+
score: { type: Number, required: false }
|
|
42
|
+
});
|
|
43
|
+
exports.ruleMongooseSchema = ruleMongooseSchema;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const zod = require("zod");
|
|
4
|
+
const imageCaptchaConfigSchema = zod.object({
|
|
5
|
+
solvedCount: zod.number().optional(),
|
|
6
|
+
unsolvedCount: zod.number().optional()
|
|
7
|
+
});
|
|
8
|
+
exports.imageCaptchaConfigSchema = imageCaptchaConfigSchema;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const zod = require("zod");
|
|
4
|
+
const imageCaptchaConfigSchema = require("./imageCaptcha/imageCaptchaConfigSchema.cjs");
|
|
5
|
+
const ruleConfigSchema = zod.object({
|
|
6
|
+
imageCaptcha: imageCaptchaConfigSchema.imageCaptchaConfigSchema.optional()
|
|
7
|
+
});
|
|
8
|
+
exports.ruleConfigSchema = ruleConfigSchema;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const zod = require("zod");
|
|
4
|
+
const ruleIpV4Schema = require("./v4/ruleIpV4Schema.cjs");
|
|
5
|
+
const ruleIpV6Schema = require("./v6/ruleIpV6Schema.cjs");
|
|
6
|
+
const ruleIpSchema = zod.object({
|
|
7
|
+
v4: ruleIpV4Schema.ruleIpV4Schema.optional(),
|
|
8
|
+
v6: ruleIpV6Schema.ruleIpV6Schema.optional()
|
|
9
|
+
});
|
|
10
|
+
exports.ruleIpSchema = ruleIpSchema;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
var RuleIpVersion = /* @__PURE__ */ ((RuleIpVersion2) => {
|
|
4
|
+
RuleIpVersion2["v4"] = "v4";
|
|
5
|
+
RuleIpVersion2["v6"] = "v6";
|
|
6
|
+
return RuleIpVersion2;
|
|
7
|
+
})(RuleIpVersion || {});
|
|
8
|
+
exports.RuleIpVersion = RuleIpVersion;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const zod = require("zod");
|
|
4
|
+
const ruleIpV4MaskSchema = zod.object({
|
|
5
|
+
rangeMinAsNumeric: zod.bigint(),
|
|
6
|
+
rangeMaxAsNumeric: zod.bigint(),
|
|
7
|
+
asNumeric: zod.number()
|
|
8
|
+
});
|
|
9
|
+
exports.ruleIpV4MaskSchema = ruleIpV4MaskSchema;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const zod = require("zod");
|
|
4
|
+
const ruleIpV4MaskSchema = require("./mask/ruleIpV4MaskSchema.cjs");
|
|
5
|
+
const ruleIpV4Schema = zod.object({
|
|
6
|
+
asNumeric: zod.bigint(),
|
|
7
|
+
asString: zod.string(),
|
|
8
|
+
mask: ruleIpV4MaskSchema.ruleIpV4MaskSchema.optional()
|
|
9
|
+
});
|
|
10
|
+
exports.ruleIpV4Schema = ruleIpV4Schema;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const zod = require("zod");
|
|
4
|
+
const ruleIpV6MaskSchema = zod.object({
|
|
5
|
+
rangeMinAsNumericString: zod.string(),
|
|
6
|
+
rangeMaxAsNumericString: zod.string(),
|
|
7
|
+
asNumeric: zod.number()
|
|
8
|
+
});
|
|
9
|
+
exports.ruleIpV6MaskSchema = ruleIpV6MaskSchema;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const zod = require("zod");
|
|
4
|
+
const ruleIpV6MaskSchema = require("./mask/ruleIpV6MaskSchema.cjs");
|
|
5
|
+
const ruleIpV6Schema = zod.object({
|
|
6
|
+
asNumericString: zod.string(),
|
|
7
|
+
asString: zod.string(),
|
|
8
|
+
mask: ruleIpV6MaskSchema.ruleIpV6MaskSchema.optional()
|
|
9
|
+
});
|
|
10
|
+
exports.ruleIpV6Schema = ruleIpV6Schema;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosopo/user-access-policy",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"storage:benchmark:mongoose:measure-find": "npm run storage:benchmark:mongoose -- measure-find --db-url=mongodb://localhost:27017 --target-ip-v4=0.0.136.184 --target-ip-v6=0000:0000:0000:0000:0000:0000:0000:7530"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@prosopo/api-route": "2.
|
|
27
|
-
"@prosopo/common": "2.
|
|
28
|
-
"@prosopo/types": "2.
|
|
26
|
+
"@prosopo/api-route": "2.6.0",
|
|
27
|
+
"@prosopo/common": "2.6.0",
|
|
28
|
+
"@prosopo/types": "2.6.1",
|
|
29
29
|
"ip-address": "10.0.1",
|
|
30
30
|
"mongoose": "8.6.2",
|
|
31
31
|
"zod": "3.23.8"
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"mongodb": "6.9.0",
|
|
35
35
|
"mongodb-memory-server": "10.0.0",
|
|
36
|
-
"vite": "
|
|
37
|
-
"vitest": "
|
|
36
|
+
"vite": "6.2.3",
|
|
37
|
+
"vitest": "3.0.9",
|
|
38
38
|
"yargs": "17.7.2"
|
|
39
39
|
},
|
|
40
40
|
"author": "PROSOPO LIMITED <info@prosopo.io>",
|
|
@@ -43,5 +43,10 @@
|
|
|
43
43
|
"url": "https://github.com/prosopo/captcha/issues"
|
|
44
44
|
},
|
|
45
45
|
"homepage": "https://github.com/prosopo/captcha#readme",
|
|
46
|
-
"sideEffects": false
|
|
46
|
+
"sideEffects": false,
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "git+https://github.com/prosopo/captcha.git",
|
|
50
|
+
"directory": "packages/user-access-policy"
|
|
51
|
+
}
|
|
47
52
|
}
|