Merge to main (#17)

* Fix sign up form bug

* Add run.sh to run setup and run web app

* Output node version

* Update readme with run.sh

* Fix file upload form to handle ota_update service

* Enable file upload form

Enable error boundary to catch React errors (#7)
Fix warning for link noreferrer
Include authorization header with file upload

* Remove default localhost settings (#8)

* Remove default localhost settings
Replace with deployment settings

* Fix for upload data format

* Fix test data for last commit

* Fix json link format and remove localhost default settings (#10)

* Remove default localhost settings
Replace with deployment settings

* Fix for upload data format

* Fix test data for last commit

* Fix link data format

* Fix link json again (#12)

Use id token instead of access token

* nginx things

* Web Worker Sign Out and Use Go API (#13)

* Calculate checksum and send with file upload

* Limit file upload and display rejected file error

* Add sign in timeout

* Check auth token structure before setting
Clean up

* Use web worker timer to sign out
Remove checksum
Point to Go ota update

* Remove checksum dependency

* Use compute auth service and fix static code analyzer warnings (#15)

* Clean up formatting

* Use new compute_auth service
Implment SSO
Implement token refresh
Clean up unit tests

* Fix unit tests

* Fix auth test
Fix warnings

* Update default settings for compute_auth

* Change main UI layout and add VINs to add and upload forms (#16)

* Add new upload update package form
Add new add vehicle form
Add new side menu layout
Add new toolbar layout
Update and add unit tests

* Enable add get and add vehicles

* Integration issues with ota_update service

* Update get vehicle JSON format

* Fix related unit test
Add release notes field

* Add StatusContext to display error and status messages

* Handle api error json (#18)

* Handle api error json

* Fix get vehicles error handling
Update .env.template

Co-authored-by: Rafi Greenberg <rgreenberg@fiskerinc.com>
This commit is contained in:
John Wu
2021-03-17 15:16:08 -07:00
committed by GitHub
parent 86d65b887c
commit 30155887cb
62 changed files with 4800 additions and 3716 deletions

View File

@@ -1,5 +1,6 @@
import React, { useContext, useEffect, useState } from 'react';
import auth from '../../services/auth';
import React, { useContext, useEffect, useState } from "react";
import auth from "../../services/auth";
import getTimerWorker from "../../services/timer";
const UserContext = React.createContext();
@@ -7,87 +8,153 @@ export const UserProvider = ({ children }) => {
const [fetching, setFetching] = useState(false);
const [token, setToken] = useState(null);
const [error, setError] = useState(null);
let timer;
useEffect(() => {
if (!localStorage) return;
const token = JSON.parse(localStorage.getItem("token"));
if (!token) return;
const { accessToken: { jwtToken }} = token;
const verifyToken = async (accessToken) => {
const result = await auth.verify(accessToken);
if (result.authenticated) {
setToken(token);
} else {
await signOut();
}
};
verifyToken(jwtToken);
return () => {};
const t = JSON.parse(localStorage.getItem("token"));
if (!t || !t.idToken || !t.idToken.jwtToken) return;
if (!t.idToken.payload || !t.idToken.payload.exp) return;
setToken(t);
}, []);
const signIn = async (username, password) => {
useEffect(() => {
if (!token) return;
verifyToken();
return () => {
if (timer) timer.terminate();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [token]);
const refreshTokens = async () => {
if (!token || !token.refreshToken || !token.refreshToken.token) return null;
const result = await refresh(token.refreshToken.token);
return result;
};
const isError = (resp) => {
if (resp === null) return true;
if (resp && resp.error) return true;
return false;
};
const startSessionTimer = () => {
const duration = 1000 * token.idToken.payload.exp - new Date().getTime();
if (!timer) {
timer = getTimerWorker();
timer.onMessage(async (e) => {
if (e.data === "timeout") {
const t = await refreshTokens();
if (!isError(t)) return;
signOut();
}
});
}
timer.start(duration);
};
const verifyToken = async () => {
try {
if (!username) throw new Error('Email is required');
if (!password) throw new Error('Password is required');
const {
idToken: { jwtToken: idToken },
} = token;
const result = await auth.verify(idToken);
if (!result && !result.valid) {
const t = await refreshTokens();
if (!isError(t)) return;
signOut();
return;
}
startSessionTimer();
} catch (e) {
signOut();
setError(`Verify error. ${e.message}`);
}
};
const signIn = async (code) => {
let result = null;
try {
if (!code) return;
setFetching(true);
setError(null);
const result = await auth.signIn(username, password);
if (result.message) throw new Error(result.message);
result = await auth.signIn(code);
if (result.message) {
throw new Error(result.message);
}
signedIn(result);
}
catch (error) {
setError(error.message);
}
finally {
} catch (err) {
setError(`Sign in error. ${err.message}`);
} finally {
setFetching(false);
}
return result;
};
const signUp = async (username, password, confirmPassword) => {
try {
if (!username) throw new Error('Email is required');
if (!password) throw new Error('Password is required');
if (password !== confirmPassword) throw new Error('Passwords do not match');
const signOut = () => {
setToken(null);
if (localStorage) {
localStorage.removeItem("token");
}
return getLogoutURL();
};
const signedIn = (value) => {
setToken(value);
if (!localStorage || !value || !value.idToken) return;
localStorage.setItem("token", JSON.stringify(value));
};
const refresh = async (value) => {
let result = null;
try {
if (!value) {
throw new Error("Token required");
}
setFetching(true);
setError(null);
const result = await auth.signUp(username, password);
if (result.message) throw new Error(result.message);
}
catch (error) {
setError(error.message);
}
finally {
result = await auth.refresh(value);
if (result.message) {
throw new Error(result.message);
}
signedIn(result);
} catch (err) {
setError(`Refresh error. ${err.message}`);
} finally {
setFetching(false);
}
return result;
};
const signOut = async () => {
setToken(null);
if (!localStorage) return;
localStorage.removeItem("token");
};
const signedIn = (token) => {
setToken(token);
if (!localStorage || !token || !token.accessToken) return;
localStorage.setItem("token", JSON.stringify(token));
}
const getAuthorizeURL = () => auth.ssoAuthorize();
const getLogoutURL = () => auth.ssoLogout();
return (
<UserContext.Provider value={{
fetching,
token,
error,
setError,
signIn,
signUp,
signOut,
}}>
<UserContext.Provider
value={{
fetching,
token,
error,
setError,
signIn,
signOut,
refresh,
getAuthorizeURL,
getLogoutURL,
}}
>
{children}
</UserContext.Provider>
);