2022-02-21 13:32:38 +00:00
|
|
|
import { ApolloClient, useQuery } from "@apollo/client";
|
2021-01-26 22:04:54 +00:00
|
|
|
import { IMessageContext } from "@saleor/components/messages";
|
2021-12-17 11:10:54 +00:00
|
|
|
import { APP_DEFAULT_URI, APP_MOUNT_URI, DEMO_MODE } from "@saleor/config";
|
2022-02-01 10:23:48 +00:00
|
|
|
import useLocalStorage from "@saleor/hooks/useLocalStorage";
|
2022-01-11 12:32:59 +00:00
|
|
|
import useNavigator from "@saleor/hooks/useNavigator";
|
2021-12-17 11:10:54 +00:00
|
|
|
import { commonMessages } from "@saleor/intl";
|
|
|
|
import {
|
|
|
|
GetExternalAccessTokenData,
|
|
|
|
LoginData,
|
|
|
|
useAuth,
|
|
|
|
useAuthState
|
|
|
|
} from "@saleor/sdk";
|
|
|
|
import {
|
|
|
|
isSupported as isCredentialsManagementAPISupported,
|
|
|
|
login as loginWithCredentialsManagementAPI,
|
|
|
|
saveCredentials
|
|
|
|
} from "@saleor/utils/credentialsManagement";
|
2022-01-13 13:08:07 +00:00
|
|
|
import { useEffect, useRef, useState } from "react";
|
2021-01-26 22:04:54 +00:00
|
|
|
import { IntlShape } from "react-intl";
|
2021-12-17 11:10:54 +00:00
|
|
|
import urlJoin from "url-join";
|
2021-01-26 22:04:54 +00:00
|
|
|
|
2021-12-17 11:10:54 +00:00
|
|
|
import { userDetailsQuery } from "../queries";
|
|
|
|
import {
|
|
|
|
ExternalLoginInput,
|
|
|
|
RequestExternalLoginInput,
|
|
|
|
RequestExternalLogoutInput,
|
|
|
|
UserContext,
|
|
|
|
UserContextError
|
|
|
|
} from "../types";
|
|
|
|
import { UserDetails } from "../types/UserDetails";
|
|
|
|
import { displayDemoMessage } from "../utils";
|
2021-01-26 22:04:54 +00:00
|
|
|
|
|
|
|
export interface UseAuthProviderOpts {
|
|
|
|
intl: IntlShape;
|
|
|
|
notify: IMessageContext;
|
|
|
|
apolloClient: ApolloClient<any>;
|
|
|
|
}
|
|
|
|
|
2021-12-17 11:10:54 +00:00
|
|
|
export function useAuthProvider({
|
|
|
|
intl,
|
|
|
|
notify,
|
|
|
|
apolloClient
|
|
|
|
}: UseAuthProviderOpts): UserContext {
|
|
|
|
const {
|
|
|
|
login,
|
|
|
|
getExternalAuthUrl,
|
|
|
|
getExternalAccessToken,
|
|
|
|
logout
|
|
|
|
} = useAuth();
|
2022-01-11 12:32:59 +00:00
|
|
|
const navigate = useNavigator();
|
2021-12-17 11:10:54 +00:00
|
|
|
const { authenticated, authenticating, user } = useAuthState();
|
2022-02-01 10:23:48 +00:00
|
|
|
const [requestedExternalPluginId] = useLocalStorage(
|
|
|
|
"requestedExternalPluginId",
|
|
|
|
null
|
|
|
|
);
|
2021-12-17 11:10:54 +00:00
|
|
|
const [error, setError] = useState<UserContextError>();
|
2022-01-13 13:08:07 +00:00
|
|
|
const permitCredentialsAPI = useRef(true);
|
2021-01-26 22:04:54 +00:00
|
|
|
|
2021-12-17 11:10:54 +00:00
|
|
|
useEffect(() => {
|
|
|
|
if (authenticating && error) {
|
|
|
|
setError(undefined);
|
|
|
|
}
|
|
|
|
}, [authenticating]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
2022-01-13 13:08:07 +00:00
|
|
|
if (authenticated) {
|
|
|
|
permitCredentialsAPI.current = true;
|
|
|
|
}
|
|
|
|
}, [authenticated]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
2022-02-01 10:23:48 +00:00
|
|
|
if (
|
|
|
|
!authenticated &&
|
|
|
|
!authenticating &&
|
|
|
|
!requestedExternalPluginId &&
|
|
|
|
permitCredentialsAPI.current
|
|
|
|
) {
|
2022-01-13 13:08:07 +00:00
|
|
|
permitCredentialsAPI.current = false;
|
2021-12-17 11:10:54 +00:00
|
|
|
loginWithCredentialsManagementAPI(handleLogin);
|
|
|
|
}
|
|
|
|
}, [authenticated, authenticating]);
|
2021-01-26 22:04:54 +00:00
|
|
|
|
2021-12-17 11:10:54 +00:00
|
|
|
const userDetails = useQuery<UserDetails>(userDetailsQuery, {
|
|
|
|
client: apolloClient,
|
2022-01-13 13:08:07 +00:00
|
|
|
skip: !authenticated,
|
2022-01-31 08:33:04 +00:00
|
|
|
// Don't change this to 'network-only' - update of intl provider's
|
|
|
|
// state will cause an error
|
|
|
|
fetchPolicy: "cache-and-network"
|
2021-01-26 22:04:54 +00:00
|
|
|
});
|
|
|
|
|
2021-12-17 11:10:54 +00:00
|
|
|
const handleLogout = async () => {
|
2022-01-11 12:32:59 +00:00
|
|
|
const path = APP_MOUNT_URI === APP_DEFAULT_URI ? "" : APP_MOUNT_URI;
|
|
|
|
const returnTo = urlJoin(window.location.origin, path);
|
|
|
|
|
2021-12-17 11:10:54 +00:00
|
|
|
const result = await logout({
|
|
|
|
input: JSON.stringify({
|
2022-01-11 12:32:59 +00:00
|
|
|
returnTo
|
2021-12-17 11:10:54 +00:00
|
|
|
} as RequestExternalLogoutInput)
|
|
|
|
});
|
|
|
|
|
|
|
|
if (isCredentialsManagementAPISupported) {
|
|
|
|
navigator.credentials.preventSilentAccess();
|
|
|
|
}
|
|
|
|
|
2022-01-13 13:08:07 +00:00
|
|
|
// Forget last logged in user data.
|
|
|
|
// On next login, user details query will be refetched due to cache-and-network fetch policy.
|
|
|
|
apolloClient.clearStore();
|
|
|
|
|
2022-01-11 12:32:59 +00:00
|
|
|
const errors = result?.errors || [];
|
2021-12-17 11:10:54 +00:00
|
|
|
|
2022-01-11 12:32:59 +00:00
|
|
|
const externalLogoutUrl = result
|
|
|
|
? JSON.parse(result.data?.externalLogout?.logoutData || null)?.logoutUrl
|
|
|
|
: "";
|
|
|
|
|
|
|
|
if (!errors.length) {
|
|
|
|
if (externalLogoutUrl) {
|
|
|
|
window.location.href = externalLogoutUrl;
|
|
|
|
} else {
|
2022-01-18 14:35:09 +00:00
|
|
|
navigate("/");
|
2022-01-11 12:32:59 +00:00
|
|
|
}
|
2021-12-17 11:10:54 +00:00
|
|
|
}
|
2022-01-11 12:32:59 +00:00
|
|
|
|
|
|
|
return;
|
2021-12-17 11:10:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const handleLogin = async (email: string, password: string) => {
|
|
|
|
try {
|
|
|
|
const result = await login({
|
|
|
|
email,
|
|
|
|
password
|
|
|
|
});
|
|
|
|
|
|
|
|
if (result && !result.data.tokenCreate.errors.length) {
|
|
|
|
if (DEMO_MODE) {
|
|
|
|
displayDemoMessage(intl, notify);
|
|
|
|
}
|
|
|
|
saveCredentials(result.data.tokenCreate.user, password);
|
|
|
|
} else {
|
|
|
|
setError("loginError");
|
|
|
|
}
|
|
|
|
|
|
|
|
await logoutNonStaffUser(result.data.tokenCreate);
|
|
|
|
|
|
|
|
return result.data.tokenCreate;
|
|
|
|
} catch (error) {
|
|
|
|
setError("serverError");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleRequestExternalLogin = async (
|
|
|
|
pluginId: string,
|
|
|
|
input: RequestExternalLoginInput
|
|
|
|
) => {
|
|
|
|
const result = await getExternalAuthUrl({
|
|
|
|
pluginId,
|
|
|
|
input: JSON.stringify(input)
|
|
|
|
});
|
|
|
|
|
|
|
|
return result?.data?.externalAuthenticationUrl;
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleExternalLogin = async (
|
|
|
|
pluginId: string,
|
|
|
|
input: ExternalLoginInput
|
|
|
|
) => {
|
|
|
|
try {
|
|
|
|
const result = await getExternalAccessToken({
|
|
|
|
pluginId,
|
|
|
|
input: JSON.stringify(input)
|
|
|
|
});
|
|
|
|
|
|
|
|
if (result && !result.data?.externalObtainAccessTokens.errors.length) {
|
|
|
|
if (DEMO_MODE) {
|
|
|
|
displayDemoMessage(intl, notify);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
setError("externalLoginError");
|
|
|
|
}
|
|
|
|
|
|
|
|
await logoutNonStaffUser(result.data.externalObtainAccessTokens);
|
|
|
|
|
|
|
|
return result?.data?.externalObtainAccessTokens;
|
|
|
|
} catch (error) {
|
|
|
|
setError("serverError");
|
|
|
|
}
|
2021-01-26 22:04:54 +00:00
|
|
|
};
|
|
|
|
|
2021-12-17 11:10:54 +00:00
|
|
|
const logoutNonStaffUser = async (
|
|
|
|
data: LoginData | GetExternalAccessTokenData
|
|
|
|
) => {
|
|
|
|
if (data.user && !data.user.isStaff) {
|
|
|
|
notify({
|
|
|
|
status: "error",
|
|
|
|
text: intl.formatMessage(commonMessages.unauthorizedDashboardAccess),
|
|
|
|
title: intl.formatMessage(commonMessages.insufficientPermissions)
|
|
|
|
});
|
|
|
|
await handleLogout();
|
|
|
|
}
|
|
|
|
};
|
2021-01-26 22:04:54 +00:00
|
|
|
|
|
|
|
return {
|
2021-12-17 11:10:54 +00:00
|
|
|
login: handleLogin,
|
|
|
|
requestLoginByExternalPlugin: handleRequestExternalLogin,
|
|
|
|
loginByExternalPlugin: handleExternalLogin,
|
|
|
|
logout: handleLogout,
|
|
|
|
authenticating: authenticating && !error,
|
|
|
|
authenticated: authenticated && user?.isStaff,
|
|
|
|
user: userDetails.data?.me,
|
|
|
|
error
|
2021-01-26 22:04:54 +00:00
|
|
|
};
|
|
|
|
}
|