@prosopo/user-access-policy 3.5.19 → 3.5.28
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 +84 -0
- package/dist/.export.js +21 -0
- package/dist/api/.export.js +11 -0
- package/dist/api/delete/.export.js +1 -0
- package/dist/api/{deleteAllRulesEndpoint.js → delete/deleteAllRules.js} +10 -9
- package/dist/api/delete/deleteRuleGroups.js +52 -0
- package/dist/api/delete/deleteRules.js +43 -0
- package/dist/api/read/.export.js +1 -0
- package/dist/api/read/fetchRules.js +43 -0
- package/dist/api/read/findRuleIds.js +50 -0
- package/dist/api/read/getMissingIds.js +41 -0
- package/dist/api/ruleApiRoutes.js +131 -0
- package/dist/api/rulesApiClient.js +93 -0
- package/dist/api/write/.export.js +1 -0
- package/dist/api/write/insertRules.js +102 -0
- package/dist/api/write/rehashRules.js +57 -0
- package/dist/cjs/.export.cjs +21 -0
- package/dist/cjs/api/.export.cjs +11 -0
- package/dist/cjs/api/delete/.export.cjs +1 -0
- package/dist/cjs/api/{deleteAllRulesEndpoint.cjs → delete/deleteAllRules.cjs} +9 -8
- package/dist/cjs/api/delete/deleteRuleGroups.cjs +52 -0
- package/dist/cjs/api/delete/deleteRules.cjs +43 -0
- package/dist/cjs/api/read/.export.cjs +1 -0
- package/dist/cjs/api/read/fetchRules.cjs +43 -0
- package/dist/cjs/api/read/findRuleIds.cjs +50 -0
- package/dist/cjs/api/read/getMissingIds.cjs +41 -0
- package/dist/cjs/api/ruleApiRoutes.cjs +131 -0
- package/dist/cjs/api/rulesApiClient.cjs +93 -0
- package/dist/cjs/api/write/.export.cjs +1 -0
- package/dist/cjs/api/write/insertRules.cjs +102 -0
- package/dist/cjs/api/write/rehashRules.cjs +57 -0
- package/dist/cjs/mongoose/.export.cjs +4 -0
- package/dist/cjs/mongoose/mongooseRuleSchema.cjs +36 -0
- package/dist/cjs/redis/.export.cjs +6 -0
- package/dist/cjs/redis/reader/redisAggregate.cjs +60 -0
- package/dist/cjs/redis/reader/redisRulesQuery.cjs +99 -0
- package/dist/cjs/redis/reader/redisRulesReader.cjs +230 -0
- package/dist/cjs/redis/redisClient.cjs +67 -0
- package/dist/cjs/redis/redisRuleIndex.cjs +50 -0
- package/dist/cjs/redis/redisRulesStorage.cjs +22 -9
- package/dist/cjs/redis/redisRulesWriter.cjs +91 -64
- package/dist/cjs/rule.cjs +8 -0
- package/dist/cjs/ruleInput/.export.cjs +9 -0
- package/dist/cjs/ruleInput/policyInput.cjs +25 -0
- package/dist/cjs/ruleInput/ruleInput.cjs +50 -0
- package/dist/cjs/ruleInput/userScopeInput.cjs +55 -0
- package/dist/cjs/ruleRecord.cjs +23 -0
- package/dist/cjs/rulesStorage.cjs +8 -0
- package/dist/cjs/transformRule.cjs +77 -0
- package/dist/mongoose/.export.js +4 -0
- package/dist/mongoose/mongooseRuleSchema.js +36 -0
- package/dist/redis/.export.js +6 -0
- package/dist/redis/reader/redisAggregate.js +60 -0
- package/dist/redis/reader/redisRulesQuery.js +99 -0
- package/dist/redis/reader/redisRulesReader.js +213 -0
- package/dist/redis/redisClient.js +67 -0
- package/dist/redis/redisRuleIndex.js +50 -0
- package/dist/redis/redisRulesStorage.js +23 -10
- package/dist/redis/redisRulesWriter.js +91 -64
- package/dist/rule.js +8 -0
- package/dist/ruleInput/.export.js +9 -0
- package/dist/ruleInput/policyInput.js +25 -0
- package/dist/ruleInput/ruleInput.js +50 -0
- package/dist/ruleInput/userScopeInput.js +55 -0
- package/dist/ruleRecord.js +23 -0
- package/dist/rulesStorage.js +8 -0
- package/dist/transformRule.js +77 -0
- package/entries.ts +20 -0
- package/package.json +34 -18
- package/vite.cjs.config.ts +4 -1
- package/vite.esm.config.ts +6 -1
- package/dist/accessPolicy.js +0 -80
- package/dist/accessPolicyResolver.js +0 -31
- package/dist/accessRules.js +0 -11
- package/dist/api/accessRuleApiRoutes.js +0 -79
- package/dist/api/accessRulesApiClient.js +0 -38
- package/dist/api/deleteRulesEndpoint.js +0 -34
- package/dist/api/insertRulesEndpoint.js +0 -62
- package/dist/cjs/accessPolicy.cjs +0 -80
- package/dist/cjs/accessPolicyResolver.cjs +0 -31
- package/dist/cjs/accessRules.cjs +0 -11
- package/dist/cjs/api/accessRuleApiRoutes.cjs +0 -79
- package/dist/cjs/api/accessRulesApiClient.cjs +0 -38
- package/dist/cjs/api/deleteRulesEndpoint.cjs +0 -34
- package/dist/cjs/api/insertRulesEndpoint.cjs +0 -62
- package/dist/cjs/index.cjs +0 -31
- package/dist/cjs/redis/redisRulesIndex.cjs +0 -138
- package/dist/cjs/redis/redisRulesReader.cjs +0 -142
- package/dist/cjs/util.cjs +0 -5
- package/dist/index.js +0 -32
- package/dist/redis/redisRulesIndex.js +0 -138
- package/dist/redis/redisRulesReader.js +0 -125
- package/dist/util.js +0 -5
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { FilterScopeMatch } from "../rulesStorage.js";
|
|
3
|
+
import { policyScopeInput, accessPolicyInput } from "./policyInput.js";
|
|
4
|
+
import { userScopeInput } from "./userScopeInput.js";
|
|
5
|
+
const ruleGroupInput = z.object({
|
|
6
|
+
groupId: z.coerce.string().optional(),
|
|
7
|
+
ruleGroupId: z.coerce.string().optional()
|
|
8
|
+
}).transform((ruleGroupInput2) => {
|
|
9
|
+
const { ruleGroupId, ...ruleGroup } = ruleGroupInput2;
|
|
10
|
+
if ("string" === typeof ruleGroupId) {
|
|
11
|
+
ruleGroup.groupId = ruleGroupId;
|
|
12
|
+
}
|
|
13
|
+
return ruleGroup;
|
|
14
|
+
});
|
|
15
|
+
const accessRuleInput = z.object({
|
|
16
|
+
...accessPolicyInput.shape,
|
|
17
|
+
...policyScopeInput.shape
|
|
18
|
+
}).and(userScopeInput).and(ruleGroupInput).transform((ruleInput) => ruleInput);
|
|
19
|
+
const ruleEntryInput = z.object({
|
|
20
|
+
rule: accessRuleInput,
|
|
21
|
+
expiresUnixTimestamp: z.coerce.number().optional()
|
|
22
|
+
});
|
|
23
|
+
const accessRulesFilterInput = z.object({
|
|
24
|
+
policyScope: policyScopeInput.optional(),
|
|
25
|
+
policyScopes: z.array(policyScopeInput).optional(),
|
|
26
|
+
policyScopeMatch: z.nativeEnum(FilterScopeMatch).default(FilterScopeMatch.Exact),
|
|
27
|
+
userScope: userScopeInput.optional(),
|
|
28
|
+
userScopeMatch: z.nativeEnum(FilterScopeMatch).default(FilterScopeMatch.Exact),
|
|
29
|
+
groupId: z.string().optional()
|
|
30
|
+
});
|
|
31
|
+
const getAccessRuleFiltersFromInput = (filterInput) => {
|
|
32
|
+
const { policyScopes, policyScope, ...filterBase } = filterInput;
|
|
33
|
+
const allPolicyScopes = policyScopes || [];
|
|
34
|
+
if (policyScope) {
|
|
35
|
+
allPolicyScopes.push(policyScope);
|
|
36
|
+
}
|
|
37
|
+
if (allPolicyScopes.length > 0) {
|
|
38
|
+
return allPolicyScopes.map((policyScope2) => ({
|
|
39
|
+
...filterBase,
|
|
40
|
+
policyScope: policyScope2
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
return [filterBase];
|
|
44
|
+
};
|
|
45
|
+
export {
|
|
46
|
+
accessRuleInput,
|
|
47
|
+
accessRulesFilterInput,
|
|
48
|
+
getAccessRuleFiltersFromInput,
|
|
49
|
+
ruleEntryInput
|
|
50
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { getIPAddress } from "@prosopo/util";
|
|
3
|
+
import { Address4 } from "ip-address";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
const userAttributesSchema = z.object({
|
|
6
|
+
// coerce is used for safety, as e.g., incoming userId can be digital
|
|
7
|
+
userId: z.coerce.string().optional(),
|
|
8
|
+
ja4Hash: z.coerce.string().optional(),
|
|
9
|
+
headersHash: z.coerce.string().optional(),
|
|
10
|
+
userAgentHash: z.coerce.string().optional()
|
|
11
|
+
});
|
|
12
|
+
const userAttributesInput = z.object({
|
|
13
|
+
...userAttributesSchema.shape,
|
|
14
|
+
userAgent: z.coerce.string().optional()
|
|
15
|
+
}).transform((userAttributesInput2) => {
|
|
16
|
+
const { userAgent, ...userScope } = userAttributesInput2;
|
|
17
|
+
if ("string" === typeof userAgent) {
|
|
18
|
+
userScope.userAgentHash = hashUserAgent(userAgent);
|
|
19
|
+
}
|
|
20
|
+
return userScope;
|
|
21
|
+
});
|
|
22
|
+
const hashUserAgent = (userAgent) => crypto.createHash("sha256").update(userAgent).digest("hex");
|
|
23
|
+
const userIpSchema = z.object({
|
|
24
|
+
numericIp: z.coerce.bigint().optional(),
|
|
25
|
+
numericIpMaskMin: z.coerce.bigint().optional(),
|
|
26
|
+
numericIpMaskMax: z.coerce.bigint().optional()
|
|
27
|
+
});
|
|
28
|
+
const userIpInput = z.object({
|
|
29
|
+
...userIpSchema.shape,
|
|
30
|
+
ip: z.string().optional(),
|
|
31
|
+
ipMask: z.string().optional()
|
|
32
|
+
}).transform((userIpInput2) => {
|
|
33
|
+
const { ip, ipMask, ...numericUserIp } = userIpInput2;
|
|
34
|
+
if ("string" === typeof ip) {
|
|
35
|
+
numericUserIp.numericIp = getIPAddress(ip).bigInt();
|
|
36
|
+
}
|
|
37
|
+
if ("string" === typeof ipMask) {
|
|
38
|
+
const ipObject = new Address4(ipMask);
|
|
39
|
+
numericUserIp.numericIpMaskMin = ipObject.startAddress().bigInt();
|
|
40
|
+
numericUserIp.numericIpMaskMax = ipObject.endAddress().bigInt();
|
|
41
|
+
}
|
|
42
|
+
return numericUserIp;
|
|
43
|
+
});
|
|
44
|
+
const userScopeSchema = z.object({
|
|
45
|
+
...userIpSchema.shape,
|
|
46
|
+
...userAttributesSchema.shape
|
|
47
|
+
});
|
|
48
|
+
const userScopeInput = z.object({}).and(userIpInput).and(userAttributesInput).transform(
|
|
49
|
+
// transform is used for type safety only - plain "satisfies ZodType<x>" doesn't work after ".and()"
|
|
50
|
+
(userScopeInput2) => userScopeInput2
|
|
51
|
+
);
|
|
52
|
+
export {
|
|
53
|
+
userScopeInput,
|
|
54
|
+
userScopeSchema
|
|
55
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const userAttributesRecordFields = [
|
|
2
|
+
"userId",
|
|
3
|
+
"ja4Hash",
|
|
4
|
+
"headersHash",
|
|
5
|
+
"userAgent"
|
|
6
|
+
];
|
|
7
|
+
const userIpRecordFields = [
|
|
8
|
+
"ip",
|
|
9
|
+
"ipMask"
|
|
10
|
+
];
|
|
11
|
+
const userScopeRecordFields = [
|
|
12
|
+
...userAttributesRecordFields,
|
|
13
|
+
...userIpRecordFields
|
|
14
|
+
];
|
|
15
|
+
const getUserScopeRecordFromAccessRuleRecord = (ruleRecord) => Object.fromEntries(
|
|
16
|
+
userScopeRecordFields.map((field) => [field, ruleRecord[field]]).filter(([, value]) => value !== void 0)
|
|
17
|
+
);
|
|
18
|
+
export {
|
|
19
|
+
getUserScopeRecordFromAccessRuleRecord,
|
|
20
|
+
userAttributesRecordFields,
|
|
21
|
+
userIpRecordFields,
|
|
22
|
+
userScopeRecordFields
|
|
23
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { IpRange, IpAddress } from "cidr-calc";
|
|
3
|
+
import { Address4 } from "ip-address";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { policyScopeInput, accessPolicyInput } from "./ruleInput/policyInput.js";
|
|
6
|
+
import { accessRuleInput } from "./ruleInput/ruleInput.js";
|
|
7
|
+
import { userScopeSchema } from "./ruleInput/userScopeInput.js";
|
|
8
|
+
const RULE_HASH_ALGORITHM = "md5";
|
|
9
|
+
const makeAccessRuleHash = (rule) => {
|
|
10
|
+
const valueProperties = Object.entries(rule).filter(
|
|
11
|
+
([key, value]) => "undefined" !== typeof value
|
|
12
|
+
);
|
|
13
|
+
const orderedProperties = valueProperties.sort();
|
|
14
|
+
const objectToHash = Object.fromEntries(orderedProperties);
|
|
15
|
+
return hashObject(objectToHash, RULE_HASH_ALGORITHM);
|
|
16
|
+
};
|
|
17
|
+
const transformAccessRuleRecordIntoRule = (ruleRecord) => (
|
|
18
|
+
// accessRuleInput does all the record field transformations
|
|
19
|
+
accessRuleInput.parse(ruleRecord)
|
|
20
|
+
);
|
|
21
|
+
const transformAccessRuleIntoRecord = (rule) => accessRuleToRecordScheme.parse(rule);
|
|
22
|
+
const accessRuleToRecordScheme = z.object({
|
|
23
|
+
...accessPolicyInput.shape,
|
|
24
|
+
...policyScopeInput.shape,
|
|
25
|
+
...userScopeSchema.shape,
|
|
26
|
+
groupId: z.coerce.string().optional()
|
|
27
|
+
}).transform((ruleInput) => {
|
|
28
|
+
const {
|
|
29
|
+
groupId,
|
|
30
|
+
numericIp,
|
|
31
|
+
numericIpMaskMin,
|
|
32
|
+
numericIpMaskMax,
|
|
33
|
+
userAgentHash,
|
|
34
|
+
...rule
|
|
35
|
+
} = ruleInput;
|
|
36
|
+
const record = rule;
|
|
37
|
+
if ("string" === typeof groupId) {
|
|
38
|
+
record.ruleGroupId = groupId;
|
|
39
|
+
}
|
|
40
|
+
if ("string" === typeof userAgentHash) {
|
|
41
|
+
record.userAgent = userAgentHash;
|
|
42
|
+
}
|
|
43
|
+
if ("bigint" === typeof numericIp) {
|
|
44
|
+
record.ip = getStringIpFromNumeric(numericIp);
|
|
45
|
+
}
|
|
46
|
+
if ("bigint" === typeof numericIpMaskMin && "bigint" === typeof numericIpMaskMax) {
|
|
47
|
+
record.ipMask = getCidrFromNumericIpRange(
|
|
48
|
+
numericIpMaskMin,
|
|
49
|
+
numericIpMaskMax
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return record;
|
|
53
|
+
});
|
|
54
|
+
const hashObject = (object, algorithm) => crypto.createHash(algorithm).update(
|
|
55
|
+
JSON.stringify(
|
|
56
|
+
object,
|
|
57
|
+
(key, value) => (
|
|
58
|
+
// JSON.stringify can't handle BigInt itself: throws "Do not know how to serialize a BigInt"
|
|
59
|
+
"bigint" === typeof value ? value.toString() : value
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
).digest("hex");
|
|
63
|
+
const getStringIpFromNumeric = (numericIp) => Address4.fromInteger(Number(numericIp)).address;
|
|
64
|
+
const getCidrFromNumericIpRange = (startIp, endIp) => {
|
|
65
|
+
const ipRange = new IpRange(
|
|
66
|
+
IpAddress.of(getStringIpFromNumeric(startIp)),
|
|
67
|
+
IpAddress.of(getStringIpFromNumeric(endIp))
|
|
68
|
+
);
|
|
69
|
+
const cidr = ipRange.toCidrs()[0];
|
|
70
|
+
return cidr ? `${cidr.prefix.toString()}/${cidr.prefixLen}` : void 0;
|
|
71
|
+
};
|
|
72
|
+
export {
|
|
73
|
+
getCidrFromNumericIpRange,
|
|
74
|
+
makeAccessRuleHash,
|
|
75
|
+
transformAccessRuleIntoRecord,
|
|
76
|
+
transformAccessRuleRecordIntoRule
|
|
77
|
+
};
|
package/entries.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
export const entries: Record<string, string> = {
|
|
16
|
+
".export": "src/.export.ts",
|
|
17
|
+
"api/.export": "src/api/.export.ts",
|
|
18
|
+
"redis/.export": "src/redis/.export.ts",
|
|
19
|
+
"mongoose/.export": "src/mongoose/.export.ts",
|
|
20
|
+
};
|
package/package.json
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosopo/user-access-policy",
|
|
3
|
-
"version": "3.5.
|
|
4
|
-
"main": "dist/index.js",
|
|
5
|
-
"types": "dist/index.d.ts",
|
|
3
|
+
"version": "3.5.28",
|
|
6
4
|
"type": "module",
|
|
7
5
|
"engines": {
|
|
8
|
-
"node": "
|
|
9
|
-
"npm": "10.
|
|
6
|
+
"node": ">=v20.0.0",
|
|
7
|
+
"npm": ">=10.6.0"
|
|
10
8
|
},
|
|
11
9
|
"exports": {
|
|
12
10
|
".": {
|
|
13
|
-
"types": "./dist
|
|
14
|
-
"import": "./dist
|
|
15
|
-
"require": "./dist/cjs
|
|
11
|
+
"types": "./dist/.export.d.ts",
|
|
12
|
+
"import": "./dist/.export.js",
|
|
13
|
+
"require": "./dist/cjs/.export.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./api": {
|
|
16
|
+
"types": "./dist/api/.export.d.ts",
|
|
17
|
+
"import": "./dist/api/.export.js",
|
|
18
|
+
"require": "./dist/cjs/api/.export.cjs"
|
|
19
|
+
},
|
|
20
|
+
"./redis": {
|
|
21
|
+
"types": "./dist/redis/.export.d.ts",
|
|
22
|
+
"import": "./dist/redis/.export.js",
|
|
23
|
+
"require": "./dist/cjs/redis/.export.cjs"
|
|
24
|
+
},
|
|
25
|
+
"./mongoose": {
|
|
26
|
+
"types": "./dist/mongoose/.export.d.ts",
|
|
27
|
+
"import": "./dist/mongoose/.export.js",
|
|
28
|
+
"require": "./dist/cjs/mongoose/.export.cjs"
|
|
16
29
|
}
|
|
17
30
|
},
|
|
18
31
|
"imports": {
|
|
@@ -29,24 +42,27 @@
|
|
|
29
42
|
"test": "npm run test:unit && npm run test:integration"
|
|
30
43
|
},
|
|
31
44
|
"dependencies": {
|
|
32
|
-
"@prosopo/api": "3.1.
|
|
33
|
-
"@prosopo/api-route": "2.6.
|
|
34
|
-
"@prosopo/common": "3.1.
|
|
35
|
-
"@prosopo/redis-client": "1.0.
|
|
36
|
-
"@prosopo/types": "3.
|
|
37
|
-
"@prosopo/util": "3.
|
|
45
|
+
"@prosopo/api": "3.1.33",
|
|
46
|
+
"@prosopo/api-route": "2.6.30",
|
|
47
|
+
"@prosopo/common": "3.1.22",
|
|
48
|
+
"@prosopo/redis-client": "1.0.7",
|
|
49
|
+
"@prosopo/types": "3.6.0",
|
|
50
|
+
"@prosopo/util": "3.2.0",
|
|
38
51
|
"@redis/search": "5.0.0",
|
|
52
|
+
"@redis/client": "5.0.0",
|
|
53
|
+
"cidr-calc": "1.0.4",
|
|
39
54
|
"dotenv": "16.4.5",
|
|
40
55
|
"ip-address": "10.0.1",
|
|
41
56
|
"redis": "5.0.0",
|
|
42
57
|
"zod": "3.23.8"
|
|
43
58
|
},
|
|
44
59
|
"devDependencies": {
|
|
45
|
-
"@prosopo/config": "3.1.
|
|
46
|
-
"@prosopo/util-crypto": "13.5.
|
|
60
|
+
"@prosopo/config": "3.1.22",
|
|
61
|
+
"@prosopo/util-crypto": "13.5.24",
|
|
47
62
|
"@types/node": "22.10.2",
|
|
48
|
-
"
|
|
49
|
-
"
|
|
63
|
+
"mongoose": "8.13.0",
|
|
64
|
+
"vite": "6.4.1",
|
|
65
|
+
"vitest": "3.2.4",
|
|
50
66
|
"yargs": "17.7.2"
|
|
51
67
|
},
|
|
52
68
|
"author": "PROSOPO LIMITED <info@prosopo.io>",
|
package/vite.cjs.config.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
1
|
// Copyright 2021-2025 Prosopo (UK) Ltd.
|
|
3
2
|
//
|
|
4
3
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -12,11 +11,15 @@ import path from "node:path";
|
|
|
12
11
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
12
|
// See the License for the specific language governing permissions and
|
|
14
13
|
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import path from "node:path";
|
|
15
16
|
import { ViteCommonJSConfig } from "@prosopo/config";
|
|
17
|
+
import { entries } from "./entries.js";
|
|
16
18
|
|
|
17
19
|
export default function () {
|
|
18
20
|
return ViteCommonJSConfig(
|
|
19
21
|
path.basename("."),
|
|
20
22
|
path.resolve("./tsconfig.json"),
|
|
23
|
+
entries,
|
|
21
24
|
);
|
|
22
25
|
}
|
package/vite.esm.config.ts
CHANGED
|
@@ -14,7 +14,12 @@
|
|
|
14
14
|
|
|
15
15
|
import path from "node:path";
|
|
16
16
|
import { ViteEsmConfig } from "@prosopo/config";
|
|
17
|
+
import { entries } from "./entries.js";
|
|
17
18
|
|
|
18
19
|
export default function () {
|
|
19
|
-
return ViteEsmConfig(
|
|
20
|
+
return ViteEsmConfig(
|
|
21
|
+
path.basename("."),
|
|
22
|
+
path.resolve("./tsconfig.json"),
|
|
23
|
+
entries,
|
|
24
|
+
);
|
|
20
25
|
}
|
package/dist/accessPolicy.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { CaptchaTypeSchema } from "@prosopo/types";
|
|
2
|
-
import { getIPAddress } from "@prosopo/util";
|
|
3
|
-
import { Address4 } from "ip-address";
|
|
4
|
-
import { z } from "zod";
|
|
5
|
-
import { hashUserAgent } from "./util.js";
|
|
6
|
-
var AccessPolicyType = /* @__PURE__ */ ((AccessPolicyType2) => {
|
|
7
|
-
AccessPolicyType2["Block"] = "block";
|
|
8
|
-
AccessPolicyType2["Restrict"] = "restrict";
|
|
9
|
-
return AccessPolicyType2;
|
|
10
|
-
})(AccessPolicyType || {});
|
|
11
|
-
const accessPolicySchema = z.object({
|
|
12
|
-
type: z.nativeEnum(AccessPolicyType),
|
|
13
|
-
captchaType: CaptchaTypeSchema.optional(),
|
|
14
|
-
description: z.coerce.string().optional(),
|
|
15
|
-
// Redis stores values as strings, so coerce is needed to parse properly
|
|
16
|
-
solvedImagesCount: z.coerce.number().optional(),
|
|
17
|
-
// the percentage of image panels that must be solved per image CAPTCHA
|
|
18
|
-
imageThreshold: z.coerce.number().optional(),
|
|
19
|
-
// the Proof-of-Work difficulty level
|
|
20
|
-
powDifficulty: z.coerce.number().optional(),
|
|
21
|
-
// the number of unsolved image CAPTCHA challenges to serve
|
|
22
|
-
unsolvedImagesCount: z.coerce.number().optional(),
|
|
23
|
-
// used to increase the user's score
|
|
24
|
-
frictionlessScore: z.coerce.number().optional()
|
|
25
|
-
});
|
|
26
|
-
const policyScopeSchema = z.object({
|
|
27
|
-
clientId: z.coerce.string().optional(),
|
|
28
|
-
ruleGroupId: z.coerce.string().optional()
|
|
29
|
-
});
|
|
30
|
-
const userScopeSchema = z.object({
|
|
31
|
-
// coerce is used for safety, as e.g., incoming userId can be digital
|
|
32
|
-
userId: z.coerce.string().optional(),
|
|
33
|
-
numericIp: z.coerce.bigint().optional(),
|
|
34
|
-
numericIpMaskMin: z.coerce.bigint().optional(),
|
|
35
|
-
numericIpMaskMax: z.coerce.bigint().optional(),
|
|
36
|
-
ja4Hash: z.coerce.string().optional(),
|
|
37
|
-
headersHash: z.coerce.string().optional(),
|
|
38
|
-
userAgentHash: z.coerce.string().optional()
|
|
39
|
-
});
|
|
40
|
-
const userScopeInputSchema = userScopeSchema.extend({
|
|
41
|
-
// human-friendly ip versions. If present, then converted to numeric and removed from the object
|
|
42
|
-
// 127.0.0.1
|
|
43
|
-
ip: z.string().optional(),
|
|
44
|
-
// 127.0.0.1/24
|
|
45
|
-
ipMask: z.string().optional(),
|
|
46
|
-
// human friendly user agent
|
|
47
|
-
userAgent: z.string().optional()
|
|
48
|
-
}).transform((inputUserScope) => {
|
|
49
|
-
const { ip, ipMask, userAgent, ...userScope } = inputUserScope;
|
|
50
|
-
if ("string" === typeof ip) {
|
|
51
|
-
userScope.numericIp = getIPAddress(ip).bigInt();
|
|
52
|
-
}
|
|
53
|
-
if ("string" === typeof ipMask) {
|
|
54
|
-
const ipObject = new Address4(ipMask);
|
|
55
|
-
userScope.numericIpMaskMin = ipObject.startAddress().bigInt();
|
|
56
|
-
userScope.numericIpMaskMax = ipObject.endAddress().bigInt();
|
|
57
|
-
}
|
|
58
|
-
if ("string" === typeof userAgent) {
|
|
59
|
-
userScope.userAgentHash = hashUserAgent(userAgent);
|
|
60
|
-
}
|
|
61
|
-
return userScope;
|
|
62
|
-
});
|
|
63
|
-
const accessRuleSchemaExtended = z.object({
|
|
64
|
-
// flat structure is used to fit the Redis requirements
|
|
65
|
-
...accessPolicySchema.shape,
|
|
66
|
-
...policyScopeSchema.shape,
|
|
67
|
-
...userScopeInputSchema._def.schema.shape
|
|
68
|
-
}).omit({
|
|
69
|
-
numericIp: true,
|
|
70
|
-
numericIpMaskMin: true,
|
|
71
|
-
numericIpMaskMax: true
|
|
72
|
-
});
|
|
73
|
-
export {
|
|
74
|
-
AccessPolicyType,
|
|
75
|
-
accessPolicySchema,
|
|
76
|
-
accessRuleSchemaExtended,
|
|
77
|
-
policyScopeSchema,
|
|
78
|
-
userScopeInputSchema,
|
|
79
|
-
userScopeSchema
|
|
80
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { userScopeInputSchema, policyScopeSchema } from "./accessPolicy.js";
|
|
3
|
-
var ScopeMatch = /* @__PURE__ */ ((ScopeMatch2) => {
|
|
4
|
-
ScopeMatch2["Exact"] = "exact";
|
|
5
|
-
ScopeMatch2["Greedy"] = "greedy";
|
|
6
|
-
return ScopeMatch2;
|
|
7
|
-
})(ScopeMatch || {});
|
|
8
|
-
const policyFilterSchema = z.object({
|
|
9
|
-
policyScope: policyScopeSchema.optional(),
|
|
10
|
-
/**
|
|
11
|
-
* Exact: "clientId" => client rules, "undefined" => global rules. Used by the API
|
|
12
|
-
* Greedy: "clientId" => client + global rules, "undefined" => any rules. Used by the Express middleware
|
|
13
|
-
*/
|
|
14
|
-
policyScopeMatch: z.nativeEnum(ScopeMatch).default(
|
|
15
|
-
"exact"
|
|
16
|
-
/* Exact */
|
|
17
|
-
),
|
|
18
|
-
userScope: userScopeInputSchema.optional(),
|
|
19
|
-
/**
|
|
20
|
-
* Exact: finds rules where all the given fields matches and doesn't check IP against masks. Used by the API
|
|
21
|
-
* Greedy: finds rules where any of the given fields match and checks IP against masks. Used by the Express middleware
|
|
22
|
-
*/
|
|
23
|
-
userScopeMatch: z.nativeEnum(ScopeMatch).default(
|
|
24
|
-
"exact"
|
|
25
|
-
/* Exact */
|
|
26
|
-
)
|
|
27
|
-
});
|
|
28
|
-
export {
|
|
29
|
-
ScopeMatch,
|
|
30
|
-
policyFilterSchema
|
|
31
|
-
};
|
package/dist/accessRules.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { userScopeSchema, policyScopeSchema, accessPolicySchema } from "./accessPolicy.js";
|
|
3
|
-
const accessRuleSchema = z.object({
|
|
4
|
-
// flat structure is used to fit the Redis requirements
|
|
5
|
-
...accessPolicySchema.shape,
|
|
6
|
-
...policyScopeSchema.shape,
|
|
7
|
-
...userScopeSchema.shape
|
|
8
|
-
});
|
|
9
|
-
export {
|
|
10
|
-
accessRuleSchema
|
|
11
|
-
};
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { DeleteAllRulesEndpoint } from "./deleteAllRulesEndpoint.js";
|
|
2
|
-
import { DeleteRulesEndpoint } from "./deleteRulesEndpoint.js";
|
|
3
|
-
import { InsertRulesEndpoint } from "./insertRulesEndpoint.js";
|
|
4
|
-
var accessRuleApiPaths = /* @__PURE__ */ ((accessRuleApiPaths2) => {
|
|
5
|
-
accessRuleApiPaths2["INSERT_MANY"] = "/v1/prosopo/user-access-policy/rules/insert-many";
|
|
6
|
-
accessRuleApiPaths2["DELETE_MANY"] = "/v1/prosopo/user-access-policy/rules/delete-many";
|
|
7
|
-
accessRuleApiPaths2["DELETE_ALL"] = "/v1/prosopo/user-access-policy/rules/delete-all";
|
|
8
|
-
return accessRuleApiPaths2;
|
|
9
|
-
})(accessRuleApiPaths || {});
|
|
10
|
-
class AccessRuleApiRoutes {
|
|
11
|
-
constructor(accessRulesStorage) {
|
|
12
|
-
this.accessRulesStorage = accessRulesStorage;
|
|
13
|
-
}
|
|
14
|
-
getRoutes() {
|
|
15
|
-
return [
|
|
16
|
-
{
|
|
17
|
-
path: "/v1/prosopo/user-access-policy/rules/insert-many",
|
|
18
|
-
endpoint: new InsertRulesEndpoint(this.accessRulesStorage)
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
path: "/v1/prosopo/user-access-policy/rules/delete-many",
|
|
22
|
-
endpoint: new DeleteRulesEndpoint(this.accessRulesStorage)
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
path: "/v1/prosopo/user-access-policy/rules/delete-all",
|
|
26
|
-
endpoint: new DeleteAllRulesEndpoint(this.accessRulesStorage)
|
|
27
|
-
}
|
|
28
|
-
];
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
const getExpressApiRuleRateLimits = () => {
|
|
32
|
-
const defaultWindowsMs = 6e4;
|
|
33
|
-
const defaultLimit = 5;
|
|
34
|
-
return {
|
|
35
|
-
[
|
|
36
|
-
"/v1/prosopo/user-access-policy/rules/insert-many"
|
|
37
|
-
/* INSERT_MANY */
|
|
38
|
-
]: {
|
|
39
|
-
windowMs: getIntEnvironmentVariable(
|
|
40
|
-
"PROSOPO_USER_ACCESS_POLICY_RULE_INSERT_MANY_WINDOW"
|
|
41
|
-
) || defaultWindowsMs,
|
|
42
|
-
limit: getIntEnvironmentVariable(
|
|
43
|
-
"PROSOPO_USER_ACCESS_POLICY_RULE_INSERT_MANY_LIMIT"
|
|
44
|
-
) || defaultLimit
|
|
45
|
-
},
|
|
46
|
-
[
|
|
47
|
-
"/v1/prosopo/user-access-policy/rules/delete-many"
|
|
48
|
-
/* DELETE_MANY */
|
|
49
|
-
]: {
|
|
50
|
-
windowMs: getIntEnvironmentVariable(
|
|
51
|
-
"PROSOPO_USER_ACCESS_POLICY_RULE_DELETE_MANY_WINDOW"
|
|
52
|
-
) || defaultWindowsMs,
|
|
53
|
-
limit: getIntEnvironmentVariable(
|
|
54
|
-
"PROSOPO_USER_ACCESS_POLICY_RULE_DELETE_MANY_LIMIT"
|
|
55
|
-
) || defaultLimit
|
|
56
|
-
},
|
|
57
|
-
[
|
|
58
|
-
"/v1/prosopo/user-access-policy/rules/delete-all"
|
|
59
|
-
/* DELETE_ALL */
|
|
60
|
-
]: {
|
|
61
|
-
windowMs: getIntEnvironmentVariable(
|
|
62
|
-
"PROSOPO_USER_ACCESS_POLICY_RULE_DELETE_ALL_WINDOW"
|
|
63
|
-
) || defaultWindowsMs,
|
|
64
|
-
limit: getIntEnvironmentVariable(
|
|
65
|
-
"PROSOPO_USER_ACCESS_POLICY_RULE_DELETE_ALL_LIMIT"
|
|
66
|
-
) || defaultLimit
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
};
|
|
70
|
-
const getIntEnvironmentVariable = (variableName) => {
|
|
71
|
-
const variableValue = process.env[variableName];
|
|
72
|
-
const numericValue = variableValue ? Number.parseInt(variableValue) : Number.NaN;
|
|
73
|
-
return Number.isInteger(numericValue) ? numericValue : void 0;
|
|
74
|
-
};
|
|
75
|
-
export {
|
|
76
|
-
AccessRuleApiRoutes,
|
|
77
|
-
accessRuleApiPaths,
|
|
78
|
-
getExpressApiRuleRateLimits
|
|
79
|
-
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { ApiClient } from "@prosopo/api";
|
|
2
|
-
import { accessRuleApiPaths } from "./accessRuleApiRoutes.js";
|
|
3
|
-
class AccessRulesApiClient extends ApiClient {
|
|
4
|
-
insertMany(toInsert, timestamp, signature) {
|
|
5
|
-
return this.post(accessRuleApiPaths.INSERT_MANY, toInsert, {
|
|
6
|
-
headers: {
|
|
7
|
-
"Prosopo-Site-Key": this.account,
|
|
8
|
-
timestamp,
|
|
9
|
-
signature
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
}
|
|
13
|
-
deleteMany(toDelete, timestamp, signature) {
|
|
14
|
-
return this.post(accessRuleApiPaths.DELETE_MANY, toDelete, {
|
|
15
|
-
headers: {
|
|
16
|
-
"Prosopo-Site-Key": this.account,
|
|
17
|
-
timestamp,
|
|
18
|
-
signature
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
deleteAll(timestamp, signature) {
|
|
23
|
-
return this.post(
|
|
24
|
-
accessRuleApiPaths.DELETE_ALL,
|
|
25
|
-
{},
|
|
26
|
-
{
|
|
27
|
-
headers: {
|
|
28
|
-
"Prosopo-Site-Key": this.account,
|
|
29
|
-
timestamp,
|
|
30
|
-
signature
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
export {
|
|
37
|
-
AccessRulesApiClient
|
|
38
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { ApiEndpointResponseStatus } from "@prosopo/api-route";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { policyFilterSchema } from "../accessPolicyResolver.js";
|
|
4
|
-
const deleteRulesEndpointSchema = z.array(policyFilterSchema);
|
|
5
|
-
class DeleteRulesEndpoint {
|
|
6
|
-
constructor(accessRulesStorage) {
|
|
7
|
-
this.accessRulesStorage = accessRulesStorage;
|
|
8
|
-
}
|
|
9
|
-
async processRequest(args) {
|
|
10
|
-
const allRuleIds = [];
|
|
11
|
-
for (const accessRuleFilter of args) {
|
|
12
|
-
const parsedRules = policyFilterSchema.parse(accessRuleFilter);
|
|
13
|
-
const foundRuleIds = await this.accessRulesStorage.findRuleIds(parsedRules);
|
|
14
|
-
allRuleIds.push(...foundRuleIds);
|
|
15
|
-
}
|
|
16
|
-
const uniqueRuleIds = [...new Set(allRuleIds)];
|
|
17
|
-
if (uniqueRuleIds.length > 0) {
|
|
18
|
-
await this.accessRulesStorage.deleteRules(uniqueRuleIds);
|
|
19
|
-
}
|
|
20
|
-
return {
|
|
21
|
-
status: ApiEndpointResponseStatus.SUCCESS,
|
|
22
|
-
data: {
|
|
23
|
-
deleted_count: uniqueRuleIds.length
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
getRequestArgsSchema() {
|
|
28
|
-
return deleteRulesEndpointSchema;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
export {
|
|
32
|
-
DeleteRulesEndpoint,
|
|
33
|
-
deleteRulesEndpointSchema
|
|
34
|
-
};
|