summaryrefslogtreecommitdiff
path: root/web/src
diff options
context:
space:
mode:
Diffstat (limited to 'web/src')
-rw-r--r--web/src/App.test.tsx10
-rw-r--r--web/src/App.tsx49
-rw-r--r--web/src/Routes.ts3
-rw-r--r--web/src/components/AppStoreBadges.test.tsx15
-rw-r--r--web/src/components/AppStoreBadges.tsx14
-rw-r--r--web/src/components/ColoredSnackbarContent.test.tsx20
-rw-r--r--web/src/components/ColoredSnackbarContent.tsx29
-rw-r--r--web/src/components/FailureIcon.test.tsx8
-rw-r--r--web/src/components/FailureIcon.tsx13
-rw-r--r--web/src/components/FingerTouchIcon.test.tsx8
-rw-r--r--web/src/components/FingerTouchIcon.tsx42
-rw-r--r--web/src/components/FixedTextField.test.tsx8
-rw-r--r--web/src/components/FixedTextField.tsx25
-rw-r--r--web/src/components/InformationIcon.test.tsx8
-rw-r--r--web/src/components/InformationIcon.tsx13
-rw-r--r--web/src/components/LinearProgressBar.test.tsx8
-rw-r--r--web/src/components/LinearProgressBar.tsx16
-rw-r--r--web/src/components/NotificationBar.test.tsx10
-rw-r--r--web/src/components/NotificationBar.tsx16
-rw-r--r--web/src/components/PieChartIcon.test.tsx8
-rw-r--r--web/src/components/PieChartIcon.tsx15
-rw-r--r--web/src/components/PushNotificationIcon.test.tsx8
-rw-r--r--web/src/components/PushNotificationIcon.tsx66
-rw-r--r--web/src/components/SuccessIcon.test.tsx8
-rw-r--r--web/src/components/SuccessIcon.tsx11
-rw-r--r--web/src/components/TimerIcon.test.tsx8
-rw-r--r--web/src/components/TimerIcon.tsx22
-rw-r--r--web/src/constants.ts3
-rw-r--r--web/src/hooks/Configuration.ts4
-rw-r--r--web/src/hooks/IntermittentClass.ts5
-rw-r--r--web/src/hooks/Mounted.ts6
-rw-r--r--web/src/hooks/NotificationsContext.ts25
-rw-r--r--web/src/hooks/RedirectionURL.ts6
-rw-r--r--web/src/hooks/RemoteCall.ts17
-rw-r--r--web/src/hooks/State.ts2
-rw-r--r--web/src/hooks/Timer.ts12
-rw-r--r--web/src/hooks/UserInfo.ts2
-rw-r--r--web/src/index.tsx18
-rw-r--r--web/src/layouts/LoginLayout.tsx44
-rw-r--r--web/src/models/Configuration.ts2
-rw-r--r--web/src/models/Methods.ts3
-rw-r--r--web/src/models/Notifications.ts2
-rw-r--r--web/src/react-app-env.d.ts2
-rw-r--r--web/src/serviceWorker.ts204
-rw-r--r--web/src/services/Api.ts11
-rw-r--r--web/src/services/Client.ts3
-rw-r--r--web/src/services/Configuration.ts6
-rw-r--r--web/src/services/FirstFactor.ts13
-rw-r--r--web/src/services/OneTimePassword.ts4
-rw-r--r--web/src/services/PushNotification.ts4
-rw-r--r--web/src/services/RegisterDevice.ts32
-rw-r--r--web/src/services/ResetPassword.ts3
-rw-r--r--web/src/services/SecurityKey.ts19
-rw-r--r--web/src/services/SignIn.ts3
-rw-r--r--web/src/services/SignOut.ts4
-rw-r--r--web/src/services/State.ts6
-rw-r--r--web/src/services/UserPreferences.ts9
-rw-r--r--web/src/setupTests.js4
-rw-r--r--web/src/utils/AssetPath.ts6
-rw-r--r--web/src/utils/BasePath.ts2
-rw-r--r--web/src/utils/Configuration.ts16
-rw-r--r--web/src/utils/IdentityToken.ts6
-rw-r--r--web/src/views/DeviceRegistration/RegisterOneTimePassword.tsx153
-rw-r--r--web/src/views/DeviceRegistration/RegisterSecurityKey.tsx45
-rw-r--r--web/src/views/LoadingPage/LoadingPage.tsx7
-rw-r--r--web/src/views/LoginPortal/Authenticated.tsx18
-rw-r--r--web/src/views/LoginPortal/AuthenticatedView/AuthenticatedView.tsx21
-rw-r--r--web/src/views/LoginPortal/FirstFactor/FirstFactorForm.tsx88
-rw-r--r--web/src/views/LoginPortal/LoginPortal.tsx67
-rw-r--r--web/src/views/LoginPortal/SecondFactor/IconWithContext.tsx19
-rw-r--r--web/src/views/LoginPortal/SecondFactor/MethodContainer.tsx53
-rw-r--r--web/src/views/LoginPortal/SecondFactor/MethodSelectionDialog.tsx92
-rw-r--r--web/src/views/LoginPortal/SecondFactor/OTPDial.tsx40
-rw-r--r--web/src/views/LoginPortal/SecondFactor/OneTimePasswordMethod.tsx34
-rw-r--r--web/src/views/LoginPortal/SecondFactor/PushNotificationMethod.tsx45
-rw-r--r--web/src/views/LoginPortal/SecondFactor/SecondFactorForm.tsx80
-rw-r--r--web/src/views/LoginPortal/SecondFactor/SecurityKeyMethod.tsx85
-rw-r--r--web/src/views/LoginPortal/SignOut/SignOut.tsx36
-rw-r--r--web/src/views/ResetPassword/ResetPasswordStep1.tsx45
-rw-r--r--web/src/views/ResetPassword/ResetPasswordStep2.tsx63
80 files changed, 1063 insertions, 897 deletions
diff --git a/web/src/App.test.tsx b/web/src/App.test.tsx
index 2e29af42b..67a662c24 100644
--- a/web/src/App.test.tsx
+++ b/web/src/App.test.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
+import React from "react";
+
import { shallow } from "enzyme";
-import App from './App';
-it('renders without crashing', () => {
- shallow(<App />);
+import App from "./App";
+
+it("renders without crashing", () => {
+ shallow(<App />);
});
diff --git a/web/src/App.tsx b/web/src/App.tsx
index 07bdcaf22..5cf7b2744 100644
--- a/web/src/App.tsx
+++ b/web/src/App.tsx
@@ -1,26 +1,29 @@
-import React, { useState } from 'react';
-import {
- BrowserRouter as Router, Route, Switch, Redirect
-} from "react-router-dom";
-import ResetPasswordStep1 from './views/ResetPassword/ResetPasswordStep1';
-import ResetPasswordStep2 from './views/ResetPassword/ResetPasswordStep2';
-import RegisterSecurityKey from './views/DeviceRegistration/RegisterSecurityKey';
-import RegisterOneTimePassword from './views/DeviceRegistration/RegisterOneTimePassword';
+import React, { useState } from "react";
+
+import { config as faConfig } from "@fortawesome/fontawesome-svg-core";
+import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom";
+
+import NotificationBar from "./components/NotificationBar";
+import NotificationsContext from "./hooks/NotificationsContext";
+import { Notification } from "./models/Notifications";
import {
- FirstFactorRoute, ResetPasswordStep2Route,
- ResetPasswordStep1Route, RegisterSecurityKeyRoute,
+ FirstFactorRoute,
+ ResetPasswordStep2Route,
+ ResetPasswordStep1Route,
+ RegisterSecurityKeyRoute,
RegisterOneTimePasswordRoute,
LogoutRoute,
} from "./Routes";
-import LoginPortal from './views/LoginPortal/LoginPortal';
-import NotificationsContext from './hooks/NotificationsContext';
-import { Notification } from './models/Notifications';
-import NotificationBar from './components/NotificationBar';
-import SignOut from './views/LoginPortal/SignOut/SignOut';
-import { getRememberMe, getResetPassword } from './utils/Configuration';
-import '@fortawesome/fontawesome-svg-core/styles.css'
-import { config as faConfig } from '@fortawesome/fontawesome-svg-core';
-import { getBasePath } from './utils/BasePath';
+import { getBasePath } from "./utils/BasePath";
+import { getRememberMe, getResetPassword } from "./utils/Configuration";
+import RegisterOneTimePassword from "./views/DeviceRegistration/RegisterOneTimePassword";
+import RegisterSecurityKey from "./views/DeviceRegistration/RegisterSecurityKey";
+import LoginPortal from "./views/LoginPortal/LoginPortal";
+import SignOut from "./views/LoginPortal/SignOut/SignOut";
+import ResetPasswordStep1 from "./views/ResetPassword/ResetPasswordStep1";
+import ResetPasswordStep2 from "./views/ResetPassword/ResetPasswordStep2";
+
+import "@fortawesome/fontawesome-svg-core/styles.css";
faConfig.autoAddCss = false;
@@ -28,7 +31,7 @@ const App: React.FC = () => {
const [notification, setNotification] = useState(null as Notification | null);
return (
- <NotificationsContext.Provider value={{ notification, setNotification }} >
+ <NotificationsContext.Provider value={{ notification, setNotification }}>
<Router basename={getBasePath()}>
<NotificationBar onClose={() => setNotification(null)} />
<Switch>
@@ -48,9 +51,7 @@ const App: React.FC = () => {
<SignOut />
</Route>
<Route path={FirstFactorRoute}>
- <LoginPortal
- rememberMe={getRememberMe()}
- resetPassword={getResetPassword()} />
+ <LoginPortal rememberMe={getRememberMe()} resetPassword={getResetPassword()} />
</Route>
<Route path="/">
<Redirect to={FirstFactorRoute} />
@@ -59,6 +60,6 @@ const App: React.FC = () => {
</Router>
</NotificationsContext.Provider>
);
-}
+};
export default App;
diff --git a/web/src/Routes.ts b/web/src/Routes.ts
index 093712e61..3e3ee0ac5 100644
--- a/web/src/Routes.ts
+++ b/web/src/Routes.ts
@@ -1,4 +1,3 @@
-
export const FirstFactorRoute = "/";
export const AuthenticatedRoute = "/authenticated";
@@ -11,4 +10,4 @@ export const ResetPasswordStep1Route = "/reset-password/step1";
export const ResetPasswordStep2Route = "/reset-password/step2";
export const RegisterSecurityKeyRoute = "/security-key/register";
export const RegisterOneTimePasswordRoute = "/one-time-password/register";
-export const LogoutRoute = "/logout"; \ No newline at end of file
+export const LogoutRoute = "/logout";
diff --git a/web/src/components/AppStoreBadges.test.tsx b/web/src/components/AppStoreBadges.test.tsx
index c5e2de0ee..54fa554d8 100644
--- a/web/src/components/AppStoreBadges.test.tsx
+++ b/web/src/components/AppStoreBadges.test.tsx
@@ -1,12 +1,11 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
+import React from "react";
+
+import ReactDOM from "react-dom";
+
import AppStoreBadges from "./AppStoreBadges";
-it('renders without crashing', () => {
- const div = document.createElement('div');
- ReactDOM.render(<AppStoreBadges
- iconSize={32}
- appleStoreLink="http://apple"
- googlePlayLink="http://google" />, div);
+it("renders without crashing", () => {
+ const div = document.createElement("div");
+ ReactDOM.render(<AppStoreBadges iconSize={32} appleStoreLink="http://apple" googlePlayLink="http://google" />, div);
ReactDOM.unmountComponentAtNode(div);
});
diff --git a/web/src/components/AppStoreBadges.tsx b/web/src/components/AppStoreBadges.tsx
index 8b5718454..66417dc59 100644
--- a/web/src/components/AppStoreBadges.tsx
+++ b/web/src/components/AppStoreBadges.tsx
@@ -1,8 +1,10 @@
import React from "react";
-import GooglePlay from "../assets/images/googleplay-badge.svg";
-import AppleStore from "../assets/images/applestore-badge.svg";
+
import { Link } from "@material-ui/core";
+import AppleStore from "../assets/images/applestore-badge.svg";
+import GooglePlay from "../assets/images/googleplay-badge.svg";
+
export interface Props {
iconSize: number;
googlePlayLink: string;
@@ -25,8 +27,8 @@ const AppStoreBadges = function (props: Props) {
<Link href={props.appleStoreLink} target={target}>
<img src={AppleStore} alt="apple store" style={{ width }} />
</Link>
- </div >
- )
-}
+ </div>
+ );
+};
-export default AppStoreBadges \ No newline at end of file
+export default AppStoreBadges;
diff --git a/web/src/components/ColoredSnackbarContent.test.tsx b/web/src/components/ColoredSnackbarContent.test.tsx
index 26bd1aea1..3ffbe4e23 100644
--- a/web/src/components/ColoredSnackbarContent.test.tsx
+++ b/web/src/components/ColoredSnackbarContent.test.tsx
@@ -1,23 +1,25 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import { mount, shallow } from "enzyme";
+import React from "react";
+
+import { SnackbarContent } from "@material-ui/core";
import { expect } from "chai";
+import { mount, shallow } from "enzyme";
+import ReactDOM from "react-dom";
+
import ColoredSnackbarContent from "./ColoredSnackbarContent";
-import { SnackbarContent } from '@material-ui/core';
-it('renders without crashing', () => {
- const div = document.createElement('div');
+it("renders without crashing", () => {
+ const div = document.createElement("div");
ReactDOM.render(<ColoredSnackbarContent level="success" message="this is a success" />, div);
ReactDOM.unmountComponentAtNode(div);
});
-it('should contain the message', () => {
+it("should contain the message", () => {
const el = mount(<ColoredSnackbarContent level="success" message="this is a success" />);
expect(el.text()).to.contain("this is a success");
});
/* eslint-disable @typescript-eslint/no-unused-expressions */
-it('should have correct color', () => {
+it("should have correct color", () => {
let el = shallow(<ColoredSnackbarContent level="success" message="this is a success" />);
expect(el.find(SnackbarContent).props().className!.indexOf("success") > -1).to.be.true;
@@ -30,4 +32,4 @@ it('should have correct color', () => {
el = shallow(<ColoredSnackbarContent level="warning" message="this is an warning" />);
expect(el.find(SnackbarContent).props().className!.indexOf("warning") > -1).to.be.true;
});
-/* eslint-enable @typescript-eslint/no-unused-expressions */ \ No newline at end of file
+/* eslint-enable @typescript-eslint/no-unused-expressions */
diff --git a/web/src/components/ColoredSnackbarContent.tsx b/web/src/components/ColoredSnackbarContent.tsx
index 5adda3cea..4cb5b5e40 100644
--- a/web/src/components/ColoredSnackbarContent.tsx
+++ b/web/src/components/ColoredSnackbarContent.tsx
@@ -1,13 +1,13 @@
import React from "react";
-import CheckCircleIcon from '@material-ui/icons/CheckCircle';
-import ErrorIcon from '@material-ui/icons/Error';
-import InfoIcon from '@material-ui/icons/Info';
-import WarningIcon from '@material-ui/icons/Warning';
import { makeStyles, SnackbarContent } from "@material-ui/core";
-import { amber, green } from '@material-ui/core/colors';
-import classnames from "classnames";
+import { amber, green } from "@material-ui/core/colors";
import { SnackbarContentProps } from "@material-ui/core/SnackbarContent";
+import CheckCircleIcon from "@material-ui/icons/CheckCircle";
+import ErrorIcon from "@material-ui/icons/Error";
+import InfoIcon from "@material-ui/icons/Info";
+import WarningIcon from "@material-ui/icons/Warning";
+import classnames from "classnames";
const variantIcon = {
success: CheckCircleIcon,
@@ -39,13 +39,14 @@ const ColoredSnackbarContent = function (props: Props) {
{message}
</span>
}
- {...others} />
- )
-}
+ {...others}
+ />
+ );
+};
-export default ColoredSnackbarContent
+export default ColoredSnackbarContent;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
success: {
backgroundColor: green[600],
},
@@ -66,7 +67,7 @@ const useStyles = makeStyles(theme => ({
marginRight: theme.spacing(1),
},
message: {
- display: 'flex',
- alignItems: 'center',
+ display: "flex",
+ alignItems: "center",
},
-})) \ No newline at end of file
+}));
diff --git a/web/src/components/FailureIcon.test.tsx b/web/src/components/FailureIcon.test.tsx
index df028b48f..e01698170 100644
--- a/web/src/components/FailureIcon.test.tsx
+++ b/web/src/components/FailureIcon.test.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
+import React from "react";
+
import { mount } from "enzyme";
+
import FailureIcon from "./FailureIcon";
-it('renders without crashing', () => {
+it("renders without crashing", () => {
mount(<FailureIcon />);
-}); \ No newline at end of file
+});
diff --git a/web/src/components/FailureIcon.tsx b/web/src/components/FailureIcon.tsx
index 7069646ec..bc64792b7 100644
--- a/web/src/components/FailureIcon.tsx
+++ b/web/src/components/FailureIcon.tsx
@@ -1,13 +1,12 @@
import React from "react";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+
import { faTimesCircle } from "@fortawesome/free-regular-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-export interface Props { }
+export interface Props {}
const FailureIcon = function (props: Props) {
- return (
- <FontAwesomeIcon icon={faTimesCircle} size="4x" color="red" className="failure-icon" />
- )
-}
+ return <FontAwesomeIcon icon={faTimesCircle} size="4x" color="red" className="failure-icon" />;
+};
-export default FailureIcon \ No newline at end of file
+export default FailureIcon;
diff --git a/web/src/components/FingerTouchIcon.test.tsx b/web/src/components/FingerTouchIcon.test.tsx
index d566e6830..31446e026 100644
--- a/web/src/components/FingerTouchIcon.test.tsx
+++ b/web/src/components/FingerTouchIcon.test.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
+import React from "react";
+
import { mount } from "enzyme";
+
import FingerTouchIcon from "./FingerTouchIcon";
-it('renders without crashing', () => {
+it("renders without crashing", () => {
mount(<FingerTouchIcon size={32} />);
-}); \ No newline at end of file
+});
diff --git a/web/src/components/FingerTouchIcon.tsx b/web/src/components/FingerTouchIcon.tsx
index e905dad27..d7c9ad5aa 100644
--- a/web/src/components/FingerTouchIcon.tsx
+++ b/web/src/components/FingerTouchIcon.tsx
@@ -1,21 +1,32 @@
import React from "react";
-import style from "./FingerTouchIcon.module.css";
+
import classnames from "classnames";
+import style from "./FingerTouchIcon.module.css";
+
export interface Props {
- size: number;
+ size: number;
- animated?: boolean;
- strong?: boolean;
+ animated?: boolean;
+ strong?: boolean;
}
const FingerTouchIcon = function (props: Props) {
- const shakingClass = (props.animated) ? style.shaking : undefined;
- const strong = (props.strong) ? style.strong : undefined;
+ const shakingClass = props.animated ? style.shaking : undefined;
+ const strong = props.strong ? style.strong : undefined;
return (
- <svg x="0px" y="0px" viewBox="0 0 500 500" width={props.size} height={props.size} className={classnames(style.hand, strong)}>
- <path className={shakingClass} d="M438.827,186.347l-80.213-88.149c-15.872-15.872-41.728-15.893-57.749,0.128c-5.077,5.077-8.533,11.157-10.325,17.643
+ <svg
+ x="0px"
+ y="0px"
+ viewBox="0 0 500 500"
+ width={props.size}
+ height={props.size}
+ className={classnames(style.hand, strong)}
+ >
+ <path
+ className={shakingClass}
+ d="M438.827,186.347l-80.213-88.149c-15.872-15.872-41.728-15.893-57.749,0.128c-5.077,5.077-8.533,11.157-10.325,17.643
c-15.957-12.224-38.976-11.008-53.675,3.691c-5.056,5.077-8.512,11.157-10.347,17.621c-15.957-12.181-38.976-10.987-53.653,3.712
c-4.971,4.971-8.384,10.901-10.24,17.216l-37.803-37.803c-15.872-15.872-41.728-15.893-57.749,0.128
c-15.893,15.872-15.893,41.728,0,57.621l145.237,145.237l-86.144,13.525c-23.275,3.328-40.832,23.552-40.832,47.083
@@ -31,14 +42,17 @@ const FingerTouchIcon = function (props: Props) {
c0.021,0.021,0.021,0.021,0.021,0.021h0.021c0.021,0,0.021,0.021,0.021,0.021c4.181,3.968,10.795,3.883,14.869-0.213
c4.16-4.16,4.16-10.923,0-15.083l-0.917-0.917c-3.669-3.669-5.696-8.555-5.696-13.739s2.005-10.048,5.803-13.845
c7.595-7.552,19.883-7.531,27.115-0.363l79.872,87.787C439.125,218.389,448,241.301,448,265.216
- C448,290.816,438.037,314.88,419.925,332.992z"/>
- <path className={style.wave} d="M183.381,109.931C167.851,75.563,133.547,53.333,96,53.333c-52.928,0-96,43.072-96,96
+ C448,290.816,438.037,314.88,419.925,332.992z"
+ />
+ <path
+ className={style.wave}
+ d="M183.381,109.931C167.851,75.563,133.547,53.333,96,53.333c-52.928,0-96,43.072-96,96
c0,37.547,22.229,71.851,56.597,87.403c1.429,0.64,2.923,0.939,4.395,0.939c4.053,0,7.936-2.347,9.728-6.272
c2.411-5.376,0.021-11.691-5.333-14.123c-26.752-12.096-44.053-38.763-44.053-67.947c0-41.173,33.493-74.667,74.667-74.667
c29.184,0,55.851,17.301,67.947,44.053c2.411,5.376,8.747,7.787,14.101,5.333C183.424,121.621,185.813,115.307,183.381,109.931z"
- />
+ />
</svg>
- )
-}
+ );
+};
-export default FingerTouchIcon \ No newline at end of file
+export default FingerTouchIcon;
diff --git a/web/src/components/FixedTextField.test.tsx b/web/src/components/FixedTextField.test.tsx
index 4b7e19da5..af6b8a4ab 100644
--- a/web/src/components/FixedTextField.test.tsx
+++ b/web/src/components/FixedTextField.test.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
+import React from "react";
+
import { mount } from "enzyme";
+
import FixedTextField from "./FixedTextField";
-it('renders without crashing', () => {
+it("renders without crashing", () => {
mount(<FixedTextField />);
-}); \ No newline at end of file
+});
diff --git a/web/src/components/FixedTextField.tsx b/web/src/components/FixedTextField.tsx
index 5e9c0f3b6..54febc1d5 100644
--- a/web/src/components/FixedTextField.tsx
+++ b/web/src/components/FixedTextField.tsx
@@ -1,34 +1,37 @@
import React from "react";
-import TextField, { TextFieldProps } from "@material-ui/core/TextField";
+
import { makeStyles } from "@material-ui/core";
+import TextField, { TextFieldProps } from "@material-ui/core/TextField";
/**
* This component fixes outlined TextField
* https://github.com/mui-org/material-ui/issues/14530#issuecomment-463576879
- *
+ *
* @param props the TextField props
*/
const FixedTextField = function (props: TextFieldProps) {
const style = useStyles();
return (
- <TextField {...props}
+ <TextField
+ {...props}
InputLabelProps={{
classes: {
- root: style.label
- }
+ root: style.label,
+ },
}}
- inputProps={{autoCapitalize: props.autoCapitalize}}>
+ inputProps={{ autoCapitalize: props.autoCapitalize }}
+ >
{props.children}
</TextField>
);
-}
+};
-export default FixedTextField
+export default FixedTextField;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
label: {
backgroundColor: theme.palette.background.default,
paddingLeft: theme.spacing(0.1),
paddingRight: theme.spacing(0.1),
- }
-})); \ No newline at end of file
+ },
+}));
diff --git a/web/src/components/InformationIcon.test.tsx b/web/src/components/InformationIcon.test.tsx
index d1fa2b5c9..8bd2ca559 100644
--- a/web/src/components/InformationIcon.test.tsx
+++ b/web/src/components/InformationIcon.test.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
+import React from "react";
+
import { mount } from "enzyme";
+
import InformationIcon from "./InformationIcon";
-it('renders without crashing', () => {
+it("renders without crashing", () => {
mount(<InformationIcon />);
-}); \ No newline at end of file
+});
diff --git a/web/src/components/InformationIcon.tsx b/web/src/components/InformationIcon.tsx
index 357cd5e66..91b3f033a 100644
--- a/web/src/components/InformationIcon.tsx
+++ b/web/src/components/InformationIcon.tsx
@@ -1,13 +1,12 @@
import React from "react";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+
import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-export interface Props { }
+export interface Props {}
const InformationIcon = function (props: Props) {
- return (
- <FontAwesomeIcon icon={faInfoCircle} size="4x" color="#5858ff" className="information-icon" />
- )
-}
+ return <FontAwesomeIcon icon={faInfoCircle} size="4x" color="#5858ff" className="information-icon" />;
+};
-export default InformationIcon \ No newline at end of file
+export default InformationIcon;
diff --git a/web/src/components/LinearProgressBar.test.tsx b/web/src/components/LinearProgressBar.test.tsx
index 25441a003..e436bc5bb 100644
--- a/web/src/components/LinearProgressBar.test.tsx
+++ b/web/src/components/LinearProgressBar.test.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
+import React from "react";
+
import { mount } from "enzyme";
+
import LinearProgressBar from "./LinearProgressBar";
-it('renders without crashing', () => {
+it("renders without crashing", () => {
mount(<LinearProgressBar value={40} />);
-}); \ No newline at end of file
+});
diff --git a/web/src/components/LinearProgressBar.tsx b/web/src/components/LinearProgressBar.tsx
index b28276226..96fae97ab 100644
--- a/web/src/components/LinearProgressBar.tsx
+++ b/web/src/components/LinearProgressBar.tsx
@@ -1,4 +1,5 @@
import React from "react";
+
import { makeStyles, LinearProgress } from "@material-ui/core";
import { CSSProperties } from "@material-ui/styles";
@@ -10,13 +11,13 @@ export interface Props {
}
const LinearProgressBar = function (props: Props) {
- const style = makeStyles(theme => ({
+ const style = makeStyles((theme) => ({
progressRoot: {
height: props.height ? props.height : theme.spacing(),
},
transition: {
transition: "transform .2s linear",
- }
+ },
}))();
return (
<LinearProgress
@@ -24,11 +25,12 @@ const LinearProgressBar = function (props: Props) {
variant="determinate"
classes={{
root: style.progressRoot,
- bar1Determinate: style.transition
+ bar1Determinate: style.transition,
}}
value={props.value}
- className={props.className} />
- )
-}
+ className={props.className}
+ />
+ );
+};
-export default LinearProgressBar \ No newline at end of file
+export default LinearProgressBar;
diff --git a/web/src/components/NotificationBar.test.tsx b/web/src/components/NotificationBar.test.tsx
index bc0b536fa..26fc81f44 100644
--- a/web/src/components/NotificationBar.test.tsx
+++ b/web/src/components/NotificationBar.test.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
+import React from "react";
+
import { mount } from "enzyme";
+
import NotificationBar from "./NotificationBar";
-it('renders without crashing', () => {
- mount(<NotificationBar onClose={() => { }} />);
-}); \ No newline at end of file
+it("renders without crashing", () => {
+ mount(<NotificationBar onClose={() => {}} />);
+});
diff --git a/web/src/components/NotificationBar.tsx b/web/src/components/NotificationBar.tsx
index 119692665..f4202bf4e 100644
--- a/web/src/components/NotificationBar.tsx
+++ b/web/src/components/NotificationBar.tsx
@@ -1,8 +1,10 @@
import React, { useState, useEffect } from "react";
+
import { Snackbar } from "@material-ui/core";
-import ColoredSnackbarContent from "./ColoredSnackbarContent";
+
import { useNotifications } from "../hooks/NotificationsContext";
import { Notification } from "../models/Notifications";
+import ColoredSnackbarContent from "./ColoredSnackbarContent";
export interface Props {
onClose: () => void;
@@ -26,13 +28,15 @@ const NotificationBar = function (props: Props) {
anchorOrigin={{ vertical: "top", horizontal: "right" }}
autoHideDuration={tmpNotification ? tmpNotification.timeout * 1000 : 10000}
onClose={props.onClose}
- onExited={() => setTmpNotification(null)}>
+ onExited={() => setTmpNotification(null)}
+ >
<ColoredSnackbarContent
className="notification"
level={tmpNotification ? tmpNotification.level : "info"}
- message={tmpNotification ? tmpNotification.message : ""} />
+ message={tmpNotification ? tmpNotification.message : ""}
+ />
</Snackbar>
- )
-}
+ );
+};
-export default NotificationBar \ No newline at end of file
+export default NotificationBar;
diff --git a/web/src/components/PieChartIcon.test.tsx b/web/src/components/PieChartIcon.test.tsx
index ee9a6b8c8..2a59a6c7c 100644
--- a/web/src/components/PieChartIcon.test.tsx
+++ b/web/src/components/PieChartIcon.test.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
+import React from "react";
+
import { mount } from "enzyme";
+
import PieChartIcon from "./PieChartIcon";
-it('renders without crashing', () => {
+it("renders without crashing", () => {
mount(<PieChartIcon progress={40} />);
-}); \ No newline at end of file
+});
diff --git a/web/src/components/PieChartIcon.tsx b/web/src/components/PieChartIcon.tsx
index f04448bad..8d6e35ccd 100644
--- a/web/src/components/PieChartIcon.tsx
+++ b/web/src/components/PieChartIcon.tsx
@@ -23,13 +23,18 @@ const PieChartIcon = function (props: Props) {
<svg height={`${width}`} width={`${height}`} viewBox="0 0 26 26">
<circle r="12" cx="13" cy="13" fill="none" stroke={backgroundColor} strokeWidth="2" />
<circle r="9" cx="13" cy="13" fill={backgroundColor} stroke="transparent" />
- <circle r="5" cx="13" cy="13" fill="none"
+ <circle
+ r="5"
+ cx="13"
+ cy="13"
+ fill="none"
stroke={color}
strokeWidth="10"
strokeDasharray={`${props.progress} ${maxProgress}`}
- transform="rotate(-90) translate(-26)" />
+ transform="rotate(-90) translate(-26)"
+ />
</svg>
- )
-}
+ );
+};
-export default PieChartIcon \ No newline at end of file
+export default PieChartIcon;
diff --git a/web/src/components/PushNotificationIcon.test.tsx b/web/src/components/PushNotificationIcon.test.tsx
index de0453057..e11dad583 100644
--- a/web/src/components/PushNotificationIcon.test.tsx
+++ b/web/src/components/PushNotificationIcon.test.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
+import React from "react";
+
import { mount } from "enzyme";
+
import PushNotificationIcon from "./PushNotificationIcon";
-it('renders without crashing', () => {
+it("renders without crashing", () => {
mount(<PushNotificationIcon width={32} height={32} />);
-}); \ No newline at end of file
+});
diff --git a/web/src/components/PushNotificationIcon.tsx b/web/src/components/PushNotificationIcon.tsx
index 209e5caef..9842b7ec9 100644
--- a/web/src/components/PushNotificationIcon.tsx
+++ b/web/src/components/PushNotificationIcon.tsx
@@ -1,6 +1,7 @@
import React from "react";
+
+import { useIntermittentClass } from "../hooks/IntermittentClass";
import style from "./PushNotificationIcon.module.css";
-import {useIntermittentClass} from "../hooks/IntermittentClass";
export interface Props {
width: number;
@@ -13,34 +14,59 @@ const PushNotificationIcon = function (props: Props) {
const idleMilliseconds = 2500;
const wiggleMilliseconds = 500;
const startMilliseconds = 500;
- const wiggleClass = useIntermittentClass((props.animated) ? style.wiggle : "", wiggleMilliseconds, idleMilliseconds, startMilliseconds);
+ const wiggleClass = useIntermittentClass(
+ props.animated ? style.wiggle : "",
+ wiggleMilliseconds,
+ idleMilliseconds,
+ startMilliseconds,
+ );
return (
<svg x="0px" y="0px" viewBox="0 0 60 60" width={props.width} height={props.height} className={wiggleClass}>
<g>
- <path className="case" d="M42.595,0H17.405C14.977,0,13,1.977,13,4.405v51.189C13,58.023,14.977,60,17.405,60h25.189C45.023,60,47,58.023,47,55.595
+ <path
+ className="case"
+ d="M42.595,0H17.405C14.977,0,13,1.977,13,4.405v51.189C13,58.023,14.977,60,17.405,60h25.189C45.023,60,47,58.023,47,55.595
V4.405C47,1.977,45.023,0,42.595,0z M15,8h30v38H15V8z M17.405,2h25.189C43.921,2,45,3.079,45,4.405V6H15V4.405
- C15,3.079,16.079,2,17.405,2z M42.595,58H17.405C16.079,58,15,56.921,15,55.595V48h30v7.595C45,56.921,43.921,58,42.595,58z"/>
- <path className="button" d="M30,49c-2.206,0-4,1.794-4,4s1.794,4,4,4s4-1.794,4-4S32.206,49,30,49z M30,55c-1.103,0-2-0.897-2-2s0.897-2,2-2
- s2,0.897,2,2S31.103,55,30,55z"/>
- <path className="speaker" d="M26,5h4c0.553,0,1-0.447,1-1s-0.447-1-1-1h-4c-0.553,0-1,0.447-1,1S25.447,5,26,5z"/>
- <path className="camera" d="M33,5h1c0.553,0,1-0.447,1-1s-0.447-1-1-1h-1c-0.553,0-1,0.447-1,1S32.447,5,33,5z"/>
+ C15,3.079,16.079,2,17.405,2z M42.595,58H17.405C16.079,58,15,56.921,15,55.595V48h30v7.595C45,56.921,43.921,58,42.595,58z"
+ />
+ <path
+ className="button"
+ d="M30,49c-2.206,0-4,1.794-4,4s1.794,4,4,4s4-1.794,4-4S32.206,49,30,49z M30,55c-1.103,0-2-0.897-2-2s0.897-2,2-2
+ s2,0.897,2,2S31.103,55,30,55z"
+ />
+ <path
+ className="speaker"
+ d="M26,5h4c0.553,0,1-0.447,1-1s-0.447-1-1-1h-4c-0.553,0-1,0.447-1,1S25.447,5,26,5z"
+ />
+ <path
+ className="camera"
+ d="M33,5h1c0.553,0,1-0.447,1-1s-0.447-1-1-1h-1c-0.553,0-1,0.447-1,1S32.447,5,33,5z"
+ />
</g>
-
- <path d="M56.612,4.569c-0.391-0.391-1.023-0.391-1.414,0s-0.391,1.023,0,1.414c3.736,3.736,3.736,9.815,0,13.552
+
+ <path
+ d="M56.612,4.569c-0.391-0.391-1.023-0.391-1.414,0s-0.391,1.023,0,1.414c3.736,3.736,3.736,9.815,0,13.552
c-0.391,0.391-0.391,1.023,0,1.414c0.195,0.195,0.451,0.293,0.707,0.293s0.512-0.098,0.707-0.293
- C61.128,16.434,61.128,9.085,56.612,4.569z"/>
- <path d="M52.401,6.845c-0.391-0.391-1.023-0.391-1.414,0s-0.391,1.023,0,1.414c1.237,1.237,1.918,2.885,1.918,4.639
+ C61.128,16.434,61.128,9.085,56.612,4.569z"
+ />
+ <path
+ d="M52.401,6.845c-0.391-0.391-1.023-0.391-1.414,0s-0.391,1.023,0,1.414c1.237,1.237,1.918,2.885,1.918,4.639
s-0.681,3.401-1.918,4.638c-0.391,0.391-0.391,1.023,0,1.414c0.195,0.195,0.451,0.293,0.707,0.293s0.512-0.098,0.707-0.293
- c1.615-1.614,2.504-3.764,2.504-6.052S54.017,8.459,52.401,6.845z"/>
- <path d="M4.802,5.983c0.391-0.391,0.391-1.023,0-1.414s-1.023-0.391-1.414,0c-4.516,4.516-4.516,11.864,0,16.38
+ c1.615-1.614,2.504-3.764,2.504-6.052S54.017,8.459,52.401,6.845z"
+ />
+ <path
+ d="M4.802,5.983c0.391-0.391,0.391-1.023,0-1.414s-1.023-0.391-1.414,0c-4.516,4.516-4.516,11.864,0,16.38
c0.195,0.195,0.451,0.293,0.707,0.293s0.512-0.098,0.707-0.293c0.391-0.391,0.391-1.023,0-1.414
- C1.065,15.799,1.065,9.72,4.802,5.983z"/>
- <path d="M9.013,6.569c-0.391-0.391-1.023-0.391-1.414,0c-1.615,1.614-2.504,3.764-2.504,6.052s0.889,4.438,2.504,6.053
+ C1.065,15.799,1.065,9.72,4.802,5.983z"
+ />
+ <path
+ d="M9.013,6.569c-0.391-0.391-1.023-0.391-1.414,0c-1.615,1.614-2.504,3.764-2.504,6.052s0.889,4.438,2.504,6.053
c0.195,0.195,0.451,0.293,0.707,0.293s0.512-0.098,0.707-0.293c0.391-0.391,0.391-1.023,0-1.414
- c-1.237-1.237-1.918-2.885-1.918-4.639S7.775,9.22,9.013,7.983C9.403,7.593,9.403,6.96,9.013,6.569z"/>
+ c-1.237-1.237-1.918-2.885-1.918-4.639S7.775,9.22,9.013,7.983C9.403,7.593,9.403,6.96,9.013,6.569z"
+ />
</svg>
- )
-}
+ );
+};
-export default PushNotificationIcon \ No newline at end of file
+export default PushNotificationIcon;
diff --git a/web/src/components/SuccessIcon.test.tsx b/web/src/components/SuccessIcon.test.tsx
index 15d796210..b7e460936 100644
--- a/web/src/components/SuccessIcon.test.tsx
+++ b/web/src/components/SuccessIcon.test.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
+import React from "react";
+
import { mount } from "enzyme";
+
import SuccessIcon from "./SuccessIcon";
-it('renders without crashing', () => {
+it("renders without crashing", () => {
mount(<SuccessIcon />);
-}); \ No newline at end of file
+});
diff --git a/web/src/components/SuccessIcon.tsx b/web/src/components/SuccessIcon.tsx
index b01482d04..fd4deaa77 100644
--- a/web/src/components/SuccessIcon.tsx
+++ b/web/src/components/SuccessIcon.tsx
@@ -1,11 +1,10 @@
import React from "react";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+
import { faCheckCircle } from "@fortawesome/free-regular-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
const SuccessIcon = function () {
- return (
- <FontAwesomeIcon icon={faCheckCircle} size="4x" color="green" className="success-icon" />
- )
-}
+ return <FontAwesomeIcon icon={faCheckCircle} size="4x" color="green" className="success-icon" />;
+};
-export default SuccessIcon \ No newline at end of file
+export default SuccessIcon;
diff --git a/web/src/components/TimerIcon.test.tsx b/web/src/components/TimerIcon.test.tsx
index 692cd74e8..9c2a8a36d 100644
--- a/web/src/components/TimerIcon.test.tsx
+++ b/web/src/components/TimerIcon.test.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
+import React from "react";
+
import { mount } from "enzyme";
+
import TimerIcon from "./TimerIcon";
-it('renders without crashing', () => {
+it("renders without crashing", () => {
mount(<TimerIcon width={32} height={32} />);
-}); \ No newline at end of file
+});
diff --git a/web/src/components/TimerIcon.tsx b/web/src/components/TimerIcon.tsx
index 9a185f005..48d3510e0 100644
--- a/web/src/components/TimerIcon.tsx
+++ b/web/src/components/TimerIcon.tsx
@@ -1,4 +1,5 @@
import React, { useState, useEffect } from "react";
+
import PieChartIcon from "./PieChartIcon";
export interface Props {
@@ -16,21 +17,26 @@ const TimerIcon = function (props: Props) {
useEffect(() => {
// Get the current number of seconds to initialize timer.
- const initialValue = (new Date().getTime() / 1000) % props.period / props.period * radius;
+ const initialValue = (((new Date().getTime() / 1000) % props.period) / props.period) * radius;
setTimeProgress(initialValue);
const interval = setInterval(() => {
- const value = (new Date().getTime() / 1000) % props.period / props.period * radius;
+ const value = (((new Date().getTime() / 1000) % props.period) / props.period) * radius;
setTimeProgress(value);
}, 100);
return () => clearInterval(interval);
}, [props]);
return (
- <PieChartIcon width={props.width} height={props.height}
- progress={timeProgress} maxProgress={radius}
- backgroundColor={props.backgroundColor} color={props.color} />
- )
-}
+ <PieChartIcon
+ width={props.width}
+ height={props.height}
+ progress={timeProgress}
+ maxProgress={radius}
+ backgroundColor={props.backgroundColor}
+ color={props.color}
+ />
+ );
+};
-export default TimerIcon \ No newline at end of file
+export default TimerIcon;
diff --git a/web/src/constants.ts b/web/src/constants.ts
index bcb675931..3ed6cf701 100644
--- a/web/src/constants.ts
+++ b/web/src/constants.ts
@@ -1,5 +1,4 @@
-
export const GoogleAuthenticator = {
googlePlay: "https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en_us",
appleStore: "https://apps.apple.com/us/app/google-authenticator/id388497605",
-}; \ No newline at end of file
+};
diff --git a/web/src/hooks/Configuration.ts b/web/src/hooks/Configuration.ts
index 921532b3b..bc3f6a3ec 100644
--- a/web/src/hooks/Configuration.ts
+++ b/web/src/hooks/Configuration.ts
@@ -1,6 +1,6 @@
-import { useRemoteCall } from "./RemoteCall";
import { getConfiguration } from "../services/Configuration";
+import { useRemoteCall } from "./RemoteCall";
export function useConfiguration() {
return useRemoteCall(getConfiguration, []);
-} \ No newline at end of file
+}
diff --git a/web/src/hooks/IntermittentClass.ts b/web/src/hooks/IntermittentClass.ts
index 88bcaed57..4cb028d63 100644
--- a/web/src/hooks/IntermittentClass.ts
+++ b/web/src/hooks/IntermittentClass.ts
@@ -4,7 +4,8 @@ export function useIntermittentClass(
classname: string,
activeMilliseconds: number,
inactiveMillisecond: number,
- startMillisecond?: number) {
+ startMillisecond?: number,
+) {
const [currentClass, setCurrentClass] = useState("");
const [firstTime, setFirstTime] = useState(true);
@@ -34,4 +35,4 @@ export function useIntermittentClass(
}, [currentClass, classname, activeMilliseconds, inactiveMillisecond, startMillisecond, firstTime]);
return currentClass;
-} \ No newline at end of file
+}
diff --git a/web/src/hooks/Mounted.ts b/web/src/hooks/Mounted.ts
index be4ab3a55..96efb7c2b 100644
--- a/web/src/hooks/Mounted.ts
+++ b/web/src/hooks/Mounted.ts
@@ -4,7 +4,9 @@ export function useIsMountedRef() {
const isMountedRef = useRef(false);
useEffect(() => {
isMountedRef.current = true;
- return () => { isMountedRef.current = false };
+ return () => {
+ isMountedRef.current = false;
+ };
});
return isMountedRef;
-} \ No newline at end of file
+}
diff --git a/web/src/hooks/NotificationsContext.ts b/web/src/hooks/NotificationsContext.ts
index 48ff7b0a5..0cacc3c53 100644
--- a/web/src/hooks/NotificationsContext.ts
+++ b/web/src/hooks/NotificationsContext.ts
@@ -1,33 +1,33 @@
-import { Level } from "../components/ColoredSnackbarContent";
import { useCallback, createContext, useContext } from "react";
+
+import { Level } from "../components/ColoredSnackbarContent";
import { Notification } from "../models/Notifications";
const defaultOptions = {
timeout: 5,
-}
+};
interface NotificationContextProps {
notification: Notification | null;
setNotification: (n: Notification | null) => void;
}
-const NotificationsContext = createContext<NotificationContextProps>(
- { notification: null, setNotification: () => { } });
+const NotificationsContext = createContext<NotificationContextProps>({ notification: null, setNotification: () => {} });
export default NotificationsContext;
-
export function useNotifications() {
let useNotificationsProps = useContext(NotificationsContext);
const notificationBuilder = (level: Level) => {
return (message: string, timeout?: number) => {
useNotificationsProps.setNotification({
- level, message,
- timeout: timeout ? timeout : defaultOptions.timeout
+ level,
+ message,
+ timeout: timeout ? timeout : defaultOptions.timeout,
});
- }
- }
+ };
+ };
const resetNotification = () => useNotificationsProps.setNotification(null);
/* eslint-disable react-hooks/exhaustive-deps */
@@ -38,7 +38,6 @@ export function useNotifications() {
/* eslint-enable react-hooks/exhaustive-deps */
const isActive = useNotificationsProps.notification !== null;
-
return {
notification: useNotificationsProps.notification,
resetNotification,
@@ -46,6 +45,6 @@ export function useNotifications() {
createSuccessNotification,
createWarnNotification,
createErrorNotification,
- isActive
- }
-} \ No newline at end of file
+ isActive,
+ };
+}
diff --git a/web/src/hooks/RedirectionURL.ts b/web/src/hooks/RedirectionURL.ts
index 670be718a..311cc27ba 100644
--- a/web/src/hooks/RedirectionURL.ts
+++ b/web/src/hooks/RedirectionURL.ts
@@ -4,7 +4,5 @@ import { useLocation } from "react-router";
export function useRedirectionURL() {
const location = useLocation();
const queryParams = queryString.parse(location.search);
- return (queryParams && "rd" in queryParams)
- ? queryParams["rd"] as string
- : undefined;
-} \ No newline at end of file
+ return queryParams && "rd" in queryParams ? (queryParams["rd"] as string) : undefined;
+}
diff --git a/web/src/hooks/RemoteCall.ts b/web/src/hooks/RemoteCall.ts
index 8136aa46a..a33afb37f 100644
--- a/web/src/hooks/RemoteCall.ts
+++ b/web/src/hooks/RemoteCall.ts
@@ -1,9 +1,11 @@
import { useState, useCallback, DependencyList } from "react";
-type PromisifiedFunction<Ret> = (...args: any) => Promise<Ret>
+type PromisifiedFunction<Ret> = (...args: any) => Promise<Ret>;
-export function useRemoteCall<Ret>(fn: PromisifiedFunction<Ret>, deps: DependencyList)
- : [Ret | undefined, PromisifiedFunction<void>, boolean, Error | undefined] {
+export function useRemoteCall<Ret>(
+ fn: PromisifiedFunction<Ret>,
+ deps: DependencyList,
+): [Ret | undefined, PromisifiedFunction<void>, boolean, Error | undefined] {
const [data, setData] = useState(undefined as Ret | undefined);
const [inProgress, setInProgress] = useState(false);
const [error, setError] = useState(undefined as Error | undefined);
@@ -22,10 +24,5 @@ export function useRemoteCall<Ret>(fn: PromisifiedFunction<Ret>, deps: Dependenc
}
}, [setInProgress, setError, fnCallback]);
- return [
- data,
- triggerCallback,
- inProgress,
- error,
- ]
-} \ No newline at end of file
+ return [data, triggerCallback, inProgress, error];
+}
diff --git a/web/src/hooks/State.ts b/web/src/hooks/State.ts
index c33a6cf7b..f3c16e8b9 100644
--- a/web/src/hooks/State.ts
+++ b/web/src/hooks/State.ts
@@ -3,4 +3,4 @@ import { useRemoteCall } from "./RemoteCall";
export function useAutheliaState() {
return useRemoteCall(getState, []);
-} \ No newline at end of file
+}
diff --git a/web/src/hooks/Timer.ts b/web/src/hooks/Timer.ts
index 5e3c95074..63515f36b 100644
--- a/web/src/hooks/Timer.ts
+++ b/web/src/hooks/Timer.ts
@@ -21,8 +21,8 @@ export function useTimer(timeoutMs: number): [number, () => void, () => void] {
}
const intervalNode = setInterval(() => {
- const elapsedMs = (startDate) ? new Date().getTime() - startDate.getTime() : 0;
- let p = elapsedMs / timeoutMs * 100.0;
+ const elapsedMs = startDate ? new Date().getTime() - startDate.getTime() : 0;
+ let p = (elapsedMs / timeoutMs) * 100.0;
if (p >= 100) {
p = 100;
setStartDate(undefined);
@@ -33,9 +33,5 @@ export function useTimer(timeoutMs: number): [number, () => void, () => void] {
return () => clearInterval(intervalNode);
}, [startDate, setPercent, setStartDate, timeoutMs]);
- return [
- percent,
- trigger,
- clear,
- ]
-} \ No newline at end of file
+ return [percent, trigger, clear];
+}
diff --git a/web/src/hooks/UserInfo.ts b/web/src/hooks/UserInfo.ts
index ad00a0864..96e34f443 100644
--- a/web/src/hooks/UserInfo.ts
+++ b/web/src/hooks/UserInfo.ts
@@ -3,4 +3,4 @@ import { useRemoteCall } from "./RemoteCall";
export function useUserPreferences() {
return useRemoteCall(getUserPreferences, []);
-} \ No newline at end of file
+}
diff --git a/web/src/index.tsx b/web/src/index.tsx
index cff565f93..1fb7ad7b9 100644
--- a/web/src/index.tsx
+++ b/web/src/index.tsx
@@ -1,11 +1,13 @@
-import './utils/AssetPath';
-import React from 'react';
-import ReactDOM from 'react-dom';
-import './index.css';
-import App from './App';
-import * as serviceWorker from './serviceWorker';
-
-ReactDOM.render(<App />, document.getElementById('root'));
+import "./utils/AssetPath";
+import React from "react";
+
+import ReactDOM from "react-dom";
+
+import "./index.css";
+import App from "./App";
+import * as serviceWorker from "./serviceWorker";
+
+ReactDOM.render(<App />, document.getElementById("root"));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
diff --git a/web/src/layouts/LoginLayout.tsx b/web/src/layouts/LoginLayout.tsx
index a5da78b89..20017c388 100644
--- a/web/src/layouts/LoginLayout.tsx
+++ b/web/src/layouts/LoginLayout.tsx
@@ -1,8 +1,9 @@
import React, { ReactNode } from "react";
+
import { Grid, makeStyles, Container, Typography, Link } from "@material-ui/core";
-import { ReactComponent as UserSvg } from "../assets/images/user.svg";
import { grey } from "@material-ui/core/colors";
+import { ReactComponent as UserSvg } from "../assets/images/user.svg";
export interface Props {
id?: string;
@@ -14,13 +15,7 @@ export interface Props {
const LoginLayout = function (props: Props) {
const style = useStyles();
return (
- <Grid
- id={props.id}
- className={style.root}
- container
- spacing={0}
- alignItems="center"
- justify="center">
+ <Grid id={props.id} className={style.root} container spacing={0} alignItems="center" justify="center">
<Container maxWidth="xs" className={style.rootContainer}>
<Grid container>
<Grid item xs={12}>
@@ -34,27 +29,28 @@ const LoginLayout = function (props: Props) {
<Grid item xs={12} className={style.body}>
{props.children}
</Grid>
- {props.showBrand ? <Grid item xs={12}>
- <Link
- href="https://github.com/authelia/authelia"
- target="_blank"
- className={style.poweredBy}>
- Powered by Authelia
- </Link>
- </Grid>
- : null
- }
+ {props.showBrand ? (
+ <Grid item xs={12}>
+ <Link
+ href="https://github.com/authelia/authelia"
+ target="_blank"
+ className={style.poweredBy}
+ >
+ Powered by Authelia
+ </Link>
+ </Grid>
+ ) : null}
</Grid>
</Container>
</Grid>
);
-}
+};
-export default LoginLayout
+export default LoginLayout;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
root: {
- minHeight: '90vh',
+ minHeight: "90vh",
textAlign: "center",
// marginTop: theme.spacing(10),
},
@@ -71,5 +67,5 @@ const useStyles = makeStyles(theme => ({
poweredBy: {
fontSize: "0.7em",
color: grey[500],
- }
-})) \ No newline at end of file
+ },
+}));
diff --git a/web/src/models/Configuration.ts b/web/src/models/Configuration.ts
index ba04e7f96..01bd10ef0 100644
--- a/web/src/models/Configuration.ts
+++ b/web/src/models/Configuration.ts
@@ -4,4 +4,4 @@ export interface Configuration {
available_methods: Set<SecondFactorMethod>;
second_factor_enabled: boolean;
totp_period: number;
-} \ No newline at end of file
+}
diff --git a/web/src/models/Methods.ts b/web/src/models/Methods.ts
index ab80212bb..e075e9c7c 100644
--- a/web/src/models/Methods.ts
+++ b/web/src/models/Methods.ts
@@ -1,6 +1,5 @@
-
export enum SecondFactorMethod {
TOTP = 1,
U2F = 2,
- MobilePush = 3
+ MobilePush = 3,
}
diff --git a/web/src/models/Notifications.ts b/web/src/models/Notifications.ts
index 6b7d5d347..321a0c087 100644
--- a/web/src/models/Notifications.ts
+++ b/web/src/models/Notifications.ts
@@ -4,4 +4,4 @@ export interface Notification {
message: string;
level: Level;
timeout: number;
-} \ No newline at end of file
+}
diff --git a/web/src/react-app-env.d.ts b/web/src/react-app-env.d.ts
index ab49f1b52..2c004b416 100644
--- a/web/src/react-app-env.d.ts
+++ b/web/src/react-app-env.d.ts
@@ -1,2 +1,2 @@
/// <reference types="react-scripts" />
-declare var __webpack_public_path__: string; \ No newline at end of file
+declare var __webpack_public_path__: string;
diff --git a/web/src/serviceWorker.ts b/web/src/serviceWorker.ts
index 15d90cb81..56a6df78c 100644
--- a/web/src/serviceWorker.ts
+++ b/web/src/serviceWorker.ts
@@ -11,133 +11,123 @@
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
- window.location.hostname === 'localhost' ||
- // [::1] is the IPv6 localhost address.
- window.location.hostname === '[::1]' ||
- // 127.0.0.1/8 is considered localhost for IPv4.
- window.location.hostname.match(
- /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
- )
+ window.location.hostname === "localhost" ||
+ // [::1] is the IPv6 localhost address.
+ window.location.hostname === "[::1]" ||
+ // 127.0.0.1/8 is considered localhost for IPv4.
+ window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/),
);
type Config = {
- onSuccess?: (registration: ServiceWorkerRegistration) => void;
- onUpdate?: (registration: ServiceWorkerRegistration) => void;
+ onSuccess?: (registration: ServiceWorkerRegistration) => void;
+ onUpdate?: (registration: ServiceWorkerRegistration) => void;
};
export function register(config?: Config) {
- if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
- // The URL constructor is available in all browsers that support SW.
- const publicUrl = new URL(
- (process as { env: { [key: string]: string } }).env.PUBLIC_URL,
- window.location.href
- );
- if (publicUrl.origin !== window.location.origin) {
- // Our service worker won't work if PUBLIC_URL is on a different origin
- // from what our page is served on. This might happen if a CDN is used to
- // serve assets; see https://github.com/facebook/create-react-app/issues/2374
- return;
- }
+ if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
+ // The URL constructor is available in all browsers that support SW.
+ const publicUrl = new URL((process as { env: { [key: string]: string } }).env.PUBLIC_URL, window.location.href);
+ if (publicUrl.origin !== window.location.origin) {
+ // Our service worker won't work if PUBLIC_URL is on a different origin
+ // from what our page is served on. This might happen if a CDN is used to
+ // serve assets; see https://github.com/facebook/create-react-app/issues/2374
+ return;
+ }
- window.addEventListener('load', () => {
- const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
+ window.addEventListener("load", () => {
+ const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
- if (isLocalhost) {
- // This is running on localhost. Let's check if a service worker still exists or not.
- checkValidServiceWorker(swUrl, config);
+ if (isLocalhost) {
+ // This is running on localhost. Let's check if a service worker still exists or not.
+ checkValidServiceWorker(swUrl, config);
- // Add some additional logging to localhost, pointing developers to the
- // service worker/PWA documentation.
- navigator.serviceWorker.ready.then(() => {
- console.log(
- 'This web app is being served cache-first by a service ' +
- 'worker. To learn more, visit https://bit.ly/CRA-PWA'
- );
+ // Add some additional logging to localhost, pointing developers to the
+ // service worker/PWA documentation.
+ navigator.serviceWorker.ready.then(() => {
+ console.log(
+ "This web app is being served cache-first by a service " +
+ "worker. To learn more, visit https://bit.ly/CRA-PWA",
+ );
+ });
+ } else {
+ // Is not localhost. Just register service worker
+ registerValidSW(swUrl, config);
+ }
});
- } else {
- // Is not localhost. Just register service worker
- registerValidSW(swUrl, config);
- }
- });
- }
+ }
}
function registerValidSW(swUrl: string, config?: Config) {
- navigator.serviceWorker
- .register(swUrl)
- .then(registration => {
- registration.onupdatefound = () => {
- const installingWorker = registration.installing;
- if (installingWorker == null) {
- return;
- }
- installingWorker.onstatechange = () => {
- if (installingWorker.state === 'installed') {
- if (navigator.serviceWorker.controller) {
- // At this point, the updated precached content has been fetched,
- // but the previous service worker will still serve the older
- // content until all client tabs are closed.
- console.log(
- 'New content is available and will be used when all ' +
- 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
- );
+ navigator.serviceWorker
+ .register(swUrl)
+ .then((registration) => {
+ registration.onupdatefound = () => {
+ const installingWorker = registration.installing;
+ if (installingWorker == null) {
+ return;
+ }
+ installingWorker.onstatechange = () => {
+ if (installingWorker.state === "installed") {
+ if (navigator.serviceWorker.controller) {
+ // At this point, the updated precached content has been fetched,
+ // but the previous service worker will still serve the older
+ // content until all client tabs are closed.
+ console.log(
+ "New content is available and will be used when all " +
+ "tabs for this page are closed. See https://bit.ly/CRA-PWA.",
+ );
- // Execute callback
- if (config && config.onUpdate) {
- config.onUpdate(registration);
- }
- } else {
- // At this point, everything has been precached.
- // It's the perfect time to display a
- // "Content is cached for offline use." message.
- console.log('Content is cached for offline use.');
+ // Execute callback
+ if (config && config.onUpdate) {
+ config.onUpdate(registration);
+ }
+ } else {
+ // At this point, everything has been precached.
+ // It's the perfect time to display a
+ // "Content is cached for offline use." message.
+ console.log("Content is cached for offline use.");
- // Execute callback
- if (config && config.onSuccess) {
- config.onSuccess(registration);
- }
- }
- }
- };
- };
- })
- .catch(error => {
- console.error('Error during service worker registration:', error);
- });
+ // Execute callback
+ if (config && config.onSuccess) {
+ config.onSuccess(registration);
+ }
+ }
+ }
+ };
+ };
+ })
+ .catch((error) => {
+ console.error("Error during service worker registration:", error);
+ });
}
function checkValidServiceWorker(swUrl: string, config?: Config) {
- // Check if the service worker can be found. If it can't reload the page.
- fetch(swUrl)
- .then(response => {
- // Ensure service worker exists, and that we really are getting a JS file.
- const contentType = response.headers.get('content-type');
- if (
- response.status === 404 ||
- (contentType != null && contentType.indexOf('javascript') === -1)
- ) {
- // No service worker found. Probably a different app. Reload the page.
- navigator.serviceWorker.ready.then(registration => {
- registration.unregister().then(() => {
- window.location.reload();
- });
+ // Check if the service worker can be found. If it can't reload the page.
+ fetch(swUrl)
+ .then((response) => {
+ // Ensure service worker exists, and that we really are getting a JS file.
+ const contentType = response.headers.get("content-type");
+ if (response.status === 404 || (contentType != null && contentType.indexOf("javascript") === -1)) {
+ // No service worker found. Probably a different app. Reload the page.
+ navigator.serviceWorker.ready.then((registration) => {
+ registration.unregister().then(() => {
+ window.location.reload();
+ });
+ });
+ } else {
+ // Service worker found. Proceed as normal.
+ registerValidSW(swUrl, config);
+ }
+ })
+ .catch(() => {
+ console.log("No internet connection found. App is running in offline mode.");
});
- } else {
- // Service worker found. Proceed as normal.
- registerValidSW(swUrl, config);
- }
- })
- .catch(() => {
- console.log(
- 'No internet connection found. App is running in offline mode.'
- );
- });
}
export function unregister() {
- if ('serviceWorker' in navigator) {
- navigator.serviceWorker.ready.then(registration => {
- registration.unregister();
- });
- }
+ if ("serviceWorker" in navigator) {
+ navigator.serviceWorker.ready.then((registration) => {
+ registration.unregister();
+ });
+ }
}
diff --git a/web/src/services/Api.ts b/web/src/services/Api.ts
index 0ec8ae90f..2b5be2ce8 100644
--- a/web/src/services/Api.ts
+++ b/web/src/services/Api.ts
@@ -1,4 +1,5 @@
import { AxiosResponse } from "axios";
+
import { getBasePath } from "../utils/BasePath";
const basePath = getBasePath();
@@ -14,13 +15,13 @@ export const CompleteU2FRegistrationStep2Path = basePath + "/api/secondfactor/u2
export const InitiateU2FSignInPath = basePath + "/api/secondfactor/u2f/sign_request";
export const CompleteU2FSignInPath = basePath + "/api/secondfactor/u2f/sign";
-export const CompletePushNotificationSignInPath = basePath + "/api/secondfactor/duo"
-export const CompleteTOTPSignInPath = basePath + "/api/secondfactor/totp"
+export const CompletePushNotificationSignInPath = basePath + "/api/secondfactor/duo";
+export const CompleteTOTPSignInPath = basePath + "/api/secondfactor/totp";
export const InitiateResetPasswordPath = basePath + "/api/reset-password/identity/start";
export const CompleteResetPasswordPath = basePath + "/api/reset-password/identity/finish";
// Do the password reset during completion.
-export const ResetPasswordPath = basePath + "/api/reset-password"
+export const ResetPasswordPath = basePath + "/api/reset-password";
export const LogoutPath = basePath + "/api/logout";
export const StatePath = basePath + "/api/state";
@@ -52,7 +53,7 @@ export function toData<T>(resp: AxiosResponse<ServiceResponse<T>>): T | undefine
if (resp.data && "status" in resp.data && resp.data["status"] === "OK") {
return resp.data.data as T;
}
- return undefined
+ return undefined;
}
export function hasServiceError<T>(resp: AxiosResponse<ServiceResponse<T>>) {
@@ -61,4 +62,4 @@ export function hasServiceError<T>(resp: AxiosResponse<ServiceResponse<T>>) {
return { errored: true, message: errResp.message };
}
return { errored: false, message: null };
-} \ No newline at end of file
+}
diff --git a/web/src/services/Client.ts b/web/src/services/Client.ts
index e30d10148..56681446c 100644
--- a/web/src/services/Client.ts
+++ b/web/src/services/Client.ts
@@ -1,4 +1,5 @@
import axios from "axios";
+
import { ServiceResponse, hasServiceError, toData } from "./Api";
export async function PostWithOptionalResponse<T = undefined>(path: string, body?: any) {
@@ -30,4 +31,4 @@ export async function Get<T = undefined>(path: string): Promise<T> {
throw new Error("unexpected type of response");
}
return d;
-} \ No newline at end of file
+}
diff --git a/web/src/services/Configuration.ts b/web/src/services/Configuration.ts
index 1c9651ab7..0d6bcdd32 100644
--- a/web/src/services/Configuration.ts
+++ b/web/src/services/Configuration.ts
@@ -1,7 +1,7 @@
-import { Get } from "./Client";
+import { Configuration } from "../models/Configuration";
import { ConfigurationPath } from "./Api";
+import { Get } from "./Client";
import { toEnum, Method2FA } from "./UserPreferences";
-import { Configuration } from "../models/Configuration";
interface ConfigurationPayload {
available_methods: Method2FA[];
@@ -12,4 +12,4 @@ interface ConfigurationPayload {
export async function getConfiguration(): Promise<Configuration> {
const config = await Get<ConfigurationPayload>(ConfigurationPath);
return { ...config, available_methods: new Set(config.available_methods.map(toEnum)) };
-} \ No newline at end of file
+}
diff --git a/web/src/services/FirstFactor.ts b/web/src/services/FirstFactor.ts
index 91c29b36d..3d9c24989 100644
--- a/web/src/services/FirstFactor.ts
+++ b/web/src/services/FirstFactor.ts
@@ -9,17 +9,16 @@ interface PostFirstFactorBody {
targetURL?: string;
}
-export async function postFirstFactor(
- username: string, password: string,
- rememberMe: boolean, targetURL?: string) {
+export async function postFirstFactor(username: string, password: string, rememberMe: boolean, targetURL?: string) {
const data: PostFirstFactorBody = {
- username, password,
- keepMeLoggedIn: rememberMe
+ username,
+ password,
+ keepMeLoggedIn: rememberMe,
};
if (targetURL) {
data.targetURL = targetURL;
}
const res = await PostWithOptionalResponse<SignInResponse>(FirstFactorPath, data);
- return res ? res : {} as SignInResponse;
-} \ No newline at end of file
+ return res ? res : ({} as SignInResponse);
+}
diff --git a/web/src/services/OneTimePassword.ts b/web/src/services/OneTimePassword.ts
index fa892f9cc..687a6a863 100644
--- a/web/src/services/OneTimePassword.ts
+++ b/web/src/services/OneTimePassword.ts
@@ -1,5 +1,5 @@
-import { PostWithOptionalResponse } from "./Client";
import { CompleteTOTPSignInPath } from "./Api";
+import { PostWithOptionalResponse } from "./Client";
import { SignInResponse } from "./SignIn";
interface CompleteU2FSigninBody {
@@ -13,4 +13,4 @@ export function completeTOTPSignIn(passcode: string, targetURL: string | undefin
body.targetURL = targetURL;
}
return PostWithOptionalResponse<SignInResponse>(CompleteTOTPSignInPath, body);
-} \ No newline at end of file
+}
diff --git a/web/src/services/PushNotification.ts b/web/src/services/PushNotification.ts
index a70ccef38..66bfefca6 100644
--- a/web/src/services/PushNotification.ts
+++ b/web/src/services/PushNotification.ts
@@ -1,5 +1,5 @@
-import { PostWithOptionalResponse } from "./Client";
import { CompletePushNotificationSignInPath } from "./Api";
+import { PostWithOptionalResponse } from "./Client";
import { SignInResponse } from "./SignIn";
interface CompleteU2FSigninBody {
@@ -12,4 +12,4 @@ export function completePushNotificationSignIn(targetURL: string | undefined) {
body.targetURL = targetURL;
}
return PostWithOptionalResponse<SignInResponse>(CompletePushNotificationSignInPath, body);
-} \ No newline at end of file
+}
diff --git a/web/src/services/RegisterDevice.ts b/web/src/services/RegisterDevice.ts
index 67a57e358..ce4cb7614 100644
--- a/web/src/services/RegisterDevice.ts
+++ b/web/src/services/RegisterDevice.ts
@@ -1,9 +1,12 @@
+import U2fApi from "u2f-api";
+
import {
- InitiateTOTPRegistrationPath, CompleteTOTPRegistrationPath,
- InitiateU2FRegistrationPath, CompleteU2FRegistrationStep1Path,
- CompleteU2FRegistrationStep2Path
+ InitiateTOTPRegistrationPath,
+ CompleteTOTPRegistrationPath,
+ InitiateU2FRegistrationPath,
+ CompleteU2FRegistrationStep1Path,
+ CompleteU2FRegistrationStep2Path,
} from "./Api";
-import U2fApi from "u2f-api";
import { Post, PostWithOptionalResponse } from "./Client";
export async function initiateTOTPRegistrationProcess() {
@@ -16,28 +19,27 @@ interface CompleteTOTPRegistrationResponse {
}
export async function completeTOTPRegistrationProcess(processToken: string) {
- return Post<CompleteTOTPRegistrationResponse>(
- CompleteTOTPRegistrationPath, { token: processToken });
+ return Post<CompleteTOTPRegistrationResponse>(CompleteTOTPRegistrationPath, { token: processToken });
}
-
export async function initiateU2FRegistrationProcess() {
return PostWithOptionalResponse(InitiateU2FRegistrationPath);
}
interface U2RRegistrationStep1Response {
- appId: string,
- registerRequests: [{
- version: string,
- challenge: string,
- }]
+ appId: string;
+ registerRequests: [
+ {
+ version: string;
+ challenge: string;
+ },
+ ];
}
export async function completeU2FRegistrationProcessStep1(processToken: string) {
- return Post<U2RRegistrationStep1Response>(
- CompleteU2FRegistrationStep1Path, { token: processToken });
+ return Post<U2RRegistrationStep1Response>(CompleteU2FRegistrationStep1Path, { token: processToken });
}
export async function completeU2FRegistrationProcessStep2(response: U2fApi.RegisterResponse) {
return PostWithOptionalResponse(CompleteU2FRegistrationStep2Path, response);
-} \ No newline at end of file
+}
diff --git a/web/src/services/ResetPassword.ts b/web/src/services/ResetPassword.ts
index 2d4819175..48612a892 100644
--- a/web/src/services/ResetPassword.ts
+++ b/web/src/services/ResetPassword.ts
@@ -1,7 +1,6 @@
import { InitiateResetPasswordPath, CompleteResetPasswordPath, ResetPasswordPath } from "./Api";
import { PostWithOptionalResponse } from "./Client";
-
export async function initiateResetPasswordProcess(username: string) {
return PostWithOptionalResponse(InitiateResetPasswordPath, { username });
}
@@ -12,4 +11,4 @@ export async function completeResetPasswordProcess(token: string) {
export async function resetPassword(newPassword: string) {
return PostWithOptionalResponse(ResetPasswordPath, { password: newPassword });
-} \ No newline at end of file
+}
diff --git a/web/src/services/SecurityKey.ts b/web/src/services/SecurityKey.ts
index 8a593d962..7db823b5e 100644
--- a/web/src/services/SecurityKey.ts
+++ b/web/src/services/SecurityKey.ts
@@ -1,16 +1,17 @@
-import { Post, PostWithOptionalResponse } from "./Client";
-import { InitiateU2FSignInPath, CompleteU2FSignInPath } from "./Api";
import u2fApi from "u2f-api";
+
+import { InitiateU2FSignInPath, CompleteU2FSignInPath } from "./Api";
+import { Post, PostWithOptionalResponse } from "./Client";
import { SignInResponse } from "./SignIn";
interface InitiateU2FSigninResponse {
- appId: string,
- challenge: string,
+ appId: string;
+ challenge: string;
registeredKeys: {
- appId: string,
- keyHandle: string,
- version: string,
- }[]
+ appId: string;
+ keyHandle: string;
+ version: string;
+ }[];
}
export async function initiateU2FSignin() {
@@ -28,4 +29,4 @@ export function completeU2FSignin(signResponse: u2fApi.SignResponse, targetURL:
body.targetURL = targetURL;
}
return PostWithOptionalResponse<SignInResponse>(CompleteU2FSignInPath, body);
-} \ No newline at end of file
+}
diff --git a/web/src/services/SignIn.ts b/web/src/services/SignIn.ts
index 2dfceac68..219ffd846 100644
--- a/web/src/services/SignIn.ts
+++ b/web/src/services/SignIn.ts
@@ -1,2 +1 @@
-
-export type SignInResponse = { redirect: string } | undefined; \ No newline at end of file
+export type SignInResponse = { redirect: string } | undefined;
diff --git a/web/src/services/SignOut.ts b/web/src/services/SignOut.ts
index a376ceb65..6209a132b 100644
--- a/web/src/services/SignOut.ts
+++ b/web/src/services/SignOut.ts
@@ -1,6 +1,6 @@
-import { PostWithOptionalResponse } from "./Client";
import { LogoutPath } from "./Api";
+import { PostWithOptionalResponse } from "./Client";
export async function signOut() {
return PostWithOptionalResponse(LogoutPath);
-} \ No newline at end of file
+}
diff --git a/web/src/services/State.ts b/web/src/services/State.ts
index 5b1830983..b653952e8 100644
--- a/web/src/services/State.ts
+++ b/web/src/services/State.ts
@@ -1,5 +1,5 @@
-import { Get } from "./Client";
import { StatePath } from "./Api";
+import { Get } from "./Client";
export enum AuthenticationLevel {
Unauthenticated = 0,
@@ -9,9 +9,9 @@ export enum AuthenticationLevel {
export interface AutheliaState {
username: string;
- authentication_level: AuthenticationLevel
+ authentication_level: AuthenticationLevel;
}
export async function getState(): Promise<AutheliaState> {
return Get<AutheliaState>(StatePath);
-} \ No newline at end of file
+}
diff --git a/web/src/services/UserPreferences.ts b/web/src/services/UserPreferences.ts
index c63db1b52..9fbb2a81d 100644
--- a/web/src/services/UserPreferences.ts
+++ b/web/src/services/UserPreferences.ts
@@ -1,7 +1,7 @@
-import { Get, PostWithOptionalResponse } from "./Client";
-import { UserInfoPath, UserInfo2FAMethodPath } from "./Api";
import { SecondFactorMethod } from "../models/Methods";
import { UserInfo } from "../models/UserInfo";
+import { UserInfoPath, UserInfo2FAMethodPath } from "./Api";
+import { Get, PostWithOptionalResponse } from "./Client";
export type Method2FA = "u2f" | "totp" | "mobile_push";
@@ -44,6 +44,5 @@ export async function getUserPreferences(): Promise<UserInfo> {
}
export function setPreferred2FAMethod(method: SecondFactorMethod) {
- return PostWithOptionalResponse(UserInfo2FAMethodPath,
- { method: toString(method) } as MethodPreferencePayload);
-} \ No newline at end of file
+ return PostWithOptionalResponse(UserInfo2FAMethodPath, { method: toString(method) } as MethodPreferencePayload);
+}
diff --git a/web/src/setupTests.js b/web/src/setupTests.js
index 21fc6bb60..81b86e1d0 100644
--- a/web/src/setupTests.js
+++ b/web/src/setupTests.js
@@ -1,5 +1,5 @@
-import { configure } from 'enzyme';
-import Adapter from 'enzyme-adapter-react-16';
+import { configure } from "enzyme";
+import Adapter from "enzyme-adapter-react-16";
document.body.setAttribute("data-basepath", "");
document.body.setAttribute("data-rememberme", "true");
document.body.setAttribute("data-resetpassword", "true");
diff --git a/web/src/utils/AssetPath.ts b/web/src/utils/AssetPath.ts
index 358130b89..8ff5e9f47 100644
--- a/web/src/utils/AssetPath.ts
+++ b/web/src/utils/AssetPath.ts
@@ -1,7 +1,7 @@
import { getBasePath } from "./BasePath";
-__webpack_public_path__ = "/"
+__webpack_public_path__ = "/";
if (getBasePath() !== "") {
- __webpack_public_path__ = getBasePath() + "/"
-} \ No newline at end of file
+ __webpack_public_path__ = getBasePath() + "/";
+}
diff --git a/web/src/utils/BasePath.ts b/web/src/utils/BasePath.ts
index 5c5553c94..f09d231ef 100644
--- a/web/src/utils/BasePath.ts
+++ b/web/src/utils/BasePath.ts
@@ -2,4 +2,4 @@ import { getEmbeddedVariable } from "./Configuration";
export function getBasePath() {
return getEmbeddedVariable("basepath");
-} \ No newline at end of file
+}
diff --git a/web/src/utils/Configuration.ts b/web/src/utils/Configuration.ts
index e8d42946d..81e279974 100644
--- a/web/src/utils/Configuration.ts
+++ b/web/src/utils/Configuration.ts
@@ -1,16 +1,16 @@
export function getEmbeddedVariable(variableName: string) {
- const value = document.body.getAttribute(`data-${variableName}`);
- if (value === null) {
- throw new Error(`No ${variableName} embedded variable detected`);
- }
+ const value = document.body.getAttribute(`data-${variableName}`);
+ if (value === null) {
+ throw new Error(`No ${variableName} embedded variable detected`);
+ }
- return value;
+ return value;
}
export function getRememberMe() {
- return getEmbeddedVariable("rememberme") === "true";
+ return getEmbeddedVariable("rememberme") === "true";
}
export function getResetPassword() {
- return getEmbeddedVariable("resetpassword") === "true";
-} \ No newline at end of file
+ return getEmbeddedVariable("resetpassword") === "true";
+}
diff --git a/web/src/utils/IdentityToken.ts b/web/src/utils/IdentityToken.ts
index 67269d478..7e1960015 100644
--- a/web/src/utils/IdentityToken.ts
+++ b/web/src/utils/IdentityToken.ts
@@ -2,7 +2,5 @@ import queryString from "query-string";
export function extractIdentityToken(locationSearch: string) {
const queryParams = queryString.parse(locationSearch);
- return (queryParams && "token" in queryParams)
- ? queryParams["token"] as string
- : null;
-} \ No newline at end of file
+ return queryParams && "token" in queryParams ? (queryParams["token"] as string) : null;
+}
diff --git a/web/src/views/DeviceRegistration/RegisterOneTimePassword.tsx b/web/src/views/DeviceRegistration/RegisterOneTimePassword.tsx
index 93219dbc4..9f126e139 100644
--- a/web/src/views/DeviceRegistration/RegisterOneTimePassword.tsx
+++ b/web/src/views/DeviceRegistration/RegisterOneTimePassword.tsx
@@ -1,18 +1,20 @@
import React, { useEffect, useCallback, useState } from "react";
-import LoginLayout from "../../layouts/LoginLayout";
-import classnames from "classnames";
+
+import { IconDefinition, faCopy, faKey, faTimesCircle } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { makeStyles, Typography, Button, IconButton, Link, CircularProgress, TextField } from "@material-ui/core";
-import QRCode from 'qrcode.react';
+import { red } from "@material-ui/core/colors";
+import classnames from "classnames";
+import QRCode from "qrcode.react";
+import { useHistory, useLocation } from "react-router";
+
import AppStoreBadges from "../../components/AppStoreBadges";
import { GoogleAuthenticator } from "../../constants";
-import { useHistory, useLocation } from "react-router";
-import { completeTOTPRegistrationProcess } from "../../services/RegisterDevice";
import { useNotifications } from "../../hooks/NotificationsContext";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { IconDefinition, faCopy, faKey, faTimesCircle } from "@fortawesome/free-solid-svg-icons";
-import { red } from "@material-ui/core/colors";
-import { extractIdentityToken } from "../../utils/IdentityToken";
+import LoginLayout from "../../layouts/LoginLayout";
import { FirstFactorRoute } from "../../Routes";
+import { completeTOTPRegistrationProcess } from "../../services/RegisterDevice";
+import { extractIdentityToken } from "../../utils/IdentityToken";
const RegisterOneTimePassword = function () {
const style = useStyles();
@@ -32,7 +34,7 @@ const RegisterOneTimePassword = function () {
const handleDoneClick = () => {
history.push(FirstFactorRoute);
- }
+ };
const completeRegistrationProcess = useCallback(async () => {
if (!processToken) {
@@ -52,74 +54,77 @@ const RegisterOneTimePassword = function () {
setIsLoading(false);
}, [processToken, createErrorNotification]);
- useEffect(() => { completeRegistrationProcess() }, [completeRegistrationProcess]);
+ useEffect(() => {
+ completeRegistrationProcess();
+ }, [completeRegistrationProcess]);
function SecretButton(text: string | undefined, action: string, icon: IconDefinition) {
return (
- <IconButton
- className={style.secretButtons}
- color="primary"
- onClick={() => {
- navigator.clipboard.writeText(`${text}`);
- createSuccessNotification(`${action}`);
- }}
- >
- <FontAwesomeIcon icon={icon} />
- </IconButton>
- )
+ <IconButton
+ className={style.secretButtons}
+ color="primary"
+ onClick={() => {
+ navigator.clipboard.writeText(`${text}`);
+ createSuccessNotification(`${action}`);
+ }}
+ >
+ <FontAwesomeIcon icon={icon} />
+ </IconButton>
+ );
}
- const qrcodeFuzzyStyle = (isLoading || hasErrored) ? style.fuzzy : undefined
+ const qrcodeFuzzyStyle = isLoading || hasErrored ? style.fuzzy : undefined;
return (
- <LoginLayout title="Scan QRCode">
- <div className={style.root}>
- <div className={style.googleAuthenticator}>
- <Typography className={style.googleAuthenticatorText}>Need Google Authenticator?</Typography>
- <AppStoreBadges
- iconSize={128}
- targetBlank
- className={style.googleAuthenticatorBadges}
- googlePlayLink={GoogleAuthenticator.googlePlay}
- appleStoreLink={GoogleAuthenticator.appleStore} />
- </div>
- <div className={style.qrcodeContainer}>
- <Link href={secretURL}>
- <QRCode
- value={secretURL}
- className={classnames(qrcodeFuzzyStyle, style.qrcode)}
- size={256} />
- {!hasErrored && isLoading ? <CircularProgress className={style.loader} size={128} /> : null}
- {hasErrored ? <FontAwesomeIcon className={style.failureIcon} icon={faTimesCircle} /> : null}
- </Link>
- </div>
- <div>
- {secretURL !== "empty"
- ? <TextField
- id="secret-url"
- label="Secret"
- className={style.secret}
- value={secretURL}
- InputProps={{
- readOnly: true
- }} /> : null}
- {secretBase32 ? SecretButton(secretBase32, "OTP Secret copied to clipboard.", faKey) : null}
- {secretURL !== "empty" ? SecretButton(secretURL, "OTP URL copied to clipboard.", faCopy) : null}
- </div>
- <Button
- variant="contained"
- color="primary"
- className={style.doneButton}
- onClick={handleDoneClick}
- disabled={isLoading}>
- Done
- </Button>
- </div>
- </LoginLayout>
- )
-}
+ <LoginLayout title="Scan QRCode">
+ <div className={style.root}>
+ <div className={style.googleAuthenticator}>
+ <Typography className={style.googleAuthenticatorText}>Need Google Authenticator?</Typography>
+ <AppStoreBadges
+ iconSize={128}
+ targetBlank
+ className={style.googleAuthenticatorBadges}
+ googlePlayLink={GoogleAuthenticator.googlePlay}
+ appleStoreLink={GoogleAuthenticator.appleStore}
+ />
+ </div>
+ <div className={style.qrcodeContainer}>
+ <Link href={secretURL}>
+ <QRCode value={secretURL} className={classnames(qrcodeFuzzyStyle, style.qrcode)} size={256} />
+ {!hasErrored && isLoading ? <CircularProgress className={style.loader} size={128} /> : null}
+ {hasErrored ? <FontAwesomeIcon className={style.failureIcon} icon={faTimesCircle} /> : null}
+ </Link>
+ </div>
+ <div>
+ {secretURL !== "empty" ? (
+ <TextField
+ id="secret-url"
+ label="Secret"
+ className={style.secret}
+ value={secretURL}
+ InputProps={{
+ readOnly: true,
+ }}
+ />
+ ) : null}
+ {secretBase32 ? SecretButton(secretBase32, "OTP Secret copied to clipboard.", faKey) : null}
+ {secretURL !== "empty" ? SecretButton(secretURL, "OTP URL copied to clipboard.", faCopy) : null}
+ </div>
+ <Button
+ variant="contained"
+ color="primary"
+ className={style.doneButton}
+ onClick={handleDoneClick}
+ disabled={isLoading}
+ >
+ Done
+ </Button>
+ </div>
+ </LoginLayout>
+ );
+};
-export default RegisterOneTimePassword
+export default RegisterOneTimePassword;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
root: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),
@@ -129,7 +134,7 @@ const useStyles = makeStyles(theme => ({
marginBottom: theme.spacing(2),
},
fuzzy: {
- filter: "blur(10px)"
+ filter: "blur(10px)",
},
secret: {
marginTop: theme.spacing(1),
@@ -163,5 +168,5 @@ const useStyles = makeStyles(theme => ({
left: "calc(128px - 64px)",
color: red[400],
fontSize: "128px",
- }
-})) \ No newline at end of file
+ },
+}));
diff --git a/web/src/views/DeviceRegistration/RegisterSecurityKey.tsx b/web/src/views/DeviceRegistration/RegisterSecurityKey.tsx
index b58e5f7f5..11cbea3b4 100644
--- a/web/src/views/DeviceRegistration/RegisterSecurityKey.tsx
+++ b/web/src/views/DeviceRegistration/RegisterSecurityKey.tsx
@@ -1,13 +1,18 @@
import React, { useState, useEffect, useCallback } from "react";
-import LoginLayout from "../../layouts/LoginLayout";
-import FingerTouchIcon from "../../components/FingerTouchIcon";
+
import { makeStyles, Typography, Button } from "@material-ui/core";
import { useHistory, useLocation } from "react-router";
+import u2fApi from "u2f-api";
+
+import FingerTouchIcon from "../../components/FingerTouchIcon";
+import { useNotifications } from "../../hooks/NotificationsContext";
+import LoginLayout from "../../layouts/LoginLayout";
import { FirstFactorPath } from "../../services/Api";
+import {
+ completeU2FRegistrationProcessStep1,
+ completeU2FRegistrationProcessStep2,
+} from "../../services/RegisterDevice";
import { extractIdentityToken } from "../../utils/IdentityToken";
-import { completeU2FRegistrationProcessStep1, completeU2FRegistrationProcessStep2 } from "../../services/RegisterDevice";
-import { useNotifications } from "../../hooks/NotificationsContext";
-import u2fApi from "u2f-api";
const RegisterSecurityKey = function () {
const style = useStyles();
@@ -18,10 +23,9 @@ const RegisterSecurityKey = function () {
const processToken = extractIdentityToken(location.search);
-
const handleBackClick = () => {
history.push(FirstFactorPath);
- }
+ };
const registerStep1 = useCallback(async () => {
if (!processToken) {
@@ -37,7 +41,7 @@ const RegisterSecurityKey = function () {
appId: res.appId,
challenge: r.challenge,
version: r.version,
- })
+ });
}
const registerResponse = await u2fApi.register(registerRequests, [], 60);
await completeU2FRegistrationProcessStep2(registerResponse);
@@ -45,8 +49,9 @@ const RegisterSecurityKey = function () {
history.push(FirstFactorPath);
} catch (err) {
console.error(err);
- createErrorNotification("Failed to register your security key. " +
- "The identity verification process might have timed out.");
+ createErrorNotification(
+ "Failed to register your security key. The identity verification process might have timed out.",
+ );
}
}, [processToken, createErrorNotification, history]);
@@ -60,20 +65,24 @@ const RegisterSecurityKey = function () {
<FingerTouchIcon size={64} animated />
</div>
<Typography className={style.instruction}>Touch the token on your security key</Typography>
- <Button color="primary" onClick={handleBackClick}>Retry</Button>
- <Button color="primary" onClick={handleBackClick}>Cancel</Button>
+ <Button color="primary" onClick={handleBackClick}>
+ Retry
+ </Button>
+ <Button color="primary" onClick={handleBackClick}>
+ Cancel
+ </Button>
</LoginLayout>
- )
-}
+ );
+};
-export default RegisterSecurityKey
+export default RegisterSecurityKey;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
icon: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),
},
instruction: {
paddingBottom: theme.spacing(4),
- }
-})) \ No newline at end of file
+ },
+}));
diff --git a/web/src/views/LoadingPage/LoadingPage.tsx b/web/src/views/LoadingPage/LoadingPage.tsx
index e923c1d7b..6ae4ac779 100644
--- a/web/src/views/LoadingPage/LoadingPage.tsx
+++ b/web/src/views/LoadingPage/LoadingPage.tsx
@@ -1,6 +1,7 @@
import React from "react";
-import ReactLoading from "react-loading";
+
import { Typography, Grid } from "@material-ui/core";
+import ReactLoading from "react-loading";
const LoadingPage = function () {
return (
@@ -11,6 +12,6 @@ const LoadingPage = function () {
</Grid>
</Grid>
);
-}
+};
-export default LoadingPage \ No newline at end of file
+export default LoadingPage;
diff --git a/web/src/views/LoginPortal/Authenticated.tsx b/web/src/views/LoginPortal/Authenticated.tsx
index ec17f14f8..b7a246c48 100644
--- a/web/src/views/LoginPortal/Authenticated.tsx
+++ b/web/src/views/LoginPortal/Authenticated.tsx
@@ -1,7 +1,9 @@
import React from "react";
-import SuccessIcon from "../../components/SuccessIcon";
+
import { Typography, makeStyles } from "@material-ui/core";
+import SuccessIcon from "../../components/SuccessIcon";
+
const Authenticated = function () {
const classes = useStyles();
return (
@@ -11,14 +13,14 @@ const Authenticated = function () {
</div>
<Typography>Authenticated</Typography>
</div>
- )
-}
+ );
+};
-export default Authenticated
+export default Authenticated;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
iconContainer: {
marginBottom: theme.spacing(2),
- flex: "0 0 100%"
- }
-})) \ No newline at end of file
+ flex: "0 0 100%",
+ },
+}));
diff --git a/web/src/views/LoginPortal/AuthenticatedView/AuthenticatedView.tsx b/web/src/views/LoginPortal/AuthenticatedView/AuthenticatedView.tsx
index 9b4b55002..2c4a91bb4 100644
--- a/web/src/views/LoginPortal/AuthenticatedView/AuthenticatedView.tsx
+++ b/web/src/views/LoginPortal/AuthenticatedView/AuthenticatedView.tsx
@@ -1,6 +1,8 @@
import React from "react";
+
import { Grid, makeStyles, Button } from "@material-ui/core";
import { useHistory } from "react-router";
+
import LoginLayout from "../../../layouts/LoginLayout";
import { LogoutRoute as SignOutRoute } from "../../../Routes";
import Authenticated from "../Authenticated";
@@ -15,13 +17,10 @@ const AuthenticatedView = function (props: Props) {
const handleLogoutClick = () => {
history.push(SignOutRoute);
- }
+ };
return (
- <LoginLayout
- id="authenticated-stage"
- title={`Hi ${props.name}`}
- showBrand>
+ <LoginLayout id="authenticated-stage" title={`Hi ${props.name}`} showBrand>
<Grid container>
<Grid item xs={12}>
<Button color="secondary" onClick={handleLogoutClick} id="logout-button">
@@ -33,17 +32,17 @@ const AuthenticatedView = function (props: Props) {
</Grid>
</Grid>
</LoginLayout>
- )
-}
+ );
+};
-export default AuthenticatedView
+export default AuthenticatedView;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
mainContainer: {
border: "1px solid #d6d6d6",
borderRadius: "10px",
padding: theme.spacing(4),
marginTop: theme.spacing(2),
marginBottom: theme.spacing(2),
- }
-}))
+ },
+}));
diff --git a/web/src/views/LoginPortal/FirstFactor/FirstFactorForm.tsx b/web/src/views/LoginPortal/FirstFactor/FirstFactorForm.tsx
index 6529676a7..4552c9c5f 100644
--- a/web/src/views/LoginPortal/FirstFactor/FirstFactorForm.tsx
+++ b/web/src/views/LoginPortal/FirstFactor/FirstFactorForm.tsx
@@ -1,13 +1,15 @@
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
-import classnames from "classnames";
+
import { makeStyles, Grid, Button, FormControlLabel, Checkbox, Link } from "@material-ui/core";
+import classnames from "classnames";
import { useHistory } from "react-router";
-import LoginLayout from "../../../layouts/LoginLayout";
+
+import FixedTextField from "../../../components/FixedTextField";
import { useNotifications } from "../../../hooks/NotificationsContext";
-import { postFirstFactor } from "../../../services/FirstFactor";
-import { ResetPasswordStep1Route } from "../../../Routes";
import { useRedirectionURL } from "../../../hooks/RedirectionURL";
-import FixedTextField from "../../../components/FixedTextField";
+import LoginLayout from "../../../layouts/LoginLayout";
+import { ResetPasswordStep1Route } from "../../../Routes";
+import { postFirstFactor } from "../../../services/FirstFactor";
export interface Props {
disabled: boolean;
@@ -47,7 +49,7 @@ const FirstFactorForm = function (props: Props) {
const handleSignIn = async () => {
if (username === "" || password === "") {
if (username === "") {
- setUsernameError(true)
+ setUsernameError(true);
}
if (password === "") {
@@ -62,8 +64,7 @@ const FirstFactorForm = function (props: Props) {
props.onAuthenticationSuccess(res ? res.redirect : undefined);
} catch (err) {
console.error(err);
- createErrorNotification(
- "Incorrect username or password.");
+ createErrorNotification("Incorrect username or password.");
props.onAuthenticationFailure();
setPassword("");
passwordRef.current.focus();
@@ -75,10 +76,7 @@ const FirstFactorForm = function (props: Props) {
};
return (
- <LoginLayout
- id="first-factor-stage"
- title="Sign in"
- showBrand>
+ <LoginLayout id="first-factor-stage" title="Sign in" showBrand>
<Grid container spacing={2} className={style.root}>
<Grid item xs={12}>
<FixedTextField
@@ -92,21 +90,22 @@ const FirstFactorForm = function (props: Props) {
error={usernameError}
disabled={disabled}
fullWidth
- onChange={v => setUsername(v.target.value)}
+ onChange={(v) => setUsername(v.target.value)}
onFocus={() => setUsernameError(false)}
autoCapitalize="none"
onKeyPress={(ev) => {
- if (ev.key === 'Enter') {
+ if (ev.key === "Enter") {
if (!username.length) {
- setUsernameError(true)
+ setUsernameError(true);
} else if (username.length && password.length) {
handleSignIn();
} else {
- setUsernameError(false)
+ setUsernameError(false);
passwordRef.current.focus();
}
}
- }} />
+ }}
+ />
</Grid>
<Grid item xs={12}>
<FixedTextField
@@ -120,11 +119,11 @@ const FirstFactorForm = function (props: Props) {
disabled={disabled}
value={password}
error={passwordError}
- onChange={v => setPassword(v.target.value)}
+ onChange={(v) => setPassword(v.target.value)}
onFocus={() => setPasswordError(false)}
type="password"
onKeyPress={(ev) => {
- if (ev.key === 'Enter') {
+ if (ev.key === "Enter") {
if (!username.length) {
usernameRef.current.focus();
} else if (!password.length) {
@@ -133,13 +132,20 @@ const FirstFactorForm = function (props: Props) {
handleSignIn();
ev.preventDefault();
}
- }} />
+ }}
+ />
</Grid>
- {props.rememberMe || props.resetPassword ?
- <Grid item xs={12} className={props.rememberMe
- ? classnames(style.leftAlign, style.actionRow)
- : classnames(style.leftAlign, style.flexEnd, style.actionRow)}>
- {props.rememberMe ?
+ {props.rememberMe || props.resetPassword ? (
+ <Grid
+ item
+ xs={12}
+ className={
+ props.rememberMe
+ ? classnames(style.leftAlign, style.actionRow)
+ : classnames(style.leftAlign, style.flexEnd, style.actionRow)
+ }
+ >
+ {props.rememberMe ? (
<FormControlLabel
control={
<Checkbox
@@ -148,7 +154,7 @@ const FirstFactorForm = function (props: Props) {
checked={rememberMe}
onChange={handleRememberMeChange}
onKeyPress={(ev) => {
- if (ev.key === 'Enter') {
+ if (ev.key === "Enter") {
if (!username.length) {
usernameRef.current.focus();
} else if (!password.length) {
@@ -158,20 +164,25 @@ const FirstFactorForm = function (props: Props) {
}
}}
value="rememberMe"
- color="primary"/>
+ color="primary"
+ />
}
className={style.rememberMe}
label="Remember me"
- /> : null}
- {props.resetPassword ?
+ />
+ ) : null}
+ {props.resetPassword ? (
<Link
id="reset-password-button"
component="button"
onClick={handleResetPasswordClick}
- className={style.resetLink}>
+ className={style.resetLink}
+ >
Reset password?
- </Link> : null}
- </Grid> : null}
+ </Link>
+ ) : null}
+ </Grid>
+ ) : null}
<Grid item xs={12}>
<Button
id="sign-in-button"
@@ -179,18 +190,19 @@ const FirstFactorForm = function (props: Props) {
color="primary"
fullWidth
disabled={disabled}
- onClick={handleSignIn}>
+ onClick={handleSignIn}
+ >
Sign in
</Button>
</Grid>
</Grid>
</LoginLayout>
- )
-}
+ );
+};
-export default FirstFactorForm
+export default FirstFactorForm;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
root: {
marginTop: theme.spacing(),
marginBottom: theme.spacing(),
@@ -219,4 +231,4 @@ const useStyles = makeStyles(theme => ({
textAlign: "right",
verticalAlign: "bottom",
},
-})); \ No newline at end of file
+}));
diff --git a/web/src/views/LoginPortal/LoginPortal.tsx b/web/src/views/LoginPortal/LoginPortal.tsx
index f93bc00d0..47a9a0ae2 100644
--- a/web/src/views/LoginPortal/LoginPortal.tsx
+++ b/web/src/views/LoginPortal/LoginPortal.tsx
@@ -1,20 +1,26 @@
import React, { useEffect, Fragment, ReactNode, useState, useCallback } from "react";
+
import { Switch, Route, Redirect, useHistory, useLocation } from "react-router";
-import FirstFactorForm from "./FirstFactor/FirstFactorForm";
-import SecondFactorForm from "./SecondFactor/SecondFactorForm";
-import {
- FirstFactorRoute, SecondFactorRoute, SecondFactorTOTPRoute,
- SecondFactorPushRoute, SecondFactorU2FRoute, AuthenticatedRoute
-} from "../../Routes";
-import { useAutheliaState } from "../../hooks/State";
-import LoadingPage from "../LoadingPage/LoadingPage";
-import { AuthenticationLevel } from "../../services/State";
+
+import { useConfiguration } from "../../hooks/Configuration";
import { useNotifications } from "../../hooks/NotificationsContext";
import { useRedirectionURL } from "../../hooks/RedirectionURL";
+import { useAutheliaState } from "../../hooks/State";
import { useUserPreferences as userUserInfo } from "../../hooks/UserInfo";
import { SecondFactorMethod } from "../../models/Methods";
-import { useConfiguration } from "../../hooks/Configuration";
+import {
+ FirstFactorRoute,
+ SecondFactorRoute,
+ SecondFactorTOTPRoute,
+ SecondFactorPushRoute,
+ SecondFactorU2FRoute,
+ AuthenticatedRoute,
+} from "../../Routes";
+import { AuthenticationLevel } from "../../services/State";
+import LoadingPage from "../LoadingPage/LoadingPage";
import AuthenticatedView from "./AuthenticatedView/AuthenticatedView";
+import FirstFactorForm from "./FirstFactor/FirstFactorForm";
+import SecondFactorForm from "./SecondFactor/SecondFactorForm";
export interface Props {
rememberMe: boolean;
@@ -35,7 +41,9 @@ const LoginPortal = function (props: Props) {
const redirect = useCallback((url: string) => history.push(url), [history]);
// Fetch the state when portal is mounted.
- useEffect(() => { fetchState() }, [fetchState]);
+ useEffect(() => {
+ fetchState();
+ }, [fetchState]);
// Fetch preferences and configuration when user is authenticated.
useEffect(() => {
@@ -76,9 +84,7 @@ const LoginPortal = function (props: Props) {
// Redirect to the correct stage if not enough authenticated
useEffect(() => {
if (state) {
- const redirectionSuffix = redirectionURL
- ? `?rd=${encodeURIComponent(redirectionURL)}`
- : '';
+ const redirectionSuffix = redirectionURL ? `?rd=${encodeURIComponent(redirectionURL)}` : "";
if (state.authentication_level === AuthenticationLevel.Unauthenticated) {
setFirstFactorDisabled(false);
@@ -107,9 +113,10 @@ const LoginPortal = function (props: Props) {
// Refresh state
fetchState();
}
- }
+ };
- const firstFactorReady = state !== undefined &&
+ const firstFactorReady =
+ state !== undefined &&
state.authentication_level === AuthenticationLevel.Unauthenticated &&
location.pathname === FirstFactorRoute;
@@ -123,16 +130,20 @@ const LoginPortal = function (props: Props) {
resetPassword={props.resetPassword}
onAuthenticationStart={() => setFirstFactorDisabled(true)}
onAuthenticationFailure={() => setFirstFactorDisabled(false)}
- onAuthenticationSuccess={handleAuthSuccess} />
+ onAuthenticationSuccess={handleAuthSuccess}
+ />
</ComponentOrLoading>
</Route>
<Route path={SecondFactorRoute}>
- {state && userInfo && configuration ? <SecondFactorForm
- authenticationLevel={state.authentication_level}
- userInfo={userInfo}
- configuration={configuration}
- onMethodChanged={() => fetchUserInfo()}
- onAuthenticationSuccess={handleAuthSuccess} /> : null}
+ {state && userInfo && configuration ? (
+ <SecondFactorForm
+ authenticationLevel={state.authentication_level}
+ userInfo={userInfo}
+ configuration={configuration}
+ onMethodChanged={() => fetchUserInfo()}
+ onAuthenticationSuccess={handleAuthSuccess}
+ />
+ ) : null}
</Route>
<Route path={AuthenticatedRoute} exact>
{userInfo ? <AuthenticatedView name={userInfo.display_name} /> : null}
@@ -141,10 +152,10 @@ const LoginPortal = function (props: Props) {
<Redirect to={FirstFactorRoute} />
</Route>
</Switch>
- )
-}
+ );
+};
-export default LoginPortal
+export default LoginPortal;
interface ComponentOrLoadingProps {
ready: boolean;
@@ -160,5 +171,5 @@ function ComponentOrLoading(props: ComponentOrLoadingProps) {
</div>
{props.ready ? props.children : null}
</Fragment>
- )
-} \ No newline at end of file
+ );
+}
diff --git a/web/src/views/LoginPortal/SecondFactor/IconWithContext.tsx b/web/src/views/LoginPortal/SecondFactor/IconWithContext.tsx
index 8bc3ba178..8ada92ed3 100644
--- a/web/src/views/LoginPortal/SecondFactor/IconWithContext.tsx
+++ b/web/src/views/LoginPortal/SecondFactor/IconWithContext.tsx
@@ -1,4 +1,5 @@
import React, { ReactNode } from "react";
+
import { makeStyles } from "@material-ui/core";
import classnames from "classnames";
@@ -11,7 +12,7 @@ interface IconWithContextProps {
const IconWithContext = function (props: IconWithContextProps) {
const iconSize = 64;
- const style = makeStyles(theme => ({
+ const style = makeStyles((theme) => ({
root: {},
iconContainer: {
display: "flex",
@@ -24,21 +25,17 @@ const IconWithContext = function (props: IconWithContextProps) {
},
context: {
display: "block",
- }
+ },
}))();
return (
<div className={classnames(props.className, style.root)}>
<div className={style.iconContainer}>
- <div className={style.icon}>
- {props.icon}
- </div>
- </div>
- <div className={style.context}>
- {props.context}
+ <div className={style.icon}>{props.icon}</div>
</div>
+ <div className={style.context}>{props.context}</div>
</div>
- )
-}
+ );
+};
-export default IconWithContext \ No newline at end of file
+export default IconWithContext;
diff --git a/web/src/views/LoginPortal/SecondFactor/MethodContainer.tsx b/web/src/views/LoginPortal/SecondFactor/MethodContainer.tsx
index 3dedce99e..d73904788 100644
--- a/web/src/views/LoginPortal/SecondFactor/MethodContainer.tsx
+++ b/web/src/views/LoginPortal/SecondFactor/MethodContainer.tsx
@@ -1,13 +1,15 @@
import React, { ReactNode, Fragment } from "react";
+
import { makeStyles, Typography, Link, useTheme } from "@material-ui/core";
-import InformationIcon from "../../../components/InformationIcon";
import classnames from "classnames";
+
+import InformationIcon from "../../../components/InformationIcon";
import Authenticated from "../Authenticated";
export enum State {
ALREADY_AUTHENTICATED = 1,
NOT_REGISTERED = 2,
- METHOD = 3
+ METHOD = 3,
}
export interface Props {
@@ -24,47 +26,40 @@ const DefaultMethodContainer = function (props: Props) {
const style = useStyles();
let container: ReactNode;
- let stateClass: string = '';
+ let stateClass: string = "";
switch (props.state) {
case State.ALREADY_AUTHENTICATED:
- container = <Authenticated />
+ container = <Authenticated />;
stateClass = "state-already-authenticated";
break;
case State.NOT_REGISTERED:
- container = <NotRegisteredContainer />
+ container = <NotRegisteredContainer />;
stateClass = "state-not-registered";
break;
case State.METHOD:
- container = <MethodContainer explanation={props.explanation}>
- {props.children}
- </MethodContainer>
+ container = <MethodContainer explanation={props.explanation}>{props.children}</MethodContainer>;
stateClass = "state-method";
break;
}
-
return (
<div id={props.id}>
<Typography variant="h6">{props.title}</Typography>
<div className={classnames(style.container, stateClass)} id="2fa-container">
- <div className={style.containerFlex}>
- {container}
- </div>
+ <div className={style.containerFlex}>{container}</div>
</div>
- {props.onRegisterClick
- ? <Link component="button"
- id="register-link"
- onClick={props.onRegisterClick}>
+ {props.onRegisterClick ? (
+ <Link component="button" id="register-link" onClick={props.onRegisterClick}>
Not registered yet?
</Link>
- : null}
+ ) : null}
</div>
- )
-}
+ );
+};
-export default DefaultMethodContainer
+export default DefaultMethodContainer;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
container: {
height: "200px",
},
@@ -76,17 +71,21 @@ const useStyles = makeStyles(theme => ({
alignItems: "center",
alignContent: "center",
justifyContent: "center",
- }
+ },
}));
function NotRegisteredContainer() {
const theme = useTheme();
return (
<Fragment>
- <div style={{ marginBottom: theme.spacing(2), flex: "0 0 100%" }}><InformationIcon /></div>
- <Typography style={{ color: "#5858ff" }}>Register your first device by clicking on the link below</Typography>
+ <div style={{ marginBottom: theme.spacing(2), flex: "0 0 100%" }}>
+ <InformationIcon />
+ </div>
+ <Typography style={{ color: "#5858ff" }}>
+ Register your first device by clicking on the link below
+ </Typography>
</Fragment>
- )
+ );
}
interface MethodContainerProps {
@@ -101,5 +100,5 @@ function MethodContainer(props: MethodContainerProps) {
<div style={{ marginBottom: theme.spacing(2) }}>{props.children}</div>
<Typography>{props.explanation}</Typography>
</Fragment>
- )
-} \ No newline at end of file
+ );
+}
diff --git a/web/src/views/LoginPortal/SecondFactor/MethodSelectionDialog.tsx b/web/src/views/LoginPortal/SecondFactor/MethodSelectionDialog.tsx
index 1e636fbda..b2ebaf9f0 100644
--- a/web/src/views/LoginPortal/SecondFactor/MethodSelectionDialog.tsx
+++ b/web/src/views/LoginPortal/SecondFactor/MethodSelectionDialog.tsx
@@ -1,9 +1,20 @@
import React, { ReactNode } from "react";
-import { Dialog, Grid, makeStyles, DialogContent, Button, DialogActions, Typography, useTheme } from "@material-ui/core";
-import PushNotificationIcon from "../../../components/PushNotificationIcon";
+
+import {
+ Dialog,
+ Grid,
+ makeStyles,
+ DialogContent,
+ Button,
+ DialogActions,
+ Typography,
+ useTheme,
+} from "@material-ui/core";
+
+import FingerTouchIcon from "../../../components/FingerTouchIcon";
import PieChartIcon from "../../../components/PieChartIcon";
+import PushNotificationIcon from "../../../components/PushNotificationIcon";
import { SecondFactorMethod } from "../../../models/Methods";
-import FingerTouchIcon from "../../../components/FingerTouchIcon";
export interface Props {
open: boolean;
@@ -18,37 +29,45 @@ const MethodSelectionDialog = function (props: Props) {
const style = useStyles();
const theme = useTheme();
- const pieChartIcon = <PieChartIcon width={24} height={24} maxProgress={1000} progress={150}
- color={theme.palette.primary.main} backgroundColor={"white"} />
+ const pieChartIcon = (
+ <PieChartIcon
+ width={24}
+ height={24}
+ maxProgress={1000}
+ progress={150}
+ color={theme.palette.primary.main}
+ backgroundColor={"white"}
+ />
+ );
return (
- <Dialog
- open={props.open}
- className={style.root}
- onClose={props.onClose}>
+ <Dialog open={props.open} className={style.root} onClose={props.onClose}>
<DialogContent>
<Grid container justify="center" spacing={1} id="methods-dialog">
- {props.methods.has(SecondFactorMethod.TOTP)
- ? <MethodItem
+ {props.methods.has(SecondFactorMethod.TOTP) ? (
+ <MethodItem
id="one-time-password-option"
method="One-Time Password"
icon={pieChartIcon}
- onClick={() => props.onClick(SecondFactorMethod.TOTP)} />
- : null}
- {props.methods.has(SecondFactorMethod.U2F) && props.u2fSupported
- ? <MethodItem
+ onClick={() => props.onClick(SecondFactorMethod.TOTP)}
+ />
+ ) : null}
+ {props.methods.has(SecondFactorMethod.U2F) && props.u2fSupported ? (
+ <MethodItem
id="security-key-option"
method="Security Key"
icon={<FingerTouchIcon size={32} />}
- onClick={() => props.onClick(SecondFactorMethod.U2F)} />
- : null}
- {props.methods.has(SecondFactorMethod.MobilePush)
- ? <MethodItem
+ onClick={() => props.onClick(SecondFactorMethod.U2F)}
+ />
+ ) : null}
+ {props.methods.has(SecondFactorMethod.MobilePush) ? (
+ <MethodItem
id="push-notification-option"
method="Push Notification"
icon={<PushNotificationIcon width={32} height={32} />}
- onClick={() => props.onClick(SecondFactorMethod.MobilePush)} />
- : null}
+ onClick={() => props.onClick(SecondFactorMethod.MobilePush)}
+ />
+ ) : null}
</Grid>
</DialogContent>
<DialogActions>
@@ -57,16 +76,16 @@ const MethodSelectionDialog = function (props: Props) {
</Button>
</DialogActions>
</Dialog>
- )
-}
+ );
+};
-export default MethodSelectionDialog
+export default MethodSelectionDialog;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
root: {
textAlign: "center",
- }
-}))
+ },
+}));
interface MethodItemProps {
id: string;
@@ -77,7 +96,7 @@ interface MethodItemProps {
}
function MethodItem(props: MethodItemProps) {
- const style = makeStyles(theme => ({
+ const style = makeStyles((theme) => ({
item: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),
@@ -89,18 +108,23 @@ function MethodItem(props: MethodItemProps) {
},
buttonRoot: {
display: "block",
- }
+ },
}))();
return (
<Grid item xs={12} className="method-option" id={props.id}>
- <Button className={style.item} color="primary"
+ <Button
+ className={style.item}
+ color="primary"
classes={{ root: style.buttonRoot }}
variant="contained"
- onClick={props.onClick}>
+ onClick={props.onClick}
+ >
<div className={style.icon}>{props.icon}</div>
- <div><Typography>{props.method}</Typography></div>
+ <div>
+ <Typography>{props.method}</Typography>
+ </div>
</Button>
</Grid>
- )
-} \ No newline at end of file
+ );
+}
diff --git a/web/src/views/LoginPortal/SecondFactor/OTPDial.tsx b/web/src/views/LoginPortal/SecondFactor/OTPDial.tsx
index 9a8429fe5..7e88a0f16 100644
--- a/web/src/views/LoginPortal/SecondFactor/OTPDial.tsx
+++ b/web/src/views/LoginPortal/SecondFactor/OTPDial.tsx
@@ -1,16 +1,18 @@
import React, { Fragment } from "react";
-import OtpInput from "react-otp-input";
-import TimerIcon from "../../../components/TimerIcon";
+
import { makeStyles } from "@material-ui/core";
import classnames from "classnames";
+import OtpInput from "react-otp-input";
+
+import SuccessIcon from "../../../components/SuccessIcon";
+import TimerIcon from "../../../components/TimerIcon";
import IconWithContext from "./IconWithContext";
import { State } from "./OneTimePasswordMethod";
-import SuccessIcon from "../../../components/SuccessIcon";
export interface Props {
passcode: string;
state: State;
- period: number
+ period: number;
onChange: (passcode: string) => void;
}
@@ -26,22 +28,18 @@ const OTPDial = function (props: Props) {
numInputs={6}
isDisabled={props.state === State.InProgress || props.state === State.Success}
hasErrored={props.state === State.Failure}
- inputStyle={classnames(style.otpDigitInput, props.state === State.Failure ? style.inputError : "")} />
+ inputStyle={classnames(style.otpDigitInput, props.state === State.Failure ? style.inputError : "")}
+ />
</span>
- )
+ );
- return (
- <IconWithContext
- icon={<Icon state={props.state} period={props.period} />}
- context={dial} />
- )
-}
+ return <IconWithContext icon={<Icon state={props.state} period={props.period} />} context={dial} />;
+};
-export default OTPDial
+export default OTPDial;
-const useStyles = makeStyles(theme => ({
- timeProgress: {
- },
+const useStyles = makeStyles((theme) => ({
+ timeProgress: {},
register: {
marginTop: theme.spacing(),
},
@@ -59,7 +57,7 @@ const useStyles = makeStyles(theme => ({
},
inputError: {
border: "1px solid rgba(255, 2, 2, 0.95)",
- }
+ },
}));
interface IconProps {
@@ -70,8 +68,10 @@ interface IconProps {
function Icon(props: IconProps) {
return (
<Fragment>
- {props.state !== State.Success ? <TimerIcon backgroundColor="#000" color="#FFFFFF" width={64} height={64} period={props.period} /> : null}
+ {props.state !== State.Success ? (
+ <TimerIcon backgroundColor="#000" color="#FFFFFF" width={64} height={64} period={props.period} />
+ ) : null}
{props.state === State.Success ? <SuccessIcon /> : null}
</Fragment>
- )
-} \ No newline at end of file
+ );
+}
diff --git a/web/src/views/LoginPortal/SecondFactor/OneTimePasswordMethod.tsx b/web/src/views/LoginPortal/SecondFactor/OneTimePasswordMethod.tsx
index e4bae1737..5e099b48a 100644
--- a/web/src/views/LoginPortal/SecondFactor/OneTimePasswordMethod.tsx
+++ b/web/src/views/LoginPortal/SecondFactor/OneTimePasswordMethod.tsx
@@ -1,9 +1,10 @@
import React, { useState, useEffect, useCallback } from "react";
-import MethodContainer, { State as MethodContainerState } from "./MethodContainer";
-import OTPDial from "./OTPDial";
-import { completeTOTPSignIn } from "../../../services/OneTimePassword";
+
import { useRedirectionURL } from "../../../hooks/RedirectionURL";
+import { completeTOTPSignIn } from "../../../services/OneTimePassword";
import { AuthenticationLevel } from "../../../services/State";
+import MethodContainer, { State as MethodContainerState } from "./MethodContainer";
+import OTPDial from "./OTPDial";
export enum State {
Idle = 1,
@@ -16,7 +17,7 @@ export interface Props {
id: string;
authenticationLevel: AuthenticationLevel;
registered: boolean;
- totp_period: number
+ totp_period: number;
onRegisterClick: () => void;
onSignInError: (err: Error) => void;
@@ -25,9 +26,9 @@ export interface Props {
const OneTimePasswordMethod = function (props: Props) {
const [passcode, setPasscode] = useState("");
- const [state, setState] = useState(props.authenticationLevel === AuthenticationLevel.TwoFactor
- ? State.Success
- : State.Idle);
+ const [state, setState] = useState(
+ props.authenticationLevel === AuthenticationLevel.TwoFactor ? State.Success : State.Idle,
+ );
const redirectionURL = useRedirectionURL();
const { onSignInSuccess, onSignInError } = props;
@@ -67,7 +68,9 @@ const OneTimePasswordMethod = function (props: Props) {
}
}, [props.authenticationLevel, setState]);
- useEffect(() => { signInFunc() }, [signInFunc]);
+ useEffect(() => {
+ signInFunc();
+ }, [signInFunc]);
let methodState = MethodContainerState.METHOD;
if (props.authenticationLevel === AuthenticationLevel.TwoFactor) {
@@ -82,14 +85,11 @@ const OneTimePasswordMethod = function (props: Props) {
title="One-Time Password"
explanation="Enter one-time password"
state={methodState}
- onRegisterClick={props.onRegisterClick}>
- <OTPDial
- passcode={passcode}
- onChange={setPasscode}
- state={state}
- period={props.totp_period} />
+ onRegisterClick={props.onRegisterClick}
+ >
+ <OTPDial passcode={passcode} onChange={setPasscode} state={state} period={props.totp_period} />
</MethodContainer>
- )
-}
+ );
+};
-export default OneTimePasswordMethod \ No newline at end of file
+export default OneTimePasswordMethod;
diff --git a/web/src/views/LoginPortal/SecondFactor/PushNotificationMethod.tsx b/web/src/views/LoginPortal/SecondFactor/PushNotificationMethod.tsx
index 3a6a0100b..53acd7290 100644
--- a/web/src/views/LoginPortal/SecondFactor/PushNotificationMethod.tsx
+++ b/web/src/views/LoginPortal/SecondFactor/PushNotificationMethod.tsx
@@ -1,13 +1,15 @@
import React, { useEffect, useCallback, useState, ReactNode } from "react";
-import MethodContainer, { State as MethodContainerState } from "./MethodContainer";
-import PushNotificationIcon from "../../../components/PushNotificationIcon";
-import { completePushNotificationSignIn } from "../../../services/PushNotification";
+
import { Button, makeStyles } from "@material-ui/core";
-import { useRedirectionURL } from "../../../hooks/RedirectionURL";
-import { useIsMountedRef } from "../../../hooks/Mounted";
-import SuccessIcon from "../../../components/SuccessIcon";
+
import FailureIcon from "../../../components/FailureIcon";
+import PushNotificationIcon from "../../../components/PushNotificationIcon";
+import SuccessIcon from "../../../components/SuccessIcon";
+import { useIsMountedRef } from "../../../hooks/Mounted";
+import { useRedirectionURL } from "../../../hooks/RedirectionURL";
+import { completePushNotificationSignIn } from "../../../services/PushNotification";
import { AuthenticationLevel } from "../../../services/State";
+import MethodContainer, { State as MethodContainerState } from "./MethodContainer";
export enum State {
SignInInProgress = 1,
@@ -50,7 +52,7 @@ const PushNotificationMethod = function (props: Props) {
setState(State.Success);
setTimeout(() => {
if (!mounted.current) return;
- onSignInSuccessCallback(res ? res.redirect : undefined)
+ onSignInSuccessCallback(res ? res.redirect : undefined);
}, 1500);
} catch (err) {
// If the request was initiated and the user changed 2FA method in the meantime,
@@ -63,7 +65,9 @@ const PushNotificationMethod = function (props: Props) {
}
}, [onSignInErrorCallback, onSignInSuccessCallback, setState, redirectionURL, mounted, props.authenticationLevel]);
- useEffect(() => { signInFunc() }, [signInFunc]);
+ useEffect(() => {
+ signInFunc();
+ }, [signInFunc]);
// Set successful state if user is already authenticated.
useEffect(() => {
@@ -94,23 +98,24 @@ const PushNotificationMethod = function (props: Props) {
id={props.id}
title="Push Notification"
explanation="A notification has been sent to your smartphone"
- state={methodState}>
- <div className={style.icon}>
- {icon}
- </div>
- <div className={(state !== State.Failure) ? "hidden" : ""}>
- <Button color="secondary" onClick={signInFunc}>Retry</Button>
+ state={methodState}
+ >
+ <div className={style.icon}>{icon}</div>
+ <div className={state !== State.Failure ? "hidden" : ""}>
+ <Button color="secondary" onClick={signInFunc}>
+ Retry
+ </Button>
</div>
</MethodContainer>
- )
-}
+ );
+};
-export default PushNotificationMethod
+export default PushNotificationMethod;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
icon: {
width: "64px",
height: "64px",
display: "inline-block",
- }
-})) \ No newline at end of file
+ },
+}));
diff --git a/web/src/views/LoginPortal/SecondFactor/SecondFactorForm.tsx b/web/src/views/LoginPortal/SecondFactor/SecondFactorForm.tsx
index 7218f1762..212a3dcc8 100644
--- a/web/src/views/LoginPortal/SecondFactor/SecondFactorForm.tsx
+++ b/web/src/views/LoginPortal/SecondFactor/SecondFactorForm.tsx
@@ -1,26 +1,28 @@
import React, { useState, useEffect } from "react";
+
import { Grid, makeStyles, Button } from "@material-ui/core";
-import MethodSelectionDialog from "./MethodSelectionDialog";
-import { SecondFactorMethod } from "../../../models/Methods";
import { useHistory, Switch, Route, Redirect } from "react-router";
-import LoginLayout from "../../../layouts/LoginLayout";
+import u2fApi from "u2f-api";
+
import { useNotifications } from "../../../hooks/NotificationsContext";
+import LoginLayout from "../../../layouts/LoginLayout";
+import { Configuration } from "../../../models/Configuration";
+import { SecondFactorMethod } from "../../../models/Methods";
+import { UserInfo } from "../../../models/UserInfo";
import {
- initiateTOTPRegistrationProcess,
- initiateU2FRegistrationProcess
-} from "../../../services/RegisterDevice";
-import SecurityKeyMethod from "./SecurityKeyMethod";
-import OneTimePasswordMethod from "./OneTimePasswordMethod";
-import PushNotificationMethod from "./PushNotificationMethod";
-import {
- LogoutRoute as SignOutRoute, SecondFactorTOTPRoute,
- SecondFactorPushRoute, SecondFactorU2FRoute, SecondFactorRoute
+ LogoutRoute as SignOutRoute,
+ SecondFactorTOTPRoute,
+ SecondFactorPushRoute,
+ SecondFactorU2FRoute,
+ SecondFactorRoute,
} from "../../../Routes";
-import { setPreferred2FAMethod } from "../../../services/UserPreferences";
-import { UserInfo } from "../../../models/UserInfo";
-import { Configuration } from "../../../models/Configuration";
-import u2fApi from "u2f-api";
+import { initiateTOTPRegistrationProcess, initiateU2FRegistrationProcess } from "../../../services/RegisterDevice";
import { AuthenticationLevel } from "../../../services/State";
+import { setPreferred2FAMethod } from "../../../services/UserPreferences";
+import MethodSelectionDialog from "./MethodSelectionDialog";
+import OneTimePasswordMethod from "./OneTimePasswordMethod";
+import PushNotificationMethod from "./PushNotificationMethod";
+import SecurityKeyMethod from "./SecurityKeyMethod";
const EMAIL_SENT_NOTIFICATION = "An email has been sent to your address to complete the process.";
@@ -46,7 +48,8 @@ const SecondFactorForm = function (props: Props) {
useEffect(() => {
u2fApi.ensureSupport().then(
() => setU2fSupported(true),
- () => console.error("U2F not supported"));
+ () => console.error("U2F not supported"),
+ );
}, [setU2fSupported]);
const initiateRegistration = (initiateRegistrationFunc: () => Promise<void>) => {
@@ -63,12 +66,12 @@ const SecondFactorForm = function (props: Props) {
createErrorNotification("There was a problem initiating the registration process");
}
setRegistrationInProgress(false);
- }
- }
+ };
+ };
const handleMethodSelectionClick = () => {
setMethodSelectionOpen(true);
- }
+ };
const handleMethodSelected = async (method: SecondFactorMethod) => {
try {
@@ -79,23 +82,21 @@ const SecondFactorForm = function (props: Props) {
console.error(err);
createErrorNotification("There was an issue updating preferred second factor method");
}
- }
+ };
const handleLogoutClick = () => {
history.push(SignOutRoute);
- }
+ };
return (
- <LoginLayout
- id="second-factor-stage"
- title={`Hi ${props.userInfo.display_name}`}
- showBrand>
+ <LoginLayout id="second-factor-stage" title={`Hi ${props.userInfo.display_name}`} showBrand>
<MethodSelectionDialog
open={methodSelectionOpen}
methods={props.configuration.available_methods}
u2fSupported={u2fSupported}
onClose={() => setMethodSelectionOpen(false)}
- onClick={handleMethodSelected} />
+ onClick={handleMethodSelected}
+ />
<Grid container>
<Grid item xs={12}>
<Button color="secondary" onClick={handleLogoutClick} id="logout-button">
@@ -116,8 +117,9 @@ const SecondFactorForm = function (props: Props) {
registered={props.userInfo.has_totp}
totp_period={props.configuration.totp_period}
onRegisterClick={initiateRegistration(initiateTOTPRegistrationProcess)}
- onSignInError={err => createErrorNotification(err.message)}
- onSignInSuccess={props.onAuthenticationSuccess} />
+ onSignInError={(err) => createErrorNotification(err.message)}
+ onSignInSuccess={props.onAuthenticationSuccess}
+ />
</Route>
<Route path={SecondFactorU2FRoute} exact>
<SecurityKeyMethod
@@ -126,15 +128,17 @@ const SecondFactorForm = function (props: Props) {
// Whether the user has a U2F device registered already
registered={props.userInfo.has_u2f}
onRegisterClick={initiateRegistration(initiateU2FRegistrationProcess)}
- onSignInError={err => createErrorNotification(err.message)}
- onSignInSuccess={props.onAuthenticationSuccess} />
+ onSignInError={(err) => createErrorNotification(err.message)}
+ onSignInSuccess={props.onAuthenticationSuccess}
+ />
</Route>
<Route path={SecondFactorPushRoute} exact>
<PushNotificationMethod
id="push-notification-method"
authenticationLevel={props.authenticationLevel}
- onSignInError={err => createErrorNotification(err.message)}
- onSignInSuccess={props.onAuthenticationSuccess} />
+ onSignInError={(err) => createErrorNotification(err.message)}
+ onSignInSuccess={props.onAuthenticationSuccess}
+ />
</Route>
<Route path={SecondFactorRoute}>
<Redirect to={SecondFactorTOTPRoute} />
@@ -143,12 +147,12 @@ const SecondFactorForm = function (props: Props) {
</Grid>
</Grid>
</LoginLayout>
- )
-}
+ );
+};
-export default SecondFactorForm
+export default SecondFactorForm;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
methodContainer: {
border: "1px solid #d6d6d6",
borderRadius: "10px",
@@ -156,4 +160,4 @@ const useStyles = makeStyles(theme => ({
marginTop: theme.spacing(2),
marginBottom: theme.spacing(2),
},
-}))
+}));
diff --git a/web/src/views/LoginPortal/SecondFactor/SecurityKeyMethod.tsx b/web/src/views/LoginPortal/SecondFactor/SecurityKeyMethod.tsx
index 97a4e22b0..b8c825e94 100644
--- a/web/src/views/LoginPortal/SecondFactor/SecurityKeyMethod.tsx
+++ b/web/src/views/LoginPortal/SecondFactor/SecurityKeyMethod.tsx
@@ -1,17 +1,19 @@
import React, { useCallback, useEffect, useState, Fragment } from "react";
-import MethodContainer, { State as MethodContainerState } from "./MethodContainer";
+
import { makeStyles, Button, useTheme } from "@material-ui/core";
-import { initiateU2FSignin, completeU2FSignin } from "../../../services/SecurityKey";
+import { CSSProperties } from "@material-ui/styles";
import u2fApi from "u2f-api";
-import { useRedirectionURL } from "../../../hooks/RedirectionURL";
+
+import FailureIcon from "../../../components/FailureIcon";
+import FingerTouchIcon from "../../../components/FingerTouchIcon";
+import LinearProgressBar from "../../../components/LinearProgressBar";
import { useIsMountedRef } from "../../../hooks/Mounted";
+import { useRedirectionURL } from "../../../hooks/RedirectionURL";
import { useTimer } from "../../../hooks/Timer";
-import LinearProgressBar from "../../../components/LinearProgressBar";
-import FingerTouchIcon from "../../../components/FingerTouchIcon";
-import FailureIcon from "../../../components/FailureIcon";
-import IconWithContext from "./IconWithContext";
-import { CSSProperties } from "@material-ui/styles";
+import { initiateU2FSignin, completeU2FSignin } from "../../../services/SecurityKey";
import { AuthenticationLevel } from "../../../services/State";
+import IconWithContext from "./IconWithContext";
+import MethodContainer, { State as MethodContainerState } from "./MethodContainer";
export enum State {
WaitTouch = 1,
@@ -35,7 +37,7 @@ const SecurityKeyMethod = function (props: Props) {
const style = useStyles();
const redirectionURL = useRedirectionURL();
const mounted = useIsMountedRef();
- const [timerPercent, triggerTimer,] = useTimer(signInTimeout * 1000 - 500);
+ const [timerPercent, triggerTimer] = useTimer(signInTimeout * 1000 - 500);
const { onSignInSuccess, onSignInError } = props;
/* eslint-disable react-hooks/exhaustive-deps */
@@ -61,7 +63,7 @@ const SecurityKeyMethod = function (props: Props) {
challenge: signRequest.challenge,
keyHandle: r.keyHandle,
version: r.version,
- })
+ });
}
const signResponse = await u2fApi.sign(signRequests, signInTimeout);
// If the request was initiated and the user changed 2FA method in the meantime,
@@ -79,9 +81,19 @@ const SecurityKeyMethod = function (props: Props) {
onSignInErrorCallback(new Error("Failed to initiate security key sign in process"));
setState(State.Failure);
}
- }, [onSignInSuccessCallback, onSignInErrorCallback, redirectionURL, mounted, triggerTimer, props.authenticationLevel, props.registered]);
-
- useEffect(() => { doInitiateSignIn() }, [doInitiateSignIn]);
+ }, [
+ onSignInSuccessCallback,
+ onSignInErrorCallback,
+ redirectionURL,
+ mounted,
+ triggerTimer,
+ props.authenticationLevel,
+ props.registered,
+ ]);
+
+ useEffect(() => {
+ doInitiateSignIn();
+ }, [doInitiateSignIn]);
let methodState = MethodContainerState.METHOD;
if (props.authenticationLevel === AuthenticationLevel.TwoFactor) {
@@ -96,20 +108,21 @@ const SecurityKeyMethod = function (props: Props) {
title="Security Key"
explanation="Touch the token of your security key"
state={methodState}
- onRegisterClick={props.onRegisterClick}>
+ onRegisterClick={props.onRegisterClick}
+ >
<div className={style.icon}>
<Icon state={state} timer={timerPercent} onRetryClick={doInitiateSignIn} />
</div>
</MethodContainer>
- )
-}
+ );
+};
-export default SecurityKeyMethod
+export default SecurityKeyMethod;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
icon: {
display: "inline-block",
- }
+ },
}));
interface IconProps {
@@ -125,22 +138,32 @@ function Icon(props: IconProps) {
const progressBarStyle: CSSProperties = {
marginTop: theme.spacing(),
- }
-
- const touch = <IconWithContext
- icon={<FingerTouchIcon size={64} animated strong />}
- context={<LinearProgressBar value={props.timer} style={progressBarStyle} height={theme.spacing(2)} />}
- className={state === State.WaitTouch ? undefined : "hidden"} />
-
- const failure = <IconWithContext
- icon={<FailureIcon />}
- context={<Button color="secondary" onClick={props.onRetryClick}>Retry</Button>}
- className={state === State.Failure ? undefined : "hidden"} />
+ };
+
+ const touch = (
+ <IconWithContext
+ icon={<FingerTouchIcon size={64} animated strong />}
+ context={<LinearProgressBar value={props.timer} style={progressBarStyle} height={theme.spacing(2)} />}
+ className={state === State.WaitTouch ? undefined : "hidden"}
+ />
+ );
+
+ const failure = (
+ <IconWithContext
+ icon={<FailureIcon />}
+ context={
+ <Button color="secondary" onClick={props.onRetryClick}>
+ Retry
+ </Button>
+ }
+ className={state === State.Failure ? undefined : "hidden"}
+ />
+ );
return (
<Fragment>
{touch}
{failure}
</Fragment>
- )
+ );
}
diff --git a/web/src/views/LoginPortal/SignOut/SignOut.tsx b/web/src/views/LoginPortal/SignOut/SignOut.tsx
index 056ac5de5..b44a4b73a 100644
--- a/web/src/views/LoginPortal/SignOut/SignOut.tsx
+++ b/web/src/views/LoginPortal/SignOut/SignOut.tsx
@@ -1,14 +1,16 @@
import React, { useEffect, useCallback, useState } from "react";
-import LoginLayout from "../../../layouts/LoginLayout";
-import { useNotifications } from "../../../hooks/NotificationsContext";
-import { signOut } from "../../../services/SignOut";
+
import { Typography, makeStyles } from "@material-ui/core";
import { Redirect } from "react-router";
-import { FirstFactorRoute } from "../../../Routes";
-import { useRedirectionURL } from "../../../hooks/RedirectionURL";
+
import { useIsMountedRef } from "../../../hooks/Mounted";
+import { useNotifications } from "../../../hooks/NotificationsContext";
+import { useRedirectionURL } from "../../../hooks/RedirectionURL";
+import LoginLayout from "../../../layouts/LoginLayout";
+import { FirstFactorRoute } from "../../../Routes";
+import { signOut } from "../../../services/SignOut";
-export interface Props { }
+export interface Props {}
const SignOut = function (props: Props) {
const mounted = useIsMountedRef();
@@ -33,29 +35,29 @@ const SignOut = function (props: Props) {
}
}, [createErrorNotification, setTimedOut, mounted]);
- useEffect(() => { doSignOut() }, [doSignOut]);
+ useEffect(() => {
+ doSignOut();
+ }, [doSignOut]);
if (timedOut) {
if (redirectionURL) {
window.location.href = redirectionURL;
} else {
- return <Redirect to={FirstFactorRoute} />
+ return <Redirect to={FirstFactorRoute} />;
}
}
return (
<LoginLayout title="Sign out">
- <Typography className={style.typo} >
- You're being signed out and redirected...
- </Typography>
+ <Typography className={style.typo}>You're being signed out and redirected...</Typography>
</LoginLayout>
- )
-}
+ );
+};
-export default SignOut
+export default SignOut;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
typo: {
padding: theme.spacing(),
- }
-})) \ No newline at end of file
+ },
+}));
diff --git a/web/src/views/ResetPassword/ResetPasswordStep1.tsx b/web/src/views/ResetPassword/ResetPasswordStep1.tsx
index 2709cb8c7..97e52f39e 100644
--- a/web/src/views/ResetPassword/ResetPasswordStep1.tsx
+++ b/web/src/views/ResetPassword/ResetPasswordStep1.tsx
@@ -1,11 +1,13 @@
import React, { useState } from "react";
-import LoginLayout from "../../layouts/LoginLayout";
+
import { Grid, Button, makeStyles } from "@material-ui/core";
-import { useNotifications } from "../../hooks/NotificationsContext";
import { useHistory } from "react-router";
-import { initiateResetPasswordProcess } from "../../services/ResetPassword";
-import { FirstFactorRoute } from "../../Routes";
+
import FixedTextField from "../../components/FixedTextField";
+import { useNotifications } from "../../hooks/NotificationsContext";
+import LoginLayout from "../../layouts/LoginLayout";
+import { FirstFactorRoute } from "../../Routes";
+import { initiateResetPasswordProcess } from "../../services/ResetPassword";
const ResetPasswordStep1 = function () {
const style = useStyles();
@@ -26,15 +28,15 @@ const ResetPasswordStep1 = function () {
} catch (err) {
createErrorNotification("There was an issue initiating the password reset process.");
}
- }
+ };
const handleResetClick = () => {
doInitiateResetPasswordProcess();
- }
+ };
const handleCancelClick = () => {
history.push(FirstFactorRoute);
- }
+ };
return (
<LoginLayout title="Reset password" id="reset-password-step1-stage">
@@ -49,19 +51,17 @@ const ResetPasswordStep1 = function () {
value={username}
onChange={(e) => setUsername(e.target.value)}
onKeyPress={(ev) => {
- if (ev.key === 'Enter') {
+ if (ev.key === "Enter") {
doInitiateResetPasswordProcess();
ev.preventDefault();
}
- }} />
+ }}
+ />
</Grid>
<Grid item xs={6}>
- <Button
- id="reset-button"
- variant="contained"
- color="primary"
- fullWidth
- onClick={handleResetClick}>Reset</Button>
+ <Button id="reset-button" variant="contained" color="primary" fullWidth onClick={handleResetClick}>
+ Reset
+ </Button>
</Grid>
<Grid item xs={6}>
<Button
@@ -69,18 +69,21 @@ const ResetPasswordStep1 = function () {
variant="contained"
color="primary"
fullWidth
- onClick={handleCancelClick}>Cancel</Button>
+ onClick={handleCancelClick}
+ >
+ Cancel
+ </Button>
</Grid>
</Grid>
</LoginLayout>
- )
-}
+ );
+};
-export default ResetPasswordStep1
+export default ResetPasswordStep1;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
root: {
marginTop: theme.spacing(2),
marginBottom: theme.spacing(2),
},
-})) \ No newline at end of file
+}));
diff --git a/web/src/views/ResetPassword/ResetPasswordStep2.tsx b/web/src/views/ResetPassword/ResetPasswordStep2.tsx
index 43c4b8a7f..af3dc5b7a 100644
--- a/web/src/views/ResetPassword/ResetPasswordStep2.tsx
+++ b/web/src/views/ResetPassword/ResetPasswordStep2.tsx
@@ -1,13 +1,15 @@
import React, { useState, useCallback, useEffect } from "react";
-import LoginLayout from "../../layouts/LoginLayout";
-import classnames from "classnames";
+
import { Grid, Button, makeStyles } from "@material-ui/core";
-import { useNotifications } from "../../hooks/NotificationsContext";
+import classnames from "classnames";
import { useHistory, useLocation } from "react-router";
-import { completeResetPasswordProcess, resetPassword } from "../../services/ResetPassword";
+
+import FixedTextField from "../../components/FixedTextField";
+import { useNotifications } from "../../hooks/NotificationsContext";
+import LoginLayout from "../../layouts/LoginLayout";
import { FirstFactorRoute } from "../../Routes";
+import { completeResetPasswordProcess, resetPassword } from "../../services/ResetPassword";
import { extractIdentityToken } from "../../utils/IdentityToken";
-import FixedTextField from "../../components/FixedTextField";
const ResetPasswordStep2 = function () {
const style = useStyles();
@@ -36,8 +38,9 @@ const ResetPasswordStep2 = function () {
setFormDisabled(false);
} catch (err) {
console.error(err);
- createErrorNotification("There was an issue completing the process. " +
- "The verification token might have expired.");
+ createErrorNotification(
+ "There was an issue completing the process. The verification token might have expired.",
+ );
setFormDisabled(true);
}
}, [processToken, createErrorNotification]);
@@ -54,11 +57,11 @@ const ResetPasswordStep2 = function () {
if (password2 === "") {
setErrorPassword2(true);
}
- return
+ return;
}
if (password1 !== password2) {
setErrorPassword1(true);
- setErrorPassword2(true)
+ setErrorPassword2(true);
createErrorNotification("Passwords do not match.");
return;
}
@@ -76,13 +79,11 @@ const ResetPasswordStep2 = function () {
createErrorNotification("There was an issue resetting the password.");
}
}
- }
+ };
- const handleResetClick = () =>
- doResetPassword();
+ const handleResetClick = () => doResetPassword();
- const handleCancelClick = () =>
- history.push(FirstFactorRoute);
+ const handleCancelClick = () => history.push(FirstFactorRoute);
return (
<LoginLayout title="Enter new password" id="reset-password-step2-stage">
@@ -95,9 +96,10 @@ const ResetPasswordStep2 = function () {
type="password"
value={password1}
disabled={formDisabled}
- onChange={e => setPassword1(e.target.value)}
+ onChange={(e) => setPassword1(e.target.value)}
error={errorPassword1}
- className={classnames(style.fullWidth)} />
+ className={classnames(style.fullWidth)}
+ />
</Grid>
<Grid item xs={12}>
<FixedTextField
@@ -107,15 +109,16 @@ const ResetPasswordStep2 = function () {
type="password"
disabled={formDisabled}
value={password2}
- onChange={e => setPassword2(e.target.value)}
+ onChange={(e) => setPassword2(e.target.value)}
error={errorPassword2}
onKeyPress={(ev) => {
- if (ev.key === 'Enter') {
+ if (ev.key === "Enter") {
doResetPassword();
ev.preventDefault();
}
}}
- className={classnames(style.fullWidth)} />
+ className={classnames(style.fullWidth)}
+ />
</Grid>
<Grid item xs={6}>
<Button
@@ -125,7 +128,10 @@ const ResetPasswordStep2 = function () {
name="password1"
disabled={formDisabled}
onClick={handleResetClick}
- className={style.fullWidth}>Reset</Button>
+ className={style.fullWidth}
+ >
+ Reset
+ </Button>
</Grid>
<Grid item xs={6}>
<Button
@@ -134,21 +140,24 @@ const ResetPasswordStep2 = function () {
color="primary"
name="password2"
onClick={handleCancelClick}
- className={style.fullWidth}>Cancel</Button>
+ className={style.fullWidth}
+ >
+ Cancel
+ </Button>
</Grid>
</Grid>
</LoginLayout>
- )
-}
+ );
+};
-export default ResetPasswordStep2
+export default ResetPasswordStep2;
-const useStyles = makeStyles(theme => ({
+const useStyles = makeStyles((theme) => ({
root: {
marginTop: theme.spacing(2),
marginBottom: theme.spacing(2),
},
fullWidth: {
width: "100%",
- }
-})) \ No newline at end of file
+ },
+}));