mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-30 00:52:42 +03:00
Merge branch 'development' into nt/pin-encryption
# Conflicts: # src/redux/actions/applicationActions.ts # src/redux/constants/constants.js # src/redux/reducers/applicationReducer.ts # src/screens/pinCode/container/pinCodeContainer.tsx # src/screens/settings/container/settingsContainer.tsx
This commit is contained in:
commit
30884383c2
@ -10,6 +10,8 @@
|
|||||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||||
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
|
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
|
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
|
@ -64,6 +64,7 @@ allprojects {
|
|||||||
includeGroup("com.henninghall.android")
|
includeGroup("com.henninghall.android")
|
||||||
includeGroup("org.matomo.sdk")
|
includeGroup("org.matomo.sdk")
|
||||||
includeModule("com.yqritc", "android-scalablevideoview")
|
includeModule("com.yqritc", "android-scalablevideoview")
|
||||||
|
includeModule("com.wei.android.lib", "fingerprintidentify")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,8 @@
|
|||||||
<string>Photo Library Access for allowing user to download and upload photos</string>
|
<string>Photo Library Access for allowing user to download and upload photos</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>Photo Usage Access for allowing user to upload photos</string>
|
<string>Photo Usage Access for allowing user to upload photos</string>
|
||||||
|
<key>NSFaceIDUsageDescription</key>
|
||||||
|
<string>Ecency requires FaceID access to allow you quick and secure access.</string>
|
||||||
<key>UIAppFonts</key>
|
<key>UIAppFonts</key>
|
||||||
<array>
|
<array>
|
||||||
<string>Entypo.ttf</string>
|
<string>Entypo.ttf</string>
|
||||||
|
@ -346,6 +346,8 @@ PODS:
|
|||||||
- React-Core
|
- React-Core
|
||||||
- react-native-date-picker (4.2.0):
|
- react-native-date-picker (4.2.0):
|
||||||
- React-Core
|
- React-Core
|
||||||
|
- react-native-fingerprint-scanner (6.0.0):
|
||||||
|
- React
|
||||||
- react-native-matomo-sdk (0.4.1):
|
- react-native-matomo-sdk (0.4.1):
|
||||||
- MatomoTracker (~> 7)
|
- MatomoTracker (~> 7)
|
||||||
- React (~> 0.60)
|
- React (~> 0.60)
|
||||||
@ -530,6 +532,7 @@ DEPENDENCIES:
|
|||||||
- "react-native-cameraroll (from `../node_modules/@react-native-community/cameraroll`)"
|
- "react-native-cameraroll (from `../node_modules/@react-native-community/cameraroll`)"
|
||||||
- react-native-config (from `../node_modules/react-native-config`)
|
- react-native-config (from `../node_modules/react-native-config`)
|
||||||
- react-native-date-picker (from `../node_modules/react-native-date-picker`)
|
- react-native-date-picker (from `../node_modules/react-native-date-picker`)
|
||||||
|
- react-native-fingerprint-scanner (from `../node_modules/react-native-fingerprint-scanner`)
|
||||||
- react-native-matomo-sdk (from `../node_modules/react-native-matomo-sdk`)
|
- react-native-matomo-sdk (from `../node_modules/react-native-matomo-sdk`)
|
||||||
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
||||||
- react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`)
|
- react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`)
|
||||||
@ -652,6 +655,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: "../node_modules/react-native-config"
|
:path: "../node_modules/react-native-config"
|
||||||
react-native-date-picker:
|
react-native-date-picker:
|
||||||
:path: "../node_modules/react-native-date-picker"
|
:path: "../node_modules/react-native-date-picker"
|
||||||
|
react-native-fingerprint-scanner:
|
||||||
|
:path: "../node_modules/react-native-fingerprint-scanner"
|
||||||
react-native-matomo-sdk:
|
react-native-matomo-sdk:
|
||||||
:path: "../node_modules/react-native-matomo-sdk"
|
:path: "../node_modules/react-native-matomo-sdk"
|
||||||
react-native-netinfo:
|
react-native-netinfo:
|
||||||
@ -784,6 +789,7 @@ SPEC CHECKSUMS:
|
|||||||
react-native-cameraroll: e2917a5e62da9f10c3d525e157e25e694d2d6dfa
|
react-native-cameraroll: e2917a5e62da9f10c3d525e157e25e694d2d6dfa
|
||||||
react-native-config: c98128a72bc2c3a1ca72caec0b021f0fa944aa29
|
react-native-config: c98128a72bc2c3a1ca72caec0b021f0fa944aa29
|
||||||
react-native-date-picker: d83ab9cccbc497642a93fdca783ae76ecd6b17b6
|
react-native-date-picker: d83ab9cccbc497642a93fdca783ae76ecd6b17b6
|
||||||
|
react-native-fingerprint-scanner: ac6656f18c8e45a7459302b84da41a44ad96dbbe
|
||||||
react-native-matomo-sdk: 025c54f92e1e26a4d0acee7c3f28cb0fc7e4729c
|
react-native-matomo-sdk: 025c54f92e1e26a4d0acee7c3f28cb0fc7e4729c
|
||||||
react-native-netinfo: 30fb89fa913c342be82a887b56e96be6d71201dd
|
react-native-netinfo: 30fb89fa913c342be82a887b56e96be6d71201dd
|
||||||
react-native-orientation-locker: 2da91e5391971dace445495821c899c111dcad7a
|
react-native-orientation-locker: 2da91e5391971dace445495821c899c111dcad7a
|
||||||
@ -833,4 +839,4 @@ SPEC CHECKSUMS:
|
|||||||
|
|
||||||
PODFILE CHECKSUM: 0282022703ad578ab2d9afbf3147ba3b373b4311
|
PODFILE CHECKSUM: 0282022703ad578ab2d9afbf3147ba3b373b4311
|
||||||
|
|
||||||
COCOAPODS: 1.11.2
|
COCOAPODS: 1.11.3
|
||||||
|
@ -93,6 +93,7 @@
|
|||||||
"react-native-dynamic": "^1.0.0",
|
"react-native-dynamic": "^1.0.0",
|
||||||
"react-native-extended-stylesheet": "^0.10.0",
|
"react-native-extended-stylesheet": "^0.10.0",
|
||||||
"react-native-fast-image": "^8.3.2",
|
"react-native-fast-image": "^8.3.2",
|
||||||
|
"react-native-fingerprint-scanner": "hieuvp/react-native-fingerprint-scanner",
|
||||||
"react-native-gesture-handler": "^1.9.0",
|
"react-native-gesture-handler": "^1.9.0",
|
||||||
"react-native-highlight-words": "^1.0.1",
|
"react-native-highlight-words": "^1.0.1",
|
||||||
"react-native-iap": "^7.5.6",
|
"react-native-iap": "^7.5.6",
|
||||||
|
@ -17,39 +17,42 @@ const api = axios.create({
|
|||||||
|
|
||||||
api.interceptors.request.use((request) => {
|
api.interceptors.request.use((request) => {
|
||||||
console.log('Starting ecency Request', request);
|
console.log('Starting ecency Request', request);
|
||||||
|
|
||||||
//skip code addition is register and token refresh endpoint is triggered
|
//skip code addition is register and token refresh endpoint is triggered
|
||||||
if(request.url === '/private-api/account-create'
|
if (request.url === '/private-api/account-create'
|
||||||
|| request.url === '/auth-api/hs-token-refresh'
|
|| request.url === '/auth-api/hs-token-refresh'
|
||||||
|| request.url === '/private-api/promoted-entries'
|
|| request.url === '/private-api/promoted-entries'
|
||||||
|| request.url.startsWith('private-api/leaderboard')
|
|| request.url.startsWith('private-api/leaderboard')
|
||||||
|| request.url.startsWith('/private-api/received-vesting/')
|
|| request.url.startsWith('/private-api/received-vesting/')
|
||||||
|| request.url.startsWith('/private-api/referrals/')
|
|| request.url.startsWith('/private-api/referrals/')
|
||||||
|| request.url.startsWith('/private-api/market-data')
|
|| request.url.startsWith('/private-api/market-data')
|
||||||
|| request.url.startsWith('/private-api/comment-history')
|
|| request.url.startsWith('/private-api/comment-history')
|
||||||
){
|
) {
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
//decrypt access token
|
if (!request.data?.code) {
|
||||||
const state = store.getState();
|
//if access code not already set, decrypt access token
|
||||||
const token = get(state, 'account.currentAccount.local.accessToken');
|
const state = store.getState();
|
||||||
const pin = get(state, 'application.pin');
|
const token = get(state, 'account.currentAccount.local.accessToken');
|
||||||
const digitPinCode = getDigitPinCode(pin);
|
const pin = get(state, 'application.pin');
|
||||||
const accessToken = decryptKey(token, digitPinCode);
|
const digitPinCode = getDigitPinCode(pin);
|
||||||
|
const accessToken = decryptKey(token, digitPinCode);
|
||||||
|
|
||||||
if (accessToken && !request.data?.code ) {
|
if (accessToken) {
|
||||||
if (!request.data){
|
if (!request.data) {
|
||||||
request.data = {};
|
request.data = {};
|
||||||
|
}
|
||||||
|
request.data.code = accessToken;
|
||||||
|
console.log('Added access token:', accessToken);
|
||||||
|
} else {
|
||||||
|
const isLoggedIn = state.application.isLoggedIn;
|
||||||
|
console.warn("Failed to inject accessToken", `isLoggedIn:${isLoggedIn}`)
|
||||||
|
bugsnagInstance.notify(new Error(`Failed to inject accessToken in ${request.url} call. isLoggedIn:${isLoggedIn}, local.acccessToken:${token}, pin:${pin}`))
|
||||||
}
|
}
|
||||||
request.data.code = accessToken;
|
|
||||||
console.log('Added access token:', accessToken);
|
|
||||||
} else {
|
|
||||||
const isLoggedIn = state.application.isLoggedIn;
|
|
||||||
console.warn("Failed to inject accessToken", `isLoggedIn:${isLoggedIn}`)
|
|
||||||
bugsnagInstance.notify(new Error(`Failed to inject accessToken in ${request.url} call. isLoggedIn:${isLoggedIn}`))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -229,6 +229,7 @@
|
|||||||
"delegations": "Delegations"
|
"delegations": "Delegations"
|
||||||
},
|
},
|
||||||
"pincode": "PIN code",
|
"pincode": "PIN code",
|
||||||
|
"biometric": "Finger Print / Face Unlock",
|
||||||
"reset_pin": "Reset Pin Code",
|
"reset_pin": "Reset Pin Code",
|
||||||
"reset": "Reset",
|
"reset": "Reset",
|
||||||
"nsfw_content": "NSFW",
|
"nsfw_content": "NSFW",
|
||||||
@ -419,7 +420,8 @@
|
|||||||
"forgot_text": "Oh, I forgot it...",
|
"forgot_text": "Oh, I forgot it...",
|
||||||
"pin_not_matched":"PIN do not match, Please try again.",
|
"pin_not_matched":"PIN do not match, Please try again.",
|
||||||
"attempts_postfix":"failed attempt(s)",
|
"attempts_postfix":"failed attempt(s)",
|
||||||
"message_reset_warning":"User data will be wiped on next failed attempt"
|
"message_reset_warning":"User data will be wiped on next failed attempt",
|
||||||
|
"biometric_desc":"Scan your fingerprint on the device scanner to continue"
|
||||||
},
|
},
|
||||||
"alert": {
|
"alert": {
|
||||||
"success": "Success!",
|
"success": "Success!",
|
||||||
|
@ -32,6 +32,7 @@ import {
|
|||||||
SET_SETTINGS_MIGRATED,
|
SET_SETTINGS_MIGRATED,
|
||||||
HIDE_POSTS_THUMBNAILS,
|
HIDE_POSTS_THUMBNAILS,
|
||||||
SET_TERMS_ACCEPTED,
|
SET_TERMS_ACCEPTED,
|
||||||
|
SET_IS_BIOMETRIC_ENABLED,
|
||||||
SET_ENC_UNLOCK_PIN
|
SET_ENC_UNLOCK_PIN
|
||||||
} from '../constants/constants';
|
} from '../constants/constants';
|
||||||
|
|
||||||
@ -210,6 +211,11 @@ export const setIsTermsAccepted = (isTermsAccepted:boolean) => ({
|
|||||||
type: SET_TERMS_ACCEPTED
|
type: SET_TERMS_ACCEPTED
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const setIsBiometricEnabled = (enabled:boolean) => ({
|
||||||
|
payload:enabled,
|
||||||
|
type: SET_IS_BIOMETRIC_ENABLED
|
||||||
|
})
|
||||||
|
|
||||||
export const setEncryptedUnlockPin = (encryptedUnlockPin:string) => ({
|
export const setEncryptedUnlockPin = (encryptedUnlockPin:string) => ({
|
||||||
payload:encryptedUnlockPin,
|
payload:encryptedUnlockPin,
|
||||||
type: SET_ENC_UNLOCK_PIN
|
type: SET_ENC_UNLOCK_PIN
|
||||||
|
@ -36,6 +36,7 @@ export const SET_LAST_APP_VERSION = 'SET_LAST_APP_VERSION';
|
|||||||
export const SET_COLOR_THEME = 'SET_COLOR_THEME';
|
export const SET_COLOR_THEME = 'SET_COLOR_THEME';
|
||||||
export const SET_SETTINGS_MIGRATED = 'SET_SETTINGS_MIGRATED';
|
export const SET_SETTINGS_MIGRATED = 'SET_SETTINGS_MIGRATED';
|
||||||
export const SET_TERMS_ACCEPTED = 'SET_TERMS_ACCEPTED';
|
export const SET_TERMS_ACCEPTED = 'SET_TERMS_ACCEPTED';
|
||||||
|
export const SET_IS_BIOMETRIC_ENABLED = 'SET_IS_BIOMETRIC_ENABLED';
|
||||||
export const SET_ENC_UNLOCK_PIN = 'SET_ENC_UNLOCK_PIN';
|
export const SET_ENC_UNLOCK_PIN = 'SET_ENC_UNLOCK_PIN';
|
||||||
|
|
||||||
// Accounts
|
// Accounts
|
||||||
|
@ -30,6 +30,7 @@ import {
|
|||||||
SET_SETTINGS_MIGRATED,
|
SET_SETTINGS_MIGRATED,
|
||||||
HIDE_POSTS_THUMBNAILS,
|
HIDE_POSTS_THUMBNAILS,
|
||||||
SET_TERMS_ACCEPTED,
|
SET_TERMS_ACCEPTED,
|
||||||
|
SET_IS_BIOMETRIC_ENABLED,
|
||||||
SET_ENC_UNLOCK_PIN
|
SET_ENC_UNLOCK_PIN
|
||||||
} from '../constants/constants';
|
} from '../constants/constants';
|
||||||
|
|
||||||
@ -71,6 +72,7 @@ interface State {
|
|||||||
settingsMigratedV2: boolean;
|
settingsMigratedV2: boolean;
|
||||||
hidePostsThumbnails: boolean;
|
hidePostsThumbnails: boolean;
|
||||||
isTermsAccepted: boolean;
|
isTermsAccepted: boolean;
|
||||||
|
isBiometricEnabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState:State = {
|
const initialState:State = {
|
||||||
@ -111,6 +113,7 @@ const initialState:State = {
|
|||||||
settingsMigratedV2: false,
|
settingsMigratedV2: false,
|
||||||
hidePostsThumbnails: false,
|
hidePostsThumbnails: false,
|
||||||
isTermsAccepted: false,
|
isTermsAccepted: false,
|
||||||
|
isBiometricEnabled: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function (state = initialState, action):State {
|
export default function (state = initialState, action):State {
|
||||||
@ -285,6 +288,12 @@ export default function (state = initialState, action):State {
|
|||||||
...state,
|
...state,
|
||||||
isTermsAccepted:action.payload
|
isTermsAccepted:action.payload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SET_IS_BIOMETRIC_ENABLED:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isBiometricEnabled:action.payload
|
||||||
|
}
|
||||||
|
|
||||||
case SET_ENC_UNLOCK_PIN:
|
case SET_ENC_UNLOCK_PIN:
|
||||||
return {
|
return {
|
||||||
|
@ -4,6 +4,7 @@ import { connect } from 'react-redux';
|
|||||||
import { injectIntl } from 'react-intl';
|
import { injectIntl } from 'react-intl';
|
||||||
import Config from 'react-native-config';
|
import Config from 'react-native-config';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
|
import FingerprintScanner from 'react-native-fingerprint-scanner';
|
||||||
|
|
||||||
|
|
||||||
// Actions & Services
|
// Actions & Services
|
||||||
@ -37,6 +38,8 @@ import PinCodeScreen from '../screen/pinCodeScreen';
|
|||||||
|
|
||||||
|
|
||||||
class PinCodeContainer extends Component {
|
class PinCodeContainer extends Component {
|
||||||
|
screenRef = null;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@ -74,9 +77,43 @@ class PinCodeContainer extends Component {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_processBiometric = async () => {
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
intl,
|
||||||
|
pinCodeParams: { isReset },
|
||||||
|
applicationPinCode,
|
||||||
|
isBiometricEnabled,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
if (isReset || !isBiometricEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const biometryType = await FingerprintScanner.isSensorAvailable();
|
||||||
|
console.log('biometryType is => ', biometryType);
|
||||||
|
|
||||||
|
await FingerprintScanner.authenticate({
|
||||||
|
description: intl.formatMessage({ id: 'pincode.biometric_desc' }),
|
||||||
|
});
|
||||||
|
console.log('successfully passed biometric auth');
|
||||||
|
|
||||||
|
//code gets here means biometeric succeeded
|
||||||
|
if (this.screenRef) {
|
||||||
|
const verifiedPin = decryptKey(applicationPinCode, Config.PIN_KEY, this._onDecryptFail);
|
||||||
|
this.screenRef.setPinThroughBiometric(verifiedPin);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Failed to process biometric', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
FingerprintScanner.release();
|
||||||
|
};
|
||||||
|
|
||||||
//this function updates realm with appropriate master key required for encyrption
|
//this function updates realm with appropriate master key required for encyrption
|
||||||
//this function is important: must run while chaning pin
|
//this function is important: must run while chaning pin
|
||||||
//and even logging in with existing pin code
|
//and even logging in with existing pin code
|
||||||
|
|
||||||
_updatePinCodeRealm = async (pinData) => {
|
_updatePinCodeRealm = async (pinData) => {
|
||||||
try {
|
try {
|
||||||
const { currentAccount, dispatch } = this.props;
|
const { currentAccount, dispatch } = this.props;
|
||||||
@ -388,12 +425,14 @@ class PinCodeContainer extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PinCodeScreen
|
<PinCodeScreen
|
||||||
|
ref={(ref) => (this.screenRef = ref)}
|
||||||
informationText={informationText}
|
informationText={informationText}
|
||||||
setPinCode={(pin) => this._setPinCode(pin, isReset)}
|
setPinCode={(pin) => this._setPinCode(pin, isReset)}
|
||||||
showForgotButton={!isOldPinVerified}
|
showForgotButton={!isOldPinVerified}
|
||||||
username={currentAccount.name}
|
username={currentAccount.name}
|
||||||
intl={intl}
|
intl={intl}
|
||||||
handleForgotButton={() => this._handleForgotButton()}
|
handleForgotButton={() => this._handleForgotButton()}
|
||||||
|
isReset={isReset}
|
||||||
{...this.props}
|
{...this.props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -406,6 +445,7 @@ const mapStateToProps = (state) => ({
|
|||||||
encUnlockPin: state.application.encUnlockPin,
|
encUnlockPin: state.application.encUnlockPin,
|
||||||
otherAccounts: state.account.otherAccounts,
|
otherAccounts: state.account.otherAccounts,
|
||||||
pinCodeParams: state.application.pinCodeNavigation,
|
pinCodeParams: state.application.pinCodeNavigation,
|
||||||
|
isBiometricEnabled: state.application.isBiometricEnabled,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default injectIntl(connect(mapStateToProps)(PinCodeContainer));
|
export default injectIntl(connect(mapStateToProps)(PinCodeContainer));
|
||||||
|
@ -1,27 +1,39 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { Text, TouchableOpacity, View } from 'react-native';
|
import { Text, TouchableOpacity, View } from 'react-native';
|
||||||
|
|
||||||
import { NumericKeyboard, PinAnimatedInput, UserAvatar } from '../../../components';
|
import { NumericKeyboard, PinAnimatedInput, UserAvatar } from '../../../components';
|
||||||
|
|
||||||
import styles from './pinCodeStyles';
|
import styles from './pinCodeStyles';
|
||||||
|
|
||||||
const PinCodeScreen = ({
|
const PinCodeScreen = forwardRef(({
|
||||||
informationText,
|
informationText,
|
||||||
showForgotButton,
|
showForgotButton,
|
||||||
username,
|
username,
|
||||||
handleForgotButton,
|
handleForgotButton,
|
||||||
setPinCode,
|
setPinCode,
|
||||||
}) => {
|
}, ref) => {
|
||||||
const [pin, setPin] = useState('');
|
const [pin, setPin] = useState('');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
setPinThroughBiometric(bioPin){
|
||||||
|
if(bioPin && bioPin.length === 4){
|
||||||
|
setLoading(true);
|
||||||
|
setPin(bioPin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
_handlePinComplete();
|
_handlePinComplete();
|
||||||
}, [pin]);
|
}, [pin]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const _handlePinComplete = async () => {
|
const _handlePinComplete = async () => {
|
||||||
if (pin.length === 4) {
|
if (pin.length === 4) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@ -31,6 +43,7 @@ const PinCodeScreen = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const _handleKeyboardOnPress = async (value) => {
|
const _handleKeyboardOnPress = async (value) => {
|
||||||
try {
|
try {
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@ -82,6 +95,6 @@ const PinCodeScreen = ({
|
|||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
})
|
||||||
|
|
||||||
export default PinCodeScreen;
|
export default PinCodeScreen;
|
@ -43,6 +43,7 @@ import {
|
|||||||
logoutDone,
|
logoutDone,
|
||||||
closePinCodeModal,
|
closePinCodeModal,
|
||||||
setColorTheme,
|
setColorTheme,
|
||||||
|
setIsBiometricEnabled,
|
||||||
setEncryptedUnlockPin,
|
setEncryptedUnlockPin,
|
||||||
} from '../../../redux/actions/applicationActions';
|
} from '../../../redux/actions/applicationActions';
|
||||||
import { toastNotification } from '../../../redux/actions/uiAction';
|
import { toastNotification } from '../../../redux/actions/uiAction';
|
||||||
@ -240,6 +241,14 @@ class SettingsContainer extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'biometric':
|
||||||
|
dispatch(
|
||||||
|
openPinCodeModal({
|
||||||
|
callback: () => dispatch(setIsBiometricEnabled(action)),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -460,6 +469,7 @@ const mapStateToProps = (state) => ({
|
|||||||
colorTheme: state.application.colorTheme,
|
colorTheme: state.application.colorTheme,
|
||||||
isPinCodeOpen: state.application.isPinCodeOpen,
|
isPinCodeOpen: state.application.isPinCodeOpen,
|
||||||
encUnlockPin: state.application.encUnlockPin,
|
encUnlockPin: state.application.encUnlockPin,
|
||||||
|
isBiometricEnabled: state.application.isBiometricEnabled,
|
||||||
isDefaultFooter: state.application.isDefaultFooter,
|
isDefaultFooter: state.application.isDefaultFooter,
|
||||||
isLoggedIn: state.application.isLoggedIn,
|
isLoggedIn: state.application.isLoggedIn,
|
||||||
isNotificationSettingsOpen: state.application.isNotificationOpen,
|
isNotificationSettingsOpen: state.application.isNotificationOpen,
|
||||||
|
@ -24,6 +24,7 @@ const SettingsScreen = ({
|
|||||||
isDarkTheme,
|
isDarkTheme,
|
||||||
colorThemeIndex,
|
colorThemeIndex,
|
||||||
isPinCodeOpen,
|
isPinCodeOpen,
|
||||||
|
isBiometricEnabled,
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
isNotificationSettingsOpen,
|
isNotificationSettingsOpen,
|
||||||
nsfw,
|
nsfw,
|
||||||
@ -147,6 +148,16 @@ const SettingsScreen = ({
|
|||||||
|
|
||||||
{!!isLoggedIn && !!isPinCodeOpen && (
|
{!!isLoggedIn && !!isPinCodeOpen && (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
<SettingsItem
|
||||||
|
title={intl.formatMessage({
|
||||||
|
id: 'settings.biometric',
|
||||||
|
})}
|
||||||
|
type="toggle"
|
||||||
|
actionType="biometric"
|
||||||
|
isOn={isBiometricEnabled}
|
||||||
|
handleOnChange={handleOnChange}
|
||||||
|
/>
|
||||||
|
|
||||||
<SettingsItem
|
<SettingsItem
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
id: 'settings.reset_pin',
|
id: 'settings.reset_pin',
|
||||||
@ -159,15 +170,6 @@ const SettingsScreen = ({
|
|||||||
handleOnButtonPress={handleOnButtonPress}
|
handleOnButtonPress={handleOnButtonPress}
|
||||||
/>
|
/>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
// <SettingsItem
|
|
||||||
// title={intl.formatMessage({
|
|
||||||
// id: 'settings.default_footer',
|
|
||||||
// })}
|
|
||||||
// type="toggle"
|
|
||||||
// actionType="default_footer"
|
|
||||||
// isOn={isDefaultFooter}
|
|
||||||
// handleOnChange={handleOnChange}
|
|
||||||
// />
|
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
{!!isLoggedIn && (
|
{!!isLoggedIn && (
|
||||||
|
@ -8782,6 +8782,10 @@ react-native-fast-image@^8.3.2:
|
|||||||
resolved "https://registry.yarnpkg.com/react-native-fast-image/-/react-native-fast-image-8.3.4.tgz#79edca177e30311b19d59ff335625bcbe22650d7"
|
resolved "https://registry.yarnpkg.com/react-native-fast-image/-/react-native-fast-image-8.3.4.tgz#79edca177e30311b19d59ff335625bcbe22650d7"
|
||||||
integrity sha512-LpzAdjUphihUpVEBn5fEv5AILe55rHav0YiZroPZ1rumKDhAl4u2cG01ku2Pb7l8sayjTsNu7FuURAlXUUDsow==
|
integrity sha512-LpzAdjUphihUpVEBn5fEv5AILe55rHav0YiZroPZ1rumKDhAl4u2cG01ku2Pb7l8sayjTsNu7FuURAlXUUDsow==
|
||||||
|
|
||||||
|
react-native-fingerprint-scanner@hieuvp/react-native-fingerprint-scanner:
|
||||||
|
version "6.0.0"
|
||||||
|
resolved "https://codeload.github.com/hieuvp/react-native-fingerprint-scanner/tar.gz/9cecc0db326471c571553ea85f7c016fee2f803d"
|
||||||
|
|
||||||
react-native-flipper@^0.34.0:
|
react-native-flipper@^0.34.0:
|
||||||
version "0.34.0"
|
version "0.34.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-flipper/-/react-native-flipper-0.34.0.tgz#7df1f38ba5d97a9321125fe0fccbe47d99e6fa1d"
|
resolved "https://registry.yarnpkg.com/react-native-flipper/-/react-native-flipper-0.34.0.tgz#7df1f38ba5d97a9321125fe0fccbe47d99e6fa1d"
|
||||||
|
Loading…
Reference in New Issue
Block a user