fix(frontend): correctly show an unauthorized error when a user fails to login

fixes #322
pull/376/head
sct 4 years ago
parent 67146c33ef
commit 18925decaf

@ -24,7 +24,7 @@ authRoutes.get('/me', isAuthenticated(), async (req, res) => {
return res.status(200).json(user.filter()); return res.status(200).json(user.filter());
}); });
authRoutes.post('/login', async (req, res) => { authRoutes.post('/login', async (req, res, next) => {
const userRepository = getRepository(User); const userRepository = getRepository(User);
const body = req.body as { authToken?: string }; const body = req.body as { authToken?: string };
@ -86,6 +86,22 @@ authRoutes.post('/login', async (req, res) => {
avatar: account.thumb, avatar: account.thumb,
}); });
await userRepository.save(user); await userRepository.save(user);
} else {
logger.info(
'Failed login attempt from user without access to plex server',
{
label: 'Auth',
account: {
...account,
authentication_token: '__REDACTED__',
authToken: '__REDACTED__',
},
}
);
return next({
status: 403,
message: 'You do not have access to this Plex server',
});
} }
} }
@ -97,9 +113,10 @@ authRoutes.post('/login', async (req, res) => {
return res.status(200).json(user?.filter() ?? {}); return res.status(200).json(user?.filter() ?? {});
} catch (e) { } catch (e) {
logger.error(e.message, { label: 'Auth' }); logger.error(e.message, { label: 'Auth' });
res return next({
.status(500) status: 500,
.json({ error: 'Something went wrong. Is your auth token valid?' }); message: 'Something went wrong. Is your auth token valid?',
});
} }
}); });

@ -5,12 +5,15 @@ import axios from 'axios';
import { useRouter } from 'next/dist/client/router'; import { useRouter } from 'next/dist/client/router';
import ImageFader from '../Common/ImageFader'; import ImageFader from '../Common/ImageFader';
import { defineMessages, FormattedMessage } from 'react-intl'; import { defineMessages, FormattedMessage } from 'react-intl';
import Transition from '../Transition';
const messages = defineMessages({ const messages = defineMessages({
signinplex: 'Sign in to continue', signinplex: 'Sign in to continue',
}); });
const Login: React.FC = () => { const Login: React.FC = () => {
const [error, setError] = useState('');
const [isProcessing, setProcessing] = useState(false);
const [authToken, setAuthToken] = useState<string | undefined>(undefined); const [authToken, setAuthToken] = useState<string | undefined>(undefined);
const { user, revalidate } = useUser(); const { user, revalidate } = useUser();
const router = useRouter(); const router = useRouter();
@ -20,10 +23,17 @@ const Login: React.FC = () => {
// ask swr to revalidate the user which _shouid_ come back with a valid user. // ask swr to revalidate the user which _shouid_ come back with a valid user.
useEffect(() => { useEffect(() => {
const login = async () => { const login = async () => {
const response = await axios.post('/api/v1/auth/login', { authToken }); setProcessing(true);
try {
const response = await axios.post('/api/v1/auth/login', { authToken });
if (response.data?.email) { if (response.data?.email) {
revalidate(); revalidate();
}
} catch (e) {
setError(e.response.data.message);
setAuthToken(undefined);
setProcessing(false);
} }
}; };
if (authToken) { if (authToken) {
@ -64,7 +74,40 @@ const Login: React.FC = () => {
className="bg-gray-800 bg-opacity-50 py-8 px-4 shadow sm:rounded-lg sm:px-10" className="bg-gray-800 bg-opacity-50 py-8 px-4 shadow sm:rounded-lg sm:px-10"
style={{ backdropFilter: 'blur(5px)' }} style={{ backdropFilter: 'blur(5px)' }}
> >
<Transition
show={!!error}
enter="opacity-0 transition duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="opacity-100 transition duration-300"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="rounded-md bg-red-600 p-4 mb-4">
<div className="flex">
<div className="flex-shrink-0">
<svg
className="h-5 w-5 text-red-300"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fillRule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
clipRule="evenodd"
/>
</svg>
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-red-300">{error}</h3>
</div>
</div>
</div>
</Transition>
<PlexLoginButton <PlexLoginButton
isProcessing={isProcessing}
onAuthToken={(authToken) => setAuthToken(authToken)} onAuthToken={(authToken) => setAuthToken(authToken)}
/> />
</div> </div>

@ -12,23 +12,23 @@ const plexOAuth = new PlexOAuth();
interface PlexLoginButtonProps { interface PlexLoginButtonProps {
onAuthToken: (authToken: string) => void; onAuthToken: (authToken: string) => void;
isProcessing?: boolean;
onError?: (message: string) => void; onError?: (message: string) => void;
} }
const PlexLoginButton: React.FC<PlexLoginButtonProps> = ({ const PlexLoginButton: React.FC<PlexLoginButtonProps> = ({
onAuthToken, onAuthToken,
onError, onError,
isProcessing,
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [isProcessing, setIsProcessing] = useState(false);
const getPlexLogin = async () => { const getPlexLogin = async () => {
setLoading(true); setLoading(true);
try { try {
const authToken = await plexOAuth.login(); const authToken = await plexOAuth.login();
setLoading(false); setLoading(false);
setIsProcessing(true);
onAuthToken(authToken); onAuthToken(authToken);
} catch (e) { } catch (e) {
if (onError) { if (onError) {

@ -7,7 +7,7 @@ body {
} }
.plex-button { .plex-button {
@apply w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 transition ease-in-out duration-150 text-center; @apply w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 transition ease-in-out duration-150 text-center disabled:opacity-50;
background-color: #cc7b19; background-color: #cc7b19;
} }

Loading…
Cancel
Save