Skip to content
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

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1afab5a
Biometrics lock concept
bgoncal Aug 17, 2023
a7564fb
Improvements on authentication handler and protection overlay
bgoncal Aug 21, 2023
1d757ca
Add localized placeholders
bgoncal Aug 21, 2023
c56f638
Lint autocorrect
bgoncal Nov 1, 2023
1335665
PR improvements and macOS taking in consideration
bgoncal Nov 2, 2023
f85e6ae
Linter autocorrect
bgoncal Nov 2, 2023
9fd70fa
Add missing self reference
bgoncal Nov 7, 2023
5850f35
Fix typo and move biometrics logic
bgoncal Nov 16, 2023
ce1f140
Added new UI for the "lock" screen, moved some code around to a prope…
bgoncal Nov 16, 2023
96cdfac
Biometrics lock concept
bgoncal Aug 17, 2023
fc15eac
Improvements on authentication handler and protection overlay
bgoncal Aug 21, 2023
b728292
Add localized placeholders
bgoncal Aug 21, 2023
fe07834
Lint autocorrect
bgoncal Nov 1, 2023
6ffe64c
PR improvements and macOS taking in consideration
bgoncal Nov 2, 2023
2a9ddda
Linter autocorrect
bgoncal Nov 2, 2023
1f0b692
Add missing self reference
bgoncal Nov 7, 2023
e051dd4
Fix typo and move biometrics logic
bgoncal Nov 16, 2023
63c9c46
Added new UI for the "lock" screen, moved some code around to a prope…
bgoncal Nov 16, 2023
8c656d3
Merge branch 'Biometric-lock-concept' of github.com:bgoncal/HA-iOS in…
bgoncal Dec 4, 2023
9f1a418
Merge branch 'master' into Biometric-lock-concept
bgoncal Dec 5, 2023
75982af
Removed mac implementation and moved to SwiftUI for iOS
bgoncal Dec 5, 2023
27cf8ac
Present on top most controller
bgoncal Dec 5, 2023
97839c3
Linter
bgoncal Dec 5, 2023
77e5077
Present biometric lock on window level
bgoncal Dec 5, 2023
27e2a63
Remove unneeded check
bgoncal Dec 6, 2023
2bc8f60
Improve logic to hide security toggle for mac
bgoncal Dec 6, 2023
072af4e
Use camel case for spacing values
bgoncal Dec 6, 2023
6674456
Auto disable biometric lock when delete all servers
bgoncal Dec 6, 2023
eec44b0
Re-add hebrew and estonian languages
bgoncal Dec 6, 2023
5dbb72e
Merge branch 'master' into Biometric-lock-concept
bgoncal Dec 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 168 additions & 127 deletions HomeAssistant.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

