-
Notifications
You must be signed in to change notification settings - Fork 328
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
Biometrics lock (Lock app with FaceID/TouchID/iOS Password) #2398
Conversation
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #2398 +/- ##
==========================================
- Coverage 28.37% 28.16% -0.21%
==========================================
Files 273 290 +17
Lines 30284 30834 +550
==========================================
+ Hits 8593 8685 +92
- Misses 21691 22149 +458 ☔ View full report in Codecov by Sentry. |
} | ||
|
||
private func authenticate(policy: LAPolicy) { | ||
context.evaluatePolicy(policy, localizedReason: "Authentication required") { approved, error in |
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.
the hard part here is also blocking the ui while this should be happening, and e.g. in the app switcher. how would you imagine this to be implemented?
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.
Usually most apps blur the UI using and overlay UIView, what do you think? I'd go for that, although at least in the simulator I wasn't able to dismiss iOS biometric/password screen (which is visible in the video), so maybe it is already doing that.
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.
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
cf3a0d3
to
e300ba5
Compare
@@ -410,6 +410,9 @@ Home Assistant is free and open source home automation software with a focus on | |||
"settings_details.general.visibility.options.dock_and_menu_bar" = "Dock and Menu Bar"; | |||
"settings_details.general.visibility.options.menu_bar" = "Menu Bar"; | |||
"settings_details.general.visibility.title" = "Show App In…"; | |||
"settings_details.general.security.title" = "Security"; | |||
"settings_details.general.security.action" = "Enable biometric lock"; | |||
"settings_details.general.security.footer" = "You will be required to authenticate with biometrics everytime you open the app."; |
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.
every time
Current.Log | ||
.error( | ||
[ | ||
"Failed to authenticate with biometrics": "User context can't evaluate policy for device ownership", | ||
] | ||
) |
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.
what should we tell the user if they fail to do this? should we have on-screen ui that says an error?
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.
If the user can't authenticate neither with biometrics or password then the user is locked out, I would say this is very edge case since it's credentials are the same as the iOS/macOS device. Any suggestion?
@@ -95,6 +97,16 @@ enum SettingsRootDataSource { | |||
} | |||
} | |||
|
|||
private static func security() -> SettingsButtonRow { | |||
SettingsButtonRow { |
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.
how does this work on catalyst? should we hide it or make it available -- if the latter, how do we deal with e.g. the settings scene?
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.
In catalyst it was a bit trickier, because of the "enter background/foreground" thats happens all the time even with the touchID dialog, I treated it with an extra logic to only reauthenticate when the user has reply enter background.
When the user open settings scene, the main web view scene locks again until the user unlocks it.
Screen.Recording.2023-11-16.at.16.33.08.mov
RPReplay_Final1700149090.MP4
3b3a134
to
5850f35
Compare
Sources/Shared/LocalAuthentication/BiometricsAuthenticationViewController.swift
Outdated
Show resolved
Hide resolved
Sources/Shared/LocalAuthentication/BiometricsAuthenticationViewController.swift
Outdated
Show resolved
Hide resolved
Sources/Shared/LocalAuthentication/BiometricsAuthenticationViewController.swift
Outdated
Show resolved
Hide resolved
Sources/Shared/LocalAuthentication/BiometricsAuthenticationViewController.swift
Outdated
Show resolved
Hide resolved
Sources/WatchApp/Assets.xcassets/WatchIcon.appiconset/Contents.json
Outdated
Show resolved
Hide resolved
// MARK: - Biometrics lock | ||
|
||
extension WebViewWindowController { | ||
private func listenForBiometricsLockRelatedEvents() { |
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.
what happens if the user gets signed out (e.g. remotely, due to token) while this is happening?
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.
How can I easily reproduce that? I think the overlay will stay there, but it's nice to verify
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.
go into your user profile & delete the token for your device in your profile. you can do it from the same machine or other.
if the overlay stays, it may be worth killing it off since there's nothing it's protecting (if it's the last account) and may block signing into something new. there's no way to get to settings during onboarding.
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.
Tested. Indeed the "lock screen" was still being shown even with no servers. So I updated it in a way that the user needs to authenticate one last time after the token expires, and then the biometric lock will be disabled and only reenabled if the user sets up a new server and manually enables the toggle.
Sources/Shared/LocalAuthentication/BiometricsAuthenticationService.swift
Outdated
Show resolved
Hide resolved
Sources/Shared/LocalAuthentication/BiometricsAuthenticationService.swift
Outdated
Show resolved
Hide resolved
Sources/Shared/LocalAuthentication/BiometricsAuthenticationService.swift
Outdated
Show resolved
Hide resolved
ce1f140
to
63c9c46
Compare
…to Biometric-lock-concept
b1b369b
to
8c656d3
Compare
# Conflicts: # Sources/App/Resources/Assets.xcassets/Logo.imageset/Contents.json # Sources/WatchApp/Assets.xcassets/WatchIcon.appiconset/Contents.json # Sources/WatchApp/Assets.xcassets/WatchIcon.beta.appiconset/Contents.json # Sources/WatchApp/Assets.xcassets/WatchIcon.dev.appiconset/Contents.json
// MARK: - Biometrics lock | ||
|
||
extension WebViewWindowController { | ||
private func listenForBiometricsLockRelatedEvents() { |
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.
go into your user profile & delete the token for your device in your profile. you can do it from the same machine or other.
if the overlay stays, it may be worth killing it off since there's nothing it's protecting (if it's the last account) and may block signing into something new. there's no way to get to settings during onboarding.
Sources/Shared/LocalAuthentication/BiometricsAuthenticationService.swift
Outdated
Show resolved
Hide resolved
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 think things seem good, but i am a little worried about the 'protect' part and how it works with multiple windows happening
"thread.credentials.network_name_title" = "Network Name"; | ||
"thread.credentials.network_key_title" = "Network Key"; | ||
"thread.credentials.border_agent_id_title" = "Border Agent ID"; | ||
"thread.credentials.share_credentials_button_title" = "Share credential with Home Assistant"; | ||
"thread.credentials.screen_title" = "Thread Credentials"; |
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.
bad merge?
guard let window = controller.view.window, | ||
previousRootViewController == nil else { return } | ||
|
||
self.window = window |
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.
what happens if there are multiple windows open? e.g. multi-scene support on iPad.
i think you probably want to either collate all the windows during the lock phase, or make this chain off the WebViewWindowController itself, but synchronize the unlock status
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 think I will start over with this implementation, I liked your idea of sync status. Another question... should we allow shortcut actions if the app is locked?
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 think it becomes really hard to do locking if we disallow extensions to do work. Most of them do not support being able to prompt the user for permission.
We could either:
- tell the user it won't lock extensions
- disallow extensions entirely if lock is enabled (where we cannot prompt)
- allow the user to choose which extensions should be allowed
Maybe we could add more control in app but I think the first one sounds easiest for now.
Closing PR, I will start over with a better foundation for locking the app |
Summary
Concept for locking the HA app using iOS biometrics. (FaceID wasn't working on my simulator, thats why the video shows password instead).
Pending:
Screenshots