├── .babelrc ├── .buckconfig ├── .flowconfig ├── .gitignore ├── .watchmanconfig ├── Art ├── auth_pref.png ├── bio_metric.png ├── error_handling.png ├── home.png ├── inavlid_tempt.png ├── login.png ├── max_attempts.png └── sucess.png ├── LICENSE ├── README.md ├── android ├── .idea │ ├── .name │ ├── compiler.xml │ ├── copyright │ │ ├── Hitesh.xml │ │ └── profiles_settings.xml │ ├── gradle.xml │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── libraries │ │ ├── android_jsc_r174650.xml │ │ ├── animated_vector_drawable_25_3_1.xml │ │ ├── appcompat_v7_25_3_1.xml │ │ ├── bolts_tasks_1_4_0.xml │ │ ├── cardview_v7_25_3_1.xml │ │ ├── drawee_1_0_1.xml │ │ ├── fbcore_1_0_1.xml │ │ ├── fresco_1_0_1.xml │ │ ├── imagepipeline_1_0_1.xml │ │ ├── imagepipeline_base_1_0_1.xml │ │ ├── imagepipeline_okhttp3_1_0_1.xml │ │ ├── javax_inject_1.xml │ │ ├── jsr305_3_0_0.xml │ │ ├── okhttp_3_6_0.xml │ │ ├── okhttp_urlconnection_3_6_0.xml │ │ ├── okio_1_13_0.xml │ │ ├── react_native_0_46_1.xml │ │ ├── soloader_0_1_0.xml │ │ ├── staticlayout_proxy_1_0.xml │ │ ├── support_annotations_25_3_1.xml │ │ ├── support_compat_25_3_1.xml │ │ ├── support_core_ui_25_3_1.xml │ │ ├── support_core_utils_25_3_1.xml │ │ ├── support_fragment_25_3_1.xml │ │ ├── support_media_compat_25_3_1.xml │ │ ├── support_v13_25_3_1.xml │ │ ├── support_v4_25_3_1.xml │ │ ├── support_vector_drawable_25_3_1.xml │ │ └── textlayoutbuilder_1_0_0.xml │ ├── misc.xml │ ├── modules.xml │ ├── runConfigurations.xml │ └── workspace.xml ├── app │ ├── BUCK │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── ic_launcher-web.png │ │ ├── java │ │ └── com │ │ │ └── aproject │ │ │ ├── MainActivity.java │ │ │ ├── MainApplication.java │ │ │ ├── domain │ │ │ └── storage │ │ │ │ ├── Decrypter.java │ │ │ │ └── Encryptor.java │ │ │ ├── modules │ │ │ ├── BioMetricReactPackage.java │ │ │ └── BiometricModule.java │ │ │ ├── utils │ │ │ ├── AppConstants.java │ │ │ ├── PreferenceHelper.java │ │ │ └── RootUtil.java │ │ │ └── view │ │ │ └── Fragments │ │ │ ├── FingerprintAuthenticationDialogFragment.java │ │ │ └── FingerprintUiHelper.java │ │ └── res │ │ ├── drawable-hdpi │ │ ├── ic_fp_40px.png │ │ └── tile.9.png │ │ ├── drawable-mdpi │ │ └── ic_fp_40px.png │ │ ├── drawable-nodpi │ │ └── android_robot.png │ │ ├── drawable-xhdpi │ │ └── ic_fp_40px.png │ │ ├── drawable-xxhdpi │ │ └── ic_fp_40px.png │ │ ├── drawable-xxxhdpi │ │ └── ic_fp_40px.png │ │ ├── drawable │ │ ├── card.xml │ │ ├── ic_fingerprint_error.xml │ │ └── ic_fingerprint_success.xml │ │ ├── layout │ │ ├── fingerprint_dialog_container.xml │ │ └── fingerprint_dialog_content.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keystores │ ├── BUCK │ └── debug.keystore.properties └── settings.gradle ├── app.json ├── index.android.js ├── index.ios.js ├── ios ├── AProject-tvOS │ └── Info.plist ├── AProject-tvOSTests │ └── Info.plist ├── AProject.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── AProject-tvOS.xcscheme │ │ └── AProject.xcscheme ├── AProject │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ └── main.m └── AProjectTests │ ├── AProjectTests.m │ └── Info.plist ├── package-lock.json ├── package.json └── src ├── BioMetric.js ├── Style.js ├── assets ├── fonts │ └── roboto │ │ ├── Roboto-Bold.eot │ │ ├── Roboto-Bold.ttf │ │ ├── Roboto-Bold.woff │ │ ├── Roboto-Bold.woff2 │ │ ├── Roboto-Light.eot │ │ ├── Roboto-Light.ttf │ │ ├── Roboto-Light.woff │ │ ├── Roboto-Light.woff2 │ │ ├── Roboto-Medium.eot │ │ ├── Roboto-Medium.ttf │ │ ├── Roboto-Medium.woff │ │ ├── Roboto-Medium.woff2 │ │ ├── Roboto-Regular.eot │ │ ├── Roboto-Regular.ttf │ │ ├── Roboto-Regular.woff │ │ ├── Roboto-Regular.woff2 │ │ ├── Roboto-Thin.eot │ │ ├── Roboto-Thin.ttf │ │ ├── Roboto-Thin.woff │ │ └── Roboto-Thin.woff2 └── img │ ├── app_icon.png │ ├── back_arrow.png │ ├── header.jpeg │ ├── header.jpg │ ├── login.jpeg │ ├── menu.png │ └── splash.jpeg ├── navigation └── Route.js └── scene ├── AboutPage.js ├── HomePage.js ├── LoginPage.js └── Splash.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native"] 3 | } 4 | -------------------------------------------------------------------------------- /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | .*/Libraries/react-native/ReactNative.js 16 | 17 | [include] 18 | 19 | [libs] 20 | node_modules/react-native/Libraries/react-native/react-native-interface.js 21 | node_modules/react-native/flow 22 | flow/ 23 | 24 | [options] 25 | emoji=true 26 | 27 | module.system=haste 28 | 29 | munge_underscores=true 30 | 31 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 32 | 33 | suppress_type=$FlowIssue 34 | suppress_type=$FlowFixMe 35 | suppress_type=$FixMe 36 | 37 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-7]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 38 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-7]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 39 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 40 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 41 | 42 | unsafe.enable_getters_and_setters=true 43 | 44 | [version] 45 | ^0.47.0 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | node_modules/ 16 | 17 | # Gradle files 18 | .gradle/ 19 | build/ 20 | 21 | # Local configuration file (sdk path, etc) 22 | local.properties 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Log Files 28 | *.log 29 | 30 | # Android Studio Navigation editor temp files 31 | .navigation/ 32 | 33 | # Android Studio captures folder 34 | captures/ 35 | 36 | # Intellij 37 | *.iml 38 | .idea/workspace.xml 39 | .idea/tasks.xml 40 | .idea/gradle.xml 41 | .idea/dictionaries 42 | .idea/libraries 43 | 44 | # Keystore files 45 | *.jks 46 | 47 | # External native build folder generated in Android Studio 2.2 and later 48 | .externalNativeBuild 49 | 50 | # Google Services (e.g. APIs or Firebase) 51 | google-services.json 52 | 53 | # Freeline 54 | freeline.py 55 | freeline/ 56 | freeline_project_description.json 57 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /Art/auth_pref.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/Art/auth_pref.png -------------------------------------------------------------------------------- /Art/bio_metric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/Art/bio_metric.png -------------------------------------------------------------------------------- /Art/error_handling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/Art/error_handling.png -------------------------------------------------------------------------------- /Art/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/Art/home.png -------------------------------------------------------------------------------- /Art/inavlid_tempt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/Art/inavlid_tempt.png -------------------------------------------------------------------------------- /Art/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/Art/login.png -------------------------------------------------------------------------------- /Art/max_attempts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/Art/max_attempts.png -------------------------------------------------------------------------------- /Art/sucess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/Art/sucess.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Hitesh Sahu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FingerPrint-Authentication-With-React-Native-Android 2 | 3 | This React Native project uses of Finger Print Sensor to authenticated user in Android Devices. Uses FingerprintManagerCompat to give backword compatibility for Android <23. 4 | 5 | ## Features 6 | - Uses FingerprintManagerCompat to Supports Older Version of Android(API<23) 7 | - Native Module to use fingerprint Sensor 8 | - Error Handling in the case of invalid Finger Prints, Unregistered FingerPrint, Lock is not enabled and not supporting Hardware. 9 | - After exceeding max finger print attempts, the plugin disables biometric authentication feature. 10 | - Disables biometric authentication can be enabled from Home Screen after successful login 11 | - User Credentials are Encrypted with AES algorithm and stored in file system while key is stored in Android Keystore 12 | - Check for Rooted device and flush stored credentials 13 | 14 | ## Screen Shots 15 | 16 | ### FingerPrint Authentication 17 | 18 | ![Alt text](https://github.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Aandroid/blob/master/Art/login.png "Login screen") ![Alt text](https://github.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Aandroid/blob/master/Art/auth_pref.png "Auth screen") ![Alt text](https://github.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Aandroid/blob/master/Art/bio_metric.png "FingerPrint screen") ![Alt text](https://github.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Aandroid/blob/master/Art/sucess.png "FingerPrint Success") ![Alt text](https://github.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Aandroid/blob/master/Art/home.png "FingerPrint Home") 19 | 20 | ### Error Handling 21 | 22 | ![Alt text](https://github.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Aandroid/blob/master/Art/error_handling.png "Error screen") 23 | ![Alt text](https://github.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Aandroid/blob/master/Art/inavlid_tempt.png "Error screen 2") ![Alt text](https://github.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Aandroid/blob/master/Art/max_attempts.png "Error screen 3") 24 | 25 | 26 | ## NPM Commands 27 | 28 | #### Install react native 29 | 30 | npm install -g react-native-cli 31 | 32 | #### Start server 33 | 34 | react-native start 35 | 36 | #### For Route component install react-native-deprecated-custom-components 37 | 38 | npm install react-native-deprecated-custom-components --save 39 | 40 | #### Build and install App on Emulator/Device 41 | 42 | react-native run-android 43 | 44 | #### To run app in real device 45 | 46 | adb reverse tcp:8081 tcp:8081 47 | 48 | ## Legal Notice 49 | 50 | 51 | MIT License 52 | 53 | Copyright (c) 2017 Hitesh Sahu (hiteshsahu.com) 54 | Written by Hitesh Sahu 55 | 56 | Permission is hereby granted, free of charge, to any person obtaining a copy 57 | of this software and associated documentation files (the "Software"), to deal 58 | in the Software without restriction, including without limitation the rights 59 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 60 | copies of the Software, and to permit persons to whom the Software is 61 | furnished to do so, subject to the following conditions: 62 | 63 | The above copyright notice and this permission notice shall be included in all 64 | copies or substantial portions of the Software. 65 | 66 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 67 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 68 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 69 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 70 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 71 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 72 | SOFTWARE. 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /android/.idea/.name: -------------------------------------------------------------------------------- 1 | AProject -------------------------------------------------------------------------------- /android/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /android/.idea/copyright/Hitesh.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /android/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /android/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /android/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /android/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /android/.idea/libraries/android_jsc_r174650.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/.idea/libraries/animated_vector_drawable_25_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /android/.idea/libraries/appcompat_v7_25_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/.idea/libraries/bolts_tasks_1_4_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/.idea/libraries/cardview_v7_25_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /android/.idea/libraries/drawee_1_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android/.idea/libraries/fbcore_1_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /android/.idea/libraries/fresco_1_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android/.idea/libraries/imagepipeline_1_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android/.idea/libraries/imagepipeline_base_1_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /android/.idea/libraries/imagepipeline_okhttp3_1_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android/.idea/libraries/javax_inject_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/.idea/libraries/jsr305_3_0_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/.idea/libraries/okhttp_3_6_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/.idea/libraries/okhttp_urlconnection_3_6_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/.idea/libraries/okio_1_13_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/.idea/libraries/react_native_0_46_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/.idea/libraries/soloader_0_1_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android/.idea/libraries/staticlayout_proxy_1_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/.idea/libraries/support_annotations_25_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android/.idea/libraries/support_compat_25_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/.idea/libraries/support_core_ui_25_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/.idea/libraries/support_core_utils_25_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/.idea/libraries/support_fragment_25_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/.idea/libraries/support_media_compat_25_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/.idea/libraries/support_v13_25_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /android/.idea/libraries/support_v4_25_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/.idea/libraries/support_vector_drawable_25_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /android/.idea/libraries/textlayoutbuilder_1_0_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /android/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /android/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | lib_deps = [] 12 | 13 | for jarfile in glob(['libs/*.jar']): 14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] 15 | lib_deps.append(':' + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | 21 | for aarfile in glob(['libs/*.aar']): 22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] 23 | lib_deps.append(':' + name) 24 | android_prebuilt_aar( 25 | name = name, 26 | aar = aarfile, 27 | ) 28 | 29 | android_library( 30 | name = "all-libs", 31 | exported_deps = lib_deps, 32 | ) 33 | 34 | android_library( 35 | name = "app-code", 36 | srcs = glob([ 37 | "src/main/java/**/*.java", 38 | ]), 39 | deps = [ 40 | ":all-libs", 41 | ":build_config", 42 | ":res", 43 | ], 44 | ) 45 | 46 | android_build_config( 47 | name = "build_config", 48 | package = "com.aproject", 49 | ) 50 | 51 | android_resource( 52 | name = "res", 53 | package = "com.aproject", 54 | res = "src/main/res", 55 | ) 56 | 57 | android_binary( 58 | name = "app", 59 | keystore = "//android/keystores:debug", 60 | manifest = "src/main/AndroidManifest.xml", 61 | package_type = "debug", 62 | deps = [ 63 | ":app-code", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | /* 4 | * 5 | * Copyright (C) 2017 HiteshSahu.com- All Rights Reserved 6 | * Unauthorized copying of this file, via any medium is strictly prohibited 7 | * Proprietary and confidential. 8 | * Written by Hitesh Sahu , 2017. 9 | * 10 | */ 11 | 12 | import com.android.build.OutputFile 13 | 14 | /** 15 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 16 | * and bundleReleaseJsAndAssets). 17 | * These basically call `react-native bundle` with the correct arguments during the Android build 18 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 19 | * bundle directly from the development server. Below you can see all the possible configurations 20 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 21 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 22 | * 23 | * project.ext.react = [ 24 | * // the name of the generated asset file containing your JS bundle 25 | * bundleAssetName: "index.android.bundle", 26 | * 27 | * // the entry file for bundle generation 28 | * entryFile: "index.android.js", 29 | * 30 | * // whether to bundle JS and assets in debug mode 31 | * bundleInDebug: false, 32 | * 33 | * // whether to bundle JS and assets in release mode 34 | * bundleInRelease: true, 35 | * 36 | * // whether to bundle JS and assets in another build variant (if configured). 37 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 38 | * // The configuration property can be in the following formats 39 | * // 'bundleIn${productFlavor}${buildType}' 40 | * // 'bundleIn${buildType}' 41 | * // bundleInFreeDebug: true, 42 | * // bundleInPaidRelease: true, 43 | * // bundleInBeta: true, 44 | * 45 | * // whether to disable dev mode in custom build variants (by default only disabled in release) 46 | * // for example: to disable dev mode in the staging build type (if configured) 47 | * devDisabledInStaging: true, 48 | * // The configuration property can be in the following formats 49 | * // 'devDisabledIn${productFlavor}${buildType}' 50 | * // 'devDisabledIn${buildType}' 51 | * 52 | * // the root of your project, i.e. where "package.json" lives 53 | * root: "../../", 54 | * 55 | * // where to put the JS bundle asset in debug mode 56 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 57 | * 58 | * // where to put the JS bundle asset in release mode 59 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 60 | * 61 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 62 | * // require('./image.png')), in debug mode 63 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 64 | * 65 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 66 | * // require('./image.png')), in release mode 67 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 68 | * 69 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 70 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 71 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 72 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 73 | * // for example, you might want to remove it from here. 74 | * inputExcludes: ["android/**", "ios/**"], 75 | * 76 | * // override which node gets called and with what additional arguments 77 | * nodeExecutableAndArgs: ["node"], 78 | * 79 | * // supply additional arguments to the packager 80 | * extraPackagerArgs: [] 81 | * ] 82 | */ 83 | 84 | apply from: "../../node_modules/react-native/react.gradle" 85 | 86 | /** 87 | * Set this to true to create two separate APKs instead of one: 88 | * - An APK that only works on ARM devices 89 | * - An APK that only works on x86 devices 90 | * The advantage is the size of the APK is reduced by about 4MB. 91 | * Upload all the APKs to the Play Store and people will download 92 | * the correct one based on the CPU architecture of their device. 93 | */ 94 | def enableSeparateBuildPerCPUArchitecture = false 95 | 96 | /** 97 | * Run Proguard to shrink the Java bytecode in release builds. 98 | */ 99 | def enableProguardInReleaseBuilds = false 100 | 101 | android { 102 | compileSdkVersion 24 103 | buildToolsVersion "25.0.3" 104 | 105 | defaultConfig { 106 | applicationId "com.aproject" 107 | minSdkVersion 19 108 | targetSdkVersion 25 109 | versionCode 1 110 | versionName "1.0" 111 | ndk { 112 | abiFilters "armeabi-v7a", "x86" 113 | } 114 | } 115 | splits { 116 | abi { 117 | reset() 118 | enable enableSeparateBuildPerCPUArchitecture 119 | universalApk false // If true, also generate a universal APK 120 | include "armeabi-v7a", "x86" 121 | } 122 | } 123 | buildTypes { 124 | release { 125 | minifyEnabled enableProguardInReleaseBuilds 126 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 127 | } 128 | } 129 | // applicationVariants are e.g. debug, release 130 | applicationVariants.all { variant -> 131 | variant.outputs.each { output -> 132 | // For each separate APK per architecture, set a unique version code as described here: 133 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 134 | def versionCodes = ["armeabi-v7a": 1, "x86": 2] 135 | def abi = output.getFilter(OutputFile.ABI) 136 | if (abi != null) { // null for the universal-debug, universal-release variants 137 | output.versionCodeOverride = 138 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 139 | } 140 | } 141 | } 142 | } 143 | 144 | dependencies { 145 | compile fileTree(dir: "libs", include: ["*.jar"]) 146 | compile "com.android.support:support-v4:25.3.1" 147 | compile "com.android.support:support-v13:25.3.1" 148 | compile "com.android.support:cardview-v7:25.3.1" 149 | compile "com.android.support:appcompat-v7:25.3.1" 150 | compile "com.facebook.react:react-native:+" // From node_modules 151 | } 152 | 153 | // Run this once to be able to run the application with BUCK 154 | // puts all compile dependencies into folder libs for BUCK to use 155 | task copyDownloadableDepsToLibs(type: Copy) { 156 | from configurations.compile 157 | into 'libs' 158 | } 159 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 30 | 31 | # Do not strip any method/class that is annotated with @DoNotStrip 32 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 33 | -keep @com.facebook.common.internal.DoNotStrip class * 34 | -keepclassmembers class * { 35 | @com.facebook.proguard.annotations.DoNotStrip *; 36 | @com.facebook.common.internal.DoNotStrip *; 37 | } 38 | 39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 40 | void set*(***); 41 | *** get*(); 42 | } 43 | 44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 46 | -keepclassmembers,includedescriptorclasses class * { native ; } 47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 50 | 51 | -dontwarn com.facebook.react.** 52 | 53 | # TextLayoutBuilder uses a non-public Android constructor within StaticLayout. 54 | # See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. 55 | -dontwarn android.text.StaticLayout 56 | 57 | # okhttp 58 | 59 | -keepattributes Signature 60 | -keepattributes *Annotation* 61 | -keep class okhttp3.** { *; } 62 | -keep interface okhttp3.** { *; } 63 | -dontwarn okhttp3.** 64 | 65 | # okio 66 | 67 | -keep class sun.misc.Unsafe { *; } 68 | -dontwarn java.nio.file.* 69 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 70 | -dontwarn okio.** 71 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 31 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /android/app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/android/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /android/app/src/main/java/com/aproject/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017 HiteshSahu.com- All Rights Reserved 4 | * Unauthorized copying of this file, via any medium is strictly prohibited 5 | * Proprietary and confidential. 6 | * Written by Hitesh Sahu , 2017. 7 | * 8 | */ 9 | 10 | package com.aproject; 11 | 12 | import com.facebook.react.ReactActivity; 13 | 14 | public class MainActivity extends ReactActivity { 15 | private static final String TAG = MainActivity.class.getSimpleName(); 16 | 17 | /** 18 | * Returns the name of the main component registered from JavaScript. 19 | * This is used to schedule rendering of the component. 20 | */ 21 | @Override 22 | protected String getMainComponentName() { 23 | return "AProject"; 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/aproject/MainApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017 HiteshSahu.com- All Rights Reserved 4 | * Unauthorized copying of this file, via any medium is strictly prohibited 5 | * Proprietary and confidential. 6 | * Written by Hitesh Sahu , 2017. 7 | * 8 | */ 9 | 10 | package com.aproject; 11 | 12 | import android.app.Application; 13 | 14 | import com.aproject.modules.BioMetricReactPackage; 15 | import com.facebook.react.ReactApplication; 16 | import com.facebook.react.ReactNativeHost; 17 | import com.facebook.react.ReactPackage; 18 | import com.facebook.react.shell.MainReactPackage; 19 | import com.facebook.soloader.SoLoader; 20 | 21 | import java.util.Arrays; 22 | import java.util.List; 23 | 24 | public class MainApplication extends Application implements ReactApplication { 25 | 26 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 27 | @Override 28 | public boolean getUseDeveloperSupport() { 29 | return BuildConfig.DEBUG; 30 | } 31 | 32 | @Override 33 | protected List getPackages() { 34 | return Arrays.asList( 35 | new MainReactPackage(), 36 | new BioMetricReactPackage()); // <-- Add Biometric 37 | } 38 | }; 39 | 40 | @Override 41 | public ReactNativeHost getReactNativeHost() { 42 | return mReactNativeHost; 43 | } 44 | 45 | @Override 46 | public void onCreate() { 47 | super.onCreate(); 48 | SoLoader.init(this, /* native exopackage */ false); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/aproject/domain/storage/Decrypter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017 HiteshSahu.com- All Rights Reserved 4 | * Unauthorized copying of this file, via any medium is strictly prohibited 5 | * Proprietary and confidential. 6 | * Written by Hitesh Sahu , 2017. 7 | * 8 | */ 9 | 10 | package com.aproject.domain.storage; 11 | 12 | import android.content.Context; 13 | import android.util.Base64; 14 | import android.util.Log; 15 | 16 | import com.aproject.utils.PreferenceHelper; 17 | 18 | import java.io.IOException; 19 | import java.security.InvalidAlgorithmParameterException; 20 | import java.security.InvalidKeyException; 21 | import java.security.KeyStore; 22 | import java.security.KeyStoreException; 23 | import java.security.NoSuchAlgorithmException; 24 | import java.security.NoSuchProviderException; 25 | import java.security.UnrecoverableEntryException; 26 | import java.security.cert.CertificateException; 27 | 28 | import javax.crypto.BadPaddingException; 29 | import javax.crypto.Cipher; 30 | import javax.crypto.IllegalBlockSizeException; 31 | import javax.crypto.NoSuchPaddingException; 32 | import javax.crypto.SecretKey; 33 | import javax.crypto.spec.GCMParameterSpec; 34 | 35 | /** 36 | * _____ _____ _ 37 | * | __ \ / ____| | | 38 | * | | | | ___| | _ __ _ _ _ __ | |_ ___ _ __ 39 | * | | | |/ _ \ | | '__| | | | '_ \| __/ _ \| '__| 40 | * | |__| | __/ |____| | | |_| | |_) | || (_) | | 41 | * |_____/ \___|\_____|_| \__, | .__/ \__\___/|_| 42 | * __/ | | 43 | * |___/|_| 44 | */ 45 | public final class Decrypter { 46 | 47 | private static final String TRANSFORMATION = "AES/GCM/NoPadding"; 48 | private static final String ANDROID_KEY_STORE = "AndroidKeyStore"; 49 | 50 | private KeyStore keyStore; 51 | 52 | public Decrypter() throws CertificateException, NoSuchAlgorithmException, KeyStoreException, 53 | IOException { 54 | initKeyStore(); 55 | } 56 | 57 | private void initKeyStore() throws KeyStoreException, CertificateException, 58 | NoSuchAlgorithmException, IOException { 59 | keyStore = KeyStore.getInstance(ANDROID_KEY_STORE); 60 | keyStore.load(null); 61 | } 62 | 63 | public String decrypt(final String alias, final byte[] encryptedData, Context appContext) 64 | throws UnrecoverableEntryException, NoSuchAlgorithmException, KeyStoreException, 65 | NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IOException, 66 | BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException { 67 | 68 | final Cipher cipher = Cipher.getInstance(TRANSFORMATION); 69 | String IV = PreferenceHelper.getPrefernceHelperInstace().getString(appContext, "IV", ""); 70 | 71 | if (null != IV && !IV.isEmpty()) { 72 | byte[] encryptionIv = Base64.decode(IV, Base64.DEFAULT); 73 | Log.e("Decrypter", "IV : " + IV + " IV size " + encryptionIv.length); 74 | final GCMParameterSpec spec = new GCMParameterSpec(128, encryptionIv); 75 | cipher.init(Cipher.DECRYPT_MODE, getSecretKey(alias), spec); 76 | return new String(cipher.doFinal(encryptedData), "UTF-8"); 77 | } else { 78 | return "{}"; 79 | } 80 | } 81 | 82 | private SecretKey getSecretKey(final String alias) throws NoSuchAlgorithmException, 83 | UnrecoverableEntryException, KeyStoreException { 84 | return ((KeyStore.SecretKeyEntry) keyStore.getEntry(alias, null)).getSecretKey(); 85 | } 86 | } -------------------------------------------------------------------------------- /android/app/src/main/java/com/aproject/domain/storage/Encryptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017 HiteshSahu.com- All Rights Reserved 4 | * Unauthorized copying of this file, via any medium is strictly prohibited 5 | * Proprietary and confidential. 6 | * Written by Hitesh Sahu , 2017. 7 | * 8 | */ 9 | 10 | package com.aproject.domain.storage; 11 | 12 | import android.content.Context; 13 | import android.security.keystore.KeyGenParameterSpec; 14 | import android.security.keystore.KeyProperties; 15 | import android.support.annotation.NonNull; 16 | import android.util.Base64; 17 | import android.util.Log; 18 | 19 | import com.aproject.utils.PreferenceHelper; 20 | 21 | import java.io.IOException; 22 | import java.security.InvalidAlgorithmParameterException; 23 | import java.security.InvalidKeyException; 24 | import java.security.KeyStoreException; 25 | import java.security.NoSuchAlgorithmException; 26 | import java.security.NoSuchProviderException; 27 | import java.security.SignatureException; 28 | import java.security.UnrecoverableEntryException; 29 | 30 | import javax.crypto.BadPaddingException; 31 | import javax.crypto.Cipher; 32 | import javax.crypto.IllegalBlockSizeException; 33 | import javax.crypto.KeyGenerator; 34 | import javax.crypto.NoSuchPaddingException; 35 | import javax.crypto.SecretKey; 36 | 37 | /** 38 | * ______ _____ _ 39 | * | ____| / ____| | | 40 | * | |__ _ __ | | _ __ _ _ _ __ | |_ ___ _ __ 41 | * | __| | '_ \| | | '__| | | | '_ \| __/ _ \| '__| 42 | * | |____| | | | |____| | | |_| | |_) | || (_) | | 43 | * |______|_| |_|\_____|_| \__, | .__/ \__\___/|_| 44 | * __/ | | 45 | * |___/|_| 46 | */ 47 | public final class Encryptor { 48 | 49 | private static final String TRANSFORMATION = "AES/GCM/NoPadding"; 50 | private static final String ANDROID_KEY_STORE = "AndroidKeyStore"; 51 | 52 | //private byte[] encryption; 53 | // private byte[] iv; 54 | 55 | public Encryptor() { 56 | } 57 | 58 | public byte[] encrypt(final String alias, final String textToEncrypt, Context appContext) 59 | throws UnrecoverableEntryException, NoSuchAlgorithmException, KeyStoreException, 60 | NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IOException, 61 | InvalidAlgorithmParameterException, SignatureException, BadPaddingException, 62 | IllegalBlockSizeException { 63 | 64 | final Cipher cipher = Cipher.getInstance(TRANSFORMATION); 65 | cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(alias)); 66 | 67 | String IV = Base64.encodeToString(cipher.getIV(), Base64.DEFAULT); 68 | Log.e("MILK", "IV : " + IV + " IV size " + IV.length()); 69 | 70 | PreferenceHelper.getPrefernceHelperInstace().setString(appContext, "IV", IV); 71 | // 72 | // iv = cipher.getIV(); 73 | 74 | return (/*encryption = */cipher.doFinal(textToEncrypt.getBytes("UTF-8"))); 75 | } 76 | 77 | @NonNull 78 | private SecretKey getSecretKey(final String alias) throws NoSuchAlgorithmException, 79 | NoSuchProviderException, InvalidAlgorithmParameterException { 80 | 81 | final KeyGenerator keyGenerator = KeyGenerator 82 | .getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE); 83 | 84 | keyGenerator.init(new KeyGenParameterSpec.Builder(alias, 85 | KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) 86 | .setBlockModes(KeyProperties.BLOCK_MODE_GCM) 87 | .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) 88 | .build()); 89 | 90 | return keyGenerator.generateKey(); 91 | } 92 | 93 | // public byte[] getEncryption() { 94 | // return encryption; 95 | // } 96 | 97 | // public byte[] getIv() { 98 | // return iv; 99 | // } 100 | } -------------------------------------------------------------------------------- /android/app/src/main/java/com/aproject/modules/BioMetricReactPackage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017 HiteshSahu.com- All Rights Reserved 4 | * Unauthorized copying of this file, via any medium is strictly prohibited 5 | * Proprietary and confidential. 6 | * Written by Hitesh Sahu , 2017. 7 | * 8 | */ 9 | 10 | package com.aproject.modules; 11 | 12 | import com.facebook.react.ReactPackage; 13 | import com.facebook.react.bridge.JavaScriptModule; 14 | import com.facebook.react.bridge.NativeModule; 15 | import com.facebook.react.bridge.ReactApplicationContext; 16 | import com.facebook.react.uimanager.ViewManager; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.List; 21 | 22 | public class BioMetricReactPackage implements ReactPackage { 23 | 24 | @Override 25 | public List> createJSModules() { 26 | return Collections.emptyList(); 27 | } 28 | 29 | @Override 30 | public List createViewManagers(ReactApplicationContext reactContext) { 31 | return Collections.emptyList(); 32 | } 33 | 34 | @Override 35 | public List createNativeModules( 36 | ReactApplicationContext reactContext) { 37 | List modules = new ArrayList<>(); 38 | modules.add(new BiometricModule(reactContext)); 39 | return modules; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /android/app/src/main/java/com/aproject/modules/BiometricModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017 HiteshSahu.com- All Rights Reserved 4 | * Unauthorized copying of this file, via any medium is strictly prohibited 5 | * Proprietary and confidential. 6 | * Written by Hitesh Sahu , 2017. 7 | * 8 | */ 9 | 10 | package com.aproject.modules; 11 | 12 | /** 13 | * Created by Hitesh.Sahu on 7/12/2017. 14 | */ 15 | 16 | import android.Manifest; 17 | import android.annotation.TargetApi; 18 | import android.app.Activity; 19 | import android.app.KeyguardManager; 20 | import android.content.Context; 21 | import android.content.SharedPreferences; 22 | import android.content.pm.PackageManager; 23 | import android.hardware.fingerprint.FingerprintManager; 24 | import android.os.Build; 25 | import android.security.keystore.KeyGenParameterSpec; 26 | import android.security.keystore.KeyPermanentlyInvalidatedException; 27 | import android.security.keystore.KeyProperties; 28 | import android.support.annotation.Nullable; 29 | import android.support.v4.app.ActivityCompat; 30 | import android.support.v4.hardware.fingerprint.FingerprintManagerCompat; 31 | import android.util.Base64; 32 | import android.util.Log; 33 | import android.widget.Toast; 34 | 35 | import com.aproject.domain.storage.Decrypter; 36 | import com.aproject.domain.storage.Encryptor; 37 | import com.aproject.utils.AppConstants; 38 | import com.aproject.utils.PreferenceHelper; 39 | import com.aproject.utils.RootUtil; 40 | import com.aproject.view.Fragments.FingerprintAuthenticationDialogFragment; 41 | import com.facebook.react.bridge.Callback; 42 | import com.facebook.react.bridge.ReactApplicationContext; 43 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 44 | import com.facebook.react.bridge.ReactMethod; 45 | 46 | import org.json.JSONException; 47 | import org.json.JSONObject; 48 | 49 | import java.io.BufferedReader; 50 | import java.io.File; 51 | import java.io.FileNotFoundException; 52 | import java.io.IOException; 53 | import java.io.InputStream; 54 | import java.io.InputStreamReader; 55 | import java.io.OutputStreamWriter; 56 | import java.security.InvalidAlgorithmParameterException; 57 | import java.security.InvalidKeyException; 58 | import java.security.KeyStore; 59 | import java.security.KeyStoreException; 60 | import java.security.NoSuchAlgorithmException; 61 | import java.security.NoSuchProviderException; 62 | import java.security.SignatureException; 63 | import java.security.UnrecoverableEntryException; 64 | import java.security.UnrecoverableKeyException; 65 | import java.security.cert.CertificateException; 66 | 67 | import javax.crypto.BadPaddingException; 68 | import javax.crypto.Cipher; 69 | import javax.crypto.IllegalBlockSizeException; 70 | import javax.crypto.KeyGenerator; 71 | import javax.crypto.NoSuchPaddingException; 72 | import javax.crypto.SecretKey; 73 | 74 | import static com.aproject.utils.AppConstants.DEFAULT_KEY_NAME; 75 | import static com.aproject.utils.AppConstants.DIALOG_FRAGMENT_TAG; 76 | import static com.aproject.utils.PreferenceHelper.getPrefernceHelperInstace; 77 | 78 | public class BiometricModule extends ReactContextBaseJavaModule { 79 | private static final String TAG = BiometricModule.class.getSimpleName(); 80 | private static final String BIOMETRIC_MODULE_NAME = "FingerPrintAndroid"; 81 | private static final String SAMPLE_ALIAS = "MYALIAS"; 82 | private KeyStore mKeyStore; 83 | private KeyGenerator mKeyGenerator; 84 | private SharedPreferences mSharedPreferences; 85 | private Context AppContext; 86 | private Activity activityContext; 87 | private KeyguardManager keyguardManager; 88 | private FingerprintManagerCompat fingerprintManager; 89 | private Cipher defaultCipher; 90 | private Cipher cipherNotInvalidated; 91 | private Callback errorCallback; 92 | private Callback successCallback; 93 | private Encryptor encryptor; 94 | private Decrypter decryptor; 95 | private JSONObject jsonObject; 96 | 97 | public BiometricModule(ReactApplicationContext reactContext) { 98 | super(reactContext); 99 | this.AppContext = reactContext; 100 | 101 | encryptor = new Encryptor(); 102 | 103 | try { 104 | decryptor = new Decrypter(); 105 | } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | 106 | IOException e) { 107 | e.printStackTrace(); 108 | } 109 | } 110 | 111 | @Override 112 | public String getName() { 113 | return BIOMETRIC_MODULE_NAME; 114 | } 115 | 116 | @ReactMethod 117 | public void storeUserSettings(String key, boolean value) { 118 | 119 | if (key.equalsIgnoreCase(AppConstants.LOCK_FINGERPRINT)) { 120 | Toast.makeText(AppContext, "FingerPrint is Unlocked \n After restarting the application you will be able to use Fingerprints", Toast.LENGTH_SHORT).show(); 121 | } 122 | getPrefernceHelperInstace().setBoolean(AppContext, key, value); 123 | } 124 | 125 | private boolean isSensorAvialable() { 126 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 127 | return ActivityCompat.checkSelfPermission(AppContext, Manifest.permission.USE_FINGERPRINT) == PackageManager.PERMISSION_GRANTED && 128 | AppContext.getSystemService(FingerprintManager.class).isHardwareDetected(); 129 | } else { 130 | return FingerprintManagerCompat.from(AppContext).isHardwareDetected(); 131 | } 132 | } 133 | 134 | @ReactMethod 135 | public void isFingerPrintSupported(Callback isSUpportedHw) { 136 | isSUpportedHw.invoke(isSensorAvialable()); 137 | } 138 | 139 | 140 | @ReactMethod 141 | public void isDeviceRooted(Callback isRooted) { 142 | isRooted.invoke(RootUtil.isDeviceRooted()); 143 | } 144 | 145 | @ReactMethod 146 | public void exitApp() { 147 | System.exit(0); 148 | } 149 | 150 | @ReactMethod 151 | public void retrieveUserSettings(String key, Callback successCallbackUserSettings) { 152 | 153 | if (key.equalsIgnoreCase(AppConstants.LOCK_FINGERPRINT)) { 154 | successCallbackUserSettings.invoke(PreferenceHelper.getPrefernceHelperInstace().getBoolean(AppContext, 155 | key, true)); 156 | } else { 157 | successCallbackUserSettings.invoke(PreferenceHelper.getPrefernceHelperInstace().getBoolean(AppContext, 158 | key, false)); 159 | } 160 | 161 | } 162 | 163 | 164 | public void storeCredentials() { 165 | //Encrypt JSON 166 | String encryptedJSON = encryptText(jsonObject.toString()); 167 | Log.e(TAG, "encryptText : " + encryptedJSON); 168 | 169 | //Store data in Internal file system 170 | writeToFile(encryptedJSON); 171 | } 172 | 173 | @ReactMethod 174 | public void retrieveCredentials(Callback errorCallbackCred, Callback successCallbackCred) { 175 | 176 | //Read encrypted JSON from file system 177 | String encryptedJSONFromFile = readFromFile(); 178 | 179 | //decrypt data from file system 180 | String decryptedJSON = decryptText(encryptedJSONFromFile); 181 | 182 | if (null != decryptedJSON) { 183 | try { 184 | JSONObject decryptedJSONObject = new JSONObject(decryptedJSON); 185 | successCallbackCred.invoke(decryptedJSONObject.toString()); 186 | } catch (JSONException e) { 187 | e.printStackTrace(); 188 | errorCallbackCred.invoke("Failed to retrieve Credentials"); 189 | } 190 | } else { 191 | errorCallbackCred.invoke("Failed to retrieve Credentials"); 192 | } 193 | } 194 | 195 | @ReactMethod 196 | public void authenticateUser(String userName, String passWord, Callback errorCallback, 197 | Callback successCallback) { 198 | activityContext = getCurrentActivity(); 199 | this.successCallback = successCallback; 200 | this.errorCallback = errorCallback; 201 | String errorMessage = null; 202 | 203 | //Check if device is not Rooted 204 | if (RootUtil.isDeviceRooted()) { 205 | 206 | fingerprintManager = FingerprintManagerCompat.from(AppContext); 207 | keyguardManager = (KeyguardManager) AppContext.getSystemService(Context.KEYGUARD_SERVICE); 208 | //keyguardManager = AppContext.getSystemService(KeyguardManager.class); 209 | // fingerprintManager = AppContext.getSystemService(FingerprintManager.class); 210 | 211 | jsonObject = new JSONObject(); 212 | 213 | try { 214 | jsonObject.put(AppConstants.USER_NAME, userName); 215 | jsonObject.put(AppConstants.PASS_WORD, passWord); 216 | } catch (JSONException e) { 217 | e.printStackTrace(); 218 | } 219 | 220 | // Check whether the device has a Fingerprint sensor. 221 | if (!fingerprintManager.isHardwareDetected()) { 222 | errorMessage = "Your Device does not have a Fingerprint Sensor"; 223 | errorCallback.invoke(errorMessage); 224 | } else { 225 | // Checks whether fingerprint permission is set on manifest 226 | if (ActivityCompat.checkSelfPermission(AppContext, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) { 227 | errorMessage = "Fingerprint authentication permission not enabled"; 228 | errorCallback.invoke(errorMessage); 229 | } else { 230 | // Check whether at least one fingerprint is registered 231 | if (!fingerprintManager.hasEnrolledFingerprints()) { 232 | errorMessage = "Go to 'Settings -> Security -> Fingerprint' and register at least one fingerprint"; 233 | 234 | errorCallback.invoke(errorMessage); 235 | 236 | } else { 237 | // Checks whether lock screen security is enabled or not 238 | if (!keyguardManager.isKeyguardSecure()) { 239 | 240 | errorMessage = "Secure lock screen hasn't set up.\n" 241 | + "Go to 'Settings -> Security -> Fingerprint' to set up a fingerprint"; 242 | 243 | errorCallback.invoke(errorMessage); 244 | } else { 245 | 246 | //Generate key 247 | generateKey(); 248 | 249 | //initialize cipher and pass it to FingerPrint scanner 250 | if (cipherInit()) { 251 | 252 | //Create dialog 253 | FingerprintAuthenticationDialogFragment fragment 254 | = new FingerprintAuthenticationDialogFragment(BiometricModule.this); 255 | //Assign crypto Object 256 | fragment.setCryptoObject(new FingerprintManagerCompat.CryptoObject(defaultCipher)); 257 | //Start Authentication 258 | fragment.show(activityContext.getFragmentManager(), DIALOG_FRAGMENT_TAG); 259 | 260 | } 261 | } 262 | } 263 | } 264 | } 265 | } else { 266 | errorMessage = "Fingerprint authentication feature does not work on rooted devices"; 267 | errorCallback.invoke(errorMessage); 268 | 269 | //clear stored credentials 270 | flushFileSystem(); 271 | } 272 | } 273 | 274 | @TargetApi(Build.VERSION_CODES.M) 275 | private void generateKey() { 276 | try { 277 | mKeyStore = KeyStore.getInstance("AndroidKeyStore"); 278 | } catch (Exception e) { 279 | e.printStackTrace(); 280 | } 281 | 282 | try { 283 | mKeyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); 284 | } catch (NoSuchAlgorithmException | NoSuchProviderException e) { 285 | throw new RuntimeException("Failed to get KeyGenerator instance", e); 286 | } 287 | 288 | try { 289 | mKeyStore.load(null); 290 | mKeyGenerator.init(new 291 | KeyGenParameterSpec.Builder(DEFAULT_KEY_NAME, 292 | KeyProperties.PURPOSE_ENCRYPT | 293 | KeyProperties.PURPOSE_DECRYPT) 294 | .setBlockModes(KeyProperties.BLOCK_MODE_CBC) 295 | .setUserAuthenticationRequired(true) 296 | .setEncryptionPaddings( 297 | KeyProperties.ENCRYPTION_PADDING_PKCS7) 298 | .build()); 299 | mKeyGenerator.generateKey(); 300 | } catch (NoSuchAlgorithmException | 301 | InvalidAlgorithmParameterException 302 | | CertificateException | IOException e) { 303 | throw new RuntimeException(e); 304 | } 305 | } 306 | 307 | @TargetApi(Build.VERSION_CODES.M) 308 | private boolean cipherInit() { 309 | //Get Cipher 310 | try { 311 | defaultCipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + 312 | KeyProperties.BLOCK_MODE_CBC + "/" + 313 | KeyProperties.ENCRYPTION_PADDING_PKCS7); 314 | } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { 315 | throw new RuntimeException("Failed to get Cipher", e); 316 | } 317 | //Get key and pass it to cipher 318 | try { 319 | mKeyStore.load(null); 320 | SecretKey key = (SecretKey) mKeyStore.getKey(DEFAULT_KEY_NAME, 321 | null); 322 | defaultCipher.init(Cipher.ENCRYPT_MODE, key); 323 | return true; 324 | } catch (KeyPermanentlyInvalidatedException e) { 325 | return false; 326 | } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException | NoSuchAlgorithmException | InvalidKeyException e) { 327 | throw new RuntimeException("Failed to init Cipher", e); 328 | } 329 | } 330 | 331 | public void authenticationSuccess(boolean withFingerprint, 332 | @Nullable FingerprintManagerCompat.CryptoObject cryptoObject) { 333 | 334 | storeCredentials(); 335 | 336 | if (null != successCallback) { 337 | successCallback.invoke(); 338 | } 339 | } 340 | 341 | // // Show confirmation, if fingerprint was used show crypto information. 342 | // public void showConfirmation(byte[] encrypted) { 343 | // if (encrypted != null) { 344 | // Toast.makeText(AppContext, 345 | // "Confirmation " + Base64.encodeToString(encrypted, 0 /* flags */), 346 | // Toast.LENGTH_LONG).show(); 347 | // } 348 | // } 349 | 350 | // /** 351 | // * Tries to encrypt some data with the generated key in which is 352 | // * only works if the user has just authenticated via fingerprint. 353 | // */ 354 | // private void tryEncrypt(Cipher cipher) { 355 | // try { 356 | // byte[] encrypted = cipher.doFinal(SECRET_MESSAGE.getBytes()); 357 | // showConfirmation(encrypted); 358 | // } catch (BadPaddingException | IllegalBlockSizeException e) { 359 | // Toast.makeText(AppContext, "Failed to encrypt the data with the generated key. " 360 | // + "Retry the purchase", Toast.LENGTH_LONG).show(); 361 | // Log.e(TAG, "Failed to encrypt the data with the generated key." + e.getMessage()); 362 | // } 363 | // } 364 | 365 | public void authenticationFailed(String errorMessage) { 366 | if (null != errorCallback) 367 | errorCallback.invoke(errorMessage); 368 | } 369 | 370 | private String decryptText(String encryptedText) { 371 | 372 | byte[] inputEncryptedJSONFromFile = Base64.decode(encryptedText, Base64.DEFAULT); 373 | String decryptedJSON = null; 374 | try { 375 | decryptedJSON = decryptor 376 | .decrypt(SAMPLE_ALIAS, inputEncryptedJSONFromFile, AppContext/*, encryptor.getIv()*/); 377 | } catch (UnrecoverableEntryException | NoSuchAlgorithmException | 378 | KeyStoreException | NoSuchPaddingException | NoSuchProviderException | 379 | IOException | InvalidKeyException e) { 380 | Log.e(TAG, "Error DecryptData : " + e.getMessage(), e); 381 | } catch (IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) { 382 | Log.e(TAG, "Error DecryptData : " + e.getMessage(), e); 383 | e.printStackTrace(); 384 | } 385 | return decryptedJSON; 386 | } 387 | 388 | private String encryptText(String inputJSON) { 389 | String encryptedJSON = null; 390 | try { 391 | final byte[] encryptedText = encryptor 392 | .encrypt(SAMPLE_ALIAS, inputJSON, AppContext); 393 | encryptedJSON = Base64.encodeToString(encryptedText, Base64.DEFAULT); 394 | } catch (UnrecoverableEntryException | NoSuchAlgorithmException | NoSuchProviderException | 395 | KeyStoreException | IOException | NoSuchPaddingException | InvalidKeyException e) { 396 | Log.e(TAG, "Error EncryptData : " + e.getMessage(), e); 397 | } catch (InvalidAlgorithmParameterException | SignatureException | 398 | IllegalBlockSizeException | BadPaddingException e) { 399 | e.printStackTrace(); 400 | Log.e(TAG, "Error EncryptData : " + e.getMessage(), e); 401 | } 402 | return encryptedJSON; 403 | } 404 | 405 | private void writeToFile(String data) { 406 | try { 407 | OutputStreamWriter outputStreamWriter = new OutputStreamWriter(AppContext.openFileOutput("config.txt", Context.MODE_PRIVATE)); 408 | outputStreamWriter.write(data); 409 | outputStreamWriter.close(); 410 | } catch (IOException e) { 411 | Log.e("Exception", "File write failed: " + e.toString()); 412 | } 413 | } 414 | 415 | private String readFromFile() { 416 | 417 | String encryptedJSONFromFile = "{}"; 418 | 419 | try { 420 | InputStream inputStream = AppContext.openFileInput("config.txt"); 421 | 422 | if (inputStream != null) { 423 | InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 424 | BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 425 | String receiveString = ""; 426 | StringBuilder stringBuilder = new StringBuilder(); 427 | 428 | while ((receiveString = bufferedReader.readLine()) != null) { 429 | stringBuilder.append(receiveString); 430 | } 431 | 432 | inputStream.close(); 433 | encryptedJSONFromFile = stringBuilder.toString(); 434 | } 435 | } catch (FileNotFoundException e) { 436 | Log.e(TAG, "File not found: " + e.toString()); 437 | e.printStackTrace(); 438 | } catch (IOException e) { 439 | Log.e(TAG, "Can not read file: " + e.toString()); 440 | e.printStackTrace(); 441 | } 442 | 443 | Log.e(TAG, "readFileSystem : " + encryptedJSONFromFile); 444 | 445 | return encryptedJSONFromFile; 446 | } 447 | 448 | private void flushFileSystem() { 449 | AppContext.deleteFile(new File(AppContext.getFilesDir(), "config.txt").getName()); 450 | } 451 | } 452 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/aproject/utils/AppConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017 HiteshSahu.com- All Rights Reserved 4 | * Unauthorized copying of this file, via any medium is strictly prohibited 5 | * Proprietary and confidential. 6 | * Written by Hitesh Sahu , 2017. 7 | * 8 | */ 9 | 10 | package com.aproject.utils; 11 | 12 | /** 13 | * Created by hitesh.sahu on 7/13/2017. 14 | */ 15 | 16 | public interface AppConstants { 17 | 18 | String DIALOG_FRAGMENT_TAG = "myFragment"; 19 | String SECRET_MESSAGE = "Very secret message"; 20 | String DEFAULT_KEY_NAME = "default_key"; 21 | String CREDENTAIL_FILE_NAME = "Freezer"; 22 | 23 | String USER_NAME = "userName"; 24 | String PASS_WORD = "passWord"; 25 | String LOCK_FINGERPRINT = "LOCK_FINGERPRINT"; 26 | } 27 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/aproject/utils/PreferenceHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017 HiteshSahu.com- All Rights Reserved 4 | * Unauthorized copying of this file, via any medium is strictly prohibited 5 | * Proprietary and confidential. 6 | * Written by Hitesh Sahu , 2017. 7 | * 8 | */ 9 | 10 | package com.aproject.utils; 11 | 12 | import android.content.Context; 13 | import android.preference.PreferenceManager; 14 | 15 | /** 16 | * @author Hitesh 17 | */ 18 | public class PreferenceHelper { 19 | 20 | public final static String FIRST_TIME = "FirstTime"; 21 | public final static String WHATS_NEW_LAST_SHOWN = "whats_new_last_shown"; 22 | public final static String SUBMIT_LOGS = "CrashLogs"; 23 | // Handle Local Caching of data for responsiveness 24 | public static final String MY_CART_LIST_LOCAL = "MyCartItems"; 25 | private static final String USER_LOGGED_IN = "isLoggedIn"; 26 | private static PreferenceHelper preferenceHelperInstance = new PreferenceHelper(); 27 | 28 | private PreferenceHelper() { 29 | } 30 | 31 | public static PreferenceHelper getPrefernceHelperInstace() { 32 | 33 | return preferenceHelperInstance; 34 | } 35 | 36 | public void setBoolean(Context appContext, String key, Boolean value) { 37 | 38 | PreferenceManager.getDefaultSharedPreferences(appContext).edit() 39 | .putBoolean(key, value).apply(); 40 | } 41 | 42 | public void setInteger(Context appContext, String key, int value) { 43 | 44 | PreferenceManager.getDefaultSharedPreferences(appContext).edit() 45 | .putInt(key, value).apply(); 46 | } 47 | 48 | public void setFloat(Context appContext, String key, float value) { 49 | 50 | PreferenceManager.getDefaultSharedPreferences(appContext).edit() 51 | .putFloat(key, value).apply(); 52 | } 53 | 54 | public void setString(Context appContext, String key, String value) { 55 | 56 | PreferenceManager.getDefaultSharedPreferences(appContext).edit() 57 | .putString(key, value).apply(); 58 | } 59 | 60 | // To retrieve values from shared preferences: 61 | 62 | public boolean getBoolean(Context appContext, String key, 63 | Boolean defaultValue) { 64 | 65 | return PreferenceManager.getDefaultSharedPreferences(appContext) 66 | .getBoolean(key, defaultValue); 67 | } 68 | 69 | public int getInteger(Context appContext, String key, int defaultValue) { 70 | 71 | return PreferenceManager.getDefaultSharedPreferences(appContext) 72 | .getInt(key, defaultValue); 73 | } 74 | 75 | public float getString(Context appContext, String key, float defaultValue) { 76 | 77 | return PreferenceManager.getDefaultSharedPreferences(appContext) 78 | .getFloat(key, defaultValue); 79 | } 80 | 81 | public String getString(Context appContext, String key, String defaultValue) { 82 | 83 | return PreferenceManager.getDefaultSharedPreferences(appContext) 84 | .getString(key, defaultValue); 85 | } 86 | 87 | public void setUserLoggedIn(boolean UserLoggedIn, Context appContext) { 88 | 89 | setBoolean(appContext, USER_LOGGED_IN, UserLoggedIn); 90 | } 91 | 92 | public boolean isUserLoggedIn(Context appContext) { 93 | 94 | return getBoolean(appContext, USER_LOGGED_IN, false); 95 | } 96 | 97 | } -------------------------------------------------------------------------------- /android/app/src/main/java/com/aproject/utils/RootUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017 HiteshSahu.com- All Rights Reserved 4 | * Unauthorized copying of this file, via any medium is strictly prohibited 5 | * Proprietary and confidential. 6 | * Written by Hitesh Sahu , 2017. 7 | * 8 | */ 9 | 10 | package com.aproject.utils; 11 | 12 | import java.io.BufferedReader; 13 | import java.io.File; 14 | import java.io.InputStreamReader; 15 | 16 | public class RootUtil { 17 | public static boolean isDeviceRooted() { 18 | return checkRootMethod1() || checkRootMethod2() || checkRootMethod3(); 19 | } 20 | 21 | private static boolean checkRootMethod1() { 22 | String buildTags = android.os.Build.TAGS; 23 | return buildTags != null && buildTags.contains("test-keys"); 24 | } 25 | 26 | private static boolean checkRootMethod2() { 27 | String[] paths = {"/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su", 28 | "/system/bin/failsafe/su", "/data/local/su", "/su/bin/su"}; 29 | for (String path : paths) { 30 | if (new File(path).exists()) return true; 31 | } 32 | return false; 33 | } 34 | 35 | private static boolean checkRootMethod3() { 36 | Process process = null; 37 | try { 38 | process = Runtime.getRuntime().exec(new String[]{"/system/xbin/which", "su"}); 39 | BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())); 40 | return in.readLine() != null; 41 | } catch (Throwable t) { 42 | return false; 43 | } finally { 44 | if (process != null) process.destroy(); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /android/app/src/main/java/com/aproject/view/Fragments/FingerprintAuthenticationDialogFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017 HiteshSahu.com- All Rights Reserved 4 | * Unauthorized copying of this file, via any medium is strictly prohibited 5 | * Proprietary and confidential. 6 | * Written by Hitesh Sahu , 2017. 7 | * 8 | */ 9 | 10 | package com.aproject.view.Fragments; 11 | 12 | import android.app.DialogFragment; 13 | import android.content.Context; 14 | import android.content.SharedPreferences; 15 | import android.os.Bundle; 16 | import android.preference.PreferenceManager; 17 | import android.support.v4.hardware.fingerprint.FingerprintManagerCompat; 18 | import android.view.LayoutInflater; 19 | import android.view.View; 20 | import android.view.ViewGroup; 21 | import android.widget.ImageView; 22 | import android.widget.TextView; 23 | import android.widget.Toast; 24 | 25 | import com.aproject.MainActivity; 26 | import com.aproject.R; 27 | import com.aproject.modules.BiometricModule; 28 | 29 | /** 30 | * A dialog which uses fingerprint APIs to authenticate the user, and falls back to password 31 | * authentication if fingerprint is not available. 32 | */ 33 | public class FingerprintAuthenticationDialogFragment extends DialogFragment 34 | implements FingerprintUiHelper.Callback { 35 | 36 | private FingerprintManagerCompat.CryptoObject mCryptoObject; 37 | private FingerprintUiHelper mFingerprintUiHelper; 38 | private MainActivity mActivity; 39 | private SharedPreferences mSharedPreferences; 40 | private BiometricModule biometricModule; 41 | 42 | public FingerprintAuthenticationDialogFragment(BiometricModule biometricModule) { 43 | this.biometricModule = biometricModule; 44 | } 45 | 46 | @Override 47 | public void onCreate(Bundle savedInstanceState) { 48 | super.onCreate(savedInstanceState); 49 | // Do not create a new Fragment when the Activity is re-created such as orientation changes. 50 | setRetainInstance(true); 51 | setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog); 52 | } 53 | 54 | @Override 55 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 56 | Bundle savedInstanceState) { 57 | getDialog().setTitle(getString(R.string.sign_in)); 58 | View rootView = inflater.inflate(R.layout.fingerprint_dialog_container, container, false); 59 | rootView.findViewById(R.id.cancel_button).setOnClickListener(new View.OnClickListener() { 60 | @Override 61 | public void onClick(View view) { 62 | dismiss(); 63 | } 64 | }); 65 | 66 | rootView.findViewById(R.id.cancel_button).setOnClickListener(new View.OnClickListener() { 67 | @Override 68 | public void onClick(View v) { 69 | dismiss(); 70 | } 71 | }); 72 | 73 | mFingerprintUiHelper = new FingerprintUiHelper( 74 | FingerprintManagerCompat.from(mActivity), 75 | (ImageView) rootView.findViewById(R.id.fingerprint_icon), 76 | (TextView) rootView.findViewById(R.id.fingerprint_status), this); 77 | 78 | // If fingerprint authentication is not available, switch immediately to the backup 79 | if (!mFingerprintUiHelper.isFingerprintAuthAvailable()) { 80 | Toast.makeText(getActivity(), "Error : " + getActivity().getString(R.string.fingerprint_not_supported), Toast.LENGTH_LONG).show(); 81 | onAuthenticationError(getActivity().getString(R.string.fingerprint_not_supported)); 82 | dismiss(); 83 | 84 | } 85 | return rootView; 86 | } 87 | 88 | /** 89 | * Sets the crypto object to be passed in when authenticating with fingerprint. 90 | */ 91 | public void setCryptoObject(FingerprintManagerCompat.CryptoObject cryptoObject) { 92 | mCryptoObject = cryptoObject; 93 | } 94 | 95 | @Override 96 | public void onAuthenticationSuccess() { 97 | // authentication was successful. 98 | biometricModule.authenticationSuccess(true /* withFingerprint */, mCryptoObject); 99 | dismiss(); 100 | } 101 | 102 | @Override 103 | public void onAuthenticationError(String errorMessage) { 104 | biometricModule.authenticationFailed(errorMessage); 105 | } 106 | 107 | @Override 108 | public void maxAttemptExceed() { 109 | dismiss(); 110 | } 111 | 112 | @Override 113 | public void onResume() { 114 | super.onResume(); 115 | mFingerprintUiHelper.startListening(mCryptoObject); 116 | } 117 | 118 | @Override 119 | public void onPause() { 120 | super.onPause(); 121 | mFingerprintUiHelper.stopListening(); 122 | } 123 | 124 | @Override 125 | public void onAttach(Context context) { 126 | super.onAttach(context); 127 | mActivity = (MainActivity) getActivity(); 128 | mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/aproject/view/Fragments/FingerprintUiHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2017 HiteshSahu.com- All Rights Reserved 4 | * Unauthorized copying of this file, via any medium is strictly prohibited 5 | * Proprietary and confidential. 6 | * Written by Hitesh Sahu , 2017. 7 | * 8 | */ 9 | 10 | package com.aproject.view.Fragments; 11 | 12 | import android.annotation.TargetApi; 13 | import android.os.Build; 14 | import android.support.v4.hardware.fingerprint.FingerprintManagerCompat; 15 | import android.widget.ImageView; 16 | import android.widget.TextView; 17 | import android.widget.Toast; 18 | 19 | import com.aproject.R; 20 | import com.aproject.utils.PreferenceHelper; 21 | 22 | import static android.hardware.fingerprint.FingerprintManager.FINGERPRINT_ERROR_LOCKOUT; 23 | 24 | /** 25 | * Small helper class to manage text/icon around fingerprint authentication UI. 26 | */ 27 | @TargetApi(Build.VERSION_CODES.M) 28 | public class FingerprintUiHelper extends FingerprintManagerCompat.AuthenticationCallback { 29 | 30 | private static final long ERROR_TIMEOUT_MILLIS = 1600; 31 | private static final long SUCCESS_DELAY_MILLIS = 1300; 32 | private final FingerprintManagerCompat mFingerprintManager; 33 | private final ImageView mIcon; 34 | private final TextView mErrorTextView; 35 | private final Callback mCallback; 36 | private android.support.v4.os.CancellationSignal mCancellationSignal; 37 | // private int failureCount; 38 | 39 | private boolean mSelfCancelled; 40 | private Runnable mResetErrorTextRunnable = new Runnable() { 41 | @Override 42 | public void run() { 43 | mErrorTextView.setTextColor( 44 | mErrorTextView.getResources().getColor(R.color.hint_color, null)); 45 | mErrorTextView.setText( 46 | mErrorTextView.getResources().getString(R.string.fingerprint_hint)); 47 | mIcon.setImageResource(R.drawable.ic_fp_40px); 48 | } 49 | }; 50 | 51 | FingerprintUiHelper(FingerprintManagerCompat fingerprintManager, 52 | ImageView icon, TextView errorTextView, Callback callback) { 53 | mFingerprintManager = fingerprintManager; 54 | mIcon = icon; 55 | mErrorTextView = errorTextView; 56 | mCallback = callback; 57 | // failureCount = 0; 58 | } 59 | 60 | public void startListening(FingerprintManagerCompat.CryptoObject cryptoObject) { 61 | if (!isFingerprintAuthAvailable()) { 62 | return; 63 | } 64 | mCancellationSignal = new android.support.v4.os.CancellationSignal(); 65 | mSelfCancelled = false; 66 | // The line below prevents the false positive inspection from Android Studio 67 | // noinspection ResourceType 68 | mFingerprintManager 69 | .authenticate(cryptoObject, 0 /* flags */,mCancellationSignal, this, null); 70 | mIcon.setImageResource(R.drawable.ic_fp_40px); 71 | } 72 | 73 | @Override 74 | public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) { 75 | mErrorTextView.removeCallbacks(mResetErrorTextRunnable); 76 | mIcon.setImageResource(R.drawable.ic_fingerprint_success); 77 | mErrorTextView.setTextColor( 78 | mErrorTextView.getResources().getColor(R.color.success_color, null)); 79 | mErrorTextView.setText( 80 | mErrorTextView.getResources().getString(R.string.fingerprint_success)); 81 | mIcon.postDelayed(new Runnable() { 82 | @Override 83 | public void run() { 84 | mCallback.onAuthenticationSuccess(); 85 | } 86 | }, SUCCESS_DELAY_MILLIS); 87 | } 88 | 89 | @Override 90 | public void onAuthenticationError(int errMsgId, final CharSequence errString) { 91 | if (!mSelfCancelled) { 92 | showError(errString); 93 | 94 | if (errMsgId == FINGERPRINT_ERROR_LOCKOUT) { 95 | // mIcon.postDelayed(new Runnable() { 96 | // @Override 97 | // public void run() { 98 | // mCallback.onAuthenticationError(""); 99 | // } 100 | // }, ERROR_TIMEOUT_MILLIS); 101 | 102 | PreferenceHelper.getPrefernceHelperInstace().setBoolean(mIcon.getContext(), "LOCK_FINGERPRINT", false); 103 | 104 | Toast.makeText(mIcon.getContext(), "YOU HAVE EXCEED MAX NUMBER OF ATTEMPTS \n Please Use Your Credentials to LogIn", Toast.LENGTH_SHORT).show(); 105 | 106 | mCallback.maxAttemptExceed(); 107 | 108 | 109 | } 110 | } 111 | } 112 | 113 | @Override 114 | public void onAuthenticationHelp(int helpMsgId, final CharSequence helpString) { 115 | showError(helpString); 116 | // mIcon.postDelayed(new Runnable() { 117 | // @Override 118 | // public void run() { 119 | // mCallback.onAuthenticationError(helpString.toString()); 120 | // } 121 | // }, ERROR_TIMEOUT_MILLIS); 122 | } 123 | 124 | @Override 125 | public void onAuthenticationFailed() { 126 | showError(mIcon.getResources().getString( 127 | R.string.fingerprint_not_recognized)); 128 | 129 | // mIcon.postDelayed(new Runnable() { 130 | // @Override 131 | // public void run() { 132 | // mCallback.onAuthenticationError(mIcon.getResources().getString( 133 | // R.string.fingerprint_not_recognized)); 134 | // } 135 | // }, ERROR_TIMEOUT_MILLIS); 136 | 137 | //Toast.makeText(getActivity(), "Error : " + getActivity().getString(R.string.fingerprint_not_supported), Toast.LENGTH_LONG).show(); 138 | 139 | // failureCount++; 140 | // if (failureCount == 3) { 141 | // mIcon.postDelayed(new Runnable() { 142 | // @Override 143 | // public void run() { 144 | // mCallback.onAuthenticationError("Max Attempts Crossed"); 145 | // } 146 | // }, ERROR_TIMEOUT_MILLIS); 147 | // } 148 | } 149 | 150 | private void showError(CharSequence error) { 151 | mIcon.setImageResource(R.drawable.ic_fingerprint_error); 152 | mErrorTextView.setText(error); 153 | mErrorTextView.setTextColor( 154 | mErrorTextView.getResources().getColor(R.color.warning_color, null)); 155 | mErrorTextView.removeCallbacks(mResetErrorTextRunnable); 156 | mErrorTextView.postDelayed(mResetErrorTextRunnable, ERROR_TIMEOUT_MILLIS); 157 | 158 | } 159 | 160 | public void stopListening() { 161 | if (mCancellationSignal != null) { 162 | mSelfCancelled = true; 163 | mCancellationSignal.cancel(); 164 | mCancellationSignal = null; 165 | } 166 | } 167 | 168 | public boolean isFingerprintAuthAvailable() { 169 | // The line below prevents the false positive inspection from Android Studio 170 | // noinspection ResourceType 171 | return mFingerprintManager.isHardwareDetected() 172 | && mFingerprintManager.hasEnrolledFingerprints(); 173 | } 174 | 175 | public interface Callback { 176 | 177 | void onAuthenticationSuccess(); 178 | 179 | void onAuthenticationError(String errorMessage); 180 | 181 | void maxAttemptExceed(); 182 | 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/ic_fp_40px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/android/app/src/main/res/drawable-hdpi/ic_fp_40px.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/tile.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/android/app/src/main/res/drawable-hdpi/tile.9.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/ic_fp_40px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/android/app/src/main/res/drawable-mdpi/ic_fp_40px.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-nodpi/android_robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/android/app/src/main/res/drawable-nodpi/android_robot.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/ic_fp_40px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/android/app/src/main/res/drawable-xhdpi/ic_fp_40px.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/android/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/ic_fp_40px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/b7177486c67b2e649b37540be46c4110134c4c69/android/app/src/main/res/drawable-xxxhdpi/ic_fp_40px.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/card.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_fingerprint_error.xml: -------------------------------------------------------------------------------- 1 | 9 | 14 | 17 | 20 | 21 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_fingerprint_success.xml: -------------------------------------------------------------------------------- 1 | 9 | 14 | 17 | 20 | 21 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/fingerprint_dialog_container.xml: -------------------------------------------------------------------------------- 1 | 9 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 33 | 34 | 40 | 41 |