128 changes: 65 additions & 63 deletions Sources/App/Resources/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -547,41 +547,6 @@
</array>
</dict>
</array>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneConfigurationName</key>
<string>WebView</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).WebViewSceneDelegate</string>
</dict>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SettingsSceneDelegate</string>
<key>UISceneConfigurationName</key>
<string>Settings</string>
</dict>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).AboutSceneDelegate</string>
<key>UISceneConfigurationName</key>
<string>About</string>
</dict>
</array>
</dict>
</dict>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>FIREBASE_ANALYTICS_COLLECTION_ENABLED</key>
Expand Down Expand Up @@ -623,6 +588,8 @@
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NFCReaderUsageDescription</key>
<string>Reading and writing NFC tags allows you to trigger events.</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
Expand All @@ -634,21 +601,36 @@
<string>_home-assistant._tcp</string>
<string>_matter._tcp</string>
</array>
<key>NSCameraUsageDescription</key>
<string>Take photos and send them to your Home Assistant server.</string>
<key>NSCrossWebsiteTrackingUsageDescription</key>
<string>Optionally enable cross-website tracking if your configuration requires it.</string>
<key>NSFaceIDUsageDescription</key>
<string>We use FaceID to protect the App access.</string>
<key>NSFocusStatusUsageDescription</key>
<string>Report your focus status as a sensor.</string>
<key>NSLocalNetworkUsageDescription</key>
<string>Locate and communicate with your Home Assistant instance.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We suggest selecting &quot;Always Allow&quot; for the best location experience.
Selecting &quot;Only While Using the App&quot; will disable iBeacons, geofences,
<string>We suggest selecting "Always Allow" for the best location experience.
Selecting "Only While Using the App" will disable iBeacons, geofences,
background location updates and accurate reporting.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>We always need access to your location for features like iBeacons, geofences,
background location updates and accurate reporting.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Only allowing location access while app is in use will disable iBeacons, geofences,
background location updates and accurate reporting.</string>
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
<key>TemporaryFullAccuracyReasonManualUpdate</key>
<string>[localized in strings file]</string>
</dict>
<key>NSLocationUsageDescription</key>
<string>When enabled, your device location is sent to your Home Assistant server as a device
tracker.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Only allowing location access while app is in use will disable iBeacons, geofences,
background location updates and accurate reporting.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Record audio using your Home Assistant frontend.</string>
<key>NSMotionUsageDescription</key>
<string>Motion is used to improve location updates with current motion type, as well as
provide basic pedometer data.</string>
Expand All @@ -658,24 +640,8 @@
<string>Photo Library access is needed to allow saving photos from the web view.</string>
<key>NSSiriUsageDescription</key>
<string>We use Siri to allow created shortcuts to interact with the app.</string>
<key>NFCReaderUsageDescription</key>
<string>Reading and writing NFC tags allows you to trigger events.</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>Used to dictate text to Assist.</string>
<key>NSCameraUsageDescription</key>
<string>Take photos and send them to your Home Assistant server.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Record audio using your Home Assistant frontend.</string>
<key>NSFocusStatusUsageDescription</key>
<string>Report your focus status as a sensor.</string>
<key>com.apple.developer.nfc.readersession.felica.systemcodes</key>
<array>
<string>12FC</string>
</array>
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>D2760000850101</string>
</array>
<key>NSUserActivityTypes</key>
<array>
<string>CallServiceIntent</string>
Expand All @@ -690,6 +656,41 @@
<string>WidgetOpenPageIntent</string>
<string>AssistIntent</string>
</array>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneConfigurationName</key>
<string>WebView</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).WebViewSceneDelegate</string>
</dict>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneConfigurationName</key>
<string>Settings</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SettingsSceneDelegate</string>
</dict>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneConfigurationName</key>
<string>About</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).AboutSceneDelegate</string>
</dict>
</array>
</dict>
</dict>
<key>UIApplicationShortcutItems</key>
<array>
<dict>
Expand Down Expand Up @@ -731,12 +732,13 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSCrossWebsiteTrackingUsageDescription</key>
<string>Optionally enable cross-website tracking if your configuration requires it.</string>
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
<key>TemporaryFullAccuracyReasonManualUpdate</key>
<string>[localized in strings file]</string>
</dict>
<key>com.apple.developer.nfc.readersession.felica.systemcodes</key>
<array>
<string>12FC</string>
</array>
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>D2760000850101</string>
</array>
</dict>
</plist>
5 changes: 5 additions & 0 deletions Sources/App/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,11 @@ 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 every time you open the app.";
"settings_details.general.security.authentication_policy" = "Authentication required";
"settings_details.general.security.unlock_button" = "Unlock";
"settings_details.location.background_refresh.disabled" = "Disabled";
"settings_details.location.background_refresh.enabled" = "Enabled";
"settings_details.location.background_refresh.title" = "Background Refresh";
Expand Down
11 changes: 11 additions & 0 deletions Sources/App/Resources/et.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ Home Assistant is free and open source home automation software with a focus on
"settings.developer.crashlytics_test.non_fatal.notification.body" = "When you press OK, a non-fatal error will be sent to Crashlytics. It may take up to 5 minutes to appear in the console.";
"settings.developer.crashlytics_test.non_fatal.notification.title" = "About to submit a non-fatal error";
"settings.developer.crashlytics_test.non_fatal.title" = "Test Crashlytics Non-Fatal Error";
"settings.developer.mock_thread_credentials_sharing.title" = "Simulator Thread Credentials Sharing";
"settings.developer.debug_strings.title" = "Debug strings";
"settings.developer.export_log_files.title" = "Export log files";
"settings.developer.footer" = "Don't use these if you don't know what you are doing!";
Expand Down Expand Up @@ -411,6 +412,11 @@ 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 every time you open the app.";
"settings_details.general.security.authentication_policy" = "Authentication required";
"settings_details.general.security.unlock_button" = "Unlock";
"settings_details.location.background_refresh.disabled" = "Disabled";
"settings_details.location.background_refresh.enabled" = "Enabled";
"settings_details.location.background_refresh.title" = "Background Refresh";
Expand Down Expand Up @@ -769,3 +775,8 @@ Home Assistant is free and open source home automation software with a focus on
"widgets.open_page.not_configured" = "No Pages Available";
"widgets.open_page.title" = "Open Page";
"yes_label" = "Yes";
"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";
Comment on lines +778 to +782
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bad merge?

