Commit eaae7249 by Nguyễn Thị Thúy

add fingerprint and keychain lib

parent 06bb0724
{
"version": 1,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.dcv.invest",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"properties": [],
"versionCode": 16,
"versionName": "2.0",
"enabled": true,
"outputFile": "app-release.apk"
}
]
}
\ No newline at end of file
......@@ -2,24 +2,27 @@
package="com.dcv.invest">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
>
android:usesCleartextTraffic="true">
<!-- <meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/bootsplash_background" /> -->
......@@ -27,24 +30,28 @@
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:exported="true"
android:label="@string/app_name"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="appdcvinvest" android:host="screen" android:pathPrefix="/"
/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="screen"
android:pathPrefix="/"
android:scheme="appdcvinvest" />
</intent-filter>
</activity>
<activity
android:name="com.zoontek.rnbootsplash.RNBootSplashActivity"
android:theme="@style/BootTheme"
android:launchMode="singleTask">
android:launchMode="singleTask"
android:theme="@style/BootTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
......@@ -52,8 +59,6 @@
</intent-filter>
</activity>
......
......@@ -4,6 +4,8 @@ import android.app.Application;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.rnfingerprint.FingerprintAuthPackage;
import com.rnfingerprint.FingerprintAuthPackage;
import com.learnium.RNDeviceInfo.RNDeviceInfo;
import com.reactnativecommunity.netinfo.NetInfoPackage;
import com.facebook.react.ReactInstanceManager;
......
......@@ -4,7 +4,7 @@ buildscript {
ext {
buildToolsVersion = "29.0.2"
minSdkVersion = 21
compileSdkVersion = 28
compileSdkVersion = 29
targetSdkVersion = 29
}
repositories {
......
rootProject.name = 'Invest'
include ':react-native-touch-id'
project(':react-native-touch-id').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-touch-id/android')
include ':react-native-device-info'
project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
include ':@react-native-community_netinfo'
......
......@@ -903,7 +903,7 @@
CODE_SIGN_ENTITLEMENTS = Invest/Invest.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 7;
CURRENT_PROJECT_VERSION = 8;
DEVELOPMENT_TEAM = MXZ24GRH48;
ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
......@@ -937,7 +937,7 @@
CODE_SIGN_ENTITLEMENTS = Invest/Invest.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 7;
CURRENT_PROJECT_VERSION = 8;
DEVELOPMENT_TEAM = MXZ24GRH48;
INFOPLIST_FILE = Invest/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
......
......@@ -63,7 +63,7 @@
<key>NSCameraUsageDescription</key>
<string>Accect connect camera</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<string/>
<key>NSPhotoLibraryUsageDescription</key>
<string>To upload images</string>
<key>UIAppFonts</key>
......@@ -100,5 +100,7 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>NSFaceIDUsageDescription</key>
<string>Enabling Face ID allows you quick and secure access to your account.</string>
</dict>
</plist>
......@@ -91,6 +91,8 @@ target 'Invest' do
pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info'
pod 'TouchID', :path => '../node_modules/react-native-touch-id'
target 'InvestTests' do
inherit! :complete
# Pods for testing
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -30,7 +30,7 @@
"react-hook-form": "^6.15.4",
"react-native": "0.62.2",
"react-native-autocomplete-input": "^5.0.0",
"react-native-bootsplash": "^3.2.0",
"react-native-bootsplash": "^3.2.3",
"react-native-confirmation-code-field": "^6.5.1",
"react-native-datepicker": "^1.7.2",
"react-native-device-info": "^8.1.2",
......@@ -40,6 +40,7 @@
"react-native-i18n": "^2.0.15",
"react-native-image-crop-picker": "^0.36.2",
"react-native-indicators": "^0.17.0",
"react-native-keychain": "^7.0.0",
"react-native-linear-gradient": "^2.5.6",
"react-native-modal": "^11.7.0",
"react-native-modal-dropdown": "^1.0.0",
......@@ -51,6 +52,7 @@
"react-native-simple-radio-button": "^2.7.4",
"react-native-swiper": "^1.6.0",
"react-native-tab-view": "^2.15.2",
"react-native-touch-id": "^4.4.1",
"react-native-vector-icons": "^8.0.0",
"react-native-webview": "^11.2.5",
"react-native-youtube": "^2.0.1",
......
......@@ -29,6 +29,13 @@ import messaging from '@react-native-firebase/messaging';
import I18n from '../../helper/i18/i18n';
import AppText from '../../components/AppText';
import {showAlert, TYPE} from '../../components/DropdownAlert';
import EntypoIcon from 'react-native-vector-icons/Entypo';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import TouchID from 'react-native-touch-id';
import {call} from 'redux-saga/effects';
import KeychainService from '../../services/keychainService';
import * as Keychain from 'react-native-keychain';
const Login = (props) => {
const {navigation} = props;
......@@ -37,6 +44,11 @@ const Login = (props) => {
const [pass, setPass] = useState('');
const navigate = useNavigation();
const optionalConfigObject = {
title: 'Authentication Required', // Android
color: '#e00606', // Android,
fallbackLabel: '', // iOS (if empty, then label is hidden)
};
const getTokenDevice = async () => {
let fcmToken = await AsyncStorage.getItem(KEY.FIREBASE);
......@@ -60,18 +72,37 @@ const Login = (props) => {
const account = JSON.parse(jsonValue);
if (account) {
onSubmitLogin(account.email, account.pass);
} else {
try {
// Retrieve the credentials
const credentials = await Keychain.getGenericPassword();
if (credentials) {
console.log(
'Credentials successfully loaded for user ' + credentials
);
} else {
console.log('No credentials stored');
}
} catch (error) {
console.log("Keychain couldn't be accessed!", error);
}
}
};
function* authorize() {
let isFingerPrintAuthenticated = yield call(KeychainService.getCredentials);
}
const onSubmitLogin = async (email, pass) => {
const titles = [
I18n.t('Username').toLowerCase(),
I18n.t('Password').toLowerCase(),
];
const index = checkFormatArray([email, pass]);
if (index === true) {
firebase = await AsyncStorage.getItem(KEY.FIREBASE);
let firebase = await AsyncStorage.getItem(KEY.FIREBASE);
props.showLoading();
const res = await loginApi({
email,
......@@ -92,6 +123,7 @@ const Login = (props) => {
index: 1,
routes: [{name: TABNAVIGATOR}],
});
await Keychain.setGenericPassword(email, pass);
} else {
showAlert(TYPE.ERROR, I18n.t('Notification'), res.data.message);
}
......@@ -110,6 +142,29 @@ const Login = (props) => {
);
}
};
const clickFingerprintHandler = () => {
TouchID.isSupported()
.then(authenticate => {
console.log(authenticate);
pressHandler();
})
.catch(error => {
showAlert(TYPE.WARN, I18n.t('Notification'), 'TouchID not supported');
});
};
const pressHandler = () => {
TouchID.authenticate('to demo this react-native component', optionalConfigObject)
.then(success => {
console.log(success);
onSubmitLogin('thuynt@dcv.vn', '123456');
showAlert(TYPE.WARN, I18n.t('Notification'), 'success');
})
.catch(error => {
console.log(error);
showAlert(TYPE.WARN, I18n.t('Notification'), 'Authentication Failed');
});
};
return (
<View
......@@ -135,7 +190,7 @@ const Login = (props) => {
<TouchableOpacity
onPress={() => navigate.navigate(CONFIRMEMAIL)}
style={styles.forgotView}>
<AppText i18nKey={'ForgotPassword'} style={styles.txtTitle} />
<AppText i18nKey={'ForgotPassword'} style={styles.txtTitle}/>
</TouchableOpacity>
<View
......@@ -146,21 +201,37 @@ const Login = (props) => {
<TouchableOpacity
onPress={() => onSubmitLogin(email, pass)}
style={styles.wrapLogin}>
<AppText i18nKey={'Login'} style={styles.txtLogin} />
<Image source={R.images.iconRight1} style={styles.imgIcon} />
<AppText i18nKey={'Login'} style={styles.txtLogin}/>
<Image source={R.images.iconRight1} style={styles.imgIcon}/>
</TouchableOpacity>
<View style={{flexDirection: 'row', marginTop: WIDTHXD(50)}}>
<TouchableOpacity
onPress={() => {
clickFingerprintHandler();
}}>
<EntypoIcon name={'fingerprint'} size={WIDTHXD(80)} color={R.colors.main}/>
</TouchableOpacity>
<View style={{width: WIDTHXD(80)}}/>
<TouchableOpacity
onPress={() => {
// navigation.navigate('REGISTOR');
}}>
<Icon name={'face-recognition'} size={WIDTHXD(80)} color={R.colors.main}/>
</TouchableOpacity>
</View>
<View style={styles.row}>
<AppText i18nKey={'Have_account'} style={styles.txtTitle} />
<AppText i18nKey={'Have_account'} style={styles.txtTitle}/>
<TouchableOpacity
onPress={() => {
navigation.navigate('REGISTOR');
}}>
<AppText i18nKey={'Register'} style={styles.txtRegistor} />
<AppText i18nKey={'Register'} style={styles.txtRegistor}/>
</TouchableOpacity>
</View>
</View>
<View style={{height: 100}} />
<View style={{height: 100}}/>
</View>
);
};
......
export const root = 'http://api.dcvinvest.com/';
export const root = 'http://services.dcvinvest.com/';
export default {
urllogin: root + 'api/auth/customer-login',
......
......@@ -156,13 +156,13 @@ export default {
ChangePasswordSuccess: 'Change password success',
EnterAllInfo: 'Please complete all information ',
Date: 'Date',
ReviewService: 'Review service of DCV Invest',
ReviewService: 'Review services of DCV Invest',
VeryBad: 'Very bad',
Bad: 'Bad',
Normal: 'Normal',
Good: 'Good',
VeryGood: 'Very good',
ShareYourFeel: 'Share your feel about service',
ShareYourFeel: 'Share your feel about services',
UploadImage: 'Upload image',
BonusMoney: 'Bonus money',
Content: 'Content',
......
import TouchID from 'react-native-touch-id';
import {Platform} from 'react-native'
export const checkBiometricSupportednEnrolled = async () => {
const optionalConfigObject = {
unifiedErrors: false, // use unified error messages (default false)
passcodeFallback: false // if true is passed, it will allow isSupported to return an error if the device is not enrolled in touch id/face id etc. Otherwise, it will just tell you what method is supported, even if the user is not enrolled. (default false)
}
return new Promise((resolve, reject) => {
//isSupported returns both cases 1. if supported 2. Is enabled/configured/enrolled
TouchID.isSupported(optionalConfigObject)
.then(biometryType => {
// Success code.
// as we are focusing on fingerprint for now
if (biometryType && biometryType != 'FaceID') {
resolve(true);
} else {
let fingerprintLableForOS = Platform.OS == "ios" ? "Touch ID" : "Fingerprint";
reject( fingerprintLableForOS + " is not available on this device");
}
})
.catch(error => {
// iOS Error Format and android error formats are different
// android use code and ios use name
// check at https://github.com/naoufal/react-native-touch-id
let errorCode = Platform.OS == "ios" ? error.name : error.code;
if (errorCode === "LAErrorTouchIDNotEnrolled" || errorCode === "NOT_AVAILABLE" || errorCode === "NOT_ENROLLED") {
let fingerprintLableForOS = Platform.OS == "ios" ? "Touch ID" : "Fingerprint";
resolve(fingerprintLableForOS + " has no enrolled fingers. Please go to settings and enable " + fingerprintLableForOS + " on this device.");
} else {
reject(Platform.OS == "ios" ? error.message : translations.t(error.code));
}
});
});
}
export const authenticateFingerPrint = () => {
return new Promise((resolve, reject) => {
// configuration object for more detailed dialog setup and style:
// const optionalConfigObject = {
// title: 'Authentication Required', // Android
// imageColor: '#e00606', // Android
// imageErrorColor: '#ff0000', // Android
// sensorDescription: 'Touch sensor', // Android
// sensorErrorDescription: 'Failed', // Android
// cancelText: 'Cancel', // Android
// fallbackLabel: 'Show Passcode', // iOS (if empty, then label is hidden)
// unifiedErrors: false, // use unified error messages (default false)
// passcodeFallback: false, // iOS - allows the device to fall back to using the passcode, if faceid/touch is not available. this does not mean that if touchid/faceid fails the first few times it will revert to passcode, rather that if the former are not enrolled, then it will use the passcode.
// };
let fingerprintLableForOS = Platform.OS == "ios" ? "Touch ID" : "Fingerprint";
TouchID.authenticate('Login to [appname] using ' + fingerprintLableForOS)
.then(success => {
// console.log('Authenticated Successfully', success)
resolve(success)
})
.catch(error => {
console.log('Authentication Failed', error.code)
reject(error)
});
});
}
import * as Keychain from 'react-native-keychain';
import { Platform } from "react-native";
export const setCredentials = async (username, password) => {
return new Promise((resolve, reject) => {
// Store the credentials
Keychain.setGenericPassword(username, password)
.then(resp => {
resolve(true)
})
.catch(err => {
console.log("err: ", err);
reject(err);
});
});
}
export const getCredentials = async () => {
return new Promise((resolve, reject) => {
Keychain.getGenericPassword()
.then((credentials) => {
if (credentials && credentials.username) {
// console.log('Credentials successfully loaded for user ' + credentials.username);
resolve(credentials);
} else {
// console.log('No credentials stored');
resolve(null);
}
})
.catch(err => {
console.log("err: ", err);
reject(err);
});
});
}
......@@ -692,9 +692,9 @@
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.7.2":
version "7.13.10"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.5.tgz#665450911c6031af38f81db530f387ec04cd9a98"
integrity sha512-121rumjddw9c3NCQ55KGkyE1h/nzWhU/owjhw0l4mQrkzz4x9SGS1X8gFLraHwX7td3Yo4QTL+qj0NcIzN87BA==
dependencies:
regenerator-runtime "^0.13.4"
......@@ -2590,7 +2590,7 @@ chalk@^3.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chalk@^4.0.0, chalk@^4.1.0:
chalk@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz"
integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
......@@ -2598,6 +2598,14 @@ chalk@^4.0.0, chalk@^4.1.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chalk@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad"
integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
char-regex@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz"
......@@ -6806,10 +6814,10 @@ react-native-autocomplete-input@^5.0.0:
resolved "https://registry.yarnpkg.com/react-native-autocomplete-input/-/react-native-autocomplete-input-5.0.0.tgz#2bcba7be7846fe84e1e753362e3fe40c86fd7c46"
integrity sha512-JsVm1rLNdyf2mLN0cw8XKTP6xwsCw+laPOxb7j81XOZhsS7nQaWytwp6+YEvSi3bnMRuUpvOUbCiS55av9/0/w==
react-native-bootsplash@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-native-bootsplash/-/react-native-bootsplash-3.2.0.tgz#671861fdd75444f91196d3e64d3539ef50c3a30f"
integrity sha512-1+xMWLxqIUPbKiiwrbiekw3uKtuyNpm0R1eg5p3/ISRMXs0eZy7DHfiyCqcLq1N1a3Gv0oTZn1E7WEA2NjgdhA==
react-native-bootsplash@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/react-native-bootsplash/-/react-native-bootsplash-3.2.3.tgz#5f985a492696e14c73dc3b8475be5385b7436593"
integrity sha512-JNuDZ1sL9kppFrZ4OcK/ZM6gf9h5NmM6VfsLJEfa/lSPlD5wXoOyXIaeBn/6odaIPxSp31WIryeaNiZZIltu7g==
dependencies:
chalk "^4.1.0"
fs-extra "^9.1.0"
......@@ -6879,6 +6887,11 @@ react-native-iphone-x-helper@^1.3.0:
resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz"
integrity sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==
react-native-keychain@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/react-native-keychain/-/react-native-keychain-7.0.0.tgz#11fd559fe86ae89f934b8c75ae228247deed5494"
integrity sha512-tH26sgW4OxB/llXmhO+DajFISEUoF1Ip2+WSDMIgCt8SP1xRE81m2qFzgIOc/7StYsUERxHhDPkxvq2H0/Goig==
react-native-linear-gradient@^2.5.6:
version "2.5.6"
resolved "https://registry.yarnpkg.com/react-native-linear-gradient/-/react-native-linear-gradient-2.5.6.tgz#96215cbc5ec7a01247a20890888aa75b834d44a0"
......@@ -6948,6 +6961,11 @@ react-native-tab-view@^2.15.2:
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-2.15.2.tgz"
integrity sha512-2hxLkBnZtEKFDyfvNO5EUywhy3f/EiLOBO8SWqKj4BMBTO0QwnybaPE5MVF00Fhz+VA4+h/iI40Dkrrtq70dGg==
react-native-touch-id@^4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/react-native-touch-id/-/react-native-touch-id-4.4.1.tgz#8b1bb2d04c30bac36bb9696d2d723e719c4a8b08"
integrity sha512-1jTl8fC+0fxvqegy/XXTyo6vMvPhjzkoDdaqoYZx0OH8AT250NuXnNPyKktvigIcys3+2acciqOeaCall7lrvg==
react-native-vector-icons@^8.0.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-8.1.0.tgz"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment