Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Commit

Permalink
Fix #7849: Update Sync Local Authentication Logic (#7878)
Browse files Browse the repository at this point in the history
  • Loading branch information
soner-yuksel authored Aug 15, 2023
1 parent ddcbec2 commit fea59db
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -698,10 +698,9 @@ class TabTrayController: AuthenticationController {
syncAPI: braveCore.syncAPI,
syncProfileService: braveCore.syncProfileService,
tabManager: tabManager,
windowProtection: windowProtection,
requiresAuthentication: true)
windowProtection: windowProtection)

syncSettingsScreen.syncStatusDelegate = self
syncSettingsScreen.syncStatusDelegate = self

openInsideSettingsNavigation(with: syncSettingsScreen)
default:
Expand Down
3 changes: 1 addition & 2 deletions Sources/Brave/Frontend/Settings/SettingsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,7 @@ class SettingsViewController: TableViewController {
syncProfileService:
syncProfileServices,
tabManager: tabManager,
windowProtection: windowProtection,
requiresAuthentication: true)
windowProtection: windowProtection)

self.navigationController?
.pushViewController(syncSettingsViewController, animated: true)
Expand Down
98 changes: 68 additions & 30 deletions Sources/Brave/Frontend/Sync/SyncSettingsTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,18 @@ class SyncSettingsTableViewController: SyncViewController, UITableViewDelegate,
syncAPI: BraveSyncAPI,
syncProfileService: BraveSyncProfileServiceIOS,
tabManager: TabManager,
windowProtection: WindowProtection?,
requiresAuthentication: Bool) {
windowProtection: WindowProtection?) {
self.isModallyPresented = isModallyPresented
self.syncAPI = syncAPI
self.syncProfileService = syncProfileService
self.tabManager = tabManager

super.init(windowProtection: windowProtection, requiresAuthentication: requiresAuthentication, isModallyPresented: isModallyPresented)
// Local Authentication (Biometric - Pincode) needed only for actions
// Enabling - disabling password sync and add new device
super.init(windowProtection: windowProtection,
requiresAuthentication: false,
isModallyPresented: isModallyPresented,
dismissPresenter: false)
}

required init?(coder: NSCoder) {
Expand Down Expand Up @@ -259,25 +263,50 @@ class SyncSettingsTableViewController: SyncViewController, UITableViewDelegate,
}

