2020-07-20 10:12:14 +00:00
|
|
|
import { IMessageContext } from "@saleor/components/messages";
|
2020-05-25 23:38:52 +00:00
|
|
|
import { DEMO_MODE } from "@saleor/config";
|
2020-07-07 10:14:12 +00:00
|
|
|
import { User } from "@saleor/fragments/types/User";
|
2019-10-25 12:35:48 +00:00
|
|
|
import useNotifier from "@saleor/hooks/useNotifier";
|
2021-01-18 11:19:04 +00:00
|
|
|
import { commonMessages } from "@saleor/intl";
|
2020-07-20 09:46:59 +00:00
|
|
|
import { getMutationStatus } from "@saleor/misc";
|
2019-09-06 15:30:33 +00:00
|
|
|
import {
|
|
|
|
isSupported as isCredentialsManagementAPISupported,
|
|
|
|
login as loginWithCredentialsManagementAPI,
|
|
|
|
saveCredentials
|
|
|
|
} from "@saleor/utils/credentialsManagement";
|
2020-07-20 10:12:14 +00:00
|
|
|
import ApolloClient from "apollo-client";
|
2020-07-21 13:55:50 +00:00
|
|
|
import React, { useContext, useEffect, useRef, useState } from "react";
|
2020-07-20 10:12:14 +00:00
|
|
|
import { useApolloClient, useMutation } from "react-apollo";
|
|
|
|
import { IntlShape, useIntl } from "react-intl";
|
2020-05-14 09:30:32 +00:00
|
|
|
|
|
|
|
import { UserContext } from "./";
|
2020-05-07 11:04:15 +00:00
|
|
|
import {
|
2020-07-14 14:31:41 +00:00
|
|
|
tokenAuthMutation,
|
|
|
|
tokenRefreshMutation,
|
|
|
|
tokenVerifyMutation
|
2020-05-07 11:04:15 +00:00
|
|
|
} from "./mutations";
|
2020-07-14 14:31:41 +00:00
|
|
|
import { RefreshToken, RefreshTokenVariables } from "./types/RefreshToken";
|
|
|
|
import { TokenAuth, TokenAuthVariables } from "./types/TokenAuth";
|
|
|
|
import { VerifyToken, VerifyTokenVariables } from "./types/VerifyToken";
|
2020-05-25 23:38:52 +00:00
|
|
|
import {
|
|
|
|
displayDemoMessage,
|
2020-07-23 13:37:39 +00:00
|
|
|
getTokens,
|
|
|
|
removeTokens,
|
|
|
|
setAuthToken,
|
|
|
|
setTokens
|
2020-05-25 23:38:52 +00:00
|
|
|
} from "./utils";
|
2019-06-19 14:40:52 +00:00
|
|
|
|
2020-07-20 09:46:59 +00:00
|
|
|
const persistToken = false;
|
|
|
|
|
2020-07-21 13:55:50 +00:00
|
|
|
export function useAuthProvider(
|
2020-07-20 10:12:14 +00:00
|
|
|
intl: IntlShape,
|
|
|
|
notify: IMessageContext,
|
|
|
|
apolloClient: ApolloClient<any>
|
|
|
|
) {
|
2020-07-20 09:46:59 +00:00
|
|
|
const [userContext, setUserContext] = useState<undefined | User>(undefined);
|
2020-07-21 13:55:50 +00:00
|
|
|
const autologinPromise = useRef<Promise<any>>();
|
2020-07-23 13:37:39 +00:00
|
|
|
const refreshPromise = useRef<Promise<boolean>>();
|
2020-07-20 09:46:59 +00:00
|
|
|
|
2021-01-18 11:19:04 +00:00
|
|
|
useEffect(() => {
|
|
|
|
const token = getTokens().auth;
|
|
|
|
if (!!token && !userContext) {
|
|
|
|
autologinPromise.current = tokenVerify({ variables: { token } });
|
|
|
|
} else {
|
|
|
|
autologinPromise.current = loginWithCredentialsManagementAPI(login);
|
|
|
|
}
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (userContext && !userContext.isStaff) {
|
|
|
|
logout();
|
|
|
|
notify({
|
|
|
|
status: "error",
|
|
|
|
text: intl.formatMessage(commonMessages.unauthorizedDashboardAccess),
|
|
|
|
title: intl.formatMessage(commonMessages.insufficientPermissions)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}, [userContext]);
|
|
|
|
|
2020-07-20 09:46:59 +00:00
|
|
|
const logout = () => {
|
|
|
|
setUserContext(undefined);
|
|
|
|
if (isCredentialsManagementAPISupported) {
|
|
|
|
navigator.credentials.preventSilentAccess();
|
|
|
|
}
|
2020-07-23 13:37:39 +00:00
|
|
|
removeTokens();
|
2020-07-20 09:46:59 +00:00
|
|
|
};
|
|
|
|
|
2020-07-14 14:31:41 +00:00
|
|
|
const [tokenAuth, tokenAuthResult] = useMutation<
|
|
|
|
TokenAuth,
|
|
|
|
TokenAuthVariables
|
2020-07-20 09:46:59 +00:00
|
|
|
>(tokenAuthMutation, {
|
2020-07-20 10:12:14 +00:00
|
|
|
client: apolloClient,
|
2021-01-18 11:19:04 +00:00
|
|
|
onCompleted: ({ tokenCreate }) => {
|
|
|
|
if (tokenCreate.errors.length > 0) {
|
2020-07-20 09:58:39 +00:00
|
|
|
logout();
|
|
|
|
}
|
|
|
|
|
2021-01-18 11:19:04 +00:00
|
|
|
const user = tokenCreate.user;
|
2020-07-20 09:46:59 +00:00
|
|
|
|
|
|
|
// FIXME: Now we set state also when auth fails and returned user is
|
|
|
|
// `null`, because the LoginView uses this `null` to display error.
|
|
|
|
setUserContext(user);
|
|
|
|
if (user) {
|
2021-01-18 11:19:04 +00:00
|
|
|
setTokens(tokenCreate.token, tokenCreate.csrfToken, persistToken);
|
2020-07-20 09:46:59 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
onError: logout
|
|
|
|
});
|
2020-07-14 14:31:41 +00:00
|
|
|
const [tokenRefresh] = useMutation<RefreshToken, RefreshTokenVariables>(
|
2020-07-20 09:46:59 +00:00
|
|
|
tokenRefreshMutation,
|
|
|
|
{
|
2020-07-20 10:12:14 +00:00
|
|
|
client: apolloClient,
|
2020-07-20 09:46:59 +00:00
|
|
|
onError: logout
|
|
|
|
}
|
2020-07-14 14:31:41 +00:00
|
|
|
);
|
|
|
|
const [tokenVerify, tokenVerifyResult] = useMutation<
|
|
|
|
VerifyToken,
|
|
|
|
VerifyTokenVariables
|
2020-07-20 09:46:59 +00:00
|
|
|
>(tokenVerifyMutation, {
|
2020-07-20 10:12:14 +00:00
|
|
|
client: apolloClient,
|
2020-07-20 09:46:59 +00:00
|
|
|
onCompleted: result => {
|
|
|
|
if (result.tokenVerify === null) {
|
|
|
|
logout();
|
|
|
|
} else {
|
|
|
|
const user = result.tokenVerify?.user;
|
|
|
|
|
|
|
|
if (!!user) {
|
|
|
|
setUserContext(user);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onError: logout
|
|
|
|
});
|
2020-07-14 14:31:41 +00:00
|
|
|
|
|
|
|
const tokenAuthOpts = {
|
|
|
|
...tokenAuthResult,
|
|
|
|
status: getMutationStatus(tokenAuthResult)
|
|
|
|
};
|
|
|
|
const tokenVerifyOpts = {
|
|
|
|
...tokenVerifyResult,
|
|
|
|
status: getMutationStatus(tokenVerifyResult)
|
|
|
|
};
|
2020-07-13 15:44:02 +00:00
|
|
|
|
|
|
|
const onLogin = () => {
|
2020-05-25 23:38:52 +00:00
|
|
|
if (DEMO_MODE) {
|
|
|
|
displayDemoMessage(intl, notify);
|
|
|
|
}
|
|
|
|
};
|
2019-10-25 12:35:48 +00:00
|
|
|
|
2020-07-13 15:44:02 +00:00
|
|
|
const login = async (email: string, password: string) => {
|
2020-07-21 13:55:50 +00:00
|
|
|
const result = await tokenAuth({ variables: { email, password } });
|
|
|
|
|
|
|
|
if (result && !result.data.tokenCreate.errors.length) {
|
|
|
|
if (!!onLogin) {
|
|
|
|
onLogin();
|
2019-09-05 14:05:56 +00:00
|
|
|
}
|
2020-07-21 13:55:50 +00:00
|
|
|
saveCredentials(result.data.tokenCreate.user, password);
|
|
|
|
|
|
|
|
return result.data.tokenCreate.user;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
2019-09-03 13:42:15 +00:00
|
|
|
};
|
|
|
|
|
2020-07-23 13:37:39 +00:00
|
|
|
const loginByToken = (auth: string, refresh: string, user: User) => {
|
2020-07-13 15:44:02 +00:00
|
|
|
setUserContext(user);
|
2020-07-23 13:37:39 +00:00
|
|
|
setTokens(auth, refresh, persistToken);
|
2019-06-19 14:40:52 +00:00
|
|
|
};
|
|
|
|
|
2020-07-23 13:37:39 +00:00
|
|
|
const refreshToken = (): Promise<boolean> => {
|
|
|
|
if (!!refreshPromise.current) {
|
|
|
|
return refreshPromise.current;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Promise(resolve => {
|
|
|
|
const token = getTokens().refresh;
|
2020-05-07 11:04:15 +00:00
|
|
|
|
2020-07-23 13:37:39 +00:00
|
|
|
return tokenRefresh({ variables: { token } }).then(refreshData => {
|
|
|
|
if (!!refreshData.data.tokenRefresh?.token) {
|
|
|
|
setAuthToken(refreshData.data.tokenRefresh.token, persistToken);
|
|
|
|
return resolve(true);
|
|
|
|
}
|
2020-05-07 11:04:15 +00:00
|
|
|
|
2020-07-23 13:37:39 +00:00
|
|
|
return resolve(false);
|
|
|
|
});
|
|
|
|
});
|
2020-05-07 11:04:15 +00:00
|
|
|
};
|
|
|
|
|
2020-07-20 10:12:14 +00:00
|
|
|
return {
|
2020-07-21 13:55:50 +00:00
|
|
|
autologinPromise,
|
2020-07-20 10:12:14 +00:00
|
|
|
login,
|
|
|
|
loginByToken,
|
|
|
|
logout,
|
|
|
|
refreshToken,
|
|
|
|
tokenAuthOpts,
|
|
|
|
tokenVerifyOpts,
|
|
|
|
userContext
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
interface AuthProviderProps {
|
|
|
|
children: React.ReactNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
|
|
|
const apolloClient = useApolloClient();
|
|
|
|
const intl = useIntl();
|
|
|
|
const notify = useNotifier();
|
|
|
|
|
|
|
|
const {
|
|
|
|
login,
|
|
|
|
loginByToken,
|
|
|
|
logout,
|
|
|
|
tokenAuthOpts,
|
|
|
|
refreshToken,
|
|
|
|
tokenVerifyOpts,
|
|
|
|
userContext
|
|
|
|
} = useAuthProvider(intl, notify, apolloClient);
|
|
|
|
|
2020-07-13 15:44:02 +00:00
|
|
|
return (
|
|
|
|
<UserContext.Provider
|
|
|
|
value={{
|
|
|
|
login,
|
|
|
|
loginByToken,
|
|
|
|
logout,
|
|
|
|
tokenAuthLoading: tokenAuthOpts.loading,
|
|
|
|
tokenRefresh: refreshToken,
|
|
|
|
tokenVerifyLoading: tokenVerifyOpts.loading,
|
|
|
|
user: userContext
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{children}
|
|
|
|
</UserContext.Provider>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export const useAuth = () => {
|
|
|
|
const user = useContext(UserContext);
|
2020-07-14 14:31:41 +00:00
|
|
|
const isAuthenticated = !!user.user;
|
2020-07-13 15:44:02 +00:00
|
|
|
|
|
|
|
return {
|
2020-07-23 13:37:39 +00:00
|
|
|
hasToken: !!getTokens(),
|
2020-07-13 15:44:02 +00:00
|
|
|
isAuthenticated,
|
|
|
|
tokenAuthLoading: user.tokenAuthLoading,
|
|
|
|
tokenVerifyLoading: user.tokenVerifyLoading,
|
2020-07-14 08:11:43 +00:00
|
|
|
user: user.user
|
2020-07-13 15:44:02 +00:00
|
|
|
};
|
|
|
|
};
|
2019-06-19 14:40:52 +00:00
|
|
|
|
2020-07-13 15:44:02 +00:00
|
|
|
export default AuthProvider;
|