@prosopo/user-access-policy 3.3.2 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # @prosopo/user-access-policy
2
2
 
3
+ ## 3.4.0
4
+ ### Minor Changes
5
+
6
+ - df4e030: Revising UAP rule getters
7
+
8
+ ### Patch Changes
9
+
10
+ - 91bbe87: configure typecheck before bundle for vue packages
11
+ - 91bbe87: make typecheck script always recompile
12
+ - 346e092: NODE_ENV default to "development"
13
+ - 5d36e05: remove tsc --force
14
+ - Updated dependencies [828066d]
15
+ - Updated dependencies [df4e030]
16
+ - Updated dependencies [91bbe87]
17
+ - Updated dependencies [3ef4fd2]
18
+ - Updated dependencies [91bbe87]
19
+ - Updated dependencies [346e092]
20
+ - Updated dependencies [5d36e05]
21
+ - @prosopo/api-route@2.6.10
22
+ - @prosopo/common@3.1.2
23
+ - @prosopo/types@3.0.6
24
+ - @prosopo/config@3.1.3
25
+ - @prosopo/util@3.0.5
26
+
3
27
  ## 3.3.2
4
28
  ### Patch Changes
5
29
 
@@ -1,6 +1,5 @@
1
- import * as util from "node:util";
2
1
  import { z } from "zod";
