@frontegg/entitlements-javascript-commons 1.0.0-alpha.9 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +0 -8
- package/dist/user-entitlements/is-entitled.evaluator.js +8 -24
- 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 +5 -4
- package/dist/user-entitlements/types.js.map +1 -1
- package/docs/CHANGELOG.md +96 -0
- package/package.json +1 -1
- package/src/index.ts +6 -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 +8 -25
- 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 +12 -29
- package/src/user-entitlements/tests/permissions.utils.spec.ts +21 -0
- package/src/user-entitlements/types.ts +5 -6
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, FronteggAttributes, 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.id,
|
|
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,EAAY;KACzB,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,11 +1,3 @@
|
|
|
1
1
|
import { EntitlementResult, UserEntitlementsContext, Attributes } from './types';
|
|
2
2
|
export declare function evaluateIsEntitledToFeature(featureKey: string, userEntitlementsContext: UserEntitlementsContext, attributes?: Attributes): EntitlementResult;
|
|
3
3
|
export declare function evaluateIsEntitledToPermissions(permissionKey: string, userEntitlementsContext: UserEntitlementsContext, attributes?: Attributes): EntitlementResult;
|
|
4
|
-
/**
|
|
5
|
-
* Merges the `custom` and `frontegg` Records into a single Record,
|
|
6
|
-
* Alters the `frontegg` Record keys with a prefix
|
|
7
|
-
* Example:
|
|
8
|
-
* Input: { 'custom': { 'customAttribute': 'someValue' }, 'frontegg': { 'email': 'user@email.com' } }
|
|
9
|
-
* Output: { 'customAttribute': 'someValue', 'imported.email': 'user@email.com' }
|
|
10
|
-
*/
|
|
11
|
-
export declare function prepareAttributes(attributes?: Attributes): Record<string, unknown>;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
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");
|
|
7
|
-
|
|
8
|
+
const permissions_utils_1 = require("./permissions.utils");
|
|
9
|
+
function evaluateIsEntitledToFeature(featureKey, userEntitlementsContext, attributes = {}) {
|
|
8
10
|
const feature = userEntitlementsContext.features[featureKey];
|
|
9
11
|
let hasExpired = false;
|
|
10
12
|
if (feature && feature.expireTime !== null) {
|
|
@@ -14,7 +16,8 @@ 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
|
}
|
|
@@ -26,8 +29,8 @@ function evaluateIsEntitledToFeature(featureKey, userEntitlementsContext, attrib
|
|
|
26
29
|
}
|
|
27
30
|
exports.evaluateIsEntitledToFeature = evaluateIsEntitledToFeature;
|
|
28
31
|
function evaluateIsEntitledToPermissions(permissionKey, userEntitlementsContext, attributes) {
|
|
29
|
-
const
|
|
30
|
-
if (!
|
|
32
|
+
const hasPermission = (0, permissions_utils_1.checkPermission)(userEntitlementsContext.permissions, permissionKey);
|
|
33
|
+
if (!hasPermission) {
|
|
31
34
|
return { isEntitled: false, justification: types_1.NotEntitledJustification.MISSING_PERMISSION };
|
|
32
35
|
}
|
|
33
36
|
const linkedFeatures = getLinkedFeatures(permissionKey, userEntitlementsContext);
|
|
@@ -53,23 +56,4 @@ exports.evaluateIsEntitledToPermissions = evaluateIsEntitledToPermissions;
|
|
|
53
56
|
function getLinkedFeatures(permissionKey, userEntitlementsContext) {
|
|
54
57
|
return Object.keys(userEntitlementsContext.features).filter((featureKey) => userEntitlementsContext.features[featureKey].linkedPermissions.includes(permissionKey));
|
|
55
58
|
}
|
|
56
|
-
/**
|
|
57
|
-
* Merges the `custom` and `frontegg` Records into a single Record,
|
|
58
|
-
* Alters the `frontegg` Record keys with a prefix
|
|
59
|
-
* Example:
|
|
60
|
-
* Input: { 'custom': { 'customAttribute': 'someValue' }, 'frontegg': { 'email': 'user@email.com' } }
|
|
61
|
-
* Output: { 'customAttribute': 'someValue', 'imported.email': 'user@email.com' }
|
|
62
|
-
*/
|
|
63
|
-
function prepareAttributes(attributes = {}) {
|
|
64
|
-
const { custom = {}, frontegg = {} } = attributes;
|
|
65
|
-
const importedAttributesPrefix = 'imported.'; // Not Final
|
|
66
|
-
return {
|
|
67
|
-
...custom,
|
|
68
|
-
...Object.keys(frontegg).reduce((modifiedImportedAttributes, key) => {
|
|
69
|
-
modifiedImportedAttributes[`${importedAttributesPrefix}${key}`] = frontegg[key];
|
|
70
|
-
return modifiedImportedAttributes;
|
|
71
|
-
}, {}),
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
exports.prepareAttributes = prepareAttributes;
|
|
75
59
|
//# sourceMappingURL=is-entitled.evaluator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-entitled.evaluator.js","sourceRoot":"","sources":["../../src/user-entitlements/is-entitled.evaluator.ts"],"names":[],"mappings":";;;AAAA,mCAMiB;
|
|
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;
|
|
@@ -21,11 +21,12 @@ export type FronteggAttributes = {
|
|
|
21
21
|
tenantId?: string;
|
|
22
22
|
userId?: string;
|
|
23
23
|
email?: string;
|
|
24
|
-
|
|
25
|
-
[unmappedAttribute: string]: unknown;
|
|
24
|
+
emailVerified?: boolean;
|
|
26
25
|
};
|
|
26
|
+
export type Permissions = Record<string, true>;
|
|
27
27
|
export type Attributes = {
|
|
28
28
|
custom?: CustomAttributes;
|
|
29
|
-
|
|
29
|
+
jwt?: JwtAttributes;
|
|
30
30
|
};
|
|
31
|
+
export type JwtAttributes = Record<string, unknown>;
|
|
31
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,99 @@
|
|
|
1
|
+
## [1.0.1](https://github.com/frontegg/entitlements-javascript-commons/compare/v-1.0.0...v-1.0.1) (2023-11-06)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **user-entitlements:** fix mapper for frontegg userId ([8095488](https://github.com/frontegg/entitlements-javascript-commons/commit/809548805898c3b2c6bfc853ee2421361a16628b))
|
|
7
|
+
|
|
8
|
+
# 1.0.0 (2023-10-31)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* fix export order ([#16](https://github.com/frontegg/entitlements-javascript-commons/issues/16)) ([d7fafa4](https://github.com/frontegg/entitlements-javascript-commons/commit/d7fafa427e5f99fffe541f9fa78fd9b7507045c3))
|
|
14
|
+
* **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))
|
|
15
|
+
* **dep:** remove flat dependency ([e8a2daf](https://github.com/frontegg/entitlements-javascript-commons/commit/e8a2dafde0612ebfacc8e2d7e346d189276e5f72))
|
|
16
|
+
* **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))
|
|
17
|
+
* **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))
|
|
18
|
+
* **user-entitlements:** exported utility function ([4d81b3e](https://github.com/frontegg/entitlements-javascript-commons/commit/4d81b3e04b1de59047c6b5911f09391a4ccafcb9))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
* additional (handy) exports that SDKs might use to interact with feature flags (FR-13491) ([a7d1fc2](https://github.com/frontegg/entitlements-javascript-commons/commit/a7d1fc2f596cf379d10cb34ae7aa55a7111c1244))
|
|
24
|
+
* create pipeline and release infra ([16fd6d1](https://github.com/frontegg/entitlements-javascript-commons/commit/16fd6d165cff4c3ae28e2392db2480d41dd591b1))
|
|
25
|
+
* **conditions:** add condition evaluator ([#5](https://github.com/frontegg/entitlements-javascript-commons/issues/5)) ([5ca2446](https://github.com/frontegg/entitlements-javascript-commons/commit/5ca24465a76b9fa103977e5600a6d870da5520cb))
|
|
26
|
+
* **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))
|
|
27
|
+
* **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))
|
|
28
|
+
* **operations:** add string operations ([#2](https://github.com/frontegg/entitlements-javascript-commons/issues/2)) ([e2e63a7](https://github.com/frontegg/entitlements-javascript-commons/commit/e2e63a74211a723dc326918e42e2093fcca86779))
|
|
29
|
+
* **rule:** add rule evaluator ([#6](https://github.com/frontegg/entitlements-javascript-commons/issues/6)) ([5fbf4da](https://github.com/frontegg/entitlements-javascript-commons/commit/5fbf4da00a3d9df2908d8899723a64b1bd80a7c2))
|
|
30
|
+
* **sanitizers:** add value sanitizers ([#12](https://github.com/frontegg/entitlements-javascript-commons/issues/12)) ([1decf2c](https://github.com/frontegg/entitlements-javascript-commons/commit/1decf2c01e0a86055bc856db5ff115a2318f1c59))
|
|
31
|
+
* **user-entitlements:** add frontegg attributes ([878f4aa](https://github.com/frontegg/entitlements-javascript-commons/commit/878f4aa5f284fc2dd27ffae63ed9c0c74b2c8adb))
|
|
32
|
+
* **user-entitlements:** add frontegg attributes ([b1c3e30](https://github.com/frontegg/entitlements-javascript-commons/commit/b1c3e30e420e8972167087c5745ef49ac0c6b859))
|
|
33
|
+
* **user-entitlements:** add missing types ([fd375c1](https://github.com/frontegg/entitlements-javascript-commons/commit/fd375c15fea40ddbf8e259a73f8831fa9dbb763e))
|
|
34
|
+
* **user-entitlements:** add user entitlements evaluation logic ([d924a05](https://github.com/frontegg/entitlements-javascript-commons/commit/d924a056498b4b040dd765b262cde42201644653))
|
|
35
|
+
* **user-entitlements:** export function signature parameters types ([2207986](https://github.com/frontegg/entitlements-javascript-commons/commit/220798611a91875e594c83f76baed6c18f5ac19a))
|
|
36
|
+
* **user-entitlements:** export types ([06f6f13](https://github.com/frontegg/entitlements-javascript-commons/commit/06f6f13263bcfecc098290da35b310393bcecda4))
|
|
37
|
+
* **user-entitlements:** handle jwt attributes ([cc0ce70](https://github.com/frontegg/entitlements-javascript-commons/commit/cc0ce70f4c3ebf2b3b410865d740c23ab1d0d9ed))
|
|
38
|
+
* **user-entitlements:** introduce wildcard to permission check ([986ba21](https://github.com/frontegg/entitlements-javascript-commons/commit/986ba213cbf88aef99495e3fd6fc2bf1203ec7e6))
|
|
39
|
+
|
|
40
|
+
# [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)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### Bug Fixes
|
|
44
|
+
|
|
45
|
+
* **user-entitlements:** exported utility function ([4d81b3e](https://github.com/frontegg/entitlements-javascript-commons/commit/4d81b3e04b1de59047c6b5911f09391a4ccafcb9))
|
|
46
|
+
|
|
47
|
+
# [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)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
### Features
|
|
51
|
+
|
|
52
|
+
* **user-entitlements:** introduce wildcard to permission check ([986ba21](https://github.com/frontegg/entitlements-javascript-commons/commit/986ba213cbf88aef99495e3fd6fc2bf1203ec7e6))
|
|
53
|
+
|
|
54
|
+
# [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)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
### Bug Fixes
|
|
58
|
+
|
|
59
|
+
* **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))
|
|
60
|
+
|
|
61
|
+
# [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)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
### Bug Fixes
|
|
65
|
+
|
|
66
|
+
* **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))
|
|
67
|
+
|
|
68
|
+
# [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)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
### Bug Fixes
|
|
72
|
+
|
|
73
|
+
* **dep:** remove flat dependency ([e8a2daf](https://github.com/frontegg/entitlements-javascript-commons/commit/e8a2dafde0612ebfacc8e2d7e346d189276e5f72))
|
|
74
|
+
|
|
75
|
+
# [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)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
### Bug Fixes
|
|
79
|
+
|
|
80
|
+
* **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))
|
|
81
|
+
|
|
82
|
+
# [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)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
### Features
|
|
86
|
+
|
|
87
|
+
* **user-entitlements:** handle jwt attributes ([cc0ce70](https://github.com/frontegg/entitlements-javascript-commons/commit/cc0ce70f4c3ebf2b3b410865d740c23ab1d0d9ed))
|
|
88
|
+
|
|
89
|
+
# [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)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
### Features
|
|
93
|
+
|
|
94
|
+
* **user-entitlements:** add missing types ([fd375c1](https://github.com/frontegg/entitlements-javascript-commons/commit/fd375c15fea40ddbf8e259a73f8831fa9dbb763e))
|
|
95
|
+
* **user-entitlements:** export types ([06f6f13](https://github.com/frontegg/entitlements-javascript-commons/commit/06f6f13263bcfecc098290da35b310393bcecda4))
|
|
96
|
+
|
|
1
97
|
# [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)
|
|
2
98
|
|
|
3
99
|
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -5,9 +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,
|
|
9
14
|
FronteggAttributes,
|
|
10
15
|
NotEntitledJustification,
|
|
11
16
|
UserEntitlementsContext,
|
|
12
17
|
EntitlementResult,
|
|
18
|
+
Attributes,
|
|
13
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.id 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
|
+
}
|
|
@@ -5,12 +5,15 @@ import {
|
|
|
5
5
|
UserEntitlementsContext,
|
|
6
6
|
Attributes,
|
|
7
7
|
} from './types';
|
|
8
|
+
|
|
8
9
|
import { evaluateFeatureFlag } from '../feature-flags';
|
|
10
|
+
import { prepareAttributes } from './attributes.utils';
|
|
9
11
|
import { TreatmentEnum } from '../rules';
|
|
12
|
+
import { checkPermission } from './permissions.utils';
|
|
10
13
|
export function evaluateIsEntitledToFeature(
|
|
11
14
|
featureKey: string,
|
|
12
15
|
userEntitlementsContext: UserEntitlementsContext,
|
|
13
|
-
attributes
|
|
16
|
+
attributes: Attributes = {},
|
|
14
17
|
): EntitlementResult {
|
|
15
18
|
const feature = userEntitlementsContext.features[featureKey];
|
|
16
19
|
let hasExpired = false;
|
|
@@ -23,7 +26,8 @@ export function evaluateIsEntitledToFeature(
|
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
if (feature && feature.featureFlag) {
|
|
26
|
-
const
|
|
29
|
+
const preparedAttributes = prepareAttributes(attributes);
|
|
30
|
+
const { treatment } = evaluateFeatureFlag(feature.featureFlag, preparedAttributes);
|
|
27
31
|
if (treatment === TreatmentEnum.True) {
|
|
28
32
|
return { isEntitled: true };
|
|
29
33
|
}
|
|
@@ -40,9 +44,8 @@ export function evaluateIsEntitledToPermissions(
|
|
|
40
44
|
userEntitlementsContext: UserEntitlementsContext,
|
|
41
45
|
attributes?: Attributes,
|
|
42
46
|
): EntitlementResult {
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
if (!permission) {
|
|
47
|
+
const hasPermission = checkPermission(userEntitlementsContext.permissions, permissionKey);
|
|
48
|
+
if (!hasPermission) {
|
|
46
49
|
return { isEntitled: false, justification: NotEntitledJustification.MISSING_PERMISSION };
|
|
47
50
|
}
|
|
48
51
|
|
|
@@ -77,23 +80,3 @@ function getLinkedFeatures(permissionKey: string, userEntitlementsContext: UserE
|
|
|
77
80
|
userEntitlementsContext.features[featureKey].linkedPermissions.includes(permissionKey),
|
|
78
81
|
);
|
|
79
82
|
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Merges the `custom` and `frontegg` Records into a single Record,
|
|
83
|
-
* Alters the `frontegg` Record keys with a prefix
|
|
84
|
-
* Example:
|
|
85
|
-
* Input: { 'custom': { 'customAttribute': 'someValue' }, 'frontegg': { 'email': 'user@email.com' } }
|
|
86
|
-
* Output: { 'customAttribute': 'someValue', 'imported.email': 'user@email.com' }
|
|
87
|
-
*/
|
|
88
|
-
export function prepareAttributes(attributes: Attributes = {}): Record<string, unknown> {
|
|
89
|
-
const { custom = {}, frontegg = {} } = attributes;
|
|
90
|
-
const importedAttributesPrefix = 'imported.'; // Not Final
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
...custom,
|
|
94
|
-
...Object.keys(frontegg).reduce((modifiedImportedAttributes, key) => {
|
|
95
|
-
modifiedImportedAttributes[`${importedAttributesPrefix}${key}`] = frontegg[key];
|
|
96
|
-
return modifiedImportedAttributes;
|
|
97
|
-
}, {}),
|
|
98
|
-
};
|
|
99
|
-
}
|
|
@@ -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
|
+
id: '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.id': '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
|
+
id: '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,14 +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
|
-
import {
|
|
5
|
-
EntitlementResult,
|
|
6
|
-
NotEntitledJustification,
|
|
7
|
-
NO_EXPIRATION_TIME,
|
|
8
|
-
UserEntitlementsContext,
|
|
9
|
-
Attributes,
|
|
10
|
-
} from '../types';
|
|
5
|
+
import { EntitlementResult, NotEntitledJustification, NO_EXPIRATION_TIME, UserEntitlementsContext } from '../types';
|
|
11
6
|
import { FeatureFlag } from '../../feature-flags/types';
|
|
7
|
+
|
|
12
8
|
const mockFeatureFlag: FeatureFlag = {
|
|
13
9
|
on: true,
|
|
14
10
|
defaultTreatment: TreatmentEnum.True,
|
|
@@ -31,10 +27,13 @@ const falsyEntitlementResultMissingPermission: EntitlementResult = {
|
|
|
31
27
|
justification: NotEntitledJustification.MISSING_PERMISSION,
|
|
32
28
|
};
|
|
33
29
|
describe('evaluateIsEntitledToFeature', () => {
|
|
30
|
+
beforeAll(() => {
|
|
31
|
+
jest.spyOn(AttributesUtils, 'prepareAttributes').mockReturnValue({ testAttribute: 'test-value' });
|
|
32
|
+
});
|
|
34
33
|
describe('entitled', () => {
|
|
35
34
|
describe('feature-flag evaluated truthy', () => {
|
|
36
35
|
beforeAll(async () => {
|
|
37
|
-
jest.spyOn(
|
|
36
|
+
jest.spyOn(FeatureFlagEvalutor, 'evaluateFeatureFlag').mockReturnValue({ treatment: TreatmentEnum.True });
|
|
38
37
|
});
|
|
39
38
|
|
|
40
39
|
test('feature granted with valid expiration date', async () => {
|
|
@@ -100,7 +99,7 @@ describe('evaluateIsEntitledToFeature', () => {
|
|
|
100
99
|
});
|
|
101
100
|
describe('feature-flag evaluated falsy', () => {
|
|
102
101
|
beforeAll(async () => {
|
|
103
|
-
jest.spyOn(
|
|
102
|
+
jest.spyOn(FeatureFlagEvalutor, 'evaluateFeatureFlag').mockReturnValue({ treatment: TreatmentEnum.False });
|
|
104
103
|
});
|
|
105
104
|
test('feature granted with no expiration date', async () => {
|
|
106
105
|
const userEntitlementContext: UserEntitlementsContext = {
|
|
@@ -168,7 +167,7 @@ describe('evaluateIsEntitledToFeature', () => {
|
|
|
168
167
|
describe('not entitled', () => {
|
|
169
168
|
describe('feature-flag evaluated falsy', () => {
|
|
170
169
|
beforeAll(async () => {
|
|
171
|
-
jest.spyOn(
|
|
170
|
+
jest.spyOn(FeatureFlagEvalutor, 'evaluateFeatureFlag').mockReturnValue({ treatment: TreatmentEnum.False });
|
|
172
171
|
});
|
|
173
172
|
test('feature has not been granted', async () => {
|
|
174
173
|
const userEntitlementContext: UserEntitlementsContext = {
|
|
@@ -176,6 +175,7 @@ describe('evaluateIsEntitledToFeature', () => {
|
|
|
176
175
|
'test-feature': {
|
|
177
176
|
expireTime: null,
|
|
178
177
|
linkedPermissions: [],
|
|
178
|
+
featureFlag: mockFeatureFlag,
|
|
179
179
|
},
|
|
180
180
|
},
|
|
181
181
|
permissions: {},
|
|
@@ -190,6 +190,7 @@ describe('evaluateIsEntitledToFeature', () => {
|
|
|
190
190
|
'test-feature': {
|
|
191
191
|
expireTime: Date.now() - 3600,
|
|
192
192
|
linkedPermissions: [],
|
|
193
|
+
featureFlag: mockFeatureFlag,
|
|
193
194
|
},
|
|
194
195
|
},
|
|
195
196
|
permissions: {},
|
|
@@ -295,21 +296,3 @@ describe('evaluateIsEntitledToPermission', () => {
|
|
|
295
296
|
expect(result).toEqual(falsyEntitlementResultBundleExpired);
|
|
296
297
|
});
|
|
297
298
|
});
|
|
298
|
-
|
|
299
|
-
describe('prepareAttributes', () => {
|
|
300
|
-
test('given custom & frontegg attributes, expected is merged Record, frontegg attributes altered with prefix', async () => {
|
|
301
|
-
const attributes: Attributes = {
|
|
302
|
-
custom: { testAttribute: 'testValue' },
|
|
303
|
-
frontegg: { email: 'test@email.com', unknownFronteggAttribute: 'unknownFronteggAttribute' },
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
const expectedPreparedAttributes: Record<string, unknown> = {
|
|
307
|
-
testAttribute: 'testValue',
|
|
308
|
-
'imported.email': 'test@email.com',
|
|
309
|
-
'imported.unknownFronteggAttribute': 'unknownFronteggAttribute',
|
|
310
|
-
};
|
|
311
|
-
const preparedAttributes = IsEntitledEvaluators.prepareAttributes(attributes);
|
|
312
|
-
|
|
313
|
-
expect(preparedAttributes).toEqual(expectedPreparedAttributes);
|
|
314
|
-
});
|
|
315
|
-
});
|
|
@@ -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 = {
|
|
@@ -28,10 +28,9 @@ export type FronteggAttributes = {
|
|
|
28
28
|
tenantId?: string;
|
|
29
29
|
userId?: string;
|
|
30
30
|
email?: string;
|
|
31
|
-
|
|
32
|
-
[unmappedAttribute: string]: unknown;
|
|
31
|
+
emailVerified?: boolean;
|
|
33
32
|
};
|
|
34
|
-
|
|
35
|
-
export type Attributes = { custom?: CustomAttributes;
|
|
36
|
-
|
|
33
|
+
export type Permissions = Record<string, true>;
|
|
34
|
+
export type Attributes = { custom?: CustomAttributes; jwt?: JwtAttributes };
|
|
35
|
+
export type JwtAttributes = Record<string, unknown>;
|
|
37
36
|
export const NO_EXPIRATION_TIME = -1;
|