@frontegg/entitlements-javascript-commons 1.0.0-alpha.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/operations/date/sanitizers.d.ts +2 -0
- package/dist/operations/date/sanitizers.js +16 -5
- package/dist/operations/date/sanitizers.js.map +1 -1
- package/dist/operations/numeric/sanitizers.js +2 -2
- package/dist/operations/string/sanitizers.js +2 -2
- package/dist/operations/string/sanitizers.js.map +1 -1
- package/dist/user-entitlements/attributes.utils.d.ts +11 -0
- package/dist/user-entitlements/attributes.utils.js +43 -0
- package/dist/user-entitlements/attributes.utils.js.map +1 -0
- package/dist/user-entitlements/flatten.utils.d.ts +8 -0
- package/dist/user-entitlements/flatten.utils.js +39 -0
- package/dist/user-entitlements/flatten.utils.js.map +1 -0
- package/dist/user-entitlements/index.d.ts +2 -0
- package/dist/user-entitlements/index.js +2 -0
- package/dist/user-entitlements/index.js.map +1 -1
- package/dist/user-entitlements/is-entitled.evaluator.d.ts +3 -3
- package/dist/user-entitlements/is-entitled.evaluator.js +11 -5
- package/dist/user-entitlements/is-entitled.evaluator.js.map +1 -1
- package/dist/user-entitlements/permissions.utils.d.ts +3 -0
- package/dist/user-entitlements/permissions.utils.js +12 -0
- package/dist/user-entitlements/permissions.utils.js.map +1 -0
- package/dist/user-entitlements/types.d.ts +13 -1
- package/dist/user-entitlements/types.js.map +1 -1
- package/docs/CHANGELOG.md +97 -0
- package/package.json +1 -1
- package/src/index.ts +7 -0
- package/src/operations/date/sanitizers.ts +19 -4
- package/src/operations/date/tests/sanitizers.spec.ts +18 -1
- package/src/operations/numeric/sanitizers.ts +2 -2
- package/src/operations/string/sanitizers.ts +2 -2
- package/src/user-entitlements/attributes.utils.ts +43 -0
- package/src/user-entitlements/flatten.utils.ts +52 -0
- package/src/user-entitlements/index.ts +2 -0
- package/src/user-entitlements/is-entitled.evaluator.ts +20 -9
- package/src/user-entitlements/permissions.utils.ts +10 -0
- package/src/user-entitlements/tests/attributes.utils.spec.ts +75 -0
- package/src/user-entitlements/tests/is-entitled.evaluator.spec.ts +11 -4
- package/src/user-entitlements/tests/permissions.utils.spec.ts +21 -0
- package/src/user-entitlements/types.ts +10 -1
package/dist/index.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ export { FeatureFlagEvaluationResult, FeatureFlag, evaluateFeatureFlag } from '.
|
|
|
2
2
|
export { TreatmentEnum, Rule } from './rules';
|
|
3
3
|
export { Condition } from './conditions';
|
|
4
4
|
export { OperationEnum, ConditionValue } from './operations/types';
|
|
5
|
-
export { evaluateIsEntitledToFeature, evaluateIsEntitledToPermissions, CustomAttributes, NotEntitledJustification, UserEntitlementsContext, EntitlementResult, } from './user-entitlements';
|
|
5
|
+
export { evaluateIsEntitledToFeature, evaluateIsEntitledToPermissions, prepareAttributes, checkPermission, createPermissionCheckRegex, Permissions, JwtAttributes, CustomAttributes, FronteggAttributes, NotEntitledJustification, UserEntitlementsContext, EntitlementResult, Attributes, } from './user-entitlements';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NotEntitledJustification = exports.evaluateIsEntitledToPermissions = exports.evaluateIsEntitledToFeature = exports.OperationEnum = exports.TreatmentEnum = exports.evaluateFeatureFlag = void 0;
|
|
3
|
+
exports.NotEntitledJustification = exports.createPermissionCheckRegex = exports.checkPermission = exports.prepareAttributes = exports.evaluateIsEntitledToPermissions = exports.evaluateIsEntitledToFeature = exports.OperationEnum = exports.TreatmentEnum = exports.evaluateFeatureFlag = void 0;
|
|
4
4
|
var feature_flags_1 = require("./feature-flags");
|
|
5
5
|
Object.defineProperty(exports, "evaluateFeatureFlag", { enumerable: true, get: function () { return feature_flags_1.evaluateFeatureFlag; } });
|
|
6
6
|
var rules_1 = require("./rules");
|
|
@@ -10,5 +10,8 @@ Object.defineProperty(exports, "OperationEnum", { enumerable: true, get: functio
|
|
|
10
10
|
var user_entitlements_1 = require("./user-entitlements");
|
|
11
11
|
Object.defineProperty(exports, "evaluateIsEntitledToFeature", { enumerable: true, get: function () { return user_entitlements_1.evaluateIsEntitledToFeature; } });
|
|
12
12
|
Object.defineProperty(exports, "evaluateIsEntitledToPermissions", { enumerable: true, get: function () { return user_entitlements_1.evaluateIsEntitledToPermissions; } });
|
|
13
|
+
Object.defineProperty(exports, "prepareAttributes", { enumerable: true, get: function () { return user_entitlements_1.prepareAttributes; } });
|
|
14
|
+
Object.defineProperty(exports, "checkPermission", { enumerable: true, get: function () { return user_entitlements_1.checkPermission; } });
|
|
15
|
+
Object.defineProperty(exports, "createPermissionCheckRegex", { enumerable: true, get: function () { return user_entitlements_1.createPermissionCheckRegex; } });
|
|
13
16
|
Object.defineProperty(exports, "NotEntitledJustification", { enumerable: true, get: function () { return user_entitlements_1.NotEntitledJustification; } });
|
|
14
17
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,iDAAgG;AAA7C,oHAAA,mBAAmB,OAAA;AACtE,iCAA8C;AAArC,sGAAA,aAAa,OAAA;AAEtB,4CAAmE;AAA1D,sGAAA,aAAa,OAAA;AACtB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,iDAAgG;AAA7C,oHAAA,mBAAmB,OAAA;AACtE,iCAA8C;AAArC,sGAAA,aAAa,OAAA;AAEtB,4CAAmE;AAA1D,sGAAA,aAAa,OAAA;AACtB,yDAc6B;AAb3B,gIAAA,2BAA2B,OAAA;AAC3B,oIAAA,+BAA+B,OAAA;AAC/B,sHAAA,iBAAiB,OAAA;AACjB,oHAAA,eAAe,OAAA;AACf,+HAAA,0BAA0B,OAAA;AAK1B,6HAAA,wBAAwB,OAAA"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Sanitizer, SanitizersMapper } from '../types';
|
|
2
2
|
import { BetweenDateOperationPayload, DateOperationPayload, SingleDateOperationPayload } from './types';
|
|
3
|
+
export declare const sanitizeDateValue: (value: Date | string | number) => Date;
|
|
4
|
+
export declare const isValidDate: (value: unknown) => boolean;
|
|
3
5
|
export declare const sanitizeSingleDate: Sanitizer<SingleDateOperationPayload>;
|
|
4
6
|
export declare const sanitizeDateRange: Sanitizer<BetweenDateOperationPayload>;
|
|
5
7
|
export declare const DateSanitizersMapper: SanitizersMapper<DateOperationPayload>;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DateSanitizersMapper = exports.sanitizeDateRange = exports.sanitizeSingleDate = void 0;
|
|
3
|
+
exports.DateSanitizersMapper = exports.sanitizeDateRange = exports.sanitizeSingleDate = exports.isValidDate = exports.sanitizeDateValue = void 0;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
|
+
const sanitizeDateValue = (value) => {
|
|
6
|
+
return new Date(value);
|
|
7
|
+
};
|
|
8
|
+
exports.sanitizeDateValue = sanitizeDateValue;
|
|
9
|
+
const isValidDate = (value) => value instanceof Date && !isNaN(value);
|
|
10
|
+
exports.isValidDate = isValidDate;
|
|
5
11
|
const sanitizeSingleDate = (value) => {
|
|
6
|
-
const
|
|
12
|
+
const sanitizedDateValue = value.date ? (0, exports.sanitizeDateValue)(value.date) : undefined;
|
|
13
|
+
const sanitizedValue = sanitizedDateValue && (0, exports.isValidDate)(sanitizedDateValue) ? { date: sanitizedDateValue } : undefined;
|
|
7
14
|
return {
|
|
8
15
|
isSanitized: !!sanitizedValue,
|
|
9
16
|
sanitizedValue,
|
|
@@ -11,7 +18,11 @@ const sanitizeSingleDate = (value) => {
|
|
|
11
18
|
};
|
|
12
19
|
exports.sanitizeSingleDate = sanitizeSingleDate;
|
|
13
20
|
const sanitizeDateRange = (value) => {
|
|
14
|
-
const
|
|
21
|
+
const sanitizedStartValue = value.start ? (0, exports.sanitizeDateValue)(value.start) : undefined;
|
|
22
|
+
const sanitizedEndValue = value.end ? (0, exports.sanitizeDateValue)(value.end) : undefined;
|
|
23
|
+
const sanitizedValue = sanitizedStartValue && sanitizedEndValue && (0, exports.isValidDate)(sanitizedStartValue) && (0, exports.isValidDate)(sanitizedEndValue)
|
|
24
|
+
? { start: sanitizedStartValue, end: sanitizedEndValue }
|
|
25
|
+
: undefined;
|
|
15
26
|
return {
|
|
16
27
|
isSanitized: !!sanitizedValue,
|
|
17
28
|
sanitizedValue,
|
|
@@ -20,8 +31,8 @@ const sanitizeDateRange = (value) => {
|
|
|
20
31
|
exports.sanitizeDateRange = sanitizeDateRange;
|
|
21
32
|
exports.DateSanitizersMapper = {
|
|
22
33
|
[types_1.OperationEnum.On]: exports.sanitizeSingleDate,
|
|
23
|
-
[types_1.OperationEnum.OnOrAfter]: exports.
|
|
34
|
+
[types_1.OperationEnum.OnOrAfter]: exports.sanitizeSingleDate,
|
|
24
35
|
[types_1.OperationEnum.OnOrBefore]: exports.sanitizeSingleDate,
|
|
25
|
-
[types_1.OperationEnum.BetweenDate]: exports.
|
|
36
|
+
[types_1.OperationEnum.BetweenDate]: exports.sanitizeDateRange,
|
|
26
37
|
};
|
|
27
38
|
//# sourceMappingURL=sanitizers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitizers.js","sourceRoot":"","sources":["../../../src/operations/date/sanitizers.ts"],"names":[],"mappings":";;;AAAA,oCAAsE;
|
|
1
|
+
{"version":3,"file":"sanitizers.js","sourceRoot":"","sources":["../../../src/operations/date/sanitizers.ts"],"names":[],"mappings":";;;AAAA,oCAAsE;AAK/D,MAAM,iBAAiB,GAAG,CAAC,KAA6B,EAAQ,EAAE;IACvE,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;AACzB,CAAC,CAAC;AAFW,QAAA,iBAAiB,qBAE5B;AAEK,MAAM,WAAW,GAAG,CAAC,KAAc,EAAW,EAAE,CAAC,KAAK,YAAY,IAAI,IAAI,CAAC,KAAK,CAAC,KAA0B,CAAC,CAAC;AAAvG,QAAA,WAAW,eAA4F;AAE7G,MAAM,kBAAkB,GAA0C,CAAC,KAAK,EAAE,EAAE;IACjF,MAAM,kBAAkB,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAA,yBAAiB,EAAC,KAAK,CAAC,IAAoB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClG,MAAM,cAAc,GAClB,kBAAkB,IAAI,IAAA,mBAAW,EAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAEnG,OAAO;QACL,WAAW,EAAE,CAAC,CAAC,cAAc;QAC7B,cAAc;KACf,CAAC;AACJ,CAAC,CAAC;AATW,QAAA,kBAAkB,sBAS7B;AAEK,MAAM,iBAAiB,GAA2C,CAAC,KAAK,EAAE,EAAE;IACjF,MAAM,mBAAmB,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAA,yBAAiB,EAAC,KAAK,CAAC,KAAqB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACrG,MAAM,iBAAiB,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAA,yBAAiB,EAAC,KAAK,CAAC,GAAmB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/F,MAAM,cAAc,GAClB,mBAAmB,IAAI,iBAAiB,IAAI,IAAA,mBAAW,EAAC,mBAAmB,CAAC,IAAI,IAAA,mBAAW,EAAC,iBAAiB,CAAC;QAC5G,CAAC,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,iBAAiB,EAAE;QACxD,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO;QACL,WAAW,EAAE,CAAC,CAAC,cAAc;QAC7B,cAAc;KACf,CAAC;AACJ,CAAC,CAAC;AAZW,QAAA,iBAAiB,qBAY5B;AAEW,QAAA,oBAAoB,GAA2C;IAC1E,CAAC,qBAAa,CAAC,EAAE,CAAC,EAAE,0BAAkB;IACtC,CAAC,qBAAa,CAAC,SAAS,CAAC,EAAE,0BAAkB;IAC7C,CAAC,qBAAa,CAAC,UAAU,CAAC,EAAE,0BAAkB;IAC9C,CAAC,qBAAa,CAAC,WAAW,CAAC,EAAE,yBAAiB;CAC/C,CAAC"}
|
|
@@ -23,10 +23,10 @@ const sanitizeNumericRange = (value) => {
|
|
|
23
23
|
exports.sanitizeNumericRange = sanitizeNumericRange;
|
|
24
24
|
exports.NumericSanitizersMapper = {
|
|
25
25
|
[types_1.OperationEnum.Equal]: exports.sanitizeSingleNumber,
|
|
26
|
-
[types_1.OperationEnum.GreaterThan]: exports.
|
|
26
|
+
[types_1.OperationEnum.GreaterThan]: exports.sanitizeSingleNumber,
|
|
27
27
|
[types_1.OperationEnum.GreaterThanEqual]: exports.sanitizeSingleNumber,
|
|
28
28
|
[types_1.OperationEnum.LesserThan]: exports.sanitizeSingleNumber,
|
|
29
|
-
[types_1.OperationEnum.LesserThanEqual]: exports.
|
|
29
|
+
[types_1.OperationEnum.LesserThanEqual]: exports.sanitizeSingleNumber,
|
|
30
30
|
[types_1.OperationEnum.BetweenNumeric]: exports.sanitizeNumericRange,
|
|
31
31
|
};
|
|
32
32
|
//# sourceMappingURL=sanitizers.js.map
|
|
@@ -24,8 +24,8 @@ exports.sanitizeListString = sanitizeListString;
|
|
|
24
24
|
exports.StringSanitizersMapper = {
|
|
25
25
|
[types_1.OperationEnum.Matches]: exports.sanitizeSingleString,
|
|
26
26
|
[types_1.OperationEnum.Contains]: exports.sanitizeListString,
|
|
27
|
-
[types_1.OperationEnum.StartsWith]: exports.
|
|
28
|
-
[types_1.OperationEnum.EndsWith]: exports.
|
|
27
|
+
[types_1.OperationEnum.StartsWith]: exports.sanitizeListString,
|
|
28
|
+
[types_1.OperationEnum.EndsWith]: exports.sanitizeListString,
|
|
29
29
|
[types_1.OperationEnum.InList]: exports.sanitizeListString,
|
|
30
30
|
};
|
|
31
31
|
//# sourceMappingURL=sanitizers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitizers.js","sourceRoot":"","sources":["../../../src/operations/string/sanitizers.ts"],"names":[],"mappings":";;;AAAA,oCAAsE;AAGtE,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC;AAEzE,MAAM,oBAAoB,GAA4C,CAAC,KAAK,EAAE,EAAE;IACrF,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAEnH,OAAO;QACL,WAAW,EAAE,CAAC,CAAC,cAAc;QAC7B,cAAc;KACf,CAAC;AACJ,CAAC,CAAC;AAPW,QAAA,oBAAoB,wBAO/B;AAEK,MAAM,kBAAkB,GAA0C,CAAC,KAAK,EAAE,EAAE;IACjF,MAAM,cAAc,GAClB,KAAK,CAAC,IAAI,KAAK,SAAS,IAAgB,KAAK,CAAC,IAAK,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC/E,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAgB,EAAE;QAClC,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO;QACL,WAAW,EAAE,CAAC,CAAC,cAAc;QAC7B,cAAc;KACf,CAAC;AACJ,CAAC,CAAC;AAVW,QAAA,kBAAkB,sBAU7B;AAEW,QAAA,sBAAsB,GAA6C;IAC9E,CAAC,qBAAa,CAAC,OAAO,CAAC,EAAE,4BAAoB;IAC7C,CAAC,qBAAa,CAAC,QAAQ,CAAC,EAAE,0BAAkB;IAC5C,CAAC,qBAAa,CAAC,UAAU,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"sanitizers.js","sourceRoot":"","sources":["../../../src/operations/string/sanitizers.ts"],"names":[],"mappings":";;;AAAA,oCAAsE;AAGtE,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC;AAEzE,MAAM,oBAAoB,GAA4C,CAAC,KAAK,EAAE,EAAE;IACrF,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAEnH,OAAO;QACL,WAAW,EAAE,CAAC,CAAC,cAAc;QAC7B,cAAc;KACf,CAAC;AACJ,CAAC,CAAC;AAPW,QAAA,oBAAoB,wBAO/B;AAEK,MAAM,kBAAkB,GAA0C,CAAC,KAAK,EAAE,EAAE;IACjF,MAAM,cAAc,GAClB,KAAK,CAAC,IAAI,KAAK,SAAS,IAAgB,KAAK,CAAC,IAAK,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC/E,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAgB,EAAE;QAClC,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO;QACL,WAAW,EAAE,CAAC,CAAC,cAAc;QAC7B,cAAc;KACf,CAAC;AACJ,CAAC,CAAC;AAVW,QAAA,kBAAkB,sBAU7B;AAEW,QAAA,sBAAsB,GAA6C;IAC9E,CAAC,qBAAa,CAAC,OAAO,CAAC,EAAE,4BAAoB;IAC7C,CAAC,qBAAa,CAAC,QAAQ,CAAC,EAAE,0BAAkB;IAC5C,CAAC,qBAAa,CAAC,UAAU,CAAC,EAAE,0BAAkB;IAC9C,CAAC,qBAAa,CAAC,QAAQ,CAAC,EAAE,0BAAkB;IAC5C,CAAC,qBAAa,CAAC,MAAM,CAAC,EAAE,0BAAkB;CAC3C,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Attributes, JwtAttributes, FronteggAttributes } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Merges both `custom` and `jwt` records, map Frontegg attributes and modifies record keys with corrisponding prefixes
|
|
4
|
+
*
|
|
5
|
+
* Example:
|
|
6
|
+
* Input: { 'custom': { 'customAttribute': 'someValue' }, 'jwt': { 'email': 'user@email.com', other: 'some-vaule' } }
|
|
7
|
+
* Output: { 'customAttribute': 'someValue', 'frontegg.email': 'user@email.com', 'jwt.email': 'user@email.com', 'jwt.other': 'some-vaule' }
|
|
8
|
+
*/
|
|
9
|
+
export declare function prepareAttributes(attributes?: Attributes, customFronteggAttributesMapper?: (jwtAttributes: JwtAttributes) => FronteggAttributes): Record<string, unknown>;
|
|
10
|
+
export declare function defaultFronteggAttributesMapper(jwt: JwtAttributes): FronteggAttributes;
|
|
11
|
+
export declare function modifyObjectKeysWithPrefix(object: Record<string, unknown>, prefix: string): Record<string, unknown>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.modifyObjectKeysWithPrefix = exports.defaultFronteggAttributesMapper = exports.prepareAttributes = void 0;
|
|
4
|
+
const flatten_utils_1 = require("./flatten.utils");
|
|
5
|
+
/**
|
|
6
|
+
* Merges both `custom` and `jwt` records, map Frontegg attributes and modifies record keys with corrisponding prefixes
|
|
7
|
+
*
|
|
8
|
+
* Example:
|
|
9
|
+
* Input: { 'custom': { 'customAttribute': 'someValue' }, 'jwt': { 'email': 'user@email.com', other: 'some-vaule' } }
|
|
10
|
+
* Output: { 'customAttribute': 'someValue', 'frontegg.email': 'user@email.com', 'jwt.email': 'user@email.com', 'jwt.other': 'some-vaule' }
|
|
11
|
+
*/
|
|
12
|
+
function prepareAttributes(attributes = {}, customFronteggAttributesMapper) {
|
|
13
|
+
const { custom = {}, jwt = {} } = attributes;
|
|
14
|
+
const flatJwtAttributes = (0, flatten_utils_1.flatten)(jwt);
|
|
15
|
+
const fronteggAttributes = customFronteggAttributesMapper
|
|
16
|
+
? customFronteggAttributesMapper(jwt)
|
|
17
|
+
: defaultFronteggAttributesMapper(jwt);
|
|
18
|
+
const fronteggAttributesPrefix = 'frontegg.';
|
|
19
|
+
const jwtAttributesPrefix = 'jwt.';
|
|
20
|
+
return {
|
|
21
|
+
...custom,
|
|
22
|
+
...modifyObjectKeysWithPrefix(fronteggAttributes, fronteggAttributesPrefix),
|
|
23
|
+
...modifyObjectKeysWithPrefix(flatJwtAttributes, jwtAttributesPrefix),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
exports.prepareAttributes = prepareAttributes;
|
|
27
|
+
function defaultFronteggAttributesMapper(jwt) {
|
|
28
|
+
return {
|
|
29
|
+
email: jwt.email,
|
|
30
|
+
emailVerified: jwt.email_verified,
|
|
31
|
+
tenantId: jwt.tenantId,
|
|
32
|
+
userId: jwt.userId,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
exports.defaultFronteggAttributesMapper = defaultFronteggAttributesMapper;
|
|
36
|
+
function modifyObjectKeysWithPrefix(object, prefix) {
|
|
37
|
+
return Object.keys(object).reduce((modifiedObject, currentKey) => {
|
|
38
|
+
modifiedObject[`${prefix}${currentKey}`] = object[currentKey];
|
|
39
|
+
return modifiedObject;
|
|
40
|
+
}, {});
|
|
41
|
+
}
|
|
42
|
+
exports.modifyObjectKeysWithPrefix = modifyObjectKeysWithPrefix;
|
|
43
|
+
//# sourceMappingURL=attributes.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attributes.utils.js","sourceRoot":"","sources":["../../src/user-entitlements/attributes.utils.ts"],"names":[],"mappings":";;;AACA,mDAA0C;AAC1C;;;;;;GAMG;AACH,SAAgB,iBAAiB,CAC/B,aAAyB,EAAE,EAC3B,8BAAqF;IAErF,MAAM,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,GAAG,UAAU,CAAC;IAC7C,MAAM,iBAAiB,GAAG,IAAA,uBAAO,EAA+B,GAAG,CAAC,CAAC;IACrE,MAAM,kBAAkB,GAAG,8BAA8B;QACvD,CAAC,CAAC,8BAA8B,CAAC,GAAG,CAAC;QACrC,CAAC,CAAC,+BAA+B,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,wBAAwB,GAAG,WAAW,CAAC;IAC7C,MAAM,mBAAmB,GAAG,MAAM,CAAC;IAEnC,OAAO;QACL,GAAG,MAAM;QACT,GAAG,0BAA0B,CAAC,kBAAkB,EAAE,wBAAwB,CAAC;QAC3E,GAAG,0BAA0B,CAAC,iBAAiB,EAAE,mBAAmB,CAAC;KACtE,CAAC;AACJ,CAAC;AAjBD,8CAiBC;AAED,SAAgB,+BAA+B,CAAC,GAAkB;IAChE,OAAO;QACL,KAAK,EAAE,GAAG,CAAC,KAAe;QAC1B,aAAa,EAAE,GAAG,CAAC,cAAyB;QAC5C,QAAQ,EAAE,GAAG,CAAC,QAAkB;QAChC,MAAM,EAAE,GAAG,CAAC,MAAgB;KAC7B,CAAC;AACJ,CAAC;AAPD,0EAOC;AAED,SAAgB,0BAA0B,CAAC,MAA+B,EAAE,MAAc;IACxF,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,cAAc,EAAE,UAAU,EAAE,EAAE;QAC/D,cAAc,CAAC,GAAG,MAAM,GAAG,UAAU,EAAE,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;QAC9D,OAAO,cAAc,CAAC;IACxB,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC;AALD,gEAKC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** DISCLAIMER - THIS CODE BELONGS TO https://github.com/hughsk/flat */
|
|
2
|
+
export interface FlattenOptions {
|
|
3
|
+
delimiter?: string;
|
|
4
|
+
maxDepth?: number;
|
|
5
|
+
safe?: boolean;
|
|
6
|
+
transformKey?: (key: string) => string;
|
|
7
|
+
}
|
|
8
|
+
export declare function flatten<TTraget, TResult>(target: TTraget, opts?: FlattenOptions): TResult;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.flatten = void 0;
|
|
4
|
+
function flatten(target, opts) {
|
|
5
|
+
opts = opts || {};
|
|
6
|
+
const delimiter = (opts === null || opts === void 0 ? void 0 : opts.delimiter) || '.';
|
|
7
|
+
const maxDepth = opts === null || opts === void 0 ? void 0 : opts.maxDepth;
|
|
8
|
+
const transformKey = (opts === null || opts === void 0 ? void 0 : opts.transformKey) || keyIdentity;
|
|
9
|
+
const output = {};
|
|
10
|
+
function step(object, prev, currentDepth) {
|
|
11
|
+
currentDepth = currentDepth || 1;
|
|
12
|
+
Object.keys(object).forEach(function (key) {
|
|
13
|
+
const value = object[key];
|
|
14
|
+
const isarray = (opts === null || opts === void 0 ? void 0 : opts.safe) && Array.isArray(value);
|
|
15
|
+
const type = Object.prototype.toString.call(value);
|
|
16
|
+
const isbuffer = isBuffer(value);
|
|
17
|
+
const isobject = type === '[object Object]' || type === '[object Array]';
|
|
18
|
+
const newKey = prev ? prev + delimiter + transformKey(key) : transformKey(key);
|
|
19
|
+
if (!isarray &&
|
|
20
|
+
!isbuffer &&
|
|
21
|
+
isobject &&
|
|
22
|
+
Object.keys(value).length &&
|
|
23
|
+
(!(opts === null || opts === void 0 ? void 0 : opts.maxDepth) || (maxDepth && currentDepth < maxDepth))) {
|
|
24
|
+
return step(value, newKey, currentDepth + 1);
|
|
25
|
+
}
|
|
26
|
+
output[newKey] = value;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
step(target);
|
|
30
|
+
return output;
|
|
31
|
+
}
|
|
32
|
+
exports.flatten = flatten;
|
|
33
|
+
function isBuffer(obj) {
|
|
34
|
+
return obj && obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj);
|
|
35
|
+
}
|
|
36
|
+
function keyIdentity(key) {
|
|
37
|
+
return key;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=flatten.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flatten.utils.js","sourceRoot":"","sources":["../../src/user-entitlements/flatten.utils.ts"],"names":[],"mappings":";;;AAQA,SAAgB,OAAO,CAAmB,MAAe,EAAE,IAAqB;IAC9E,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;IAElB,MAAM,SAAS,GAAG,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,SAAS,KAAI,GAAG,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,QAAQ,CAAC;IAChC,MAAM,YAAY,GAAG,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,YAAY,KAAI,WAAW,CAAC;IACvD,MAAM,MAAM,GAAG,EAAE,CAAC;IAElB,SAAS,IAAI,CAAC,MAAM,EAAE,IAAK,EAAE,YAAa;QACxC,YAAY,GAAG,YAAY,IAAI,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,UAAU,GAAG;YACvC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAC1B,MAAM,OAAO,GAAG,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,IAAI,KAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACnD,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnD,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;YACjC,MAAM,QAAQ,GAAG,IAAI,KAAK,iBAAiB,IAAI,IAAI,KAAK,gBAAgB,CAAC;YAEzE,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;YAC/E,IACE,CAAC,OAAO;gBACR,CAAC,QAAQ;gBACT,QAAQ;gBACR,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM;gBACzB,CAAC,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,QAAQ,CAAA,IAAI,CAAC,QAAQ,IAAI,YAAY,GAAG,QAAQ,CAAC,CAAC,EAC1D;gBACA,OAAO,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,GAAG,CAAC,CAAC,CAAC;aAC9C;YAED,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,CAAC;IAEb,OAAO,MAAiB,CAAC;AAC3B,CAAC;AAnCD,0BAmCC;AAED,SAAS,QAAQ,CAAC,GAAG;IACnB,OAAO,GAAG,IAAI,GAAG,CAAC,WAAW,IAAI,OAAO,GAAG,CAAC,WAAW,CAAC,QAAQ,KAAK,UAAU,IAAI,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACnH,CAAC;AAED,SAAS,WAAW,CAAC,GAAG;IACtB,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -16,4 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./is-entitled.evaluator"), exports);
|
|
18
18
|
__exportStar(require("./types"), exports);
|
|
19
|
+
__exportStar(require("./attributes.utils"), exports);
|
|
20
|
+
__exportStar(require("./permissions.utils"), exports);
|
|
19
21
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/user-entitlements/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC;AACxC,0CAAwB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/user-entitlements/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC;AACxC,0CAAwB;AACxB,qDAAmC;AACnC,sDAAoC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function evaluateIsEntitledToFeature(featureKey: string, userEntitlementsContext: UserEntitlementsContext, attributes?:
|
|
3
|
-
export declare function evaluateIsEntitledToPermissions(permissionKey: string, userEntitlementsContext: UserEntitlementsContext, attributes?:
|
|
1
|
+
import { EntitlementResult, UserEntitlementsContext, Attributes } from './types';
|
|
2
|
+
export declare function evaluateIsEntitledToFeature(featureKey: string, userEntitlementsContext: UserEntitlementsContext, attributes?: Attributes): EntitlementResult;
|
|
3
|
+
export declare function evaluateIsEntitledToPermissions(permissionKey: string, userEntitlementsContext: UserEntitlementsContext, attributes?: Attributes): EntitlementResult;
|
|
@@ -3,7 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.evaluateIsEntitledToPermissions = exports.evaluateIsEntitledToFeature = void 0;
|
|
4
4
|
const types_1 = require("./types");
|
|
5
5
|
const feature_flags_1 = require("../feature-flags");
|
|
6
|
+
const attributes_utils_1 = require("./attributes.utils");
|
|
6
7
|
const rules_1 = require("../rules");
|
|
8
|
+
const permissions_utils_1 = require("./permissions.utils");
|
|
7
9
|
function evaluateIsEntitledToFeature(featureKey, userEntitlementsContext, attributes = {}) {
|
|
8
10
|
const feature = userEntitlementsContext.features[featureKey];
|
|
9
11
|
let hasExpired = false;
|
|
@@ -14,17 +16,21 @@ function evaluateIsEntitledToFeature(featureKey, userEntitlementsContext, attrib
|
|
|
14
16
|
}
|
|
15
17
|
}
|
|
16
18
|
if (feature && feature.featureFlag) {
|
|
17
|
-
const
|
|
19
|
+
const preparedAttributes = (0, attributes_utils_1.prepareAttributes)(attributes);
|
|
20
|
+
const { treatment } = (0, feature_flags_1.evaluateFeatureFlag)(feature.featureFlag, preparedAttributes);
|
|
18
21
|
if (treatment === rules_1.TreatmentEnum.True) {
|
|
19
22
|
return { isEntitled: true };
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
|
-
return {
|
|
25
|
+
return {
|
|
26
|
+
isEntitled: false,
|
|
27
|
+
justification: hasExpired ? types_1.NotEntitledJustification.BUNDLE_EXPIRED : types_1.NotEntitledJustification.MISSING_FEATURE,
|
|
28
|
+
};
|
|
23
29
|
}
|
|
24
30
|
exports.evaluateIsEntitledToFeature = evaluateIsEntitledToFeature;
|
|
25
|
-
function evaluateIsEntitledToPermissions(permissionKey, userEntitlementsContext, attributes
|
|
26
|
-
const
|
|
27
|
-
if (!
|
|
31
|
+
function evaluateIsEntitledToPermissions(permissionKey, userEntitlementsContext, attributes) {
|
|
32
|
+
const hasPermission = (0, permissions_utils_1.checkPermission)(userEntitlementsContext.permissions, permissionKey);
|
|
33
|
+
if (!hasPermission) {
|
|
28
34
|
return { isEntitled: false, justification: types_1.NotEntitledJustification.MISSING_PERMISSION };
|
|
29
35
|
}
|
|
30
36
|
const linkedFeatures = getLinkedFeatures(permissionKey, userEntitlementsContext);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-entitled.evaluator.js","sourceRoot":"","sources":["../../src/user-entitlements/is-entitled.evaluator.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"is-entitled.evaluator.js","sourceRoot":"","sources":["../../src/user-entitlements/is-entitled.evaluator.ts"],"names":[],"mappings":";;;AAAA,mCAMiB;AAEjB,oDAAuD;AACvD,yDAAuD;AACvD,oCAAyC;AACzC,2DAAsD;AACtD,SAAgB,2BAA2B,CACzC,UAAkB,EAClB,uBAAgD,EAChD,aAAyB,EAAE;IAE3B,MAAM,OAAO,GAAG,uBAAuB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC7D,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,OAAO,IAAI,OAAO,CAAC,UAAU,KAAK,IAAI,EAAE;QAC1C,UAAU,GAAG,OAAO,CAAC,UAAU,KAAK,0BAAkB,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE1F,IAAI,CAAC,UAAU,EAAE;YACf,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;SAC7B;KACF;IAED,IAAI,OAAO,IAAI,OAAO,CAAC,WAAW,EAAE;QAClC,MAAM,kBAAkB,GAAG,IAAA,oCAAiB,EAAC,UAAU,CAAC,CAAC;QACzD,MAAM,EAAE,SAAS,EAAE,GAAG,IAAA,mCAAmB,EAAC,OAAO,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;QACnF,IAAI,SAAS,KAAK,qBAAa,CAAC,IAAI,EAAE;YACpC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;SAC7B;KACF;IAED,OAAO;QACL,UAAU,EAAE,KAAK;QACjB,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,gCAAwB,CAAC,cAAc,CAAC,CAAC,CAAC,gCAAwB,CAAC,eAAe;KAC/G,CAAC;AACJ,CAAC;AA3BD,kEA2BC;AAED,SAAgB,+BAA+B,CAC7C,aAAqB,EACrB,uBAAgD,EAChD,UAAuB;IAEvB,MAAM,aAAa,GAAG,IAAA,mCAAe,EAAC,uBAAuB,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC1F,IAAI,CAAC,aAAa,EAAE;QAClB,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,gCAAwB,CAAC,kBAAkB,EAAE,CAAC;KAC1F;IAED,MAAM,cAAc,GAAG,iBAAiB,CAAC,aAAa,EAAE,uBAAuB,CAAC,CAAC;IAEjF,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE;QAC1B,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;KAC7B;IAED,IAAI,UAAU,GAAG,KAAK,CAAC;IAEvB,KAAK,MAAM,UAAU,IAAI,cAAc,EAAE;QACvC,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,2BAA2B,CAAC,UAAU,EAAE,uBAAuB,EAAE,UAAU,CAAC,CAAC;QAEnH,IAAI,UAAU,EAAE;YACd,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;SAC7B;QAED,IAAI,aAAa,KAAK,gCAAwB,CAAC,cAAc,EAAE;YAC7D,UAAU,GAAG,IAAI,CAAC;SACnB;KACF;IAED,OAAO;QACL,UAAU,EAAE,KAAK;QACjB,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,gCAAwB,CAAC,cAAc,CAAC,CAAC,CAAC,gCAAwB,CAAC,eAAe;KAC/G,CAAC;AACJ,CAAC;AAlCD,0EAkCC;AAED,SAAS,iBAAiB,CAAC,aAAqB,EAAE,uBAAgD;IAChG,OAAO,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CACzE,uBAAuB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,aAAa,CAAC,CACvF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createPermissionCheckRegex = exports.checkPermission = void 0;
|
|
4
|
+
function checkPermission(permissions, requiredPermission) {
|
|
5
|
+
return Object.keys(permissions).some((permissionKey) => createPermissionCheckRegex(permissionKey).test(requiredPermission));
|
|
6
|
+
}
|
|
7
|
+
exports.checkPermission = checkPermission;
|
|
8
|
+
function createPermissionCheckRegex(permissionKey) {
|
|
9
|
+
return new RegExp('^' + permissionKey.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$', 'gs');
|
|
10
|
+
}
|
|
11
|
+
exports.createPermissionCheckRegex = createPermissionCheckRegex;
|
|
12
|
+
//# sourceMappingURL=permissions.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.utils.js","sourceRoot":"","sources":["../../src/user-entitlements/permissions.utils.ts"],"names":[],"mappings":";;;AACA,SAAgB,eAAe,CAAC,WAAwB,EAAE,kBAA0B;IAClF,OAAO,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,EAAE,CACrD,0BAA0B,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CACnE,CAAC;AACJ,CAAC;AAJD,0CAIC;AAED,SAAgB,0BAA0B,CAAC,aAAqB;IAC9D,OAAO,IAAI,MAAM,CAAC,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,GAAG,EAAE,IAAI,CAAC,CAAC;AAChG,CAAC;AAFD,gEAEC"}
|
|
@@ -5,7 +5,7 @@ export type UserEntitlementsContext = {
|
|
|
5
5
|
linkedPermissions: string[];
|
|
6
6
|
featureFlag?: FeatureFlag;
|
|
7
7
|
}>;
|
|
8
|
-
permissions:
|
|
8
|
+
permissions: Permissions;
|
|
9
9
|
};
|
|
10
10
|
export type EntitlementResult = {
|
|
11
11
|
isEntitled: boolean;
|
|
@@ -17,4 +17,16 @@ export declare enum NotEntitledJustification {
|
|
|
17
17
|
BUNDLE_EXPIRED = "BUNDLE_EXPIRED"
|
|
18
18
|
}
|
|
19
19
|
export type CustomAttributes = Record<string, string | number | boolean | Date>;
|
|
20
|
+
export type FronteggAttributes = {
|
|
21
|
+
tenantId?: string;
|
|
22
|
+
userId?: string;
|
|
23
|
+
email?: string;
|
|
24
|
+
emailVerified?: boolean;
|
|
25
|
+
};
|
|
26
|
+
export type Permissions = Record<string, true>;
|
|
27
|
+
export type Attributes = {
|
|
28
|
+
custom?: CustomAttributes;
|
|
29
|
+
jwt?: JwtAttributes;
|
|
30
|
+
};
|
|
31
|
+
export type JwtAttributes = Record<string, unknown>;
|
|
20
32
|
export declare const NO_EXPIRATION_TIME = -1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/user-entitlements/types.ts"],"names":[],"mappings":";;;AAkBA,IAAY,wBAIX;AAJD,WAAY,wBAAwB;IAClC,+DAAmC,CAAA;IACnC,qEAAyC,CAAA;IACzC,6DAAiC,CAAA;AACnC,CAAC,EAJW,wBAAwB,GAAxB,gCAAwB,KAAxB,gCAAwB,QAInC;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/user-entitlements/types.ts"],"names":[],"mappings":";;;AAkBA,IAAY,wBAIX;AAJD,WAAY,wBAAwB;IAClC,+DAAmC,CAAA;IACnC,qEAAyC,CAAA;IACzC,6DAAiC,CAAA;AACnC,CAAC,EAJW,wBAAwB,GAAxB,gCAAwB,KAAxB,gCAAwB,QAInC;AAaY,QAAA,kBAAkB,GAAG,CAAC,CAAC,CAAC"}
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,100 @@
|
|
|
1
|
+
# 1.0.0 (2023-10-31)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* fix export order ([#16](https://github.com/frontegg/entitlements-javascript-commons/issues/16)) ([d7fafa4](https://github.com/frontegg/entitlements-javascript-commons/commit/d7fafa427e5f99fffe541f9fa78fd9b7507045c3))
|
|
7
|
+
* **date:** fix incorrect sanitizers mapping ([#25](https://github.com/frontegg/entitlements-javascript-commons/issues/25)) ([da08f16](https://github.com/frontegg/entitlements-javascript-commons/commit/da08f1628753b1794422c83327670ae09242ec11))
|
|
8
|
+
* **dep:** remove flat dependency ([e8a2daf](https://github.com/frontegg/entitlements-javascript-commons/commit/e8a2dafde0612ebfacc8e2d7e346d189276e5f72))
|
|
9
|
+
* **sanitizers:** fix numeric and date sanitizers ([#24](https://github.com/frontegg/entitlements-javascript-commons/issues/24)) ([8f5717a](https://github.com/frontegg/entitlements-javascript-commons/commit/8f5717acdcc0a1eccae84b272c7a02e315131a01))
|
|
10
|
+
* **string:** fix string sanitizers type to match opertaions ([#21](https://github.com/frontegg/entitlements-javascript-commons/issues/21)) ([4461155](https://github.com/frontegg/entitlements-javascript-commons/commit/4461155e53c0ef6f647ff4bc0215804667b52928))
|
|
11
|
+
* **user-entitlements:** exported utility function ([4d81b3e](https://github.com/frontegg/entitlements-javascript-commons/commit/4d81b3e04b1de59047c6b5911f09391a4ccafcb9))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* additional (handy) exports that SDKs might use to interact with feature flags (FR-13491) ([a7d1fc2](https://github.com/frontegg/entitlements-javascript-commons/commit/a7d1fc2f596cf379d10cb34ae7aa55a7111c1244))
|
|
17
|
+
* create pipeline and release infra ([16fd6d1](https://github.com/frontegg/entitlements-javascript-commons/commit/16fd6d165cff4c3ae28e2392db2480d41dd591b1))
|
|
18
|
+
* **conditions:** add condition evaluator ([#5](https://github.com/frontegg/entitlements-javascript-commons/issues/5)) ([5ca2446](https://github.com/frontegg/entitlements-javascript-commons/commit/5ca24465a76b9fa103977e5600a6d870da5520cb))
|
|
19
|
+
* **feature-flags:** add feature flag evaluation ([#11](https://github.com/frontegg/entitlements-javascript-commons/issues/11)) ([94679a1](https://github.com/frontegg/entitlements-javascript-commons/commit/94679a123581cd4977fd9f2087adc9e2532a638c))
|
|
20
|
+
* **operations:** add numeric operations ([#3](https://github.com/frontegg/entitlements-javascript-commons/issues/3)) ([#10](https://github.com/frontegg/entitlements-javascript-commons/issues/10)) ([0b3de2f](https://github.com/frontegg/entitlements-javascript-commons/commit/0b3de2f7f1aede036ec63e4fadf898dcf5ad32a4))
|
|
21
|
+
* **operations:** add string operations ([#2](https://github.com/frontegg/entitlements-javascript-commons/issues/2)) ([e2e63a7](https://github.com/frontegg/entitlements-javascript-commons/commit/e2e63a74211a723dc326918e42e2093fcca86779))
|
|
22
|
+
* **rule:** add rule evaluator ([#6](https://github.com/frontegg/entitlements-javascript-commons/issues/6)) ([5fbf4da](https://github.com/frontegg/entitlements-javascript-commons/commit/5fbf4da00a3d9df2908d8899723a64b1bd80a7c2))
|
|
23
|
+
* **sanitizers:** add value sanitizers ([#12](https://github.com/frontegg/entitlements-javascript-commons/issues/12)) ([1decf2c](https://github.com/frontegg/entitlements-javascript-commons/commit/1decf2c01e0a86055bc856db5ff115a2318f1c59))
|
|
24
|
+
* **user-entitlements:** add frontegg attributes ([878f4aa](https://github.com/frontegg/entitlements-javascript-commons/commit/878f4aa5f284fc2dd27ffae63ed9c0c74b2c8adb))
|
|
25
|
+
* **user-entitlements:** add frontegg attributes ([b1c3e30](https://github.com/frontegg/entitlements-javascript-commons/commit/b1c3e30e420e8972167087c5745ef49ac0c6b859))
|
|
26
|
+
* **user-entitlements:** add missing types ([fd375c1](https://github.com/frontegg/entitlements-javascript-commons/commit/fd375c15fea40ddbf8e259a73f8831fa9dbb763e))
|
|
27
|
+
* **user-entitlements:** add user entitlements evaluation logic ([d924a05](https://github.com/frontegg/entitlements-javascript-commons/commit/d924a056498b4b040dd765b262cde42201644653))
|
|
28
|
+
* **user-entitlements:** export function signature parameters types ([2207986](https://github.com/frontegg/entitlements-javascript-commons/commit/220798611a91875e594c83f76baed6c18f5ac19a))
|
|
29
|
+
* **user-entitlements:** export types ([06f6f13](https://github.com/frontegg/entitlements-javascript-commons/commit/06f6f13263bcfecc098290da35b310393bcecda4))
|
|
30
|
+
* **user-entitlements:** handle jwt attributes ([cc0ce70](https://github.com/frontegg/entitlements-javascript-commons/commit/cc0ce70f4c3ebf2b3b410865d740c23ab1d0d9ed))
|
|
31
|
+
* **user-entitlements:** introduce wildcard to permission check ([986ba21](https://github.com/frontegg/entitlements-javascript-commons/commit/986ba213cbf88aef99495e3fd6fc2bf1203ec7e6))
|
|
32
|
+
|
|
33
|
+
# [1.0.0-alpha.17](https://github.com/frontegg/entitlements-javascript-commons/compare/v-1.0.0-alpha.16...v-1.0.0-alpha.17) (2023-10-30)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
### Bug Fixes
|
|
37
|
+
|
|
38
|
+
* **user-entitlements:** exported utility function ([4d81b3e](https://github.com/frontegg/entitlements-javascript-commons/commit/4d81b3e04b1de59047c6b5911f09391a4ccafcb9))
|
|
39
|
+
|
|
40
|
+
# [1.0.0-alpha.16](https://github.com/frontegg/entitlements-javascript-commons/compare/v-1.0.0-alpha.15...v-1.0.0-alpha.16) (2023-10-30)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### Features
|
|
44
|
+
|
|
45
|
+
* **user-entitlements:** introduce wildcard to permission check ([986ba21](https://github.com/frontegg/entitlements-javascript-commons/commit/986ba213cbf88aef99495e3fd6fc2bf1203ec7e6))
|
|
46
|
+
|
|
47
|
+
# [1.0.0-alpha.15](https://github.com/frontegg/entitlements-javascript-commons/compare/v-1.0.0-alpha.14...v-1.0.0-alpha.15) (2023-10-25)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
### Bug Fixes
|
|
51
|
+
|
|
52
|
+
* **date:** fix incorrect sanitizers mapping ([#25](https://github.com/frontegg/entitlements-javascript-commons/issues/25)) ([da08f16](https://github.com/frontegg/entitlements-javascript-commons/commit/da08f1628753b1794422c83327670ae09242ec11))
|
|
53
|
+
|
|
54
|
+
# [1.0.0-alpha.14](https://github.com/frontegg/entitlements-javascript-commons/compare/v-1.0.0-alpha.13...v-1.0.0-alpha.14) (2023-10-24)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
### Bug Fixes
|
|
58
|
+
|
|
59
|
+
* **sanitizers:** fix numeric and date sanitizers ([#24](https://github.com/frontegg/entitlements-javascript-commons/issues/24)) ([8f5717a](https://github.com/frontegg/entitlements-javascript-commons/commit/8f5717acdcc0a1eccae84b272c7a02e315131a01))
|
|
60
|
+
|
|
61
|
+
# [1.0.0-alpha.13](https://github.com/frontegg/entitlements-javascript-commons/compare/v-1.0.0-alpha.12...v-1.0.0-alpha.13) (2023-10-22)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
### Bug Fixes
|
|
65
|
+
|
|
66
|
+
* **dep:** remove flat dependency ([e8a2daf](https://github.com/frontegg/entitlements-javascript-commons/commit/e8a2dafde0612ebfacc8e2d7e346d189276e5f72))
|
|
67
|
+
|
|
68
|
+
# [1.0.0-alpha.12](https://github.com/frontegg/entitlements-javascript-commons/compare/v-1.0.0-alpha.11...v-1.0.0-alpha.12) (2023-10-18)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
### Bug Fixes
|
|
72
|
+
|
|
73
|
+
* **string:** fix string sanitizers type to match opertaions ([#21](https://github.com/frontegg/entitlements-javascript-commons/issues/21)) ([4461155](https://github.com/frontegg/entitlements-javascript-commons/commit/4461155e53c0ef6f647ff4bc0215804667b52928))
|
|
74
|
+
|
|
75
|
+
# [1.0.0-alpha.11](https://github.com/frontegg/entitlements-javascript-commons/compare/v-1.0.0-alpha.10...v-1.0.0-alpha.11) (2023-10-17)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
### Features
|
|
79
|
+
|
|
80
|
+
* **user-entitlements:** handle jwt attributes ([cc0ce70](https://github.com/frontegg/entitlements-javascript-commons/commit/cc0ce70f4c3ebf2b3b410865d740c23ab1d0d9ed))
|
|
81
|
+
|
|
82
|
+
# [1.0.0-alpha.10](https://github.com/frontegg/entitlements-javascript-commons/compare/v-1.0.0-alpha.9...v-1.0.0-alpha.10) (2023-10-12)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
### Features
|
|
86
|
+
|
|
87
|
+
* **user-entitlements:** add missing types ([fd375c1](https://github.com/frontegg/entitlements-javascript-commons/commit/fd375c15fea40ddbf8e259a73f8831fa9dbb763e))
|
|
88
|
+
* **user-entitlements:** export types ([06f6f13](https://github.com/frontegg/entitlements-javascript-commons/commit/06f6f13263bcfecc098290da35b310393bcecda4))
|
|
89
|
+
|
|
90
|
+
# [1.0.0-alpha.9](https://github.com/frontegg/entitlements-javascript-commons/compare/v-1.0.0-alpha.8...v-1.0.0-alpha.9) (2023-10-12)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
### Features
|
|
94
|
+
|
|
95
|
+
* **user-entitlements:** add frontegg attributes ([878f4aa](https://github.com/frontegg/entitlements-javascript-commons/commit/878f4aa5f284fc2dd27ffae63ed9c0c74b2c8adb))
|
|
96
|
+
* **user-entitlements:** add frontegg attributes ([b1c3e30](https://github.com/frontegg/entitlements-javascript-commons/commit/b1c3e30e420e8972167087c5745ef49ac0c6b859))
|
|
97
|
+
|
|
1
98
|
# [1.0.0-alpha.8](https://github.com/frontegg/entitlements-javascript-commons/compare/v-1.0.0-alpha.7...v-1.0.0-alpha.8) (2023-10-11)
|
|
2
99
|
|
|
3
100
|
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -5,8 +5,15 @@ export { OperationEnum, ConditionValue } from './operations/types';
|
|
|
5
5
|
export {
|
|
6
6
|
evaluateIsEntitledToFeature,
|
|
7
7
|
evaluateIsEntitledToPermissions,
|
|
8
|
+
prepareAttributes,
|
|
9
|
+
checkPermission,
|
|
10
|
+
createPermissionCheckRegex,
|
|
11
|
+
Permissions,
|
|
12
|
+
JwtAttributes,
|
|
8
13
|
CustomAttributes,
|
|
14
|
+
FronteggAttributes,
|
|
9
15
|
NotEntitledJustification,
|
|
10
16
|
UserEntitlementsContext,
|
|
11
17
|
EntitlementResult,
|
|
18
|
+
Attributes,
|
|
12
19
|
} from './user-entitlements';
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import { OperationEnum, Sanitizer, SanitizersMapper } from '../types';
|
|
2
2
|
import { BetweenDateOperationPayload, DateOperationPayload, SingleDateOperationPayload } from './types';
|
|
3
3
|
|
|
4
|
+
type RawDateValue = Date | string | number;
|
|
5
|
+
|
|
6
|
+
export const sanitizeDateValue = (value: Date | string | number): Date => {
|
|
7
|
+
return new Date(value);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const isValidDate = (value: unknown): boolean => value instanceof Date && !isNaN(value as unknown as number);
|
|
11
|
+
|
|
4
12
|
export const sanitizeSingleDate: Sanitizer<SingleDateOperationPayload> = (value) => {
|
|
5
|
-
const
|
|
13
|
+
const sanitizedDateValue = value.date ? sanitizeDateValue(value.date as RawDateValue) : undefined;
|
|
14
|
+
const sanitizedValue =
|
|
15
|
+
sanitizedDateValue && isValidDate(sanitizedDateValue) ? { date: sanitizedDateValue } : undefined;
|
|
6
16
|
|
|
7
17
|
return {
|
|
8
18
|
isSanitized: !!sanitizedValue,
|
|
@@ -11,7 +21,12 @@ export const sanitizeSingleDate: Sanitizer<SingleDateOperationPayload> = (value)
|
|
|
11
21
|
};
|
|
12
22
|
|
|
13
23
|
export const sanitizeDateRange: Sanitizer<BetweenDateOperationPayload> = (value) => {
|
|
14
|
-
const
|
|
24
|
+
const sanitizedStartValue = value.start ? sanitizeDateValue(value.start as RawDateValue) : undefined;
|
|
25
|
+
const sanitizedEndValue = value.end ? sanitizeDateValue(value.end as RawDateValue) : undefined;
|
|
26
|
+
const sanitizedValue =
|
|
27
|
+
sanitizedStartValue && sanitizedEndValue && isValidDate(sanitizedStartValue) && isValidDate(sanitizedEndValue)
|
|
28
|
+
? { start: sanitizedStartValue, end: sanitizedEndValue }
|
|
29
|
+
: undefined;
|
|
15
30
|
|
|
16
31
|
return {
|
|
17
32
|
isSanitized: !!sanitizedValue,
|
|
@@ -21,7 +36,7 @@ export const sanitizeDateRange: Sanitizer<BetweenDateOperationPayload> = (value)
|
|
|
21
36
|
|
|
22
37
|
export const DateSanitizersMapper: SanitizersMapper<DateOperationPayload> = {
|
|
23
38
|
[OperationEnum.On]: sanitizeSingleDate,
|
|
24
|
-
[OperationEnum.OnOrAfter]:
|
|
39
|
+
[OperationEnum.OnOrAfter]: sanitizeSingleDate,
|
|
25
40
|
[OperationEnum.OnOrBefore]: sanitizeSingleDate,
|
|
26
|
-
[OperationEnum.BetweenDate]:
|
|
41
|
+
[OperationEnum.BetweenDate]: sanitizeDateRange,
|
|
27
42
|
};
|
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import { fc, test } from '@fast-check/jest';
|
|
2
|
-
import { sanitizeDateRange, sanitizeSingleDate } from '../sanitizers';
|
|
2
|
+
import { isValidDate, sanitizeDateRange, sanitizeDateValue, sanitizeSingleDate } from '../sanitizers';
|
|
3
3
|
|
|
4
4
|
describe('Date sanitizers', () => {
|
|
5
|
+
it.each([['2021-01-01'], ['2023-10-23T12:09:17.502Z'], [123432443], [new Date()]])(
|
|
6
|
+
'should return sanitized date when value is a string',
|
|
7
|
+
(value) => {
|
|
8
|
+
const sanitizationResult = sanitizeDateValue(value);
|
|
9
|
+
|
|
10
|
+
expect(sanitizationResult).toBeDefined();
|
|
11
|
+
expect(sanitizationResult).toEqual(new Date(value));
|
|
12
|
+
},
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
it.each([['not a date'], [], {}, [undefined]])('should return invalid date when value is not a date', (value) => {
|
|
16
|
+
const sanitizationResult = sanitizeDateValue(value as any);
|
|
17
|
+
|
|
18
|
+
expect(sanitizationResult).toBeDefined();
|
|
19
|
+
expect(isValidDate(sanitizationResult)).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
|
|
5
22
|
test.prop([fc.record({ date: fc.date() })], { verbose: true })(
|
|
6
23
|
'should return sanitized when date value exists',
|
|
7
24
|
(value) => {
|
|
@@ -26,9 +26,9 @@ export const sanitizeNumericRange: Sanitizer<BetweenNumericOperationPayload> = (
|
|
|
26
26
|
|
|
27
27
|
export const NumericSanitizersMapper: SanitizersMapper<NumericOperationPayload> = {
|
|
28
28
|
[OperationEnum.Equal]: sanitizeSingleNumber,
|
|
29
|
-
[OperationEnum.GreaterThan]:
|
|
29
|
+
[OperationEnum.GreaterThan]: sanitizeSingleNumber,
|
|
30
30
|
[OperationEnum.GreaterThanEqual]: sanitizeSingleNumber,
|
|
31
31
|
[OperationEnum.LesserThan]: sanitizeSingleNumber,
|
|
32
|
-
[OperationEnum.LesserThanEqual]:
|
|
32
|
+
[OperationEnum.LesserThanEqual]: sanitizeSingleNumber,
|
|
33
33
|
[OperationEnum.BetweenNumeric]: sanitizeNumericRange,
|
|
34
34
|
};
|
|
@@ -27,7 +27,7 @@ export const sanitizeListString: Sanitizer<ListStringOperationPayload> = (value)
|
|
|
27
27
|
export const StringSanitizersMapper: SanitizersMapper<StringOperationPayload> = {
|
|
28
28
|
[OperationEnum.Matches]: sanitizeSingleString,
|
|
29
29
|
[OperationEnum.Contains]: sanitizeListString,
|
|
30
|
-
[OperationEnum.StartsWith]:
|
|
31
|
-
[OperationEnum.EndsWith]:
|
|
30
|
+
[OperationEnum.StartsWith]: sanitizeListString,
|
|
31
|
+
[OperationEnum.EndsWith]: sanitizeListString,
|
|
32
32
|
[OperationEnum.InList]: sanitizeListString,
|
|
33
33
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Attributes, JwtAttributes, FronteggAttributes } from './types';
|
|
2
|
+
import { flatten } from './flatten.utils';
|
|
3
|
+
/**
|
|
4
|
+
* Merges both `custom` and `jwt` records, map Frontegg attributes and modifies record keys with corrisponding prefixes
|
|
5
|
+
*
|
|
6
|
+
* Example:
|
|
7
|
+
* Input: { 'custom': { 'customAttribute': 'someValue' }, 'jwt': { 'email': 'user@email.com', other: 'some-vaule' } }
|
|
8
|
+
* Output: { 'customAttribute': 'someValue', 'frontegg.email': 'user@email.com', 'jwt.email': 'user@email.com', 'jwt.other': 'some-vaule' }
|
|
9
|
+
*/
|
|
10
|
+
export function prepareAttributes(
|
|
11
|
+
attributes: Attributes = {},
|
|
12
|
+
customFronteggAttributesMapper?: (jwtAttributes: JwtAttributes) => FronteggAttributes,
|
|
13
|
+
): Record<string, unknown> {
|
|
14
|
+
const { custom = {}, jwt = {} } = attributes;
|
|
15
|
+
const flatJwtAttributes = flatten<JwtAttributes, JwtAttributes>(jwt);
|
|
16
|
+
const fronteggAttributes = customFronteggAttributesMapper
|
|
17
|
+
? customFronteggAttributesMapper(jwt)
|
|
18
|
+
: defaultFronteggAttributesMapper(jwt);
|
|
19
|
+
const fronteggAttributesPrefix = 'frontegg.';
|
|
20
|
+
const jwtAttributesPrefix = 'jwt.';
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
...custom,
|
|
24
|
+
...modifyObjectKeysWithPrefix(fronteggAttributes, fronteggAttributesPrefix),
|
|
25
|
+
...modifyObjectKeysWithPrefix(flatJwtAttributes, jwtAttributesPrefix),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function defaultFronteggAttributesMapper(jwt: JwtAttributes): FronteggAttributes {
|
|
30
|
+
return {
|
|
31
|
+
email: jwt.email as string,
|
|
32
|
+
emailVerified: jwt.email_verified as boolean,
|
|
33
|
+
tenantId: jwt.tenantId as string,
|
|
34
|
+
userId: jwt.userId as string,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function modifyObjectKeysWithPrefix(object: Record<string, unknown>, prefix: string): Record<string, unknown> {
|
|
39
|
+
return Object.keys(object).reduce((modifiedObject, currentKey) => {
|
|
40
|
+
modifiedObject[`${prefix}${currentKey}`] = object[currentKey];
|
|
41
|
+
return modifiedObject;
|
|
42
|
+
}, {});
|
|
43
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** DISCLAIMER - THIS CODE BELONGS TO https://github.com/hughsk/flat */
|
|
2
|
+
export interface FlattenOptions {
|
|
3
|
+
delimiter?: string;
|
|
4
|
+
maxDepth?: number;
|
|
5
|
+
safe?: boolean;
|
|
6
|
+
transformKey?: (key: string) => string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function flatten<TTraget, TResult>(target: TTraget, opts?: FlattenOptions): TResult {
|
|
10
|
+
opts = opts || {};
|
|
11
|
+
|
|
12
|
+
const delimiter = opts?.delimiter || '.';
|
|
13
|
+
const maxDepth = opts?.maxDepth;
|
|
14
|
+
const transformKey = opts?.transformKey || keyIdentity;
|
|
15
|
+
const output = {};
|
|
16
|
+
|
|
17
|
+
function step(object, prev?, currentDepth?) {
|
|
18
|
+
currentDepth = currentDepth || 1;
|
|
19
|
+
Object.keys(object).forEach(function (key) {
|
|
20
|
+
const value = object[key];
|
|
21
|
+
const isarray = opts?.safe && Array.isArray(value);
|
|
22
|
+
const type = Object.prototype.toString.call(value);
|
|
23
|
+
const isbuffer = isBuffer(value);
|
|
24
|
+
const isobject = type === '[object Object]' || type === '[object Array]';
|
|
25
|
+
|
|
26
|
+
const newKey = prev ? prev + delimiter + transformKey(key) : transformKey(key);
|
|
27
|
+
if (
|
|
28
|
+
!isarray &&
|
|
29
|
+
!isbuffer &&
|
|
30
|
+
isobject &&
|
|
31
|
+
Object.keys(value).length &&
|
|
32
|
+
(!opts?.maxDepth || (maxDepth && currentDepth < maxDepth))
|
|
33
|
+
) {
|
|
34
|
+
return step(value, newKey, currentDepth + 1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
output[newKey] = value;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
step(target);
|
|
42
|
+
|
|
43
|
+
return output as TResult;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function isBuffer(obj) {
|
|
47
|
+
return obj && obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function keyIdentity(key) {
|
|
51
|
+
return key;
|
|
52
|
+
}
|
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
EntitlementResult,
|
|
3
|
+
NotEntitledJustification,
|
|
4
|
+
NO_EXPIRATION_TIME,
|
|
5
|
+
UserEntitlementsContext,
|
|
6
|
+
Attributes,
|
|
7
|
+
} from './types';
|
|
8
|
+
|
|
2
9
|
import { evaluateFeatureFlag } from '../feature-flags';
|
|
10
|
+
import { prepareAttributes } from './attributes.utils';
|
|
3
11
|
import { TreatmentEnum } from '../rules';
|
|
12
|
+
import { checkPermission } from './permissions.utils';
|
|
4
13
|
export function evaluateIsEntitledToFeature(
|
|
5
14
|
featureKey: string,
|
|
6
15
|
userEntitlementsContext: UserEntitlementsContext,
|
|
7
|
-
attributes:
|
|
16
|
+
attributes: Attributes = {},
|
|
8
17
|
): EntitlementResult {
|
|
9
18
|
const feature = userEntitlementsContext.features[featureKey];
|
|
10
|
-
|
|
11
19
|
let hasExpired = false;
|
|
12
20
|
if (feature && feature.expireTime !== null) {
|
|
13
21
|
hasExpired = feature.expireTime !== NO_EXPIRATION_TIME && feature.expireTime < Date.now();
|
|
@@ -18,23 +26,26 @@ export function evaluateIsEntitledToFeature(
|
|
|
18
26
|
}
|
|
19
27
|
|
|
20
28
|
if (feature && feature.featureFlag) {
|
|
21
|
-
const
|
|
29
|
+
const preparedAttributes = prepareAttributes(attributes);
|
|
30
|
+
const { treatment } = evaluateFeatureFlag(feature.featureFlag, preparedAttributes);
|
|
22
31
|
if (treatment === TreatmentEnum.True) {
|
|
23
32
|
return { isEntitled: true };
|
|
24
33
|
}
|
|
25
34
|
}
|
|
26
35
|
|
|
27
|
-
return {
|
|
36
|
+
return {
|
|
37
|
+
isEntitled: false,
|
|
38
|
+
justification: hasExpired ? NotEntitledJustification.BUNDLE_EXPIRED : NotEntitledJustification.MISSING_FEATURE,
|
|
39
|
+
};
|
|
28
40
|
}
|
|
29
41
|
|
|
30
42
|
export function evaluateIsEntitledToPermissions(
|
|
31
43
|
permissionKey: string,
|
|
32
44
|
userEntitlementsContext: UserEntitlementsContext,
|
|
33
|
-
attributes
|
|
45
|
+
attributes?: Attributes,
|
|
34
46
|
): EntitlementResult {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
if (!permission) {
|
|
47
|
+
const hasPermission = checkPermission(userEntitlementsContext.permissions, permissionKey);
|
|
48
|
+
if (!hasPermission) {
|
|
38
49
|
return { isEntitled: false, justification: NotEntitledJustification.MISSING_PERMISSION };
|
|
39
50
|
}
|
|
40
51
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Permissions } from './types';
|
|
2
|
+
export function checkPermission(permissions: Permissions, requiredPermission: string): boolean {
|
|
3
|
+
return Object.keys(permissions).some((permissionKey) =>
|
|
4
|
+
createPermissionCheckRegex(permissionKey).test(requiredPermission),
|
|
5
|
+
);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function createPermissionCheckRegex(permissionKey: string): RegExp {
|
|
9
|
+
return new RegExp('^' + permissionKey.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$', 'gs');
|
|
10
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as AttributesUtils from '../attributes.utils';
|
|
2
|
+
import { Attributes, FronteggAttributes, JwtAttributes } from '../types';
|
|
3
|
+
describe('prepareAttributes', () => {
|
|
4
|
+
test('given custom & jwt attributes, expected is merged & flatten attributes record', () => {
|
|
5
|
+
const attributes: Attributes = {
|
|
6
|
+
custom: {
|
|
7
|
+
customAttribute: 'some-value',
|
|
8
|
+
},
|
|
9
|
+
jwt: {
|
|
10
|
+
userId: 'user-1',
|
|
11
|
+
tenantId: 'tenant-1',
|
|
12
|
+
email: 'test@email.com',
|
|
13
|
+
email_verified: true,
|
|
14
|
+
dummyAttribute: 'dummy',
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const expectedPreparedAttributes = {
|
|
19
|
+
customAttribute: 'some-value',
|
|
20
|
+
'frontegg.userId': 'user-1',
|
|
21
|
+
'frontegg.tenantId': 'tenant-1',
|
|
22
|
+
'frontegg.email': 'test@email.com',
|
|
23
|
+
'frontegg.emailVerified': true,
|
|
24
|
+
'jwt.userId': 'user-1',
|
|
25
|
+
'jwt.tenantId': 'tenant-1',
|
|
26
|
+
'jwt.email': 'test@email.com',
|
|
27
|
+
'jwt.email_verified': true,
|
|
28
|
+
'jwt.dummyAttribute': 'dummy',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const preparedAttributes = AttributesUtils.prepareAttributes(attributes);
|
|
32
|
+
|
|
33
|
+
expect(preparedAttributes).toEqual(expectedPreparedAttributes);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('defaultFronteggAttributesMapper', () => {
|
|
38
|
+
test('given jwt-attributes, expected mapped frontegg-attributes', async () => {
|
|
39
|
+
const jwtAttributes: JwtAttributes = {
|
|
40
|
+
userId: 'user-1',
|
|
41
|
+
tenantId: 'tenant-1',
|
|
42
|
+
email: 'test@email.com',
|
|
43
|
+
email_verified: true,
|
|
44
|
+
dummyAttribute: 'dummy',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const expectedFronteggAttributes: FronteggAttributes = {
|
|
48
|
+
userId: 'user-1',
|
|
49
|
+
tenantId: 'tenant-1',
|
|
50
|
+
email: 'test@email.com',
|
|
51
|
+
emailVerified: true,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const mappedAttributes = AttributesUtils.defaultFronteggAttributesMapper(jwtAttributes);
|
|
55
|
+
|
|
56
|
+
expect(mappedAttributes).toEqual(expectedFronteggAttributes);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe('modifyObjectKeysWithPrefix', () => {
|
|
61
|
+
test('given object and prefix, object keys should altered with prefix', async () => {
|
|
62
|
+
const prefix = 'test.';
|
|
63
|
+
const obj = {
|
|
64
|
+
property: 'value',
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const expectedModifiedObject = {
|
|
68
|
+
'test.property': 'value',
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const modifiedObject = AttributesUtils.modifyObjectKeysWithPrefix(obj, prefix);
|
|
72
|
+
|
|
73
|
+
expect(modifiedObject).toEqual(expectedModifiedObject);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import * as FeatureFlags from '../../feature-flags/feature-flag.evaluator';
|
|
2
1
|
import * as IsEntitledEvaluators from '../is-entitled.evaluator';
|
|
2
|
+
import * as FeatureFlagEvalutor from '../../feature-flags/feature-flag.evaluator';
|
|
3
|
+
import * as AttributesUtils from '../attributes.utils';
|
|
3
4
|
import { TreatmentEnum } from '../../rules';
|
|
4
5
|
import { EntitlementResult, NotEntitledJustification, NO_EXPIRATION_TIME, UserEntitlementsContext } from '../types';
|
|
5
6
|
import { FeatureFlag } from '../../feature-flags/types';
|
|
7
|
+
|
|
6
8
|
const mockFeatureFlag: FeatureFlag = {
|
|
7
9
|
on: true,
|
|
8
10
|
defaultTreatment: TreatmentEnum.True,
|
|
@@ -25,10 +27,13 @@ const falsyEntitlementResultMissingPermission: EntitlementResult = {
|
|
|
25
27
|
justification: NotEntitledJustification.MISSING_PERMISSION,
|
|
26
28
|
};
|
|
27
29
|
describe('evaluateIsEntitledToFeature', () => {
|
|
30
|
+
beforeAll(() => {
|
|
31
|
+
jest.spyOn(AttributesUtils, 'prepareAttributes').mockReturnValue({ testAttribute: 'test-value' });
|
|
32
|
+
});
|
|
28
33
|
describe('entitled', () => {
|
|
29
34
|
describe('feature-flag evaluated truthy', () => {
|
|
30
35
|
beforeAll(async () => {
|
|
31
|
-
jest.spyOn(
|
|
36
|
+
jest.spyOn(FeatureFlagEvalutor, 'evaluateFeatureFlag').mockReturnValue({ treatment: TreatmentEnum.True });
|
|
32
37
|
});
|
|
33
38
|
|
|
34
39
|
test('feature granted with valid expiration date', async () => {
|
|
@@ -94,7 +99,7 @@ describe('evaluateIsEntitledToFeature', () => {
|
|
|
94
99
|
});
|
|
95
100
|
describe('feature-flag evaluated falsy', () => {
|
|
96
101
|
beforeAll(async () => {
|
|
97
|
-
jest.spyOn(
|
|
102
|
+
jest.spyOn(FeatureFlagEvalutor, 'evaluateFeatureFlag').mockReturnValue({ treatment: TreatmentEnum.False });
|
|
98
103
|
});
|
|
99
104
|
test('feature granted with no expiration date', async () => {
|
|
100
105
|
const userEntitlementContext: UserEntitlementsContext = {
|
|
@@ -162,7 +167,7 @@ describe('evaluateIsEntitledToFeature', () => {
|
|
|
162
167
|
describe('not entitled', () => {
|
|
163
168
|
describe('feature-flag evaluated falsy', () => {
|
|
164
169
|
beforeAll(async () => {
|
|
165
|
-
jest.spyOn(
|
|
170
|
+
jest.spyOn(FeatureFlagEvalutor, 'evaluateFeatureFlag').mockReturnValue({ treatment: TreatmentEnum.False });
|
|
166
171
|
});
|
|
167
172
|
test('feature has not been granted', async () => {
|
|
168
173
|
const userEntitlementContext: UserEntitlementsContext = {
|
|
@@ -170,6 +175,7 @@ describe('evaluateIsEntitledToFeature', () => {
|
|
|
170
175
|
'test-feature': {
|
|
171
176
|
expireTime: null,
|
|
172
177
|
linkedPermissions: [],
|
|
178
|
+
featureFlag: mockFeatureFlag,
|
|
173
179
|
},
|
|
174
180
|
},
|
|
175
181
|
permissions: {},
|
|
@@ -184,6 +190,7 @@ describe('evaluateIsEntitledToFeature', () => {
|
|
|
184
190
|
'test-feature': {
|
|
185
191
|
expireTime: Date.now() - 3600,
|
|
186
192
|
linkedPermissions: [],
|
|
193
|
+
featureFlag: mockFeatureFlag,
|
|
187
194
|
},
|
|
188
195
|
},
|
|
189
196
|
permissions: {},
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Permissions } from '../types';
|
|
2
|
+
import { checkPermission } from '../permissions.utils';
|
|
3
|
+
describe('checkPermission', () => {
|
|
4
|
+
test.each([[{ 'test.permission': true }], [{ 'test.*': true }], [{ '*': true }]])(
|
|
5
|
+
'expected truthy result',
|
|
6
|
+
(permissions) => {
|
|
7
|
+
const requiredPermission = 'test.permission';
|
|
8
|
+
const result = checkPermission(permissions as Permissions, requiredPermission);
|
|
9
|
+
expect(result).toBeTruthy();
|
|
10
|
+
},
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
test.each([[{}], [{ 'test.permission.read': true }], [{ 'test.permission.write.*': true }]])(
|
|
14
|
+
'expected falsy result',
|
|
15
|
+
(permissions) => {
|
|
16
|
+
const requiredPermission = 'test.permission';
|
|
17
|
+
const result = checkPermission(permissions as Permissions, requiredPermission);
|
|
18
|
+
expect(result).toBeFalsy();
|
|
19
|
+
},
|
|
20
|
+
);
|
|
21
|
+
});
|
|
@@ -8,7 +8,7 @@ export type UserEntitlementsContext = {
|
|
|
8
8
|
featureFlag?: FeatureFlag;
|
|
9
9
|
}
|
|
10
10
|
>;
|
|
11
|
-
permissions:
|
|
11
|
+
permissions: Permissions;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export type EntitlementResult = {
|
|
@@ -24,4 +24,13 @@ export enum NotEntitledJustification {
|
|
|
24
24
|
|
|
25
25
|
export type CustomAttributes = Record<string, string | number | boolean | Date>;
|
|
26
26
|
|
|
27
|
+
export type FronteggAttributes = {
|
|
28
|
+
tenantId?: string;
|
|
29
|
+
userId?: string;
|
|
30
|
+
email?: string;
|
|
31
|
+
emailVerified?: boolean;
|
|
32
|
+
};
|
|
33
|
+
export type Permissions = Record<string, true>;
|
|
34
|
+
export type Attributes = { custom?: CustomAttributes; jwt?: JwtAttributes };
|
|
35
|
+
export type JwtAttributes = Record<string, unknown>;
|
|
27
36
|
export const NO_EXPIRATION_TIME = -1;
|