preparing mobile support for totp

This commit is contained in:
balzack 2024-05-16 22:20:53 -07:00
parent 5336d19608
commit 0d9fd2724e
4 changed files with 67 additions and 6 deletions

View File

@ -5,6 +5,7 @@ import { useLogin } from './useLogin.hook';
import { Colors } from 'constants/Colors'; import { Colors } from 'constants/Colors';
import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import { tos } from 'constants/TermsOfService'; import { tos } from 'constants/TermsOfService';
import { BlurView } from "@react-native-community/blur";
export function Login() { export function Login() {
@ -124,6 +125,24 @@ export function Login() {
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</Modal> </Modal>
<Modal
animationType="fade"
transparent={true}
visible={state.mfaModal}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.dismissMFA}
>
<View style={styles.mfaOverlay}>
<BlurView style={styles.mfaOverlay} blurType={Colors.overlay} blurAmount={2} reducedTransparencyFallbackColor="black" />
<KeyboardAvoidingView style={styles.mfaBase} behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
<View style={styles.mfaContainer}>
<Text style={styles.mfaTitle}>Multi-Factor Authentication</Text>
<Text style={styles.mfaDescription}>Enter your verification code</Text>
</View>
</KeyboardAvoidingView>
</View>
</Modal>
</KeyboardAvoidingView> </KeyboardAvoidingView>
); );
} }

View File

@ -22,6 +22,38 @@ export const styles = StyleSheet.create({
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
}, },
mfaOverlay: {
width: '100%',
height: '100%',
},
mfaBase: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
},
mfaContainer: {
backgroundColor: Colors.modalBase,
borderColor: Colors.modalBorder,
borderWidth: 1,
width: '80%',
maxWidth: 400,
display: 'flex',
gap: 16,
alignItems: 'center',
borderRadius: 8,
padding: 16,
},
mfaTitle: {
fontSize: 20,
},
mfaDescription: {
fontSize: 16,
},
tos: { tos: {
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',

View File

@ -18,6 +18,9 @@ export function useLogin() {
showPassword: false, showPassword: false,
agree: false, agree: false,
showTerms: false, showTerms: false,
mfaModal: false,
mfaCode: null,
mfaError: null,
}); });
const updateState = (value) => { const updateState = (value) => {
@ -77,15 +80,22 @@ export function useLogin() {
await app.actions.login(state.login.trim(), state.password); await app.actions.login(state.login.trim(), state.password);
} }
catch (err) { catch (err) {
console.log(err); if (err.message == '405' || err.message == '403' || err.message == '429') {
updateState({ busy: false, showAlert: true }); updateState({ mfaModal: true, mfaError: err.message, mfaCode: '' });
throw new Error('login failed'); }
else {
console.log(err.message);
updateState({ busy: false, showAlert: true });
throw new Error('login failed');
}
} }
updateState({ busy: false }); updateState({ busy: false });
} }
} },
dismissMFA: () => {
updateState({ mfaModal: false });
},
}; };
return { state, actions }; return { state, actions };
} }

View File

@ -8,7 +8,7 @@ export function createWebsocket(url) {
export function checkResponse(response) { export function checkResponse(response) {
if(response.status >= 400 && response.status < 600) { if(response.status >= 400 && response.status < 600) {
throw new Error(response.url + " failed"); throw new Error(response.status);
} }
} }