@objc private func didToggleSyncType(_ toggle: UISwitch) {
switch toggle.tag {
case SyncDataTypes.bookmarks.rawValue:
Preferences.Chromium.syncBookmarksEnabled.value = toggle.isOn
case SyncDataTypes.history.rawValue:
Preferences.Chromium.syncHistoryEnabled.value = toggle.isOn
case SyncDataTypes.passwords.rawValue:
Preferences.Chromium.syncPasswordsEnabled.value = toggle.isOn
case SyncDataTypes.openTabs.rawValue:
Preferences.Chromium.syncOpenTabsEnabled.value = toggle.isOn

// Sync Regular Tabs when open tabs are enabled
if Preferences.Chromium.syncOpenTabsEnabled.value {
tabManager.addRegularTabsToSyncChain()
guard let syncDataType = SyncDataTypes(rawValue: toggle.tag) else {
Logger.module.error("Invalid Sync DataType")
return
}

let toggleExistingStatus = !toggle.isOn

if syncDataType == .passwords {
if toggleExistingStatus {
performSyncDataTypeStatusChange(type: syncDataType)
} else {
askForAuthentication() { status, error in
guard status else {
toggle.setOn(toggleExistingStatus, animated: false)
return
}

toggle.setOn(!toggleExistingStatus, animated: false)
performSyncDataTypeStatusChange(type: syncDataType)
}
}
default:
return
} else {
performSyncDataTypeStatusChange(type: syncDataType)
}

func performSyncDataTypeStatusChange(type: SyncDataTypes) {
switch type {
case .bookmarks:
Preferences.Chromium.syncBookmarksEnabled.value = !toggleExistingStatus
case .history:
Preferences.Chromium.syncHistoryEnabled.value = !toggleExistingStatus
case .passwords:
Preferences.Chromium.syncPasswordsEnabled.value = !toggleExistingStatus
case .openTabs:
Preferences.Chromium.syncOpenTabsEnabled.value = !toggleExistingStatus

// Sync Regular Tabs when open tabs are enabled
if Preferences.Chromium.syncOpenTabsEnabled.value {
tabManager.addRegularTabsToSyncChain()
}
}

syncAPI.enableSyncTypes(syncProfileService: syncProfileService)
syncAPI.enableSyncTypes(syncProfileService: syncProfileService)
}
}

/// Update visibility of view shown when no devices returned for sync session
Expand Down Expand Up @@ -307,11 +336,15 @@ class SyncSettingsTableViewController: SyncViewController, UITableViewDelegate,

@objc
private func onSyncInternalsTapped() {
let syncInternalsController = syncAPI.createSyncInternalsController().then {
$0.title = Strings.braveSyncInternalsTitle
askForAuthentication() { [weak self] status, error in
guard let self = self, status else { return }

let syncInternalsController = self.syncAPI.createSyncInternalsController().then {
$0.title = Strings.braveSyncInternalsTitle
}

self.navigationController?.pushViewController(syncInternalsController, animated: true)
}

navigationController?.pushViewController(syncInternalsController, animated: true)
}
}

Expand Down Expand Up @@ -559,16 +592,21 @@ extension SyncSettingsTableViewController {
}

private func addAnotherDevice() {
let view = SyncSelectDeviceTypeViewController()

view.syncInitHandler = { title, type in
let view = SyncAddDeviceViewController(title: title, type: type, syncAPI: self.syncAPI)
view.addDeviceHandler = {
self.navigationController?.popToViewController(self, animated: true)
askForAuthentication() { [weak self] status, error in
guard let self = self, status else { return }

let view = SyncSelectDeviceTypeViewController()

view.syncInitHandler = { title, type in
let view = SyncAddDeviceViewController(title: title, type: type, syncAPI: self.syncAPI)
view.addDeviceHandler = {
self.navigationController?.popToViewController(self, animated: true)
}
self.navigationController?.pushViewController(view, animated: true)
}

self.navigationController?.pushViewController(view, animated: true)
}
navigationController?.pushViewController(view, animated: true)
}
}

Expand Down
19 changes: 16 additions & 3 deletions Sources/Brave/Frontend/Sync/SyncViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,35 @@ import Combine
class SyncViewController: AuthenticationController {

private let isModallyPresented: Bool
private let dismissPresenter: Bool
private var localAuthObservers = Set<AnyCancellable>()

// MARK: Lifecycle


/// Constructor for Sync View Controller that enables
/// functionality related with local authentication and internet connection
/// - Parameters:
/// - windowProtection: WindowProtection for passcode window functionality
/// - requiresAuthentication: Boolean determines viewing the screen requires local auth
/// - isAuthenticationCancellable: Determines if the niometric authentication has cancel function
/// - isModallyPresented: Checks if view controller presented modally in order to determine dismiss type
/// - dismissPresenter: Boolean that determines cancel functionality dismisses the presented controller
init(windowProtection: WindowProtection? = nil,
requiresAuthentication: Bool = false,
isAuthenticationCancellable: Bool = true,
isModallyPresented: Bool = false) {
isModallyPresented: Bool = false,
dismissPresenter: Bool = true) {
self.isModallyPresented = isModallyPresented
self.dismissPresenter = dismissPresenter
super.init(windowProtection: windowProtection, requiresAuthentication: requiresAuthentication)

windowProtection?.isCancellable = isAuthenticationCancellable

windowProtection?.cancelPressed
.sink { [weak self] _ in
self?.dismissSyncController()
if dismissPresenter {
self?.dismissSyncController()
}
}.store(in: &localAuthObservers)
}

Expand Down
97 changes: 44 additions & 53 deletions Sources/Brave/Frontend/Sync/SyncWelcomeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -196,70 +196,62 @@ class SyncWelcomeViewController: SyncViewController {

@objc
private func newToSyncAction() {
askForAuthentication() { [weak self] status, error in
guard let self = self, status else { return }
let addDevice = SyncSelectDeviceTypeViewController()
addDevice.syncInitHandler = { [weak self] (title, type) in
guard let self = self else { return }

let addDevice = SyncSelectDeviceTypeViewController()
addDevice.syncInitHandler = { [weak self] (title, type) in
guard let self = self else { return }

func pushAddDeviceVC() {
self.syncServiceObserver = nil
guard self.syncAPI.isInSyncGroup else {
addDevice.disableNavigationPrevention()
let alert = UIAlertController(title: Strings.syncUnsuccessful, message: Strings.syncUnableCreateGroup, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: Strings.OKString, style: .default, handler: nil))
addDevice.present(alert, animated: true, completion: nil)
return
}

let view = SyncAddDeviceViewController(title: title, type: type, syncAPI: self.syncAPI)
view.addDeviceHandler = self.pushSettings
view.navigationItem.hidesBackButton = true
self.navigationController?.pushViewController(view, animated: true)
}

if self.syncAPI.isInSyncGroup {
pushAddDeviceVC()
func pushAddDeviceVC() {
self.syncServiceObserver = nil
guard self.syncAPI.isInSyncGroup else {
addDevice.disableNavigationPrevention()
let alert = UIAlertController(title: Strings.syncUnsuccessful, message: Strings.syncUnableCreateGroup, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: Strings.OKString, style: .default, handler: nil))
addDevice.present(alert, animated: true, completion: nil)
return
}

addDevice.enableNavigationPrevention()

// DidJoinSyncChain result should be also checked when creating a new chain
self.syncAPI.setDidJoinSyncChain { result in
if result {
self.syncDeviceInfoObserver = self.syncAPI.addDeviceStateObserver { [weak self] in
guard let self else { return }
self.syncServiceObserver = nil
self.syncDeviceInfoObserver = nil

pushAddDeviceVC()
}
} else {
self.syncAPI.leaveSyncGroup()
addDevice.disableNavigationPrevention()
self.navigationController?.popViewController(animated: true)
let view = SyncAddDeviceViewController(title: title, type: type, syncAPI: self.syncAPI)
view.addDeviceHandler = self.pushSettings
view.navigationItem.hidesBackButton = true
self.navigationController?.pushViewController(view, animated: true)
}

if self.syncAPI.isInSyncGroup {
pushAddDeviceVC()
return
}

addDevice.enableNavigationPrevention()

// DidJoinSyncChain result should be also checked when creating a new chain
self.syncAPI.setDidJoinSyncChain { result in
if result {
self.syncDeviceInfoObserver = self.syncAPI.addDeviceStateObserver { [weak self] in
guard let self else { return }
self.syncServiceObserver = nil
self.syncDeviceInfoObserver = nil

pushAddDeviceVC()
}
} else {
self.syncAPI.leaveSyncGroup()
addDevice.disableNavigationPrevention()
self.navigationController?.popViewController(animated: true)
}

self.syncAPI.joinSyncGroup(codeWords: self.syncAPI.getSyncCode(), syncProfileService: self.syncProfileServices)
self.handleSyncSetupFailure()
}

self.navigationController?.pushViewController(addDevice, animated: true)
self.syncAPI.joinSyncGroup(codeWords: self.syncAPI.getSyncCode(), syncProfileService: self.syncProfileServices)
self.handleSyncSetupFailure()
}

navigationController?.pushViewController(addDevice, animated: true)
}

@objc
private func existingUserAction() {
askForAuthentication() { [weak self] status, error in
guard let self = self, status else { return }

let pairCamera = SyncPairCameraViewController(syncAPI: syncAPI)
pairCamera.delegate = self
self.navigationController?.pushViewController(pairCamera, animated: true)
}
let pairCamera = SyncPairCameraViewController(syncAPI: syncAPI)
pairCamera.delegate = self
navigationController?.pushViewController(pairCamera, animated: true)
}

@objc
Expand Down Expand Up @@ -288,8 +280,7 @@ class SyncWelcomeViewController: SyncViewController {
syncAPI: syncAPI,
syncProfileService: syncProfileServices,
tabManager: tabManager,
windowProtection: windowProtection,
requiresAuthentication: false)
windowProtection: windowProtection)

navigationController?.pushViewController(syncSettingsVC, animated: true)
}
Expand Down
11 changes: 10 additions & 1 deletion Sources/Brave/Frontend/Widgets/LoadingViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ public class LoadingViewController: UIViewController {
public class AuthenticationController: LoadingViewController {
enum AuthViewType {
case sync, tabTray

var detailText: String {
switch self {
case .sync:
return Strings.Sync.syncSetPasscodeAlertDescription
case .tabTray:
return Strings.Privacy.tabTraySetPasscodeAlertDescription
}
}
}

let windowProtection: WindowProtection?
Expand Down Expand Up @@ -90,7 +99,7 @@ public class AuthenticationController: LoadingViewController {
func showSetPasscodeError(viewType: AuthViewType, completion: @escaping (() -> Void)) {
let alert = UIAlertController(
title: Strings.Sync.syncSetPasscodeAlertTitle,
message: viewType == .sync ? Strings.Sync.syncSetPasscodeAlertDescription : Strings.Privacy.tabTraySetPasscodeAlertDescription,
message: viewType.detailText,
preferredStyle: .alert)

alert.addAction(
Expand Down
2 changes: 1 addition & 1 deletion Sources/BraveStrings/BraveStrings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3286,7 +3286,7 @@ extension Strings {
"login.syncSetPasscodeAlertDescription",
tableName: "BraveShared",
bundle: .module,
value: "To setup sync chain or see settings, you must first set a passcode on your device.",
value: "To add a device to sync chain or toggle password sync, you must first set a passcode on your device.",
comment: "The message displayed in alert when a user needs to set a passcode")
}
}
Expand Down

0 comments on commit fea59db

Please sign in to comment.