3
- import { userScopeInputSchema, policyScopeSchema, AccessPolicyType } from "./accessPolicy.js";
2
+ import { userScopeInputSchema, policyScopeSchema } from "./accessPolicy.js";
4
3
  var ScopeMatch = /* @__PURE__ */ ((ScopeMatch2) => {
5
4
  ScopeMatch2["Exact"] = "exact";
6
5
  ScopeMatch2["Greedy"] = "greedy";
@@ -26,45 +25,7 @@ const policyFilterSchema = z.object({
26
25
  /* Exact */
27
26
  )
28
27
  });
29
- const createAccessPolicyResolver = (accessRulesReader, logger) => {
30
- return async (filter) => {
31
- const accessRules = await accessRulesReader.findRules(filter);
32
- const primaryAccessRule = resolvePrimaryRule(accessRules);
33
- logger.debug(() => ({
34
- msg: "Resolved access policy",
35
- // filter contains BigInt, which can't be handled directly via logger.
36
- data: {
37
- inspect: util.inspect(
38
- {
39
- filter,
40
- accessRules,
41
- primaryAccessRule
42
- },
43
- { depth: null }
44
- )
45
- }
46
- }));
47
- return primaryAccessRule;
48
- };
49
- };
50
- const resolvePrimaryRule = (rules) => {
51
- const blockingRules = rules.filter(
52
- (accessRule) => AccessPolicyType.Block === accessRule.type
53
- );
54
- const rulesToEvaluate = blockingRules.length > 0 ? blockingRules : rules;
55
- return resolveMostLocalRule(rulesToEvaluate);
56
- };
57
- const resolveMostLocalRule = (rules) => {
58
- const clientRules = rules.filter(
59
- (accessRule) => "string" === typeof accessRule.clientId
60
- );
61
- if (clientRules.length > 0) {
62
- return clientRules.shift();
63
- }
64
- return rules.shift();
65
- };
66
28
  export {
67
29
  ScopeMatch,
68
- createAccessPolicyResolver,
69
30
  policyFilterSchema
70
31
  };
@@ -1,25 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const util = require("node:util");
4
3
  const zod = require("zod");
5
4
  const accessPolicy = require("./accessPolicy.cjs");
6
- function _interopNamespaceDefault(e) {
7
- const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
8
- if (e) {
9
- for (const k in e) {
10
- if (k !== "default") {
11
- const d = Object.getOwnPropertyDescriptor(e, k);
12
- Object.defineProperty(n, k, d.get ? d : {
13
- enumerable: true,
14
- get: () => e[k]
15
- });
16
- }
17
- }
18
- }
19
- n.default = e;
20
- return Object.freeze(n);
21
- }
22
- const util__namespace = /* @__PURE__ */ _interopNamespaceDefault(util);
23
5
  var ScopeMatch = /* @__PURE__ */ ((ScopeMatch2) => {
24
6
  ScopeMatch2["Exact"] = "exact";
25
7
  ScopeMatch2["Greedy"] = "greedy";
@@ -45,43 +27,5 @@ const policyFilterSchema = zod.z.object({
45
27
  /* Exact */
46
28
  )
47
29
  });
48
- const createAccessPolicyResolver = (accessRulesReader, logger) => {
49
- return async (filter) => {
50
- const accessRules = await accessRulesReader.findRules(filter);
51
- const primaryAccessRule = resolvePrimaryRule(accessRules);
52
- logger.debug(() => ({
53
- msg: "Resolved access policy",
54
- // filter contains BigInt, which can't be handled directly via logger.
55
- data: {
56
- inspect: util__namespace.inspect(
57
- {
58
- filter,
59
- accessRules,
60
- primaryAccessRule
61
- },
62
- { depth: null }
63
- )
64
- }
65
- }));
66
- return primaryAccessRule;
67
- };
68
- };
69
- const resolvePrimaryRule = (rules) => {
70
- const blockingRules = rules.filter(
71
- (accessRule) => accessPolicy.AccessPolicyType.Block === accessRule.type
72
- );
73
- const rulesToEvaluate = blockingRules.length > 0 ? blockingRules : rules;
74
- return resolveMostLocalRule(rulesToEvaluate);
75
- };
76
- const resolveMostLocalRule = (rules) => {
77
- const clientRules = rules.filter(
78
- (accessRule) => "string" === typeof accessRule.clientId
79
- );
80
- if (clientRules.length > 0) {
81
- return clientRules.shift();
82
- }
83
- return rules.shift();
84
- };
85
30
  exports.ScopeMatch = ScopeMatch;
86
- exports.createAccessPolicyResolver = createAccessPolicyResolver;
87
31
  exports.policyFilterSchema = policyFilterSchema;
@@ -13,10 +13,10 @@ const createApiRuleRoutesProvider = (rulesStorage) => {
13
13
  };
14
14
  exports.AccessPolicyType = accessPolicy.AccessPolicyType;
15
15
  exports.accessPolicySchema = accessPolicy.accessPolicySchema;
16
+ exports.accessRuleSchemaExtended = accessPolicy.accessRuleSchemaExtended;
16
17
  exports.policyScopeSchema = accessPolicy.policyScopeSchema;
17
18
  exports.userScopeInputSchema = accessPolicy.userScopeInputSchema;
18
19
  exports.ScopeMatch = accessPolicyResolver.ScopeMatch;
19
- exports.createAccessPolicyResolver = accessPolicyResolver.createAccessPolicyResolver;
20
20
  exports.accessRuleApiPaths = accessRuleApiRoutes.accessRuleApiPaths;
21
21
  exports.getExpressApiRuleRateLimits = accessRuleApiRoutes.getExpressApiRuleRateLimits;
22
22
  exports.deleteAllRulesEndpointSchema = deleteAllRulesEndpoint.deleteAllRulesEndpointSchema;
@@ -26,11 +26,11 @@ const accessRulesIndex = {
26
26
  },
27
27
  numericIpMaskMin: search.SCHEMA_FIELD_TYPE.NUMERIC,
28
28
  numericIpMaskMax: search.SCHEMA_FIELD_TYPE.NUMERIC,
29
- userId: search.SCHEMA_FIELD_TYPE.TAG,
29
+ userId: { type: search.SCHEMA_FIELD_TYPE.TAG, INDEXMISSING: true },
30
30
  numericIp: { type: search.SCHEMA_FIELD_TYPE.NUMERIC, INDEXMISSING: true },
31
- ja4Hash: search.SCHEMA_FIELD_TYPE.TAG,
32
- headersHash: search.SCHEMA_FIELD_TYPE.TAG,
33
- userAgentHash: search.SCHEMA_FIELD_TYPE.TAG
31
+ ja4Hash: { type: search.SCHEMA_FIELD_TYPE.TAG, INDEXMISSING: true },
32
+ headersHash: { type: search.SCHEMA_FIELD_TYPE.TAG, INDEXMISSING: true },
33
+ userAgentHash: { type: search.SCHEMA_FIELD_TYPE.TAG, INDEXMISSING: true }
34
34
  },
35
35
  // the satisfy statement is to guarantee that the keys are right
36
36
  options: {
@@ -38,7 +38,12 @@ const accessRulesIndex = {
38
38
  PREFIX: [accessRuleRedisKeyPrefix]
39
39
  }
40
40
  };
41
- const createRedisAccessRulesIndex = async (client) => redisIndex.createRedisIndex(client, accessRulesIndex);
41
+ const createRedisAccessRulesIndex = async (client, indexName) => {
42
+ if (indexName) {
43
+ accessRulesIndex.name = indexName;
44
+ }
45
+ return redisIndex.createRedisIndex(client, accessRulesIndex);
46
+ };
42
47
  const numericIndexFields = [
43
48
  "numericIp",
44
49
  "numericIpMaskMin",
@@ -79,16 +84,28 @@ const getPolicyScopeQuery = (policyScope, scopeMatchType) => {
79
84
  return accessPolicyResolver.ScopeMatch.Exact === scopeMatchType ? "ismissing(@clientId)" : "";
80
85
  };
81
86
  const getUserScopeQuery = (userScope, scopeMatchType) => {
82
- const scopeEntries = Object.entries(userScope).filter(([_, value]) => value !== void 0);
83
- const scopeJoinType = accessPolicyResolver.ScopeMatch.Exact === scopeMatchType ? " " : " | ";
87
+ let scopeEntries = Object.entries(userScope);
88
+ let scopeJoinType = " ";
89
+ if (scopeMatchType === accessPolicyResolver.ScopeMatch.Greedy) {
90
+ scopeEntries = scopeEntries.filter(
91
+ ([_, value]) => value !== void 0
92
+ );
93
+ scopeJoinType = " | ";
94
+ }
84
95
  return scopeEntries.map(
85
96
  ([scopeFieldName, scopeFieldValue]) => getUserScopeFieldQuery(scopeFieldName, scopeFieldValue, scopeMatchType)
86
97
  ).join(scopeJoinType);
87
98
  };
88
99
  const getUserScopeFieldQuery = (fieldName, fieldValue, matchType) => {
89
- if (accessPolicyResolver.ScopeMatch.Greedy === matchType && "function" === typeof greedyFieldComparisons[fieldName]) {
100
+ if (
101
+ //ScopeMatch.Greedy === matchType &&
102
+ "function" === typeof greedyFieldComparisons[fieldName]
103
+ ) {
90
104
  return greedyFieldComparisons[fieldName](fieldValue);
91
105
  }
106
+ if (fieldValue === void 0) {
107
+ return `ismissing(@${fieldName})`;
108
+ }
92
109
  return numericIndexFields.includes(fieldName) ? `@${fieldName}:[${fieldValue}]` : `@${fieldName}:{${fieldValue}}`;
93
110
  };
94
111
  const getRedisAccessRuleKey = (rule) => accessRuleRedisKeyPrefix + crypto.createHash(accessRuleContentHashAlgorithm).update(
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { AccessPolicyType, accessPolicySchema, policyScopeSchema, userScopeInputSchema } from "./accessPolicy.js";
2
- import { ScopeMatch, createAccessPolicyResolver } from "./accessPolicyResolver.js";
1
+ import { AccessPolicyType, accessPolicySchema, accessRuleSchemaExtended, policyScopeSchema, userScopeInputSchema } from "./accessPolicy.js";
2
+ import { ScopeMatch } from "./accessPolicyResolver.js";
3
3
  import { AccessRuleApiRoutes } from "./api/accessRuleApiRoutes.js";
4
4
  import { accessRuleApiPaths, getExpressApiRuleRateLimits } from "./api/accessRuleApiRoutes.js";
5
5
  import { deleteAllRulesEndpointSchema } from "./api/deleteAllRulesEndpoint.js";
@@ -15,7 +15,7 @@ export {
15
15
  ScopeMatch,
16
16
  accessPolicySchema,
17
17
  accessRuleApiPaths,
18
- createAccessPolicyResolver,
18
+ accessRuleSchemaExtended,
19
19
  createApiRuleRoutesProvider,
20
20
  createRedisAccessRulesIndex,
21
21
  createRedisAccessRulesStorage,
@@ -24,11 +24,11 @@ const accessRulesIndex = {
24
24
  },
25
25
  numericIpMaskMin: SCHEMA_FIELD_TYPE.NUMERIC,
26
26
  numericIpMaskMax: SCHEMA_FIELD_TYPE.NUMERIC,
27
- userId: SCHEMA_FIELD_TYPE.TAG,
27
+ userId: { type: SCHEMA_FIELD_TYPE.TAG, INDEXMISSING: true },
28
28
  numericIp: { type: SCHEMA_FIELD_TYPE.NUMERIC, INDEXMISSING: true },
29
- ja4Hash: SCHEMA_FIELD_TYPE.TAG,
30
- headersHash: SCHEMA_FIELD_TYPE.TAG,
31
- userAgentHash: SCHEMA_FIELD_TYPE.TAG
29
+ ja4Hash: { type: SCHEMA_FIELD_TYPE.TAG, INDEXMISSING: true },
30
+ headersHash: { type: SCHEMA_FIELD_TYPE.TAG, INDEXMISSING: true },
31
+ userAgentHash: { type: SCHEMA_FIELD_TYPE.TAG, INDEXMISSING: true }
32
32
  },
33
33
  // the satisfy statement is to guarantee that the keys are right
34
34
  options: {
@@ -36,7 +36,12 @@ const accessRulesIndex = {
36
36
  PREFIX: [accessRuleRedisKeyPrefix]
37
37
  }
38
38
  };
39
- const createRedisAccessRulesIndex = async (client) => createRedisIndex(client, accessRulesIndex);
39
+ const createRedisAccessRulesIndex = async (client, indexName) => {
40
+ if (indexName) {
41
+ accessRulesIndex.name = indexName;
42
+ }
43
+ return createRedisIndex(client, accessRulesIndex);
44
+ };
40
45
  const numericIndexFields = [
41
46
  "numericIp",
42
47
  "numericIpMaskMin",
@@ -77,16 +82,28 @@ const getPolicyScopeQuery = (policyScope, scopeMatchType) => {
77
82
  return ScopeMatch.Exact === scopeMatchType ? "ismissing(@clientId)" : "";
78
83
  };
79
84
  const getUserScopeQuery = (userScope, scopeMatchType) => {
80
- const scopeEntries = Object.entries(userScope).filter(([_, value]) => value !== void 0);
81
- const scopeJoinType = ScopeMatch.Exact === scopeMatchType ? " " : " | ";
85
+ let scopeEntries = Object.entries(userScope);
86
+ let scopeJoinType = " ";
87
+ if (scopeMatchType === ScopeMatch.Greedy) {
88
+ scopeEntries = scopeEntries.filter(
89
+ ([_, value]) => value !== void 0
90
+ );
91
+ scopeJoinType = " | ";
92
+ }
82
93
  return scopeEntries.map(
83
94
  ([scopeFieldName, scopeFieldValue]) => getUserScopeFieldQuery(scopeFieldName, scopeFieldValue, scopeMatchType)
84
95
  ).join(scopeJoinType);
85
96
  };
86
97
  const getUserScopeFieldQuery = (fieldName, fieldValue, matchType) => {
87
- if (ScopeMatch.Greedy === matchType && "function" === typeof greedyFieldComparisons[fieldName]) {
98
+ if (
99
+ //ScopeMatch.Greedy === matchType &&
100
+ "function" === typeof greedyFieldComparisons[fieldName]
101
+ ) {
88
102
  return greedyFieldComparisons[fieldName](fieldValue);
89
103
  }
104
+ if (fieldValue === void 0) {
105
+ return `ismissing(@${fieldName})`;
106
+ }
90
107
  return numericIndexFields.includes(fieldName) ? `@${fieldName}:[${fieldValue}]` : `@${fieldName}:{${fieldValue}}`;
91
108
  };
92
109
  const getRedisAccessRuleKey = (rule) => accessRuleRedisKeyPrefix + crypto.createHash(accessRuleContentHashAlgorithm).update(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/user-access-policy",
3
- "version": "3.3.2",
3
+ "version": "3.4.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -20,23 +20,23 @@
20
20
  },
21
21
  "scripts": {
22
22
  "clean": "del-cli --verbose dist tsconfig.tsbuildinfo",
23
- "build": "NODE_ENV=${NODE_ENV:-production}; vite build --config vite.esm.config.ts --mode $NODE_ENV",
23
+ "build": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.esm.config.ts --mode $NODE_ENV",
24
24
  "build:tsc": "tsc --build --verbose",
25
- "build:cjs": "NODE_ENV=${NODE_ENV:-production}; vite build --config vite.cjs.config.ts --mode $NODE_ENV",
26
- "typecheck": "tsc --build --declaration --emitDeclarationOnly --force",
25
+ "build:cjs": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV",
26
+ "typecheck": "tsc --build --declaration --emitDeclarationOnly",
27
27
  "test": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --config ./vite.test.config.ts"
28
28
  },
29
29
  "dependencies": {
30
- "@prosopo/api-route": "2.6.9",
31
- "@prosopo/common": "3.1.1",
32
- "@prosopo/types": "3.0.5",
33
- "@prosopo/util": "3.0.4",
30
+ "@prosopo/api-route": "2.6.10",
31
+ "@prosopo/common": "3.1.2",
32
+ "@prosopo/types": "3.0.6",
33
+ "@prosopo/util": "3.0.5",
34
34
  "axios": "1.10.0",
35
35
  "esbuild": "0.25.6",
36
36
  "ip-address": "10.0.1",
37
37
  "redis": "5.0.0",
38
38
  "zod": "3.23.8",
39
- "@prosopo/config": "3.1.2",
39
+ "@prosopo/config": "3.1.3",
40
40
  "webpack-dev-server": "5.2.2"
41
41
  },
42
42
  "devDependencies": {