Skip to content
This repository has been archived by the owner on Dec 5, 2023. It is now read-only.

Commit

Permalink
Fixes Authorization (#5)
Browse files Browse the repository at this point in the history
Co-authored-by: Yauheni <[email protected]>
  • Loading branch information
YauheniDraichykau and Yauheni authored Sep 11, 2023
1 parent c1fe9e8 commit dd93f9e
Show file tree
Hide file tree
Showing 10 changed files with 47 additions and 36 deletions.
3 changes: 1 addition & 2 deletions frontend/src/features/Auth/atoms.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { atom } from 'jotai';
import { AUTH_TOKEN_LOCAL_STORAGE_KEY } from './consts';

export const AUTH_TOKEN_ATOM = atom<string | null>(localStorage.getItem(AUTH_TOKEN_LOCAL_STORAGE_KEY));
export const AUTH_TOKEN_ATOM = atom<string | null>('');

export const TESTNET_USERNAME_ATOM = atom('');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ function ProtectedRoute({ children }: ProtectedRouteProps) {
const location = useLocation();

if (!authToken && account) {
return <Navigate to={`/${NOT_AUTHORIZED}`} replace />;
return <Navigate to={NOT_AUTHORIZED} replace />;
}

if (!authToken) {
return <Navigate to={`/${LOGIN}`} state={{ from: location }} replace />;
return <Navigate to={LOGIN} state={{ from: location }} replace />;
}

return children;
Expand Down
14 changes: 6 additions & 8 deletions frontend/src/features/Auth/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { AUTH_MESSAGE, AUTH_TOKEN_LOCAL_STORAGE_KEY } from './consts';
import { AUTH_TOKEN_ATOM, IS_AUTH_READY_ATOM, TESTNET_USERNAME_ATOM } from './atoms';
import { fetchAuth, post } from './utils';
import { AuthResponse, ISignInError, SignInResponse } from './types';
import { NOT_AUTHORIZED, PLAY } from '@/App.routes';
import { LOGIN, NOT_AUTHORIZED, PLAY } from '@/App.routes';

function useAuth() {
const { account, login, logout } = useAccount();
Expand All @@ -34,6 +34,7 @@ function useAuth() {
data: AUTH_MESSAGE,
type: 'bytes',
});

const res = await post('auth/login', {
signature,
publicKey: address,
Expand All @@ -42,19 +43,15 @@ function useAuth() {

if (!res.ok) {
const data: ISignInError = await res.json();

if (data.message) {
alert.error(data.message);
}
alert.error(data.message);

setAuthToken(null);
setTestnameUsername('');
await login(account);
navigate(NOT_AUTHORIZED, { replace: true });
navigate(`/${NOT_AUTHORIZED}`, { replace: true });
} else {
const data: SignInResponse = await res.json();
const { accessToken, username } = data;

await login(account);
setAuthToken(accessToken);
setTestnameUsername(username || '');
Expand All @@ -68,6 +65,7 @@ function useAuth() {
const signOut = () => {
logout();
setAuthToken(null);
navigate(LOGIN, { replace: true });
};

const auth = () => {
Expand Down Expand Up @@ -103,7 +101,7 @@ function useAuthSync() {
if (!isAccountReady) return;
auth();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [authToken]);
}, [isAccountReady]);

useEffect(() => {
if (!isAuthReady) return;
Expand Down
21 changes: 17 additions & 4 deletions frontend/src/features/Auth/types.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
type SignInResponse = {
export type SignInResponse = {
accessToken: string;
username: string;
};

type AuthResponse = {
export type AuthResponse = {
email: string;
id: string;
publicKey: string;
username: string;
};

export type { SignInResponse, AuthResponse };

export type ISignInError = {
errors?: {
message: string;
};
message?: string;
};

export type IApiError = {
code: number;
content: {
error: {}; // ??
errors: {
location: string; // "body"
msg: string; // "Please enter valid email"
path: string; // "email"
type: string; // "field"
value: string; // ""
}[];
};
message: string;
};
12 changes: 7 additions & 5 deletions frontend/src/features/Auth/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AnyJson } from '@polkadot/types/types';
import { AUTH_API_ADDRESS } from './consts';
import { IApiError } from './types';

export function trimEndSlash(url: string): string {
return url?.endsWith('/') ? url.slice(0, -1) : url;
Expand All @@ -14,17 +15,18 @@ const post = (url: string, payload: AnyJson) =>
body: JSON.stringify(payload),
});

const fetchAuth = <T>(url: string, method: string, token: string) =>
const fetchAuth = <T>(url: string, method: string, token: string, payload?: AnyJson) =>
fetch(`${API_URL}/${url}`, {
method,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
}).then((response) => {
if (!response.ok) throw new Error(response.statusText);

return response.json() as T;
body: payload ? JSON.stringify(payload) : undefined,
}).then(async (response) => {
const json = await response.json();
if (!response.ok) throw new Error(await (json as IApiError).message);
return json as T;
});

export { post, fetchAuth };
3 changes: 2 additions & 1 deletion frontend/src/features/Game/component/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { usePlayerMoveMessage, useStartGameMessage } from '../../hooks';
import { YourRewards } from '../YourRewards';
import { Loader } from '@/components';
import { WinStatus } from './Layout.interface';
import { PLAY } from '@/App.routes';

function LayoutComponent() {
const [currentGame] = useAtom(CURRENT_GAME);
Expand Down Expand Up @@ -96,7 +97,7 @@ function LayoutComponent() {
},
onError: () => {
console.log('error');
navigate('/');
navigate(PLAY, { replace: true });
},
});
}
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/features/Main/components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import carsImg from '@/assets/icons/introdution-cars-img.webp';
import carsImgPng from '@/assets/icons/introdution-cars-img.png';

import { CURRENT_GAME } from '@/atoms';
import { START } from '@/App.routes';

function Layout() {
const navigate = useNavigate();
const currentGame = useAtomValue(CURRENT_GAME);

const handleGoToPlay = () => {
navigate('/start');
navigate(START, { replace: true });
};

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useNavigate } from 'react-router-dom';
import Identicon from '@polkadot/react-identicon';
import { decodeAddress } from '@gear-js/api';
import { useAccount, useAlert } from '@gear-js/react-hooks';
Expand All @@ -20,9 +19,7 @@ import { useAuth } from '@/features/Auth/hooks';
function WalletModal({ onClose }: WalletModalProps) {
const { extensions, account } = useAccount();
const alert = useAlert();
const { wallet, walletAccounts, setWalletId, resetWalletId, getWalletAccounts, saveWallet, removeWallet } =
useWallet();
const navigate = useNavigate();
const { wallet, walletAccounts, setWalletId, resetWalletId, getWalletAccounts } = useWallet();
const { signIn, signOut } = useAuth();

const getWallets = () =>
Expand Down Expand Up @@ -52,11 +49,8 @@ function WalletModal({ onClose }: WalletModalProps) {
const { address, meta } = _account;
const isActive = address === account?.address;

const handleClick = () => {
signIn(_account).then(() => {
navigate(`/`);
});
saveWallet();
const handleClick = async () => {
await signIn(_account);
onClose();
};

Expand Down Expand Up @@ -86,7 +80,6 @@ function WalletModal({ onClose }: WalletModalProps) {

const handleLogoutButtonClick = () => {
signOut();
removeWallet();
onClose();
};

Expand Down
3 changes: 2 additions & 1 deletion frontend/src/pages/LoginPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import { useAccount } from '@gear-js/react-hooks';
import { WalletInfo } from '@/features/Wallet/components/WalletInfo';
import { useAuth } from '@/features/Auth/hooks';
import { Welcome } from '@/features/Auth/components';
import { PLAY } from '@/App.routes';

function LoginPage() {
const { authToken } = useAuth();
const { account } = useAccount();

if (authToken) {
<Navigate to="/" replace />;
return <Navigate to={PLAY} replace />;
}

return (
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/pages/NotAuthorizedPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { useAccount } from '@gear-js/react-hooks';
import { Navigate } from 'react-router-dom';
import { LOGIN } from '@/App.routes';
import { LOGIN, PLAY } from '@/App.routes';
import { NotAuthorized } from '@/features/Auth/components';
import { useAuth } from '@/features/Auth/hooks';

function NotAuthorizedPage() {
const { account } = useAccount();
const { authToken } = useAuth();

if (!account) return <Navigate to={`/${LOGIN}`} />;
if (!account) return <Navigate to={LOGIN} replace />;
if (account && authToken) return <Navigate to={PLAY} replace />;

return <NotAuthorized />;
}
Expand Down

0 comments on commit dd93f9e

Please sign in to comment.