macOS: Don't sign out on rebooting the Mac (#2816)

Fixes #2809.

Tested the case where the user:
- while being signed in and connected in the Firezone app, logs out of
macOS
  - logs in as another user

In the above case, the app:
- sees that there's a token reference stored in the tunnel, but is
unable to access the token (the token is per user)
  - so the app signs the user out

This PR is stacked on top of PR #2804.
This commit is contained in:
Roopesh Chander
2023-12-07 23:45:53 +05:30
committed by GitHub
parent 391ec1e50d
commit 2eb9e7db2d
3 changed files with 40 additions and 15 deletions

View File

@@ -39,6 +39,7 @@ public struct TunnelShutdownEvent: Codable, CustomStringConvertible {
}
public enum Action {
case doNothing
case signoutImmediately
case retryThenSignout
}
@@ -50,8 +51,10 @@ public struct TunnelShutdownEvent: Codable, CustomStringConvertible {
public var action: Action {
switch reason {
case .stopped(let reason):
if reason == .userInitiated || reason == .userLogout || reason == .userSwitch {
if reason == .userInitiated {
return .signoutImmediately
} else if reason == .userLogout || reason == .userSwitch {
return .doNothing
} else {
return .retryThenSignout
}

View File

@@ -88,6 +88,9 @@ final class AuthStore: ObservableObject {
.sink { [weak self] status in
guard let self = self else { return }
Task {
if status == .disconnected {
self.handleTunnelDisconnectionEvent()
}
if status == .connected {
self.resetReconnectionAttemptsRemaining()
}
@@ -170,26 +173,40 @@ final class AuthStore: ObservableObject {
do {
try await tunnelStore.start()
} catch {
logger.error("\(#function): Error starting tunnel: \(String(describing: error))")
if let tsEvent = TunnelShutdownEvent.loadFromDisk() {
self.logger.log(
"\(#function): Tunnel shutdown event: \(tsEvent, privacy: .public)"
if case TunnelStoreError.startTunnelErrored(let startTunnelError) = error {
logger.error(
"\(#function): Starting tunnel errored: \(String(describing: startTunnelError))"
)
switch tsEvent.action {
case .signoutImmediately:
Task {
await self.signOut()
}
case .retryThenSignout:
self.retryStartTunnel()
}
handleTunnelDisconnectionEvent()
} else {
self.logger.log("\(#function): Tunnel shutdown event not found")
logger.error("\(#function): Starting tunnel failed: \(String(describing: error))")
// Disconnection event will be handled in the tunnel status change handler
}
}
}
}
func handleTunnelDisconnectionEvent() {
logger.log("\(#function)")
if let tsEvent = TunnelShutdownEvent.loadFromDisk() {
self.logger.log(
"\(#function): Tunnel shutdown event: \(tsEvent, privacy: .public)"
)
switch tsEvent.action {
case .signoutImmediately:
Task {
await self.signOut()
}
case .retryThenSignout:
self.retryStartTunnel()
case .doNothing:
break
}
} else {
self.logger.log("\(#function): Tunnel shutdown event not found")
}
}
func retryStartTunnel() {
// Try to reconnect, but don't try more than 3 times at a time.
// If this gets called the third time, sign out.

View File

@@ -15,6 +15,7 @@ enum TunnelStoreError: Error {
case cannotSaveToTunnelWhenConnected
case cannotSignOutWhenConnected
case stopAlreadyBeingAttempted
case startTunnelErrored(Error)
}
public struct TunnelProviderKeys {
@@ -173,7 +174,11 @@ final class TunnelStore: ObservableObject {
try await tunnel.loadFromPreferences()
let session = castToSession(tunnel.connection)
try session.startTunnel()
do {
try session.startTunnel()
} catch {
throw TunnelStoreError.startTunnelErrored(error)
}
try await withCheckedThrowingContinuation { continuation in
self.startTunnelContinuation = continuation
}