@webiny/app-security 0.0.0-unstable.d7f521b032 → 0.0.0-unstable.de38392959
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/README.md +5 -2
- package/Security.d.ts +2 -2
- package/Security.js +3 -1
- package/Security.js.map +1 -1
- package/components/HasPermission.js +23 -13
- package/components/HasPermission.js.map +1 -1
- package/components/SecureRoute.js +3 -1
- package/components/SecureRoute.js.map +1 -1
- package/components/SecureView.js +3 -1
- package/components/SecureView.js.map +1 -1
- package/components/index.js +3 -1
- package/components/index.js.map +1 -1
- package/contexts/Security.d.ts +8 -2
- package/contexts/Security.js +36 -3
- package/contexts/Security.js.map +1 -1
- package/hooks/usePermission.js +3 -1
- package/hooks/usePermission.js.map +1 -1
- package/hooks/useSecurity.js +3 -1
- package/hooks/useSecurity.js.map +1 -1
- package/index.js +3 -1
- package/index.js.map +1 -1
- package/package.json +16 -17
- package/types.js +3 -1
package/README.md
CHANGED
|
@@ -67,8 +67,11 @@ Auth.configure({
|
|
|
67
67
|
}
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
+
interface AuthenticatorProps {
|
|
71
|
+
children: React.ReactNode;
|
|
72
|
+
}
|
|
70
73
|
// The `Authenticator` component.
|
|
71
|
-
const Authenticator
|
|
74
|
+
const Authenticator = (props: AuthenticatorProps) => {
|
|
72
75
|
const { setIdentity } = useSecurity();
|
|
73
76
|
|
|
74
77
|
useEffect(() => {
|
|
@@ -101,7 +104,7 @@ Finally, use the `useSecurity` React hook in any of your components:
|
|
|
101
104
|
import React from "react";
|
|
102
105
|
import { useSecurity } from "@webiny/app-security";
|
|
103
106
|
|
|
104
|
-
const MyComponent
|
|
107
|
+
const MyComponent = () => {
|
|
105
108
|
const { identity } = useSecurity();
|
|
106
109
|
|
|
107
110
|
if (identity) {
|
package/Security.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const Security:
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare const Security: () => JSX.Element;
|
package/Security.js
CHANGED
package/Security.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["SecurityProviderHOC","Component","SecurityProvider","children","Security"],"sources":["Security.tsx"],"sourcesContent":["// Importing from `app-core` and NOT from `app-admin`, to avoid circular dependency.\n// This can be resolved in a different way, by changing the location of `AppInstaller` component (currently in `app-admin`).\n// But this is a faster solution, as I'm really short on time :)\nimport React from \"react\";\nimport { Provider } from \"@webiny/app\";\nimport { SecurityProvider as ContextProvider } from \"./contexts/Security\";\n\nconst SecurityProviderHOC = (Component: React.
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireDefault","require","_app","_Security","SecurityProviderHOC","Component","SecurityProvider","_ref","children","default","createElement","Security","Provider","hoc","exports"],"sources":["Security.tsx"],"sourcesContent":["// Importing from `app-core` and NOT from `app-admin`, to avoid circular dependency.\n// This can be resolved in a different way, by changing the location of `AppInstaller` component (currently in `app-admin`).\n// But this is a faster solution, as I'm really short on time :)\nimport React from \"react\";\nimport { Provider } from \"@webiny/app\";\nimport { SecurityProvider as ContextProvider } from \"./contexts/Security\";\n\ninterface SecurityProviderProps {\n children: React.ReactNode;\n}\n\nconst SecurityProviderHOC = (Component: React.ComponentType) => {\n return function SecurityProvider({ children }: SecurityProviderProps) {\n return (\n <ContextProvider>\n <Component>{children}</Component>\n </ContextProvider>\n );\n };\n};\n\nexport const Security = () => {\n return <Provider hoc={SecurityProviderHOC} />;\n};\n"],"mappings":";;;;;;;AAGA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,IAAA,GAAAD,OAAA;AACA,IAAAE,SAAA,GAAAF,OAAA;AALA;AACA;AACA;;AASA,IAAMG,mBAAmB,GAAG,SAAtBA,mBAAmBA,CAAIC,SAA8B,EAAK;EAC5D,OAAO,SAASC,gBAAgBA,CAAAC,IAAA,EAAsC;IAAA,IAAnCC,QAAQ,GAAAD,IAAA,CAARC,QAAQ;IACvC,oBACIT,MAAA,CAAAU,OAAA,CAAAC,aAAA,CAACP,SAAA,CAAAG,gBAAe,qBACZP,MAAA,CAAAU,OAAA,CAAAC,aAAA,CAACL,SAAS,QAAEG,QAAoB,CACnB,CAAC;EAE1B,CAAC;AACL,CAAC;AAEM,IAAMG,QAAQ,GAAG,SAAXA,QAAQA,CAAA,EAAS;EAC1B,oBAAOZ,MAAA,CAAAU,OAAA,CAAAC,aAAA,CAACR,IAAA,CAAAU,QAAQ;IAACC,GAAG,EAAET;EAAoB,CAAE,CAAC;AACjD,CAAC;AAACU,OAAA,CAAAH,QAAA,GAAAA,QAAA"}
|
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
value: true
|
|
7
7
|
});
|
|
8
8
|
exports.HasPermission = void 0;
|
|
9
|
-
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
10
9
|
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
|
|
11
10
|
var _react = _interopRequireWildcard(require("react"));
|
|
12
11
|
var _useSecurity2 = require("../hooks/useSecurity");
|
|
@@ -15,21 +14,32 @@ var HasPermission = function HasPermission(_ref) {
|
|
|
15
14
|
var children = _ref.children,
|
|
16
15
|
props = (0, _objectWithoutProperties2.default)(_ref, _excluded);
|
|
17
16
|
var _useSecurity = (0, _useSecurity2.useSecurity)(),
|
|
18
|
-
|
|
17
|
+
getPermissions = _useSecurity.getPermissions;
|
|
18
|
+
if (props.name) {
|
|
19
|
+
var _permissionsCollections = getPermissions(props.name);
|
|
20
|
+
var _hasPermission = _permissionsCollections.length > 0;
|
|
21
|
+
if (_hasPermission) {
|
|
22
|
+
return /*#__PURE__*/_react.default.createElement(_react.Fragment, null, children);
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
19
26
|
if (props.any && props.all) {
|
|
20
27
|
throw new Error("You can use either \"any\" or \"all\", but not both at the same time.");
|
|
21
28
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
var permissions = [].concat((0, _toConsumableArray2.default)(props.any || []), (0, _toConsumableArray2.default)(props.all || [])).map(function (name) {
|
|
26
|
-
return getPermission(name);
|
|
29
|
+
var anyAllPermissions = props.any || props.all || [];
|
|
30
|
+
var permissionsCollections = anyAllPermissions.map(function (name) {
|
|
31
|
+
return getPermissions(name);
|
|
27
32
|
});
|
|
28
|
-
var hasPermission = props.any ?
|
|
29
|
-
return
|
|
30
|
-
}) :
|
|
31
|
-
return
|
|
33
|
+
var hasPermission = props.any ? permissionsCollections.some(function (collection) {
|
|
34
|
+
return collection.length > 0;
|
|
35
|
+
}) : permissionsCollections.every(function (collection) {
|
|
36
|
+
return collection.length > 0;
|
|
32
37
|
});
|
|
33
|
-
|
|
38
|
+
if (hasPermission) {
|
|
39
|
+
return /*#__PURE__*/_react.default.createElement(_react.Fragment, null, children);
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
34
42
|
};
|
|
35
|
-
exports.HasPermission = HasPermission;
|
|
43
|
+
exports.HasPermission = HasPermission;
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=HasPermission.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["HasPermission","children","props","
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_useSecurity2","_excluded","HasPermission","_ref","children","props","_objectWithoutProperties2","default","_useSecurity","useSecurity","getPermissions","name","permissionsCollections","hasPermission","length","createElement","Fragment","any","all","Error","anyAllPermissions","map","some","collection","every","exports"],"sources":["HasPermission.tsx"],"sourcesContent":["import React, { Fragment } from \"react\";\nimport { useSecurity } from \"~/hooks/useSecurity\";\n\ninterface HasPermissionProps {\n any?: string[];\n all?: string[];\n name?: string;\n children: React.ReactNode;\n}\n\nexport const HasPermission = ({ children, ...props }: HasPermissionProps) => {\n const { getPermissions } = useSecurity();\n\n if (props.name) {\n const permissionsCollections = getPermissions(props.name);\n const hasPermission = permissionsCollections.length > 0;\n if (hasPermission) {\n return <Fragment>{children}</Fragment>;\n }\n\n return null;\n }\n\n if (props.any && props.all) {\n throw new Error(`You can use either \"any\" or \"all\", but not both at the same time.`);\n }\n\n const anyAllPermissions = props.any || props.all || [];\n\n const permissionsCollections = anyAllPermissions.map(name => getPermissions(name));\n\n const hasPermission = props.any\n ? permissionsCollections.some(collection => collection.length > 0)\n : permissionsCollections.every(collection => collection.length > 0);\n\n if (hasPermission) {\n return <Fragment>{children}</Fragment>;\n }\n\n return null;\n};\n"],"mappings":";;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,uBAAA,CAAAC,OAAA;AACA,IAAAC,aAAA,GAAAD,OAAA;AAAkD,IAAAE,SAAA;AAS3C,IAAMC,aAAa,GAAG,SAAhBA,aAAaA,CAAAC,IAAA,EAAmD;EAAA,IAA7CC,QAAQ,GAAAD,IAAA,CAARC,QAAQ;IAAKC,KAAK,OAAAC,yBAAA,CAAAC,OAAA,EAAAJ,IAAA,EAAAF,SAAA;EAC9C,IAAAO,YAAA,GAA2B,IAAAC,yBAAW,EAAC,CAAC;IAAhCC,cAAc,GAAAF,YAAA,CAAdE,cAAc;EAEtB,IAAIL,KAAK,CAACM,IAAI,EAAE;IACZ,IAAMC,uBAAsB,GAAGF,cAAc,CAACL,KAAK,CAACM,IAAI,CAAC;IACzD,IAAME,cAAa,GAAGD,uBAAsB,CAACE,MAAM,GAAG,CAAC;IACvD,IAAID,cAAa,EAAE;MACf,oBAAOhB,MAAA,CAAAU,OAAA,CAAAQ,aAAA,CAAClB,MAAA,CAAAmB,QAAQ,QAAEZ,QAAmB,CAAC;IAC1C;IAEA,OAAO,IAAI;EACf;EAEA,IAAIC,KAAK,CAACY,GAAG,IAAIZ,KAAK,CAACa,GAAG,EAAE;IACxB,MAAM,IAAIC,KAAK,wEAAoE,CAAC;EACxF;EAEA,IAAMC,iBAAiB,GAAGf,KAAK,CAACY,GAAG,IAAIZ,KAAK,CAACa,GAAG,IAAI,EAAE;EAEtD,IAAMN,sBAAsB,GAAGQ,iBAAiB,CAACC,GAAG,CAAC,UAAAV,IAAI;IAAA,OAAID,cAAc,CAACC,IAAI,CAAC;EAAA,EAAC;EAElF,IAAME,aAAa,GAAGR,KAAK,CAACY,GAAG,GACzBL,sBAAsB,CAACU,IAAI,CAAC,UAAAC,UAAU;IAAA,OAAIA,UAAU,CAACT,MAAM,GAAG,CAAC;EAAA,EAAC,GAChEF,sBAAsB,CAACY,KAAK,CAAC,UAAAD,UAAU;IAAA,OAAIA,UAAU,CAACT,MAAM,GAAG,CAAC;EAAA,EAAC;EAEvE,IAAID,aAAa,EAAE;IACf,oBAAOhB,MAAA,CAAAU,OAAA,CAAAQ,aAAA,CAAClB,MAAA,CAAAmB,QAAQ,QAAEZ,QAAmB,CAAC;EAC1C;EAEA,OAAO,IAAI;AACf,CAAC;AAACqB,OAAA,CAAAvB,aAAA,GAAAA,aAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["children","permission","security","useSecurity","identity","getPermission","hasPermission","Boolean","plugin","plugins","byName","render"],"sources":["SecureRoute.tsx"],"sourcesContent":["import React from \"react\";\nimport { useSecurity } from \"~/hooks/useSecurity\";\nimport { SecureRouteErrorPlugin } from \"~/types\";\nimport { plugins } from \"@webiny/plugins\";\n\ninterface SecureRouteProps {\n children: React.ReactNode;\n permission?: string;\n}\nexport default ({ children, permission }: SecureRouteProps): React.ReactElement | null => {\n const security = useSecurity();\n\n if (!security) {\n return null;\n }\n\n const { identity, getPermission } = security;\n\n if (!identity) {\n return null;\n }\n\n let hasPermission = false;\n if (identity) {\n hasPermission = permission ? Boolean(getPermission(permission)) : true;\n }\n\n if (hasPermission) {\n return children as unknown as React.ReactElement;\n }\n\n const plugin = plugins.byName<SecureRouteErrorPlugin>(\"secure-route-error\");\n if (!plugin) {\n return null;\n }\n\n return plugin.render();\n};\n"],"mappings":";;;;;;AACA;AAEA;AAA0C,
|
|
1
|
+
{"version":3,"names":["_useSecurity","require","_plugins","_default","_ref","children","permission","security","useSecurity","identity","getPermission","hasPermission","Boolean","plugin","plugins","byName","render","exports","default"],"sources":["SecureRoute.tsx"],"sourcesContent":["import React from \"react\";\nimport { useSecurity } from \"~/hooks/useSecurity\";\nimport { SecureRouteErrorPlugin } from \"~/types\";\nimport { plugins } from \"@webiny/plugins\";\n\ninterface SecureRouteProps {\n children: React.ReactNode;\n permission?: string;\n}\nexport default ({ children, permission }: SecureRouteProps): React.ReactElement | null => {\n const security = useSecurity();\n\n if (!security) {\n return null;\n }\n\n const { identity, getPermission } = security;\n\n if (!identity) {\n return null;\n }\n\n let hasPermission = false;\n if (identity) {\n hasPermission = permission ? Boolean(getPermission(permission)) : true;\n }\n\n if (hasPermission) {\n return children as unknown as React.ReactElement;\n }\n\n const plugin = plugins.byName<SecureRouteErrorPlugin>(\"secure-route-error\");\n if (!plugin) {\n return null;\n }\n\n return plugin.render();\n};\n"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAEA,IAAAC,QAAA,GAAAD,OAAA;AAA0C,IAAAE,QAAA,GAM3B,SAAAA,SAAAC,IAAA,EAA2E;EAAA,IAAxEC,QAAQ,GAAAD,IAAA,CAARC,QAAQ;IAAEC,UAAU,GAAAF,IAAA,CAAVE,UAAU;EAClC,IAAMC,QAAQ,GAAG,IAAAC,wBAAW,EAAC,CAAC;EAE9B,IAAI,CAACD,QAAQ,EAAE;IACX,OAAO,IAAI;EACf;EAEA,IAAQE,QAAQ,GAAoBF,QAAQ,CAApCE,QAAQ;IAAEC,aAAa,GAAKH,QAAQ,CAA1BG,aAAa;EAE/B,IAAI,CAACD,QAAQ,EAAE;IACX,OAAO,IAAI;EACf;EAEA,IAAIE,aAAa,GAAG,KAAK;EACzB,IAAIF,QAAQ,EAAE;IACVE,aAAa,GAAGL,UAAU,GAAGM,OAAO,CAACF,aAAa,CAACJ,UAAU,CAAC,CAAC,GAAG,IAAI;EAC1E;EAEA,IAAIK,aAAa,EAAE;IACf,OAAON,QAAQ;EACnB;EAEA,IAAMQ,MAAM,GAAGC,gBAAO,CAACC,MAAM,CAAyB,oBAAoB,CAAC;EAC3E,IAAI,CAACF,MAAM,EAAE;IACT,OAAO,IAAI;EACf;EAEA,OAAOA,MAAM,CAACG,MAAM,CAAC,CAAC;AAC1B,CAAC;AAAAC,OAAA,CAAAC,OAAA,GAAAf,QAAA"}
|
package/components/SecureView.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["SecureView","children","permission","useSecurity","getPermission","hasPermission","matchedPermission","Boolean"],"sources":["SecureView.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { useSecurity } from \"~/hooks/useSecurity\";\nimport { SecurityPermission } from \"~/types\";\n\ninterface ChildrenRenderFunctionArgs<T extends SecurityPermission> {\n hasPermission: boolean;\n permission: T | null;\n}\n\ninterface Props<T extends SecurityPermission> {\n children: ((args: ChildrenRenderFunctionArgs<T>) => React.ReactElement) | React.ReactElement;\n permission?: string;\n}\n\nfunction SecureView<T extends SecurityPermission>({\n children,\n permission\n}: Props<T>): React.ReactElement | null {\n const { getPermission } = useSecurity();\n\n let hasPermission = false;\n let matchedPermission: T | null = null;\n if (permission) {\n matchedPermission = getPermission<T>(permission);\n hasPermission = Boolean(matchedPermission);\n }\n\n if (typeof children === \"function\") {\n return children({\n hasPermission,\n permission: matchedPermission\n });\n }\n\n return hasPermission ? children : null;\n}\n\nexport default SecureView;\n"],"mappings":";;;;;;AACA;AAaA,
|
|
1
|
+
{"version":3,"names":["_useSecurity2","require","SecureView","_ref","children","permission","_useSecurity","useSecurity","getPermission","hasPermission","matchedPermission","Boolean","_default","exports","default"],"sources":["SecureView.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { useSecurity } from \"~/hooks/useSecurity\";\nimport { SecurityPermission } from \"~/types\";\n\ninterface ChildrenRenderFunctionArgs<T extends SecurityPermission> {\n hasPermission: boolean;\n permission: T | null;\n}\n\ninterface Props<T extends SecurityPermission> {\n children: ((args: ChildrenRenderFunctionArgs<T>) => React.ReactElement) | React.ReactElement;\n permission?: string;\n}\n\nfunction SecureView<T extends SecurityPermission>({\n children,\n permission\n}: Props<T>): React.ReactElement | null {\n const { getPermission } = useSecurity();\n\n let hasPermission = false;\n let matchedPermission: T | null = null;\n if (permission) {\n matchedPermission = getPermission<T>(permission);\n hasPermission = Boolean(matchedPermission);\n }\n\n if (typeof children === \"function\") {\n return children({\n hasPermission,\n permission: matchedPermission\n });\n }\n\n return hasPermission ? children : null;\n}\n\nexport default SecureView;\n"],"mappings":";;;;;;AACA,IAAAA,aAAA,GAAAC,OAAA;AAaA,SAASC,UAAUA,CAAAC,IAAA,EAGqB;EAAA,IAFpCC,QAAQ,GAAAD,IAAA,CAARC,QAAQ;IACRC,UAAU,GAAAF,IAAA,CAAVE,UAAU;EAEV,IAAAC,YAAA,GAA0B,IAAAC,yBAAW,EAAC,CAAC;IAA/BC,aAAa,GAAAF,YAAA,CAAbE,aAAa;EAErB,IAAIC,aAAa,GAAG,KAAK;EACzB,IAAIC,iBAA2B,GAAG,IAAI;EACtC,IAAIL,UAAU,EAAE;IACZK,iBAAiB,GAAGF,aAAa,CAAIH,UAAU,CAAC;IAChDI,aAAa,GAAGE,OAAO,CAACD,iBAAiB,CAAC;EAC9C;EAEA,IAAI,OAAON,QAAQ,KAAK,UAAU,EAAE;IAChC,OAAOA,QAAQ,CAAC;MACZK,aAAa,EAAbA,aAAa;MACbJ,UAAU,EAAEK;IAChB,CAAC,CAAC;EACN;EAEA,OAAOD,aAAa,GAAGL,QAAQ,GAAG,IAAI;AAC1C;AAAC,IAAAQ,QAAA,GAEcV,UAAU;AAAAW,OAAA,CAAAC,OAAA,GAAAF,QAAA"}
|
package/components/index.js
CHANGED
|
@@ -24,4 +24,6 @@ Object.defineProperty(exports, "SecureView", {
|
|
|
24
24
|
});
|
|
25
25
|
var _SecureView = _interopRequireDefault(require("./SecureView"));
|
|
26
26
|
var _SecureRoute = _interopRequireDefault(require("./SecureRoute"));
|
|
27
|
-
var _HasPermission = require("./HasPermission");
|
|
27
|
+
var _HasPermission = require("./HasPermission");
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
package/components/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["index.ts"],"sourcesContent":["export { default as SecureView } from \"./SecureView\";\nexport { default as SecureRoute } from \"./SecureRoute\";\nexport { HasPermission } from \"./HasPermission\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA"}
|
|
1
|
+
{"version":3,"names":["_SecureView","_interopRequireDefault","require","_SecureRoute","_HasPermission"],"sources":["index.ts"],"sourcesContent":["export { default as SecureView } from \"./SecureView\";\nexport { default as SecureRoute } from \"./SecureRoute\";\nexport { HasPermission } from \"./HasPermission\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,WAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,cAAA,GAAAF,OAAA"}
|
package/contexts/Security.d.ts
CHANGED
|
@@ -2,8 +2,14 @@ import React, { Dispatch, SetStateAction } from "react";
|
|
|
2
2
|
import { SecurityIdentity, SecurityPermission } from "../types";
|
|
3
3
|
export interface SecurityContext {
|
|
4
4
|
identity: SecurityIdentity | null;
|
|
5
|
+
getIdentityId: () => string | null;
|
|
5
6
|
setIdentity: Dispatch<SetStateAction<SecurityIdentity | null>>;
|
|
6
|
-
getPermission<T extends SecurityPermission = SecurityPermission>(name: string): T | null;
|
|
7
|
+
getPermission<T extends SecurityPermission = SecurityPermission>(name: string, exact?: boolean): T | null;
|
|
8
|
+
getPermissions<T extends SecurityPermission = SecurityPermission>(name: string): T[];
|
|
9
|
+
}
|
|
10
|
+
interface SecurityProviderProps {
|
|
11
|
+
children: React.ReactNode;
|
|
7
12
|
}
|
|
8
13
|
export declare const SecurityContext: React.Context<SecurityContext>;
|
|
9
|
-
export declare const SecurityProvider:
|
|
14
|
+
export declare const SecurityProvider: (props: SecurityProviderProps) => JSX.Element;
|
|
15
|
+
export {};
|
package/contexts/Security.js
CHANGED
|
@@ -12,11 +12,17 @@ var _minimatch = _interopRequireDefault(require("minimatch"));
|
|
|
12
12
|
var _react = _interopRequireWildcard(require("react"));
|
|
13
13
|
var SecurityContext = /*#__PURE__*/_react.default.createContext({
|
|
14
14
|
identity: null,
|
|
15
|
+
getIdentityId: function getIdentityId() {
|
|
16
|
+
return null;
|
|
17
|
+
},
|
|
15
18
|
setIdentity: function setIdentity() {
|
|
16
19
|
return void 0;
|
|
17
20
|
},
|
|
18
21
|
getPermission: function getPermission() {
|
|
19
22
|
return null;
|
|
23
|
+
},
|
|
24
|
+
getPermissions: function getPermissions() {
|
|
25
|
+
return [];
|
|
20
26
|
}
|
|
21
27
|
});
|
|
22
28
|
exports.SecurityContext = SecurityContext;
|
|
@@ -25,7 +31,7 @@ var SecurityProvider = function SecurityProvider(props) {
|
|
|
25
31
|
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
26
32
|
identity = _useState2[0],
|
|
27
33
|
setIdentity = _useState2[1];
|
|
28
|
-
var getPermission = (0, _react.useCallback)(function (name) {
|
|
34
|
+
var getPermission = (0, _react.useCallback)(function (name, exact) {
|
|
29
35
|
if (!identity) {
|
|
30
36
|
return null;
|
|
31
37
|
}
|
|
@@ -35,25 +41,52 @@ var SecurityProvider = function SecurityProvider(props) {
|
|
|
35
41
|
});
|
|
36
42
|
if (exactMatch) {
|
|
37
43
|
return exactMatch;
|
|
44
|
+
} else if (exact) {
|
|
45
|
+
return null;
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
// Try matching using patterns
|
|
41
49
|
return perms.find(function (p) {
|
|
42
50
|
return (0, _minimatch.default)(name, p.name);
|
|
51
|
+
}) || null;
|
|
52
|
+
}, [identity]);
|
|
53
|
+
var getPermissions = (0, _react.useCallback)(function (name) {
|
|
54
|
+
if (!identity) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
var permissions = identity.permissions || [];
|
|
58
|
+
return permissions.filter(function (current) {
|
|
59
|
+
var exactMatch = current.name === name;
|
|
60
|
+
if (exactMatch) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Try matching using patterns.
|
|
65
|
+
return (0, _minimatch.default)(name, current.name);
|
|
43
66
|
});
|
|
44
67
|
}, [identity]);
|
|
68
|
+
var getIdentityId = (0, _react.useCallback)(function () {
|
|
69
|
+
if (!identity) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return identity.id || identity.login || null;
|
|
73
|
+
}, [identity]);
|
|
45
74
|
var value = (0, _react.useMemo)(function () {
|
|
46
75
|
return {
|
|
47
76
|
identity: identity ? (0, _objectSpread2.default)((0, _objectSpread2.default)({}, identity), {}, {
|
|
48
77
|
// For backwards compatibility, expose the `getPermission` method on the `identity` object.
|
|
49
78
|
getPermission: getPermission
|
|
50
79
|
}) : null,
|
|
80
|
+
getIdentityId: getIdentityId,
|
|
51
81
|
setIdentity: setIdentity,
|
|
52
|
-
getPermission: getPermission
|
|
82
|
+
getPermission: getPermission,
|
|
83
|
+
getPermissions: getPermissions
|
|
53
84
|
};
|
|
54
85
|
}, [identity]);
|
|
55
86
|
return /*#__PURE__*/_react.default.createElement(SecurityContext.Provider, {
|
|
56
87
|
value: value
|
|
57
88
|
}, props.children);
|
|
58
89
|
};
|
|
59
|
-
exports.SecurityProvider = SecurityProvider;
|
|
90
|
+
exports.SecurityProvider = SecurityProvider;
|
|
91
|
+
|
|
92
|
+
//# sourceMappingURL=Security.js.map
|
package/contexts/Security.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["SecurityContext","React","createContext","identity","setIdentity","getPermission","SecurityProvider","props","useState","useCallback","name","perms","permissions","exactMatch","find","p","minimatch","value","useMemo","children"],"sources":["Security.tsx"],"sourcesContent":["import minimatch from \"minimatch\";\nimport React, {
|
|
1
|
+
{"version":3,"names":["_minimatch","_interopRequireDefault","require","_react","_interopRequireWildcard","SecurityContext","React","createContext","identity","getIdentityId","setIdentity","getPermission","getPermissions","exports","SecurityProvider","props","_useState","useState","_useState2","_slicedToArray2","default","useCallback","name","exact","perms","permissions","exactMatch","find","p","minimatch","filter","current","id","login","value","useMemo","_objectSpread2","createElement","Provider","children"],"sources":["Security.tsx"],"sourcesContent":["import minimatch from \"minimatch\";\nimport React, { Dispatch, SetStateAction, useCallback, useMemo, useState } from \"react\";\nimport { SecurityIdentity, SecurityPermission } from \"~/types\";\n\nexport interface SecurityContext {\n identity: SecurityIdentity | null;\n getIdentityId: () => string | null;\n\n setIdentity: Dispatch<SetStateAction<SecurityIdentity | null>>;\n\n getPermission<T extends SecurityPermission = SecurityPermission>(\n name: string,\n exact?: boolean\n ): T | null;\n\n getPermissions<T extends SecurityPermission = SecurityPermission>(name: string): T[];\n}\n\ninterface SecurityProviderProps {\n children: React.ReactNode;\n}\n\nexport const SecurityContext = React.createContext<SecurityContext>({\n identity: null,\n getIdentityId: () => null,\n setIdentity: () => {\n return void 0;\n },\n getPermission: () => {\n return null;\n },\n getPermissions: () => {\n return [];\n }\n});\n\nexport const SecurityProvider = (props: SecurityProviderProps) => {\n const [identity, setIdentity] = useState<SecurityIdentity | null>(null);\n\n const getPermission = useCallback(\n <T extends SecurityPermission = SecurityPermission>(\n name: string,\n exact?: boolean\n ): T | null => {\n if (!identity) {\n return null;\n }\n\n const perms = (identity.permissions || []) as T[];\n const exactMatch = perms.find(p => p.name === name);\n if (exactMatch) {\n return exactMatch as T;\n } else if (exact) {\n return null;\n }\n\n // Try matching using patterns\n return perms.find(p => minimatch(name, p.name)) || null;\n },\n [identity]\n );\n\n const getPermissions = useCallback(\n <T extends SecurityPermission = SecurityPermission>(name: string): Array<T> => {\n if (!identity) {\n return [];\n }\n\n const permissions = identity.permissions || [];\n\n return permissions.filter(current => {\n const exactMatch = current.name === name;\n if (exactMatch) {\n return true;\n }\n\n // Try matching using patterns.\n return minimatch(name, current.name);\n }) as T[];\n },\n [identity]\n );\n\n const getIdentityId = useCallback(() => {\n if (!identity) {\n return null;\n }\n return identity.id || identity.login || null;\n }, [identity]);\n\n const value = useMemo(() => {\n return {\n identity: identity\n ? {\n ...identity,\n // For backwards compatibility, expose the `getPermission` method on the `identity` object.\n getPermission\n }\n : null,\n getIdentityId,\n setIdentity,\n getPermission,\n getPermissions\n };\n }, [identity]);\n\n return <SecurityContext.Provider value={value}>{props.children}</SecurityContext.Provider>;\n};\n"],"mappings":"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"}
|
package/hooks/usePermission.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["usePermission","name","useSecurity","getPermission"],"sources":["usePermission.ts"],"sourcesContent":["import { useSecurity } from \"~/hooks/useSecurity\";\nimport { SecurityPermission } from \"~/types\";\n\nexport function usePermission<T extends SecurityPermission = SecurityPermission>(name: string) {\n const { getPermission } = useSecurity();\n return getPermission<T>(name);\n}\n"],"mappings":";;;;;;AAAA;AAGO,
|
|
1
|
+
{"version":3,"names":["_useSecurity2","require","usePermission","name","_useSecurity","useSecurity","getPermission"],"sources":["usePermission.ts"],"sourcesContent":["import { useSecurity } from \"~/hooks/useSecurity\";\nimport { SecurityPermission } from \"~/types\";\n\nexport function usePermission<T extends SecurityPermission = SecurityPermission>(name: string) {\n const { getPermission } = useSecurity();\n return getPermission<T>(name);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,aAAA,GAAAC,OAAA;AAGO,SAASC,aAAaA,CAAoDC,IAAY,EAAE;EAC3F,IAAAC,YAAA,GAA0B,IAAAC,yBAAW,EAAC,CAAC;IAA/BC,aAAa,GAAAF,YAAA,CAAbE,aAAa;EACrB,OAAOA,aAAa,CAAIH,IAAI,CAAC;AACjC"}
|
package/hooks/useSecurity.js
CHANGED
package/hooks/useSecurity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["useSecurity","useContext","SecurityContext"],"sources":["useSecurity.ts"],"sourcesContent":["import { useContext } from \"react\";\nimport { SecurityContext } from \"~/contexts/Security\";\n\nexport function useSecurity() {\n return useContext(SecurityContext);\n}\n"],"mappings":";;;;;;AAAA;AACA;AAEO,
|
|
1
|
+
{"version":3,"names":["_react","require","_Security","useSecurity","useContext","SecurityContext"],"sources":["useSecurity.ts"],"sourcesContent":["import { useContext } from \"react\";\nimport { SecurityContext } from \"~/contexts/Security\";\n\nexport function useSecurity() {\n return useContext(SecurityContext);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,SAAA,GAAAD,OAAA;AAEO,SAASE,WAAWA,CAAA,EAAG;EAC1B,OAAO,IAAAC,iBAAU,EAACC,yBAAe,CAAC;AACtC"}
|
package/index.js
CHANGED
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["index.ts"],"sourcesContent":["export * from \"./components\";\nexport * from \"./contexts/Security\";\nexport { SecurityContext } from \"./contexts/Security\";\nexport * from \"./hooks/useSecurity\";\nexport * from \"./hooks/usePermission\";\nexport * from \"./Security\";\n"],"mappings":";;;;;;;;;;;;;;AAAA;
|
|
1
|
+
{"version":3,"names":["_components","require","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_Security","_useSecurity","_usePermission","_Security2"],"sources":["index.ts"],"sourcesContent":["export * from \"./components\";\nexport * from \"./contexts/Security\";\nexport { SecurityContext } from \"./contexts/Security\";\nexport * from \"./hooks/useSecurity\";\nexport * from \"./hooks/usePermission\";\nexport * from \"./Security\";\n"],"mappings":";;;;;;;;;;;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,WAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAL,WAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,IAAA;MAAA,OAAAb,WAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAS,SAAA,GAAAb,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAW,SAAA,EAAAV,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAS,SAAA,CAAAT,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,IAAA;MAAA,OAAAC,SAAA,CAAAT,GAAA;IAAA;EAAA;AAAA;AAEA,IAAAU,YAAA,GAAAd,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAY,YAAA,EAAAX,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAU,YAAA,CAAAV,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,IAAA;MAAA,OAAAE,YAAA,CAAAV,GAAA;IAAA;EAAA;AAAA;AACA,IAAAW,cAAA,GAAAf,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAa,cAAA,EAAAZ,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAW,cAAA,CAAAX,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,IAAA;MAAA,OAAAG,cAAA,CAAAX,GAAA;IAAA;EAAA;AAAA;AACA,IAAAY,UAAA,GAAAhB,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAc,UAAA,EAAAb,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAY,UAAA,CAAAZ,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,IAAA;MAAA,OAAAI,UAAA,CAAAZ,GAAA;IAAA;EAAA;AAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/app-security",
|
|
3
|
-
"version": "0.0.0-unstable.
|
|
3
|
+
"version": "0.0.0-unstable.de38392959",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -13,25 +13,24 @@
|
|
|
13
13
|
],
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@webiny/app": "0.0.0-unstable.
|
|
17
|
-
"@webiny/plugins": "0.0.0-unstable.
|
|
18
|
-
"minimatch": "
|
|
16
|
+
"@webiny/app": "0.0.0-unstable.de38392959",
|
|
17
|
+
"@webiny/plugins": "0.0.0-unstable.de38392959",
|
|
18
|
+
"minimatch": "5.1.6",
|
|
19
19
|
"react": "17.0.2",
|
|
20
20
|
"react-dom": "17.0.2"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@babel/cli": "
|
|
24
|
-
"@babel/core": "
|
|
25
|
-
"@babel/plugin-proposal-class-properties": "
|
|
26
|
-
"@babel/preset-env": "
|
|
27
|
-
"@babel/preset-react": "
|
|
28
|
-
"@babel/preset-typescript": "
|
|
29
|
-
"@webiny/cli": "
|
|
30
|
-
"@webiny/project-utils": "
|
|
31
|
-
"babel-plugin-emotion": "
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"ttypescript": "^1.5.12",
|
|
23
|
+
"@babel/cli": "7.22.6",
|
|
24
|
+
"@babel/core": "7.22.8",
|
|
25
|
+
"@babel/plugin-proposal-class-properties": "7.18.6",
|
|
26
|
+
"@babel/preset-env": "7.22.7",
|
|
27
|
+
"@babel/preset-react": "7.22.5",
|
|
28
|
+
"@babel/preset-typescript": "7.22.5",
|
|
29
|
+
"@webiny/cli": "0.0.0-unstable.de38392959",
|
|
30
|
+
"@webiny/project-utils": "0.0.0-unstable.de38392959",
|
|
31
|
+
"babel-plugin-emotion": "9.2.11",
|
|
32
|
+
"rimraf": "3.0.2",
|
|
33
|
+
"ttypescript": "1.5.15",
|
|
35
34
|
"typescript": "4.7.4"
|
|
36
35
|
},
|
|
37
36
|
"publishConfig": {
|
|
@@ -49,5 +48,5 @@
|
|
|
49
48
|
]
|
|
50
49
|
}
|
|
51
50
|
},
|
|
52
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "de38392959f2692d1feb08945a3588cd80e4924c"
|
|
53
52
|
}
|