From d74c65309b731514f026bf006d84db213543ad11 Mon Sep 17 00:00:00 2001 From: Nikita Wootten Date: Mon, 31 Oct 2022 16:55:24 -0400 Subject: [PATCH 1/2] `Client Error: TypeError: resp is undefined` on transaction submission Fixes #30 and Fixes #29 - Vite proxy handles transaction requests properly - Static resources (nist logo) no longer fails to load - Bad requests no longer fail - Cleanup --- src/api/auth/AuthProvider.tsx | 15 ++++++++------- src/api/auth/instance.ts | 2 ++ src/api/transaction.ts | 5 +---- src/api/userinfo.ts | 8 +++----- src/components/{ => Footer}/Footer.tsx | 2 +- src/components/Footer/index.ts | 2 ++ src/components/Header.tsx | 15 ++++++++------- .../Transaction/TransactionResultsDisplay.tsx | 4 ++-- src/components/index.ts | 5 +++-- src/main.tsx | 7 +++---- src/pages/Transaction.tsx | 11 ++++++----- vite.config.ts | 4 +++- 12 files changed, 42 insertions(+), 38 deletions(-) rename src/components/{ => Footer}/Footer.tsx (93%) create mode 100644 src/components/Footer/index.ts diff --git a/src/api/auth/AuthProvider.tsx b/src/api/auth/AuthProvider.tsx index 5015ed4..2de5e92 100644 --- a/src/api/auth/AuthProvider.tsx +++ b/src/api/auth/AuthProvider.tsx @@ -64,12 +64,20 @@ const AuthProvider: FC<{ children: ReactNode }> = ({ children }) => { setCookies(response.data); } + async function logout() { + console.log('Logout called') + clearCookies(); + setAuthenticated(false); + window.location.href = buildLogoutHref(); + } + async function authorize(code: string) { console.log('Authorize called') setLoading(true); try { const response = await oauthAuthorize(code); setCookies(response.data); + setInterceptorIds(createInterceptors(refresh, setError, logout)); setAuthenticated(true); } catch (error) { setError(error as Error); @@ -79,13 +87,6 @@ const AuthProvider: FC<{ children: ReactNode }> = ({ children }) => { } } - async function logout() { - console.log('Logout called') - clearCookies(); - setAuthenticated(false); - window.location.href = buildLogoutHref(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps const value = useMemo(() => ({ loading, authenticated, error, authorize, logout }), [loading, error, authenticated]); diff --git a/src/api/auth/instance.ts b/src/api/auth/instance.ts index f3e09ab..203216c 100644 --- a/src/api/auth/instance.ts +++ b/src/api/auth/instance.ts @@ -50,6 +50,8 @@ export function createInterceptors( (error) => { if (error.response.status === 401) { refreshRetry(error.config, error); + } else { + return Promise.reject(error); } } ), diff --git a/src/api/transaction.ts b/src/api/transaction.ts index 70d3027..4c25945 100644 --- a/src/api/transaction.ts +++ b/src/api/transaction.ts @@ -14,8 +14,5 @@ export type TransactionResponse = Record; export async function postTransaction( request: TransactionRequest ): Promise> { - return axiosAuthInstance.post("/transaction", request).then((resp) => { - resp.data = resp.data as TransactionResponse; - return resp; - }); + return axiosAuthInstance.post("/transaction", request); } diff --git a/src/api/userinfo.ts b/src/api/userinfo.ts index 4e5508f..7c41163 100644 --- a/src/api/userinfo.ts +++ b/src/api/userinfo.ts @@ -6,13 +6,11 @@ export type UserInfoResponse = { name?: string; given_name?: string; family_name?: string; - preferred_username: string; + preferred_username?: string; + username: string email: string; }; export async function getUserInfo(): Promise> { - return axiosAuthInstance.get(`${AUTH_URL}/oauth2/userInfo`).then((resp) => { - resp.data = resp.data as UserInfoResponse; - return resp; - }); + return axiosAuthInstance.get(`${AUTH_URL}/oauth2/userInfo`); } diff --git a/src/components/Footer.tsx b/src/components/Footer/Footer.tsx similarity index 93% rename from src/components/Footer.tsx rename to src/components/Footer/Footer.tsx index 3911566..90ea85d 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer/Footer.tsx @@ -48,7 +48,7 @@ export function FooterSimple({ links }: FooterSimpleProps) { return (
- + {items}
diff --git a/src/components/Footer/index.ts b/src/components/Footer/index.ts new file mode 100644 index 0000000..399410b --- /dev/null +++ b/src/components/Footer/index.ts @@ -0,0 +1,2 @@ +import { FooterSimple } from "./Footer"; +export default FooterSimple; diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 95b55b8..88bda6d 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -14,12 +14,11 @@ import { IconLogout, IconSettings, } from "@tabler/icons"; -import { useAuth } from "api/auth"; import React from "react"; import { useState } from "react"; import LoginButton from "./LoginButton"; -import { getUserInfo } from "api"; +import { getUserInfo, useAuth } from "api"; const useStyles = createStyles((theme) => ({ link: { @@ -88,11 +87,13 @@ export default function HeaderMegaMenu() { const [userName, setUserName] = useState(""); React.useEffect(() => { - const getData = async () => { - const { preferred_username } = (await getUserInfo()).data; - setUserName(preferred_username); - }; - getData(); + if (authenticated && userName === "") { + // horribly hacky, waits until the auth interceptor has been set after being authenticated + new Promise(resolve => setTimeout(resolve, 500)).then(_ => { + getUserInfo().then(info => setUserName(info.data.username)); + }); + } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [authenticated]); return ( diff --git a/src/components/Transaction/TransactionResultsDisplay.tsx b/src/components/Transaction/TransactionResultsDisplay.tsx index 44b16b1..248b7cc 100644 --- a/src/components/Transaction/TransactionResultsDisplay.tsx +++ b/src/components/Transaction/TransactionResultsDisplay.tsx @@ -10,11 +10,11 @@ const CodeDisplay: React.FC<{text: string, label?: string}> = ({ label, text }) sx={{ borderRadius: '5px', background: '#002b36', - color: '#839496' + color: '#839496', }} >
-        
+        
           {text}
         
       
diff --git a/src/components/index.ts b/src/components/index.ts index d0d34f7..a7df27a 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,7 +1,8 @@ import LoginButton from "./LoginButton"; +import FooterSimple from "./Footer"; +import HeaderMegaMenu from "./Header"; -export { LoginButton }; -export { FooterSimple } from "./Footer"; +export { LoginButton, FooterSimple as Footer, HeaderMegaMenu as Header }; export { TransactionSelect, diff --git a/src/main.tsx b/src/main.tsx index 0c28897..f27d09a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -3,8 +3,7 @@ import ReactDOM from "react-dom/client"; import { HashRouter, Outlet, Route, Routes } from "react-router-dom"; import { AuthProvider, RequireAuth } from "api/auth"; import { Dashboard, Landing, NotFound, Transaction, UserInfo } from "pages"; -import { FooterSimple } from "components"; -import HeaderMegaMenu from "components/Header"; +import { Footer, Header } from "components"; ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( @@ -13,7 +12,7 @@ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
- +
} /> } /> - +
diff --git a/src/pages/Transaction.tsx b/src/pages/Transaction.tsx index cbdbd29..6ff68b8 100644 --- a/src/pages/Transaction.tsx +++ b/src/pages/Transaction.tsx @@ -3,16 +3,13 @@ import { Title, Grid, Button } from "@mantine/core"; import { postTransaction, TransactionRequest } from "api"; import { builders, TransactionResults, TransactionResultsDisplay, TransactionSelect } from "components"; import { IconClearAll } from "@tabler/icons"; +import { AxiosError } from "axios"; export default function Transaction() { const [responses, setResponses] = useState([]) const onSubmit = async (request: TransactionRequest) => { try { const response = await postTransaction(request); - - // fake sleeping for now - // await new Promise(r => setTimeout(r, 1000)); - // const response = {'test': 'response'}; setResponses([{ request, @@ -20,9 +17,13 @@ export default function Transaction() { date: new Date() }, ...responses]); } catch (e) { + let message = `Client Error: ${e}`; + if (e instanceof AxiosError) { + message = `Server Error (${e.code}): ${e.response?.data}`; + } else {} setResponses([{ request, - response: `Client Error: ${e}`, + response: message, date: new Date() }, ...responses]) } diff --git a/vite.config.ts b/vite.config.ts index 527c089..7c84292 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -6,7 +6,7 @@ import tsconfigPaths from "vite-tsconfig-paths"; // for deployments that are deployed to a sub-folder like /dev, specify below or use the `BASE_URL` env var const DEFAULT_BASE_URL = "/"; // to proxy transaction api requests on a different domain, specify below or use the `PROXY_URL` env var -const DEFAULT_PROXY_URL = "https://n2ft4ng3qh.execute-api.us-east-1.amazonaws.com/dev"; +const DEFAULT_PROXY_URL = "https://719hgl5ejk.execute-api.us-east-1.amazonaws.com/dev"; // https://vitejs.dev/config/ export default defineConfig({ @@ -16,6 +16,8 @@ export default defineConfig({ proxy: { "/transaction": { target: process.env.PROXY_URL ?? DEFAULT_PROXY_URL, + // Fixes SSL error on some requests + changeOrigin: true } } } From 0e92e33c71aa04641094d3e21958604763a342f7 Mon Sep 17 00:00:00 2001 From: Nikita Wootten Date: Wed, 2 Nov 2022 13:07:39 -0400 Subject: [PATCH 2/2] Remove `DEFAULT_PROXY_URL` from vite config --- .env.sample | 5 ++++- src/components/Footer/Footer.tsx | 2 +- vite.config.ts | 4 +--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.env.sample b/.env.sample index bbc237f..d163840 100644 --- a/.env.sample +++ b/.env.sample @@ -1,3 +1,6 @@ +# Cognito-defined auth parameters VITE_CLIENT_ID=some-oidc-client-id VITE_CLIENT_SECRET=some-oidc-client-secret -VITE_AUTH_URL=some-oidc-idp-url +VITE_AUTH_URL=https://{COGNITO_NAME}.auth.us-east-1.amazoncognito.com +# APIGW base URL to proxy transaction API requests +PROXY_URL=https://{APIGW_ID}.execute-api.us-east-1.amazonaws.com/{STAGE} diff --git a/src/components/Footer/Footer.tsx b/src/components/Footer/Footer.tsx index 90ea85d..fd00624 100644 --- a/src/components/Footer/Footer.tsx +++ b/src/components/Footer/Footer.tsx @@ -48,7 +48,7 @@ export function FooterSimple({ links }: FooterSimpleProps) { return (
- + {items}
diff --git a/vite.config.ts b/vite.config.ts index 7c84292..919f0f2 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,8 +5,6 @@ import tsconfigPaths from "vite-tsconfig-paths"; // for deployments that are deployed to a sub-folder like /dev, specify below or use the `BASE_URL` env var const DEFAULT_BASE_URL = "/"; -// to proxy transaction api requests on a different domain, specify below or use the `PROXY_URL` env var -const DEFAULT_PROXY_URL = "https://719hgl5ejk.execute-api.us-east-1.amazonaws.com/dev"; // https://vitejs.dev/config/ export default defineConfig({ @@ -15,7 +13,7 @@ export default defineConfig({ server: { proxy: { "/transaction": { - target: process.env.PROXY_URL ?? DEFAULT_PROXY_URL, + target: process.env.PROXY_URL, // Fixes SSL error on some requests changeOrigin: true }