|
|
@@ -1,10 +1,10 @@
|
|
|
-import React from "react";
|
|
|
+import React, { useCallback } from "react";
|
|
|
import { useContext } from "react";
|
|
|
import { AuthContext } from "./AuthContext";
|
|
|
import { isAuthorized } from "./authorization-helpers";
|
|
|
import { ScopeType, Verbs } from "./types";
|
|
|
|
|
|
-export const withAuth = <ComponentProps extends object>(
|
|
|
+export const GuardedComponent = <ComponentProps extends object>(
|
|
|
scope: ScopeType,
|
|
|
resource: string,
|
|
|
verb: Verbs | Array<Verbs>
|
|
|
@@ -17,3 +17,38 @@ export const withAuth = <ComponentProps extends object>(
|
|
|
|
|
|
return null;
|
|
|
};
|
|
|
+
|
|
|
+export type WithAuthProps = {
|
|
|
+ isAuthorized: (
|
|
|
+ scope: ScopeType,
|
|
|
+ resource: string | Array<string>,
|
|
|
+ verb: Verbs | Array<Verbs>
|
|
|
+ ) => boolean;
|
|
|
+};
|
|
|
+
|
|
|
+export function withAuth<P>(
|
|
|
+ // Then we need to type the incoming component.
|
|
|
+ // This creates a union type of whatever the component
|
|
|
+ // already accepts AND our extraInfo prop
|
|
|
+ WrappedComponent: React.ComponentType<P & WithAuthProps>
|
|
|
+) {
|
|
|
+ const displayName = `withAuth(${
|
|
|
+ WrappedComponent.displayName || WrappedComponent.name
|
|
|
+ })`;
|
|
|
+
|
|
|
+ const C = (props: P) => {
|
|
|
+ const authContext = useContext(AuthContext);
|
|
|
+
|
|
|
+ const isAuth = useCallback(
|
|
|
+ (scope: ScopeType, resource: string, verb: Verbs | Array<Verbs>) =>
|
|
|
+ isAuthorized(authContext.currentPolicy, scope, resource, verb),
|
|
|
+ [authContext.currentPolicy]
|
|
|
+ );
|
|
|
+ // At this point, the props being passed in are the original props the component expects.
|
|
|
+ return <WrappedComponent {...props} isAuthorized={isAuth} />;
|
|
|
+ };
|
|
|
+
|
|
|
+ C.displayName = displayName;
|
|
|
+ C.WrappedComponent = WrappedComponent;
|
|
|
+ return C;
|
|
|
+}
|