1- import { useState } from 'react' ;
1+ import { useState } from 'react' ;
22import {
3- TextInput ,
4- PasswordInput ,
5- Paper ,
6- Title ,
7- Container ,
8- Button ,
9- Group ,
10- Divider ,
11- Text ,
12- Alert ,
13- } from '@mantine/core' ;
3+ TextInput ,
4+ PasswordInput ,
5+ Paper ,
6+ Title ,
7+ Container ,
8+ Button ,
9+ Group ,
10+ Divider ,
11+ Text ,
12+ Alert ,
13+ } from '@mantine/core' ;
1414import classes from './AuthBanner.module.css' ;
1515import { useMutation , useQuery } from '@tanstack/react-query' ;
1616import axios from 'axios' ;
@@ -51,119 +51,99 @@ type LoginPassword = {
5151
5252
5353export function AuthBanner ( ) {
54- const [ login , setLogin ] = useState < string > ( "" ) ;
55- const [ password , setPassword ] = useState < string > ( "" ) ;
56- const [ authError , setAuthError ] = useState < string > ( "" ) ;
57- const { authInfo, setAuthInfo} = useAuthContext ( ) ;
58- const [ oidcRedirectError , setOidcRedirectError ] = useState < string > ( "" )
59- const [ showMFAFactors , setShowMFAFactors ] = useState < Array < string > > ( [ ] )
60- const [ factorResponse , setFactorResponse ] = useState < FactorResponse > ( { name : "" , code : "" } )
61- const { error, isPending, data } = useQuery < any , any , AuthMethods > ( {
62- queryKey : [ 'authmethods' ] ,
63- queryFn : ( ) =>
64- fetch ( AppSettings . url + '/authmethods' )
54+ const [ login , setLogin ] = useState < string > ( "" ) ;
55+ const [ password , setPassword ] = useState < string > ( "" ) ;
56+ const [ authError , setAuthError ] = useState < string > ( "" ) ;
57+ const { authInfo, setAuthInfo } = useAuthContext ( ) ;
58+ const [ showMFAFactors , setShowMFAFactors ] = useState < Array < string > > ( [ ] )
59+ const [ factorResponse , setFactorResponse ] = useState < FactorResponse > ( { name : "" , code : "" } )
60+ const { error, isPending, data } = useQuery < any , any , AuthMethods > ( {
61+ queryKey : [ 'authmethods' ] ,
62+ queryFn : ( ) =>
63+ fetch ( AppSettings . url + '/authmethods' )
6564 . then ( ( res ) =>
6665 res . json ( ) ,
6766 )
68- } )
69-
70- const authenticate = useMutation ( {
71- mutationFn : ( loginPassword :LoginPassword ) => {
72- setAuthError ( "" )
73- return axios . post ( AppSettings . url + '/auth' , loginPassword )
74- } ,
75- onSuccess : ( response ) => {
76- const data = response . data as LoginResponse
77- if ( data . mfaRequired ) {
78- setShowMFAFactors ( data . factors )
79- } else {
80- setAuthInfo ( { ...authInfo , token : data . token } )
81- }
82- } ,
83- onError : ( error ) => {
84- if ( error . message . includes ( "status code 401" ) ) {
85- setAuthError ( "Invalid credentials" )
86- } else if ( error . message . includes ( "status code 429" ) ) {
87- setAuthError ( "too many attempts. Try again later" )
88- } else {
89- setAuthError ( "Error: " + error . message )
90- }
91- }
92- } )
93- const oidcRedirect = useMutation ( {
94- mutationFn : ( id :string ) => {
95- return axios . get ( AppSettings . url + '/authmethods/oidc/' + id )
96- } ,
97- onSuccess : ( response ) => {
98- const data = response . data as OIDCProvider
99- const redirectURI = data . redirectURI || ""
100- if ( redirectURI === "" ) {
101- setOidcRedirectError ( "Could not redirect at this time: redirectURI is empty" )
102- } else {
103- window . location . href = redirectURI
104- }
105-
106- } ,
107- onError : ( error ) => {
108- setOidcRedirectError ( "Could not redirect at this time: " + error . message )
109- }
110- } )
111- const onClickOidcRedirect = ( id :string ) => {
112- oidcRedirect . mutate ( id )
113- }
67+ } )
11468
115- const captureEnter = ( e : React . KeyboardEvent < HTMLDivElement > ) => {
116- if ( e . key === "Enter" ) {
117- authenticate . mutate ( { login, password, factorResponse} )
69+ const authenticate = useMutation ( {
70+ mutationFn : ( loginPassword : LoginPassword ) => {
71+ setAuthError ( "" )
72+ return axios . post ( AppSettings . url + '/auth' , loginPassword )
73+ } ,
74+ onSuccess : ( response ) => {
75+ const data = response . data as LoginResponse
76+ if ( data . mfaRequired ) {
77+ setShowMFAFactors ( data . factors )
78+ } else {
79+ setAuthInfo ( { ...authInfo , token : data . token } )
11880 }
81+ } ,
82+ onError : ( error ) => {
83+ if ( error . message . includes ( "status code 401" ) ) {
84+ setAuthError ( "Invalid credentials" )
85+ } else if ( error . message . includes ( "status code 429" ) ) {
86+ setAuthError ( "too many attempts. Try again later" )
87+ } else {
88+ setAuthError ( "Error: " + error . message )
89+ }
90+ }
91+ } )
92+ const onClickOidcRedirect = ( id : string ) => {
93+ window . location . href = AppSettings . url + '/authmethods/oidc/' + id + "/redirect"
94+ }
95+
96+ const captureEnter = ( e : React . KeyboardEvent < HTMLDivElement > ) => {
97+ if ( e . key === "Enter" ) {
98+ authenticate . mutate ( { login, password, factorResponse } )
11999 }
120- const alertIcon = < TbInfoCircle />
121-
122- if ( error ) return 'An backend error has occurred: ' + error . message
100+ }
101+ const alertIcon = < TbInfoCircle />
123102
124- const authMethodsButtons = data ?. oidcProviders . map ( ( oidcProvider :OIDCProvider ) => (
125- < Container key = { oidcProvider . id } > < Button radius = "xl" fullWidth = { true } key = { oidcProvider . id } onClick = { ( ) => onClickOidcRedirect
126- ( oidcProvider . id ) } > Login with { oidcProvider . name } </ Button > </ Container >
127- ) )
103+ if ( error ) return 'An backend error has occurred: ' + error . message
128104
129- return (
130- < Container size = { 420 } my = { 40 } >
131- < Title ta = "center" className = { classes . title } >
132- VPN Server
133- </ Title >
134- < AuthError />
135- < Paper withBorder shadow = "md" p = { 30 } mt = { 30 } radius = "md" >
136- < Group grow mb = "md" mt = "md" >
137- { oidcRedirectError === "" ? "" : < p > oidcRedirectError</ p > }
138- { authMethodsButtons }
139- </ Group >
140- { isPending || data ?. localAuthDisabled ? null :
105+ const authMethodsButtons = data ?. oidcProviders . map ( ( oidcProvider : OIDCProvider ) => (
106+ < Container key = { oidcProvider . id } > < Button radius = "xl" fullWidth = { true } key = { oidcProvider . id } onClick = { ( ) => onClickOidcRedirect
107+ ( oidcProvider . id ) } > Login with { oidcProvider . name } </ Button > </ Container >
108+ ) )
109+
110+ return (
111+ < Container size = { 420 } my = { 40 } >
112+ < Title ta = "center" className = { classes . title } >
113+ VPN Server
114+ </ Title >
115+ < AuthError />
116+ < Paper withBorder shadow = "md" p = { 30 } mt = { 30 } radius = "md" >
117+ < Group grow mb = "md" mt = "md" >
118+ { authMethodsButtons }
119+ </ Group >
120+ { isPending || data ?. localAuthDisabled ? null :
121+ < >
122+ { data ?. oidcProviders === undefined || data ?. oidcProviders . length < 1 ? null :
123+ < Divider label = "Or continue with login" labelPosition = "center" my = "lg" />
124+ }
125+ { authError !== "" ?
126+ < Alert variant = "light" color = "red" title = "Error" icon = { alertIcon } > { authError } </ Alert >
127+ :
128+ null
129+ }
130+ { showMFAFactors . length > 0 ?
131+ < MFAInput factors = { showMFAFactors } setFactorResponse = { setFactorResponse } captureEnter = { captureEnter } />
132+ :
141133 < >
142- { data ?. oidcProviders === undefined || data ?. oidcProviders . length < 1 ? null :
143- < Divider label = "Or continue with login" labelPosition = "center" my = "lg" />
144- }
145- { authError !== "" ?
146- < Alert variant = "light" color = "red" title = "Error" icon = { alertIcon } > { authError } </ Alert >
147- :
148- null
149- }
150- { showMFAFactors . length > 0 ?
151- < MFAInput factors = { showMFAFactors } setFactorResponse = { setFactorResponse } captureEnter = { captureEnter } />
152- :
153- < >
154- < TextInput label = "Login" placeholder = "Your username" required onChange = { ( event ) => setLogin ( event . currentTarget . value ) } value = { login } onKeyDown = { ( e ) => captureEnter ( e ) } />
155- < PasswordInput label = "Password" placeholder = "Your password" required mt = "md" onChange = { ( event ) => setPassword ( event . currentTarget . value ) } value = { password } onKeyDown = { ( e ) => captureEnter ( e ) } />
156- </ >
157- }
158- < Button fullWidth mt = "xl" onClick = { ( ) => authenticate . mutate ( { login, password, factorResponse} ) } >
159- Sign in
160- </ Button >
161- < Text size = "xs" style = { { marginTop : 20 } } > By clicking 'Sign in', you accept the < a href = "https://in4it.com/vpn-server-terms-conditions/" target = "_blank" > Terms & Conditions </ a > </ Text >
134+ < TextInput label = "Login" placeholder = "Your username" required onChange = { ( event ) => setLogin ( event . currentTarget . value ) } value = { login } onKeyDown = { ( e ) => captureEnter ( e ) } />
135+ < PasswordInput label = "Password" placeholder = "Your password" required mt = "md" onChange = { ( event ) => setPassword ( event . currentTarget . value ) } value = { password } onKeyDown = { ( e ) => captureEnter ( e ) } />
162136 </ >
163137 }
138+ < Button fullWidth mt = "xl" onClick = { ( ) => authenticate . mutate ( { login, password, factorResponse } ) } >
139+ Sign in
140+ </ Button >
141+ < Text size = "xs" style = { { marginTop : 20 } } > By clicking 'Sign in', you accept the < a href = "https://in4it.com/vpn-server-terms-conditions/" target = "_blank" > Terms & Conditions </ a > </ Text >
142+ </ >
143+ }
144+
145+ </ Paper >
146+ </ Container >
147+ ) ;
164148
165- </ Paper >
166- </ Container >
167- ) ;
168-
169149}
0 commit comments