verdnatura-chat/app/containers/Passcode/Base/index.js

140 lines
3.8 KiB
JavaScript
Raw Normal View History

[NEW] Passcode and biometric unlock (#2059) * Update expo libs * Configure expo-local-authentication * ScreenLockedView * Authenticate server change * Auth on app resume * localAuthentication util * Add servers.lastLocalAuthenticatedSession column * Save last session date on background * Use our own version of app state redux * Fix libs * Remove inactive * ScreenLockConfigView * Apply on saved data * Auto lock option label * Starting passcode * Basic passcode flow working * Change passcode * Check if biometry is enrolled * Use fork * Migration * Patch expo-local-authentication * Use async storage * Styling * Timer * Refactor * Lock orientation portrait when not on tablet * share extension * Deep linking * Share extension * Refactoring passcode * use state * Stash * Refactor * Change passcode * Animate dots on error * Matching passcodes * Shake * Remove lib * Delete button * Fade animation on modal * Refactoring * ItemInfo * I18n * I18n * Remove unnecessary prop * Save biometry column * Raise time to lock to 30 seconds * Vibrate on wrong confirmation passcode * Reset attempts and save last authentication on local passcode confirmation * Remove inline style * Save last auth * Fix header blink * Change function name * Fix android modal * Fix vibration permission * PasscodeEnter calls biometry * Passcode on the state * Biometry button on PasscodeEnter * Show whole passcode * Secure passcode * Save passcode with promise to prevent empty passcodes and immediately lock * Patch expo-local-authentication * I18n * Fix biometry being called every time * Blur screen on app inactive * Revert "Blur screen on app inactive" This reverts commit a4ce812934adcf6cf87eb1a92aec9283e2f26753. * Remove immediately because of how Activities work on Android * Pods * New layout * stash * Layout refactored * Fix icons * Force set passcode from server * Lint * Improve permission message * Forced passcode subtitle * Disable based on admin's choice * Require local authentication on login success * Refactor * Update tests * Update react-native-device-info to fix notch * Lint * Fix modal * Fix icons * Fix min auto lock time * Review * keep enabled on mobile * fix forced by admin when enable unlock with passcode * use DEFAULT_AUTO_LOCK when manual enable screenLock * fix check has passcode * request biometry on first password * reset auto time lock when disabled on server Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com>
2020-05-08 17:04:37 +00:00
import React, {
useState, forwardRef, useImperativeHandle, useRef
} from 'react';
import { Col, Row, Grid } from 'react-native-easy-grid';
import _ from 'lodash';
import PropTypes from 'prop-types';
import * as Animatable from 'react-native-animatable';
import * as Haptics from 'expo-haptics';
import styles from './styles';
import Button from './Button';
import Dots from './Dots';
import { TYPE } from '../constants';
import { themes } from '../../../constants/colors';
import { PASSCODE_LENGTH } from '../../../constants/localAuthentication';
import LockIcon from './LockIcon';
import Title from './Title';
import Subtitle from './Subtitle';
const Base = forwardRef(({
theme, type, onEndProcess, previousPasscode, title, subtitle, onError, showBiometry, onBiometryPress
}, ref) => {
const rootRef = useRef();
const dotsRef = useRef();
const [passcode, setPasscode] = useState('');
const clearPasscode = () => setPasscode('');
const wrongPasscode = () => {
clearPasscode();
dotsRef?.current?.shake(500);
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
};
const animate = (animation, duration = 500) => {
rootRef?.current?.[animation](duration);
};
const onPressNumber = text => setPasscode((p) => {
const currentPasscode = p + text;
if (currentPasscode?.length === PASSCODE_LENGTH) {
switch (type) {
case TYPE.CHOOSE:
onEndProcess(currentPasscode);
break;
case TYPE.CONFIRM:
if (currentPasscode !== previousPasscode) {
onError();
} else {
onEndProcess(currentPasscode);
}
break;
case TYPE.ENTER:
onEndProcess(currentPasscode);
break;
default:
break;
}
}
return currentPasscode;
});
const onPressDelete = () => setPasscode((p) => {
if (p?.length > 0) {
const newPasscode = p.slice(0, -1);
return newPasscode;
}
return '';
});
useImperativeHandle(ref, () => ({
wrongPasscode, animate, clearPasscode
}));
return (
<Animatable.View ref={rootRef} style={styles.container}>
<Grid style={[styles.grid, { backgroundColor: themes[theme].passcodeBackground }]}>
<LockIcon theme={theme} />
<Title text={title} theme={theme} />
<Subtitle text={subtitle} theme={theme} />
<Row style={styles.row}>
<Animatable.View ref={dotsRef}>
<Dots passcode={passcode} theme={theme} length={PASSCODE_LENGTH} />
</Animatable.View>
</Row>
<Row style={[styles.row, styles.buttonRow]}>
{_.range(1, 4).map(i => (
<Col key={i} style={styles.colButton}>
<Button text={i} theme={theme} onPress={onPressNumber} />
</Col>
))}
</Row>
<Row style={[styles.row, styles.buttonRow]}>
{_.range(4, 7).map(i => (
<Col key={i} style={styles.colButton}>
<Button text={i} theme={theme} onPress={onPressNumber} />
</Col>
))}
</Row>
<Row style={[styles.row, styles.buttonRow]}>
{_.range(7, 10).map(i => (
<Col key={i} style={styles.colButton}>
<Button text={i} theme={theme} onPress={onPressNumber} />
</Col>
))}
</Row>
<Row style={[styles.row, styles.buttonRow]}>
{showBiometry
? (
<Col style={styles.colButton}>
<Button icon='fingerprint' theme={theme} onPress={onBiometryPress} />
</Col>
)
: <Col style={styles.colButton} />}
<Col style={styles.colButton}>
<Button text='0' theme={theme} onPress={onPressNumber} />
</Col>
<Col style={styles.colButton}>
<Button icon='backspace' theme={theme} onPress={onPressDelete} />
</Col>
</Row>
</Grid>
</Animatable.View>
);
});
Base.propTypes = {
theme: PropTypes.string,
type: PropTypes.string,
previousPasscode: PropTypes.string,
title: PropTypes.string,
subtitle: PropTypes.string,
showBiometry: PropTypes.string,
onEndProcess: PropTypes.func,
onError: PropTypes.func,
onBiometryPress: PropTypes.func
};
export default Base;