-
Notifications
You must be signed in to change notification settings - Fork 137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Authentication screen #58
Authentication screen #58
Conversation
}) | ||
|
||
const checkIfBiometryIsAvailable = async () => { | ||
const biometryIsAvailable = await isSensorAvailable() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are there some odds that isSensorAvailable
could throw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reworked it to be then/catch
I should mention https://github.com/hieuvp/react-native-fingerprint-scanner is no longer being actively maintained by the owner: hieuvp/react-native-fingerprint-scanner#178. I'm wasn't able to find an actively maintained library that seemed like a good fit. https://github.com/oblador/react-native-keychain seems maintained and GaloyMoney already has it installed, but I was running into issues with it on my Android Pixel 2. Also, how do you think the user experience of this feature will be? I could see it being a problem if some users have dirt on their hands from working, but I haven't been to El Zonte yet. An alternate way to authenticate besides logging out and then back in might be needed. |
A quick test. I have tried it on an iPhone X with FaceId (have not tried android yet) and the flow is a bit awkward: after login in, nothing really changes as of now. but then, when you restart the app, it's asking if you want to set up FaceId at the second launch. this is not the place to ask for FaceId setup. this should be either after a succesful login, or in the settings tab. I have not tried the flow of clicking on "don't allow" here. something to give a look at. also, if you log out, the faceId registration is not being reset. need to re-install the app for that. But otherwise the faceId works as expected after it has been set up. if you don't faceId you can't log in. I think there could be a fallback with a pin number of the iOS. that would be nice to have. |
const securityAction = () => { | ||
var isBiometricsEnabled = null | ||
var isPinEnabled = null | ||
|
||
RNSecureKeyStore.get("isBiometricsEnabled") | ||
.then((res) => { | ||
if (isPinEnabled !== null) { | ||
navigation.navigate("security", { mIsBiometricsEnabled: true, mIsPinEnabled: isPinEnabled }) | ||
} else { | ||
isBiometricsEnabled = true | ||
} | ||
}, (err) => { | ||
if (isPinEnabled !== null) { | ||
navigation.navigate("security", { mIsBiometricsEnabled: false, mIsPinEnabled: isPinEnabled }) | ||
} else { | ||
isBiometricsEnabled = false | ||
} | ||
}) | ||
|
||
RNSecureKeyStore.get("PIN") | ||
.then((res) => { | ||
if (isBiometricsEnabled !== null) { | ||
navigation.navigate("security", { mIsBiometricsEnabled: isBiometricsEnabled, mIsPinEnabled: true }) | ||
} else { | ||
isPinEnabled = true | ||
} | ||
}, (err) => { | ||
if (isBiometricsEnabled !== null) { | ||
navigation.navigate("security", { mIsBiometricsEnabled: isBiometricsEnabled, mIsPinEnabled: false }) | ||
} else { | ||
isPinEnabled = false | ||
} | ||
}) | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make this an util function in case we need this check somewhere else in the future
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds like pre-mature optimisation.
in case we need
I think its fine to keep it in the this file as long as its the only place we're using it.
Not a big deal though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good over all.... see comments for small cleanup suggestions.
const [isPinEnabled, setIsPinEnabled] = useState(mIsPinEnabled) | ||
|
||
useFocusEffect(() => { | ||
RNSecureKeyStore.get("isBiometricsEnabled") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can these strings "PIN"
and "isBiometricsEnabled"
be extracted into const
variables?
const securityAction = () => { | ||
var isBiometricsEnabled = null | ||
var isPinEnabled = null | ||
|
||
RNSecureKeyStore.get("isBiometricsEnabled") | ||
.then((res) => { | ||
if (isPinEnabled !== null) { | ||
navigation.navigate("security", { mIsBiometricsEnabled: true, mIsPinEnabled: isPinEnabled }) | ||
} else { | ||
isBiometricsEnabled = true | ||
} | ||
}, (err) => { | ||
if (isPinEnabled !== null) { | ||
navigation.navigate("security", { mIsBiometricsEnabled: false, mIsPinEnabled: isPinEnabled }) | ||
} else { | ||
isBiometricsEnabled = false | ||
} | ||
}) | ||
|
||
RNSecureKeyStore.get("PIN") | ||
.then((res) => { | ||
if (isBiometricsEnabled !== null) { | ||
navigation.navigate("security", { mIsBiometricsEnabled: isBiometricsEnabled, mIsPinEnabled: true }) | ||
} else { | ||
isPinEnabled = true | ||
} | ||
}, (err) => { | ||
if (isBiometricsEnabled !== null) { | ||
navigation.navigate("security", { mIsBiometricsEnabled: isBiometricsEnabled, mIsPinEnabled: false }) | ||
} else { | ||
isPinEnabled = false | ||
} | ||
}) | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds like pre-mature optimisation.
in case we need
I think its fine to keep it in the this file as long as its the only place we're using it.
Not a big deal though.
Actually had a thought regarding the accesses with magic strings ie:
I think that would make it cleaner all together. Group all functions regarding that |
7f7fd29
to
2e22710
Compare
export const AuthenticationCheckScreen: ScreenType = ({ navigation }: Props) => { | ||
useFocusEffect(() => { | ||
checkForAuthentication() | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useEffect(() => {
checkForAuthentication()
}, [])
checkForAuthentication() | ||
}) | ||
|
||
const checkForAuthentication = async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put function within useEffect scope
navigation: any, | ||
} | ||
|
||
export const AuthenticationScreen: ScreenType = ({ route, navigation }: Props) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add type related to route.params
attemptAuthentication() | ||
}) | ||
|
||
const attemptAuthentication = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
async?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think attemptAuthentication
needs to be async even though BiometricWrapper.authenticate
is async. Unless we want to await a return value of BiometricWrapper.authenticate
instead of using callbacks. Is there another reason to declare attemptAuthentication
async?
} else { | ||
description = translate("AuthenticationScreen.setUpAuthenticationDescription") | ||
} | ||
BiometricWrapper.authenticate(description, handleAuthenticationSuccess, handleAuthenticationFailure) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add 1 line comment on what this does
] | ||
}) | ||
} else { | ||
if (pinAttempts < 2) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be const outside of the loop
category: translate('common.security'), | ||
icon: 'lock-closed-outline', | ||
id: 'security', | ||
action: () => securityAction(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
action: securityAction
79af9a7
to
ff913f0
Compare
App running in the background. When coming back to the app, not asking for faceId again. But I think it ask back FaceId because the app can stay in the background for a long time. |
after too many attempt of bad pin, the "too many attempt to login, log out" text appeared maybe only for 0.2 seconds. I could barely see it before the screen had reset. |
Would you like me to add authentication when the device goes from background -> active. I have not implemented this yet, only when the app starts from terminated. Also do you think the best way to handle the "too many attempt to login, log out" is to add an |
yes. this could be done as a follow up PR. |
can be a good option yes. or it could be a popup. and when you click on ok you're being redirected at this stage. |
I have this issue on Android as well. this is the biggest issue I see so far on my end. |
Feature for #15
I have added biometric authentication using this library: https://github.com/hieuvp/react-native-fingerprint-scanner. The library should work with all devices according to the documentation including those that use face id instead of fingerprint and ios. I have only thoroughly tested with my device: an Android Pixel 2 that uses fingerprint authentication. If the library does not detect a biometry sensor available, the app should go into the Primary screen (untested).
The authentication in this pull request is mandatory and cannot be turned off in the settings. If you think this is something users would want, Opt-in/out authentication would require a boolean property added to the user object (on servers too) and a another item in the settings.
I hope we can thoroughly test this feature before merging it into the main codebase.