diff --git a/server/routes/auth.ts b/server/routes/auth.ts index 29314d337..50a5f2201 100644 --- a/server/routes/auth.ts +++ b/server/routes/auth.ts @@ -24,7 +24,7 @@ authRoutes.get('/me', isAuthenticated(), async (req, res) => { 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 body = req.body as { authToken?: string }; @@ -86,6 +86,22 @@ authRoutes.post('/login', async (req, res) => { avatar: account.thumb, }); 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() ?? {}); } catch (e) { logger.error(e.message, { label: 'Auth' }); - res - .status(500) - .json({ error: 'Something went wrong. Is your auth token valid?' }); + return next({ + status: 500, + message: 'Something went wrong. Is your auth token valid?', + }); } }); diff --git a/src/components/Login/index.tsx b/src/components/Login/index.tsx index 484010a2b..87095b7bf 100644 --- a/src/components/Login/index.tsx +++ b/src/components/Login/index.tsx @@ -5,12 +5,15 @@ import axios from 'axios'; import { useRouter } from 'next/dist/client/router'; import ImageFader from '../Common/ImageFader'; import { defineMessages, FormattedMessage } from 'react-intl'; +import Transition from '../Transition'; const messages = defineMessages({ signinplex: 'Sign in to continue', }); const Login: React.FC = () => { + const [error, setError] = useState(''); + const [isProcessing, setProcessing] = useState(false); const [authToken, setAuthToken] = useState(undefined); const { user, revalidate } = useUser(); 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. useEffect(() => { 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) { - revalidate(); + if (response.data?.email) { + revalidate(); + } + } catch (e) { + setError(e.response.data.message); + setAuthToken(undefined); + setProcessing(false); } }; 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" style={{ backdropFilter: 'blur(5px)' }} > + +
+
+
+ +
+
+

{error}

+
+
+
+
setAuthToken(authToken)} /> diff --git a/src/components/PlexLoginButton/index.tsx b/src/components/PlexLoginButton/index.tsx index 56883fb39..3c58e2336 100644 --- a/src/components/PlexLoginButton/index.tsx +++ b/src/components/PlexLoginButton/index.tsx @@ -12,23 +12,23 @@ const plexOAuth = new PlexOAuth(); interface PlexLoginButtonProps { onAuthToken: (authToken: string) => void; + isProcessing?: boolean; onError?: (message: string) => void; } const PlexLoginButton: React.FC = ({ onAuthToken, onError, + isProcessing, }) => { const intl = useIntl(); const [loading, setLoading] = useState(false); - const [isProcessing, setIsProcessing] = useState(false); const getPlexLogin = async () => { setLoading(true); try { const authToken = await plexOAuth.login(); setLoading(false); - setIsProcessing(true); onAuthToken(authToken); } catch (e) { if (onError) { diff --git a/src/styles/globals.css b/src/styles/globals.css index 18c2b0ff0..9df59f095 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -7,7 +7,7 @@ body { } .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; }