11 changes: 11 additions & 0 deletions Sources/App/Resources/he.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ Home Assistant is free and open source home automation software with a focus on
"settings.developer.crashlytics_test.non_fatal.notification.body" = "When you press OK, a non-fatal error will be sent to Crashlytics. It may take up to 5 minutes to appear in the console.";
"settings.developer.crashlytics_test.non_fatal.notification.title" = "About to submit a non-fatal error";
"settings.developer.crashlytics_test.non_fatal.title" = "Test Crashlytics Non-Fatal Error";
"settings.developer.mock_thread_credentials_sharing.title" = "Simulator Thread Credentials Sharing";
"settings.developer.debug_strings.title" = "Debug strings";
"settings.developer.export_log_files.title" = "Export log files";
"settings.developer.footer" = "Don't use these if you don't know what you are doing!";
Expand Down Expand Up @@ -411,6 +412,11 @@ 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 every time you open the app.";
"settings_details.general.security.authentication_policy" = "Authentication required";
"settings_details.general.security.unlock_button" = "Unlock";
"settings_details.location.background_refresh.disabled" = "Disabled";
"settings_details.location.background_refresh.enabled" = "Enabled";
"settings_details.location.background_refresh.title" = "Background Refresh";
Expand Down Expand Up @@ -769,3 +775,8 @@ Home Assistant is free and open source home automation software with a focus on
"widgets.open_page.not_configured" = "No Pages Available";
"widgets.open_page.title" = "Open Page";
"yes_label" = "Yes";
"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";
28 changes: 28 additions & 0 deletions Sources/App/Settings/Security/SecurityViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Eureka
import FirebaseInstallations
import FirebaseMessaging
import PromiseKit
import RealmSwift
import Shared
import UIKit

class SecurityViewController: HAFormViewController {
override func viewDidLoad() {
super.viewDidLoad()

title = L10n.SettingsDetails.General.Security.title

form
+++ Section()
<<< SwitchRow("switch", {
$0.title = L10n.SettingsDetails.General.Security.action
$0.value = Current.settingsStore.biometricsRequired
$0.onChange { row in
Current.settingsStore.biometricsRequired = row.value ?? false
bgoncal marked this conversation as resolved.
Show resolved Hide resolved
}
})
+++ Section(
footer: L10n.SettingsDetails.General.Security.footer
)
}
}
12 changes: 12 additions & 0 deletions Sources/App/Settings/SettingsRootDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum SettingsRootDataSource {
case servers
case location
case notifications
case security
case actions
case sensors
case complications
Expand All @@ -37,6 +38,7 @@ enum SettingsRootDataSource {
case .general: return SettingsRootDataSource.general()
case .location: return SettingsRootDataSource.location()
case .notifications: return SettingsRootDataSource.notifications()
case .security: return SettingsRootDataSource.security()
case .actions: return SettingsRootDataSource.actions()
case .sensors: return SettingsRootDataSource.sensors()
case .complications: return SettingsRootDataSource.complications()
Expand Down Expand Up @@ -95,6 +97,16 @@ enum SettingsRootDataSource {
}
}

private static func security() -> SettingsButtonRow {
SettingsButtonRow {
Copy link
Member

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?

Copy link
Member Author

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

$0.title = L10n.SettingsDetails.General.Security.title
$0.icon = .keyChainIcon
$0.presentationMode = .show(controllerProvider: ControllerProvider.callback {
SecurityViewController()
}, onDismiss: nil)
}
}

private static func actions() -> SettingsButtonRow {
SettingsButtonRow {
$0.title = L10n.SettingsDetails.Actions.title
Expand Down
6 changes: 5 additions & 1 deletion Sources/App/Settings/SettingsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,14 @@ class SettingsViewController: HAFormViewController {
}

if contentSections.contains(.general) {
form +++ Section()
let generalSection = Section()
<<< SettingsRootDataSource.Row.general.row
<<< SettingsRootDataSource.Row.location.row
<<< SettingsRootDataSource.Row.notifications.row
if !Current.isCatalyst {
generalSection <<< SettingsRootDataSource.Row.security.row
}
form +++ generalSection
}

if contentSections.contains(.integrations) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@testable import HomeAssistant
@testable import Shared
import XCTest

@available(iOS 13, *)
Expand Down
10 changes: 8 additions & 2 deletions Sources/App/WebView/WebViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,10 @@ final class WebViewController: UIViewController, WKNavigationDelegate, WKUIDeleg
}
}

init(server: Server, shouldLoadImmediately: Bool = false) {
init(
server: Server,
shouldLoadImmediately: Bool = false
) {
self.server = server
self.sidebarGestureRecognizer = with(UIScreenEdgePanGestureRecognizer()) {
$0.edges = .left
Expand All @@ -342,7 +345,10 @@ final class WebViewController: UIViewController, WKNavigationDelegate, WKUIDeleg
}
}

convenience init?(restoring: RestorationType?, shouldLoadImmediately: Bool = false) {
convenience init?(
restoring: RestorationType?,
shouldLoadImmediately: Bool = false
) {
if let server = restoring?.server ?? Current.servers.all.first {
self.init(server: server)
} else {
Expand Down
Loading
Loading