\n Register your first device by clicking on the link below\n \n )\n}\n\ninterface MethodContainerProps {\n explanation: string;\n children: ReactNode;\n}\n\nfunction MethodContainer(props: MethodContainerProps) {\n const theme = useTheme();\n return (\n \n
{props.children}
\n {props.explanation}\n \n )\n}","import React from \"react\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { faCheckCircle } from \"@fortawesome/free-regular-svg-icons\";\n\nconst SuccessIcon = function () {\n return (\n \n )\n}\n\nexport default SuccessIcon","import React from \"react\";\nimport SuccessIcon from \"../../components/SuccessIcon\";\nimport { Typography, makeStyles } from \"@material-ui/core\";\n\nconst Authenticated = function () {\n const classes = useStyles();\n return (\n
\n
\n \n
\n Authenticated\n
\n )\n}\n\nexport default Authenticated\n\nconst useStyles = makeStyles(theme => ({\n iconContainer: {\n marginBottom: theme.spacing(2),\n flex: \"0 0 100%\"\n }\n}))","import { Post, PostWithOptionalResponse } from \"./Client\";\nimport { InitiateU2FSignInPath, CompleteU2FSignInPath } from \"./Api\";\nimport u2fApi from \"u2f-api\";\nimport { SignInResponse } from \"./SignIn\";\n\ninterface InitiateU2FSigninResponse {\n appId: string,\n challenge: string,\n registeredKeys: {\n appId: string,\n keyHandle: string,\n version: string,\n }[]\n}\n\nexport async function initiateU2FSignin() {\n return Post(InitiateU2FSignInPath);\n}\n\ninterface CompleteU2FSigninBody {\n signResponse: u2fApi.SignResponse;\n targetURL?: string;\n}\n\nexport function completeU2FSignin(signResponse: u2fApi.SignResponse, targetURL: string | undefined) {\n const body: CompleteU2FSigninBody = { signResponse };\n if (targetURL) {\n body.targetURL = targetURL;\n }\n return PostWithOptionalResponse(CompleteU2FSignInPath, body);\n}","import { useRef, useEffect } from \"react\";\n\nexport function useIsMountedRef() {\n const isMountedRef = useRef(false);\n useEffect(() => {\n isMountedRef.current = true;\n return () => { isMountedRef.current = false };\n });\n return isMountedRef;\n}","import { Get } from \"./Client\";\nimport { StatePath } from \"./Api\";\n\nexport enum AuthenticationLevel {\n Unauthenticated = 0,\n OneFactor = 1,\n TwoFactor = 2,\n}\n\nexport interface AutheliaState {\n username: string;\n authentication_level: AuthenticationLevel\n}\n\nexport async function getState(): Promise {\n return Get(StatePath);\n}","import React, { useCallback, useEffect, useState, Fragment } from \"react\";\nimport MethodContainer, { State as MethodContainerState } from \"./MethodContainer\";\nimport { makeStyles, Button, useTheme } from \"@material-ui/core\";\nimport { initiateU2FSignin, completeU2FSignin } from \"../../../services/SecurityKey\";\nimport u2fApi from \"u2f-api\";\nimport { useRedirectionURL } from \"../../../hooks/RedirectionURL\";\nimport { useIsMountedRef } from \"../../../hooks/Mounted\";\nimport { useTimer } from \"../../../hooks/Timer\";\nimport LinearProgressBar from \"../../../components/LinearProgressBar\";\nimport FingerTouchIcon from \"../../../components/FingerTouchIcon\";\nimport FailureIcon from \"../../../components/FailureIcon\";\nimport IconWithContext from \"./IconWithContext\";\nimport { CSSProperties } from \"@material-ui/styles\";\nimport { AuthenticationLevel } from \"../../../services/State\";\n\nexport enum State {\n WaitTouch = 1,\n SigninInProgress = 2,\n Failure = 3,\n}\n\nexport interface Props {\n id: string;\n authenticationLevel: AuthenticationLevel;\n registered: boolean;\n\n onRegisterClick: () => void;\n onSignInError: (err: Error) => void;\n onSignInSuccess: (redirectURL: string | undefined) => void;\n}\n\nconst SecurityKeyMethod = function (props: Props) {\n const signInTimeout = 30;\n const [state, setState] = useState(State.WaitTouch);\n const style = useStyles();\n const redirectionURL = useRedirectionURL();\n const mounted = useIsMountedRef();\n const [timerPercent, triggerTimer,] = useTimer(signInTimeout * 1000 - 500);\n\n const { onSignInSuccess, onSignInError } = props;\n /* eslint-disable react-hooks/exhaustive-deps */\n const onSignInErrorCallback = useCallback(onSignInError, []);\n const onSignInSuccessCallback = useCallback(onSignInSuccess, []);\n /* eslint-enable react-hooks/exhaustive-deps */\n\n const doInitiateSignIn = useCallback(async () => {\n // If user is already authenticated, we don't initiate sign in process.\n if (!props.registered || props.authenticationLevel >= AuthenticationLevel.TwoFactor) {\n return;\n }\n\n try {\n triggerTimer();\n setState(State.WaitTouch);\n const signRequest = await initiateU2FSignin();\n const signRequests: u2fApi.SignRequest[] = [];\n for (var i in signRequest.registeredKeys) {\n const r = signRequest.registeredKeys[i];\n signRequests.push({\n appId: signRequest.appId,\n challenge: signRequest.challenge,\n keyHandle: r.keyHandle,\n version: r.version,\n })\n }\n const signResponse = await u2fApi.sign(signRequests, signInTimeout);\n // If the request was initiated and the user changed 2FA method in the meantime,\n // the process is interrupted to avoid updating state of unmounted component.\n if (!mounted.current) return;\n\n setState(State.SigninInProgress);\n const res = await completeU2FSignin(signResponse, redirectionURL);\n onSignInSuccessCallback(res ? res.redirect : undefined);\n } catch (err) {\n // If the request was initiated and the user changed 2FA method in the meantime,\n // the process is interrupted to avoid updating state of unmounted component.\n if (!mounted.current) return;\n console.error(err);\n onSignInErrorCallback(new Error(\"Failed to initiate security key sign in process\"));\n setState(State.Failure);\n }\n }, [onSignInSuccessCallback, onSignInErrorCallback, redirectionURL, mounted, triggerTimer, props.authenticationLevel, props.registered]);\n\n useEffect(() => { doInitiateSignIn() }, [doInitiateSignIn]);\n\n let methodState = MethodContainerState.METHOD;\n if (props.authenticationLevel === AuthenticationLevel.TwoFactor) {\n methodState = MethodContainerState.ALREADY_AUTHENTICATED;\n } else if (!props.registered) {\n methodState = MethodContainerState.NOT_REGISTERED;\n }\n\n return (\n \n
\n )\n}\n\nexport default IconWithContext","import { useState, useCallback, useEffect } from \"react\";\n\nexport function useTimer(timeoutMs: number): [number, () => void, () => void] {\n const Interval = 100;\n const [startDate, setStartDate] = useState(undefined as Date | undefined);\n const [percent, setPercent] = useState(0);\n\n const trigger = useCallback(() => {\n setPercent(0);\n setStartDate(new Date());\n }, [setStartDate, setPercent]);\n\n const clear = useCallback(() => {\n setPercent(0);\n setStartDate(undefined);\n }, []);\n\n useEffect(() => {\n if (!startDate) {\n return;\n }\n\n const intervalNode = setInterval(() => {\n const elapsedMs = (startDate) ? new Date().getTime() - startDate.getTime() : 0;\n let p = elapsedMs / timeoutMs * 100.0;\n if (p >= 100) {\n p = 100;\n setStartDate(undefined);\n }\n setPercent(p);\n }, Interval);\n\n return () => clearInterval(intervalNode);\n }, [startDate, setPercent, setStartDate, timeoutMs]);\n\n return [\n percent,\n trigger,\n clear,\n ]\n}","import React, { useState, useEffect, useCallback } from \"react\";\nimport MethodContainer, { State as MethodContainerState } from \"./MethodContainer\";\nimport OTPDial from \"./OTPDial\";\nimport { completeTOTPSignIn } from \"../../../services/OneTimePassword\";\nimport { useRedirectionURL } from \"../../../hooks/RedirectionURL\";\nimport { AuthenticationLevel } from \"../../../services/State\";\n\nexport enum State {\n Idle = 1,\n InProgress = 2,\n Success = 3,\n Failure = 4,\n}\n\nexport interface Props {\n id: string;\n authenticationLevel: AuthenticationLevel;\n registered: boolean;\n totp_period: number\n\n onRegisterClick: () => void;\n onSignInError: (err: Error) => void;\n onSignInSuccess: (redirectURL: string | undefined) => void;\n}\n\nconst OneTimePasswordMethod = function (props: Props) {\n const [passcode, setPasscode] = useState(\"\");\n const [state, setState] = useState(props.authenticationLevel === AuthenticationLevel.TwoFactor\n ? State.Success\n : State.Idle);\n const redirectionURL = useRedirectionURL();\n\n const { onSignInSuccess, onSignInError } = props;\n /* eslint-disable react-hooks/exhaustive-deps */\n const onSignInErrorCallback = useCallback(onSignInError, []);\n const onSignInSuccessCallback = useCallback(onSignInSuccess, []);\n /* eslint-enable react-hooks/exhaustive-deps */\n\n const signInFunc = useCallback(async () => {\n if (props.authenticationLevel === AuthenticationLevel.TwoFactor) {\n return;\n }\n\n const passcodeStr = `${passcode}`;\n\n if (!passcode || passcodeStr.length !== 6) {\n return;\n }\n\n try {\n setState(State.InProgress);\n const res = await completeTOTPSignIn(passcodeStr, redirectionURL);\n setState(State.Success);\n onSignInSuccessCallback(res ? res.redirect : undefined);\n } catch (err) {\n console.error(err);\n onSignInErrorCallback(new Error(\"The one-time password might be wrong\"));\n setState(State.Failure);\n }\n setPasscode(\"\");\n }, [passcode, onSignInErrorCallback, onSignInSuccessCallback, redirectionURL, props.authenticationLevel]);\n\n // Set successful state if user is already authenticated.\n useEffect(() => {\n if (props.authenticationLevel >= AuthenticationLevel.TwoFactor) {\n setState(State.Success);\n }\n }, [props.authenticationLevel, setState]);\n\n useEffect(() => { signInFunc() }, [signInFunc]);\n\n let methodState = MethodContainerState.METHOD;\n if (props.authenticationLevel === AuthenticationLevel.TwoFactor) {\n methodState = MethodContainerState.ALREADY_AUTHENTICATED;\n } else if (!props.registered) {\n methodState = MethodContainerState.NOT_REGISTERED;\n }\n\n return (\n \n \n \n )\n}\n\nexport default OneTimePasswordMethod","import React, { useState, useEffect } from \"react\";\nimport PieChartIcon from \"./PieChartIcon\";\n\nexport interface Props {\n width: number;\n height: number;\n period: number;\n\n color?: string;\n backgroundColor?: string;\n}\n\nconst TimerIcon = function (props: Props) {\n const radius = 31.6;\n const [timeProgress, setTimeProgress] = useState(0);\n\n useEffect(() => {\n // Get the current number of seconds to initialize timer.\n const initialValue = (new Date().getTime() / 1000) % props.period / props.period * radius;\n setTimeProgress(initialValue);\n\n const interval = setInterval(() => {\n const value = (new Date().getTime() / 1000) % props.period / props.period * radius;\n setTimeProgress(value);\n }, 100);\n return () => clearInterval(interval);\n }, [props]);\n\n return (\n \n )\n}\n\nexport default TimerIcon","import React, { Fragment } from \"react\";\nimport OtpInput from \"react-otp-input\";\nimport TimerIcon from \"../../../components/TimerIcon\";\nimport { makeStyles } from \"@material-ui/core\";\nimport classnames from \"classnames\";\nimport IconWithContext from \"./IconWithContext\";\nimport { State } from \"./OneTimePasswordMethod\";\nimport SuccessIcon from \"../../../components/SuccessIcon\";\n\nexport interface Props {\n passcode: string;\n state: State;\n period: number\n\n onChange: (passcode: string) => void;\n}\n\nconst OTPDial = function (props: Props) {\n const style = useStyles();\n const dial = (\n \n \n \n )\n\n return (\n }\n context={dial} />\n )\n}\n\nexport default OTPDial\n\nconst useStyles = makeStyles(theme => ({\n timeProgress: {\n },\n register: {\n marginTop: theme.spacing(),\n },\n otpInput: {\n display: \"inline-block\",\n marginTop: theme.spacing(2),\n },\n otpDigitInput: {\n padding: theme.spacing(),\n marginLeft: theme.spacing(0.5),\n marginRight: theme.spacing(0.5),\n fontSize: \"1rem\",\n borderRadius: \"5px\",\n border: \"1px solid rgba(0,0,0,0.3)\",\n },\n inputError: {\n border: \"1px solid rgba(255, 2, 2, 0.95)\",\n }\n}));\n\ninterface IconProps {\n state: State;\n period: number;\n}\n\nfunction Icon(props: IconProps) {\n return (\n \n {props.state !== State.Success ? : null}\n {props.state === State.Success ? : null}\n \n )\n}","import { PostWithOptionalResponse } from \"./Client\";\nimport { CompleteTOTPSignInPath } from \"./Api\";\nimport { SignInResponse } from \"./SignIn\";\n\ninterface CompleteU2FSigninBody {\n token: string;\n targetURL?: string;\n}\n\nexport function completeTOTPSignIn(passcode: string, targetURL: string | undefined) {\n const body: CompleteU2FSigninBody = { token: `${passcode}` };\n if (targetURL) {\n body.targetURL = targetURL;\n }\n return PostWithOptionalResponse(CompleteTOTPSignInPath, body);\n}","import React, { useEffect, useCallback, useState, ReactNode } from \"react\";\nimport MethodContainer, { State as MethodContainerState } from \"./MethodContainer\";\nimport PushNotificationIcon from \"../../../components/PushNotificationIcon\";\nimport { completePushNotificationSignIn } from \"../../../services/PushNotification\";\nimport { Button, makeStyles } from \"@material-ui/core\";\nimport { useRedirectionURL } from \"../../../hooks/RedirectionURL\";\nimport { useIsMountedRef } from \"../../../hooks/Mounted\";\nimport SuccessIcon from \"../../../components/SuccessIcon\";\nimport FailureIcon from \"../../../components/FailureIcon\";\nimport { AuthenticationLevel } from \"../../../services/State\";\n\nexport enum State {\n SignInInProgress = 1,\n Success = 2,\n Failure = 3,\n}\n\nexport interface Props {\n id: string;\n authenticationLevel: AuthenticationLevel;\n\n onSignInError: (err: Error) => void;\n onSignInSuccess: (redirectURL: string | undefined) => void;\n}\n\nconst PushNotificationMethod = function (props: Props) {\n const style = useStyles();\n const [state, setState] = useState(State.SignInInProgress);\n const redirectionURL = useRedirectionURL();\n const mounted = useIsMountedRef();\n\n const { onSignInSuccess, onSignInError } = props;\n /* eslint-disable react-hooks/exhaustive-deps */\n const onSignInErrorCallback = useCallback(onSignInError, []);\n const onSignInSuccessCallback = useCallback(onSignInSuccess, []);\n /* eslint-enable react-hooks/exhaustive-deps */\n\n const signInFunc = useCallback(async () => {\n if (props.authenticationLevel === AuthenticationLevel.TwoFactor) {\n return;\n }\n\n try {\n setState(State.SignInInProgress);\n const res = await completePushNotificationSignIn(redirectionURL);\n // If the request was initiated and the user changed 2FA method in the meantime,\n // the process is interrupted to avoid updating state of unmounted component.\n if (!mounted.current) return;\n\n setState(State.Success);\n setTimeout(() => {\n if (!mounted.current) return;\n onSignInSuccessCallback(res ? res.redirect : undefined)\n }, 1500);\n } catch (err) {\n // If the request was initiated and the user changed 2FA method in the meantime,\n // the process is interrupted to avoid updating state of unmounted component.\n if (!mounted.current) return;\n\n console.error(err);\n onSignInErrorCallback(new Error(\"There was an issue completing sign in process\"));\n setState(State.Failure);\n }\n }, [onSignInErrorCallback, onSignInSuccessCallback, setState, redirectionURL, mounted, props.authenticationLevel]);\n\n useEffect(() => { signInFunc() }, [signInFunc]);\n\n // Set successful state if user is already authenticated.\n useEffect(() => {\n if (props.authenticationLevel >= AuthenticationLevel.TwoFactor) {\n setState(State.Success);\n }\n }, [props.authenticationLevel, setState]);\n\n let icon: ReactNode;\n switch (state) {\n case State.SignInInProgress:\n icon = ;\n break;\n case State.Success:\n icon = ;\n break;\n case State.Failure:\n icon = ;\n }\n\n let methodState = MethodContainerState.METHOD;\n if (props.authenticationLevel === AuthenticationLevel.TwoFactor) {\n methodState = MethodContainerState.ALREADY_AUTHENTICATED;\n }\n\n return (\n \n
\n {icon}\n
\n
\n \n
\n \n )\n}\n\nexport default PushNotificationMethod\n\nconst useStyles = makeStyles(theme => ({\n icon: {\n width: \"64px\",\n height: \"64px\",\n display: \"inline-block\",\n }\n}))","import { PostWithOptionalResponse } from \"./Client\";\nimport { CompletePushNotificationSignInPath } from \"./Api\";\nimport { SignInResponse } from \"./SignIn\";\n\ninterface CompleteU2FSigninBody {\n targetURL?: string;\n}\n\nexport function completePushNotificationSignIn(targetURL: string | undefined) {\n const body: CompleteU2FSigninBody = {};\n if (targetURL) {\n body.targetURL = targetURL;\n }\n return PostWithOptionalResponse(CompletePushNotificationSignInPath, body);\n}","import { Get, PostWithOptionalResponse } from \"./Client\";\nimport { UserInfoPath, UserInfo2FAMethodPath } from \"./Api\";\nimport { SecondFactorMethod } from \"../models/Methods\";\nimport { UserInfo } from \"../models/UserInfo\";\n\nexport type Method2FA = \"u2f\" | \"totp\" | \"mobile_push\";\n\nexport interface UserInfoPayload {\n display_name: string;\n method: Method2FA;\n has_u2f: boolean;\n has_totp: boolean;\n}\n\nexport interface MethodPreferencePayload {\n method: Method2FA;\n}\n\nexport function toEnum(method: Method2FA): SecondFactorMethod {\n switch (method) {\n case \"u2f\":\n return SecondFactorMethod.U2F;\n case \"totp\":\n return SecondFactorMethod.TOTP;\n case \"mobile_push\":\n return SecondFactorMethod.MobilePush;\n }\n}\n\nexport function toString(method: SecondFactorMethod): Method2FA {\n switch (method) {\n case SecondFactorMethod.U2F:\n return \"u2f\";\n case SecondFactorMethod.TOTP:\n return \"totp\";\n case SecondFactorMethod.MobilePush:\n return \"mobile_push\";\n }\n}\n\nexport async function getUserPreferences(): Promise {\n const res = await Get(UserInfoPath);\n return { ...res, method: toEnum(res.method) };\n}\n\nexport function setPreferred2FAMethod(method: SecondFactorMethod) {\n return PostWithOptionalResponse(UserInfo2FAMethodPath,\n { method: toString(method) } as MethodPreferencePayload);\n}","import React, { useState, useEffect } from \"react\";\nimport { Grid, makeStyles, Button } from \"@material-ui/core\";\nimport MethodSelectionDialog from \"./MethodSelectionDialog\";\nimport { SecondFactorMethod } from \"../../../models/Methods\";\nimport { useHistory, Switch, Route, Redirect } from \"react-router\";\nimport LoginLayout from \"../../../layouts/LoginLayout\";\nimport { useNotifications } from \"../../../hooks/NotificationsContext\";\nimport {\n initiateTOTPRegistrationProcess,\n initiateU2FRegistrationProcess\n} from \"../../../services/RegisterDevice\";\nimport SecurityKeyMethod from \"./SecurityKeyMethod\";\nimport OneTimePasswordMethod from \"./OneTimePasswordMethod\";\nimport PushNotificationMethod from \"./PushNotificationMethod\";\nimport {\n LogoutRoute as SignOutRoute, SecondFactorTOTPRoute,\n SecondFactorPushRoute, SecondFactorU2FRoute, SecondFactorRoute\n} from \"../../../Routes\";\nimport { setPreferred2FAMethod } from \"../../../services/UserPreferences\";\nimport { UserInfo } from \"../../../models/UserInfo\";\nimport { Configuration } from \"../../../models/Configuration\";\nimport u2fApi from \"u2f-api\";\nimport { AuthenticationLevel } from \"../../../services/State\";\n\nconst EMAIL_SENT_NOTIFICATION = \"An email has been sent to your address to complete the process.\";\n\nexport interface Props {\n authenticationLevel: AuthenticationLevel;\n\n userInfo: UserInfo;\n configuration: Configuration;\n\n onMethodChanged: (method: SecondFactorMethod) => void;\n onAuthenticationSuccess: (redirectURL: string | undefined) => void;\n}\n\nconst SecondFactorForm = function (props: Props) {\n const style = useStyles();\n const history = useHistory();\n const [methodSelectionOpen, setMethodSelectionOpen] = useState(false);\n const { createInfoNotification, createErrorNotification } = useNotifications();\n const [registrationInProgress, setRegistrationInProgress] = useState(false);\n const [u2fSupported, setU2fSupported] = useState(false);\n\n // Check that U2F is supported.\n useEffect(() => {\n u2fApi.ensureSupport().then(\n () => setU2fSupported(true),\n () => console.error(\"U2F not supported\"));\n }, [setU2fSupported]);\n\n const initiateRegistration = (initiateRegistrationFunc: () => Promise) => {\n return async () => {\n if (registrationInProgress) {\n return;\n }\n setRegistrationInProgress(true);\n try {\n await initiateRegistrationFunc();\n createInfoNotification(EMAIL_SENT_NOTIFICATION);\n } catch (err) {\n console.error(err);\n createErrorNotification(\"There was a problem initiating the registration process\");\n }\n setRegistrationInProgress(false);\n }\n }\n\n const handleMethodSelectionClick = () => {\n setMethodSelectionOpen(true);\n }\n\n const handleMethodSelected = async (method: SecondFactorMethod) => {\n try {\n await setPreferred2FAMethod(method);\n setMethodSelectionOpen(false);\n props.onMethodChanged(method);\n } catch (err) {\n console.error(err);\n createErrorNotification(\"There was an issue updating preferred second factor method\");\n }\n }\n\n const handleLogoutClick = () => {\n history.push(SignOutRoute);\n }\n\n return (\n \n setMethodSelectionOpen(false)}\n onClick={handleMethodSelected} />\n \n \n \n {\" | \"}\n \n \n \n \n \n createErrorNotification(err.message)}\n onSignInSuccess={props.onAuthenticationSuccess} />\n \n \n createErrorNotification(err.message)}\n onSignInSuccess={props.onAuthenticationSuccess} />\n \n \n createErrorNotification(err.message)}\n onSignInSuccess={props.onAuthenticationSuccess} />\n \n \n \n \n \n \n \n \n )\n}\n\nexport default SecondFactorForm\n\nconst useStyles = makeStyles(theme => ({\n methodContainer: {\n border: \"1px solid #d6d6d6\",\n borderRadius: \"10px\",\n padding: theme.spacing(4),\n marginTop: theme.spacing(2),\n marginBottom: theme.spacing(2),\n },\n}))\n","import { useState, useCallback, DependencyList } from \"react\";\n\ntype PromisifiedFunction = (...args: any) => Promise\n\nexport function useRemoteCall(fn: PromisifiedFunction, deps: DependencyList)\n : [Ret | undefined, PromisifiedFunction, boolean, Error | undefined] {\n const [data, setData] = useState(undefined as Ret | undefined);\n const [inProgress, setInProgress] = useState(false);\n const [error, setError] = useState(undefined as Error | undefined);\n\n const fnCallback = useCallback(fn, [fn, deps]);\n\n const triggerCallback = useCallback(async () => {\n try {\n setInProgress(true);\n const res = await fnCallback();\n setInProgress(false);\n setData(res);\n } catch (err) {\n console.error(err);\n setError(err);\n }\n }, [setInProgress, setError, fnCallback]);\n\n return [\n data,\n triggerCallback,\n inProgress,\n error,\n ]\n}","import React from \"react\";\nimport ReactLoading from \"react-loading\";\nimport { Typography, Grid } from \"@material-ui/core\";\n\nconst LoadingPage = function () {\n return (\n \n \n \n Loading...\n \n \n );\n}\n\nexport default LoadingPage","import { Get } from \"./Client\";\nimport { ConfigurationPath } from \"./Api\";\nimport { toEnum, Method2FA } from \"./UserPreferences\";\nimport { Configuration } from \"../models/Configuration\";\n\ninterface ConfigurationPayload {\n available_methods: Method2FA[];\n second_factor_enabled: boolean;\n totp_period: number;\n}\n\nexport async function getConfiguration(): Promise {\n const config = await Get(ConfigurationPath);\n return { ...config, available_methods: new Set(config.available_methods.map(toEnum)) };\n}","import React from \"react\";\nimport { Grid, makeStyles, Button } from \"@material-ui/core\";\nimport { useHistory } from \"react-router\";\nimport LoginLayout from \"../../../layouts/LoginLayout\";\nimport { LogoutRoute as SignOutRoute } from \"../../../Routes\";\nimport Authenticated from \"../Authenticated\";\n\nexport interface Props {\n name: string;\n}\n\nconst AuthenticatedView = function (props: Props) {\n const style = useStyles();\n const history = useHistory();\n\n const handleLogoutClick = () => {\n history.push(SignOutRoute);\n }\n\n return (\n \n \n \n \n \n \n \n \n \n \n )\n}\n\nexport default AuthenticatedView\n\nconst useStyles = makeStyles(theme => ({\n mainContainer: {\n border: \"1px solid #d6d6d6\",\n borderRadius: \"10px\",\n padding: theme.spacing(4),\n marginTop: theme.spacing(2),\n marginBottom: theme.spacing(2),\n }\n}))\n","import React, { useEffect, Fragment, ReactNode, useState, useCallback } from \"react\";\nimport { Switch, Route, Redirect, useHistory, useLocation } from \"react-router\";\nimport FirstFactorForm from \"./FirstFactor/FirstFactorForm\";\nimport SecondFactorForm from \"./SecondFactor/SecondFactorForm\";\nimport {\n FirstFactorRoute, SecondFactorRoute, SecondFactorTOTPRoute,\n SecondFactorPushRoute, SecondFactorU2FRoute, AuthenticatedRoute\n} from \"../../Routes\";\nimport { useAutheliaState } from \"../../hooks/State\";\nimport LoadingPage from \"../LoadingPage/LoadingPage\";\nimport { AuthenticationLevel } from \"../../services/State\";\nimport { useNotifications } from \"../../hooks/NotificationsContext\";\nimport { useRedirectionURL } from \"../../hooks/RedirectionURL\";\nimport { useUserPreferences as userUserInfo } from \"../../hooks/UserInfo\";\nimport { SecondFactorMethod } from \"../../models/Methods\";\nimport { useConfiguration } from \"../../hooks/Configuration\";\nimport AuthenticatedView from \"./AuthenticatedView/AuthenticatedView\";\n\nexport interface Props {\n rememberMe: boolean;\n resetPassword: boolean;\n}\n\nconst LoginPortal = function (props: Props) {\n const history = useHistory();\n const location = useLocation();\n const redirectionURL = useRedirectionURL();\n const { createErrorNotification } = useNotifications();\n const [firstFactorDisabled, setFirstFactorDisabled] = useState(true);\n\n const [state, fetchState, , fetchStateError] = useAutheliaState();\n const [userInfo, fetchUserInfo, , fetchUserInfoError] = userUserInfo();\n const [configuration, fetchConfiguration, , fetchConfigurationError] = useConfiguration();\n\n const redirect = useCallback((url: string) => history.push(url), [history]);\n\n // Fetch the state when portal is mounted.\n useEffect(() => { fetchState() }, [fetchState]);\n\n // Fetch preferences and configuration when user is authenticated.\n useEffect(() => {\n if (state && state.authentication_level >= AuthenticationLevel.OneFactor) {\n fetchUserInfo();\n fetchConfiguration();\n }\n }, [state, fetchUserInfo, fetchConfiguration]);\n\n // Enable first factor when user is unauthenticated.\n useEffect(() => {\n if (state && state.authentication_level > AuthenticationLevel.Unauthenticated) {\n setFirstFactorDisabled(true);\n }\n }, [state, setFirstFactorDisabled]);\n\n // Display an error when state fetching fails\n useEffect(() => {\n if (fetchStateError) {\n createErrorNotification(\"There was an issue fetching the current user state\");\n }\n }, [fetchStateError, createErrorNotification]);\n\n // Display an error when configuration fetching fails\n useEffect(() => {\n if (fetchConfigurationError) {\n createErrorNotification(\"There was an issue retrieving global configuration\");\n }\n }, [fetchConfigurationError, createErrorNotification]);\n\n // Display an error when preferences fetching fails\n useEffect(() => {\n if (fetchUserInfoError) {\n createErrorNotification(\"There was an issue retrieving user preferences\");\n }\n }, [fetchUserInfoError, createErrorNotification]);\n\n // Redirect to the correct stage if not enough authenticated\n useEffect(() => {\n if (state) {\n const redirectionSuffix = redirectionURL\n ? `?rd=${encodeURIComponent(redirectionURL)}`\n : '';\n\n if (state.authentication_level === AuthenticationLevel.Unauthenticated) {\n setFirstFactorDisabled(false);\n redirect(`${FirstFactorRoute}${redirectionSuffix}`);\n } else if (state.authentication_level >= AuthenticationLevel.OneFactor && userInfo && configuration) {\n if (!configuration.second_factor_enabled) {\n redirect(AuthenticatedRoute);\n } else {\n if (userInfo.method === SecondFactorMethod.U2F) {\n redirect(`${SecondFactorU2FRoute}${redirectionSuffix}`);\n } else if (userInfo.method === SecondFactorMethod.MobilePush) {\n redirect(`${SecondFactorPushRoute}${redirectionSuffix}`);\n } else {\n redirect(`${SecondFactorTOTPRoute}${redirectionSuffix}`);\n }\n }\n }\n }\n }, [state, redirectionURL, redirect, userInfo, setFirstFactorDisabled, configuration]);\n\n const handleAuthSuccess = async (redirectionURL: string | undefined) => {\n if (redirectionURL) {\n // Do an external redirection pushed by the server.\n window.location.href = redirectionURL;\n } else {\n // Refresh state\n fetchState();\n }\n }\n\n const firstFactorReady = state !== undefined &&\n state.authentication_level === AuthenticationLevel.Unauthenticated &&\n location.pathname === FirstFactorRoute;\n\n return (\n \n \n \n setFirstFactorDisabled(true)}\n onAuthenticationFailure={() => setFirstFactorDisabled(false)}\n onAuthenticationSuccess={handleAuthSuccess} />\n \n \n \n {state && userInfo && configuration ? fetchUserInfo()}\n onAuthenticationSuccess={handleAuthSuccess} /> : null}\n \n \n {userInfo ? : null}\n \n \n \n \n \n )\n}\n\nexport default LoginPortal\n\ninterface ComponentOrLoadingProps {\n ready: boolean;\n\n children: ReactNode;\n}\n\nfunction ComponentOrLoading(props: ComponentOrLoadingProps) {\n return (\n \n
\n \n
\n {props.ready ? props.children : null}\n \n )\n}","import { getState } from \"../services/State\";\nimport { useRemoteCall } from \"./RemoteCall\";\n\nexport function useAutheliaState() {\n return useRemoteCall(getState, []);\n}","import { getUserPreferences } from \"../services/UserPreferences\";\nimport { useRemoteCall } from \"./RemoteCall\";\n\nexport function useUserPreferences() {\n return useRemoteCall(getUserPreferences, []);\n}","import { useRemoteCall } from \"./RemoteCall\";\nimport { getConfiguration } from \"../services/Configuration\";\n\nexport function useConfiguration() {\n return useRemoteCall(getConfiguration, []);\n}","import React from \"react\";\n\nimport CheckCircleIcon from '@material-ui/icons/CheckCircle';\nimport ErrorIcon from '@material-ui/icons/Error';\nimport InfoIcon from '@material-ui/icons/Info';\nimport WarningIcon from '@material-ui/icons/Warning';\nimport { makeStyles, SnackbarContent } from \"@material-ui/core\";\nimport { amber, green } from '@material-ui/core/colors';\nimport classnames from \"classnames\";\nimport { SnackbarContentProps } from \"@material-ui/core/SnackbarContent\";\n\nconst variantIcon = {\n success: CheckCircleIcon,\n warning: WarningIcon,\n error: ErrorIcon,\n info: InfoIcon,\n};\n\nexport type Level = keyof typeof variantIcon;\n\nexport interface Props extends SnackbarContentProps {\n className?: string;\n level: Level;\n message: string;\n}\n\nconst ColoredSnackbarContent = function (props: Props) {\n const classes = useStyles();\n const Icon = variantIcon[props.level];\n\n const { className, variant, message, ...others } = props;\n\n return (\n \n \n {message}\n \n }\n {...others} />\n )\n}\n\nexport default ColoredSnackbarContent\n\nconst useStyles = makeStyles(theme => ({\n success: {\n backgroundColor: green[600],\n },\n error: {\n backgroundColor: theme.palette.error.dark,\n },\n info: {\n backgroundColor: theme.palette.primary.main,\n },\n warning: {\n backgroundColor: amber[700],\n },\n icon: {\n fontSize: 20,\n },\n iconVariant: {\n opacity: 0.9,\n marginRight: theme.spacing(1),\n },\n message: {\n display: 'flex',\n alignItems: 'center',\n },\n}))","import React, { useState, useEffect } from \"react\";\nimport { Snackbar } from \"@material-ui/core\";\nimport ColoredSnackbarContent from \"./ColoredSnackbarContent\";\nimport { useNotifications } from \"../hooks/NotificationsContext\";\nimport { Notification } from \"../models/Notifications\";\n\nexport interface Props {\n onClose: () => void;\n}\n\nconst NotificationBar = function (props: Props) {\n const [tmpNotification, setTmpNotification] = useState(null as Notification | null);\n const { notification } = useNotifications();\n\n useEffect(() => {\n if (notification && notification !== null) {\n setTmpNotification(notification);\n }\n }, [notification]);\n\n const shouldSnackbarBeOpen = notification !== undefined && notification !== null;\n\n return (\n setTmpNotification(null)}>\n \n \n )\n}\n\nexport default NotificationBar","import { PostWithOptionalResponse } from \"./Client\";\nimport { LogoutPath } from \"./Api\";\n\nexport async function signOut() {\n return PostWithOptionalResponse(LogoutPath);\n}","import React, { useEffect, useCallback, useState } from \"react\";\nimport LoginLayout from \"../../../layouts/LoginLayout\";\nimport { useNotifications } from \"../../../hooks/NotificationsContext\";\nimport { signOut } from \"../../../services/SignOut\";\nimport { Typography, makeStyles } from \"@material-ui/core\";\nimport { Redirect } from \"react-router\";\nimport { FirstFactorRoute } from \"../../../Routes\";\nimport { useRedirectionURL } from \"../../../hooks/RedirectionURL\";\nimport { useIsMountedRef } from \"../../../hooks/Mounted\";\n\nexport interface Props { }\n\nconst SignOut = function (props: Props) {\n const mounted = useIsMountedRef();\n const style = useStyles();\n const { createErrorNotification } = useNotifications();\n const redirectionURL = useRedirectionURL();\n const [timedOut, setTimedOut] = useState(false);\n\n const doSignOut = useCallback(async () => {\n try {\n // TODO(c.michaud): pass redirection URL to backend for validation.\n await signOut();\n setTimeout(() => {\n if (!mounted) {\n return;\n }\n setTimedOut(true);\n }, 2000);\n } catch (err) {\n console.error(err);\n createErrorNotification(\"There was an issue signing out\");\n }\n }, [createErrorNotification, setTimedOut, mounted]);\n\n useEffect(() => { doSignOut() }, [doSignOut]);\n\n if (timedOut) {\n if (redirectionURL) {\n window.location.href = redirectionURL;\n } else {\n return \n }\n }\n\n return (\n \n \n You're being signed out and redirected...\n \n \n )\n}\n\nexport default SignOut\n\nconst useStyles = makeStyles(theme => ({\n typo: {\n padding: theme.spacing(),\n }\n}))","import React, { useState } from 'react';\nimport {\n BrowserRouter as Router, Route, Switch, Redirect\n} from \"react-router-dom\";\nimport ResetPasswordStep1 from './views/ResetPassword/ResetPasswordStep1';\nimport ResetPasswordStep2 from './views/ResetPassword/ResetPasswordStep2';\nimport RegisterSecurityKey from './views/DeviceRegistration/RegisterSecurityKey';\nimport RegisterOneTimePassword from './views/DeviceRegistration/RegisterOneTimePassword';\nimport {\n FirstFactorRoute, ResetPasswordStep2Route,\n ResetPasswordStep1Route, RegisterSecurityKeyRoute,\n RegisterOneTimePasswordRoute,\n LogoutRoute,\n} from \"./Routes\";\nimport LoginPortal from './views/LoginPortal/LoginPortal';\nimport NotificationsContext from './hooks/NotificationsContext';\nimport { Notification } from './models/Notifications';\nimport NotificationBar from './components/NotificationBar';\nimport SignOut from './views/LoginPortal/SignOut/SignOut';\nimport { getRememberMe, getResetPassword } from './utils/Configuration';\nimport '@fortawesome/fontawesome-svg-core/styles.css'\nimport { config as faConfig } from '@fortawesome/fontawesome-svg-core';\nimport { getBasePath } from './utils/BasePath';\n\nfaConfig.autoAddCss = false;\n\nconst App: React.FC = () => {\n const [notification, setNotification] = useState(null as Notification | null);\n\n return (\n \n \n setNotification(null)} />\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n );\n}\n\nexport default App;\n","// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read https://bit.ly/CRA-PWA\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.1/8 is considered localhost for IPv4.\n window.location.hostname.match(\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n )\n);\n\ntype Config = {\n onSuccess?: (registration: ServiceWorkerRegistration) => void;\n onUpdate?: (registration: ServiceWorkerRegistration) => void;\n};\n\nexport function register(config?: Config) {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(\n (process as { env: { [key: string]: string } }).env.PUBLIC_URL,\n window.location.href\n );\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n console.log(\n 'This web app is being served cache-first by a service ' +\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\n );\n });\n } else {\n // Is not localhost. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl: string, config?: Config) {\n navigator.serviceWorker\n .register(swUrl)\n .then(registration => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing;\n if (installingWorker == null) {\n return;\n }\n installingWorker.onstatechange = () => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the updated precached content has been fetched,\n // but the previous service worker will still serve the older\n // content until all client tabs are closed.\n console.log(\n 'New content is available and will be used when all ' +\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\n );\n\n // Execute callback\n if (config && config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log('Content is cached for offline use.');\n\n // Execute callback\n if (config && config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch(error => {\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl: string, config?: Config) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl)\n .then(response => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get('content-type');\n if (\n response.status === 404 ||\n (contentType != null && contentType.indexOf('javascript') === -1)\n ) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n console.log(\n 'No internet connection found. App is running in offline mode.'\n );\n });\n}\n\nexport function unregister() {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister();\n });\n }\n}\n","import './utils/AssetPath';\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './App';\nimport * as serviceWorker from './serviceWorker';\n\nReactDOM.render(, document.getElementById('root'));\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: https://bit.ly/CRA-PWA\nserviceWorker.unregister();\n","// extracted by mini-css-extract-plugin\nmodule.exports = {\"hand\":\"FingerTouchIcon_hand__fZM01\",\"strong\":\"FingerTouchIcon_strong__XLkjn\",\"shaking\":\"FingerTouchIcon_shaking__2J7jA\"};","// extracted by mini-css-extract-plugin\nmodule.exports = {\"wiggle\":\"PushNotificationIcon_wiggle__kPe3e\"};"],"sourceRoot":""}