mirror of
https://github.com/tw93/Mole.git
synced 2026-02-16 02:36:12 +00:00
refactor: improve sudo error handling to distinguish authentication failures and adjust scene view rotation speed.
This commit is contained in:
@@ -165,7 +165,7 @@ struct MoleSceneView: NSViewRepresentable {
|
|||||||
// Slower, majestic rotation
|
// Slower, majestic rotation
|
||||||
// Auto Rotation Speed
|
// Auto Rotation Speed
|
||||||
// Slower, majestic rotation normally. Fast when working.
|
// Slower, majestic rotation normally. Fast when working.
|
||||||
let baseRotation = parent.isRunning ? 0.05 : 0.002
|
let baseRotation = parent.isRunning ? 0.12 : 0.006
|
||||||
|
|
||||||
// Drag Influence
|
// Drag Influence
|
||||||
let dragInfluence = Double(parent.rotationVelocity.width) * 0.0005
|
let dragInfluence = Double(parent.rotationVelocity.width) * 0.0005
|
||||||
|
|||||||
@@ -24,11 +24,30 @@ class OptimizerService: ObservableObject {
|
|||||||
_ = try await ShellRunner.shared.runSudo(command, password: pw)
|
_ = try await ShellRunner.shared.runSudo(command, password: pw)
|
||||||
return
|
return
|
||||||
} catch {
|
} catch {
|
||||||
await MainActor.run { AuthContext.shared.clear() }
|
print("Optimizer privilege error: \(error)")
|
||||||
|
// Only clear password if it's an authentication failure
|
||||||
|
if case ShellError.authenticationFailed = error {
|
||||||
|
await MainActor.run { AuthContext.shared.clear() }
|
||||||
|
|
||||||
|
await MainActor.run {
|
||||||
|
AuthContext.shared.needsPassword = true
|
||||||
|
self.statusMessage = "Password Incorrect"
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AuthRequired: Error, LocalizedError {
|
||||||
|
var errorDescription: String? { "Authentication Failed" }
|
||||||
|
}
|
||||||
|
throw AuthRequired()
|
||||||
|
} else {
|
||||||
|
// Command failed but password likely correct.
|
||||||
|
// Do NOT clear password. Propagate error.
|
||||||
|
print("Non-auth error in optimizer: \(error)")
|
||||||
|
throw error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no password or failed, prompt via Custom Sheet
|
// If no password, prompt via Custom Sheet
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
AuthContext.shared.needsPassword = true
|
AuthContext.shared.needsPassword = true
|
||||||
self.statusMessage = "Waiting for Password..."
|
self.statusMessage = "Waiting for Password..."
|
||||||
|
|||||||
@@ -144,12 +144,23 @@ class ScannerService: ObservableObject {
|
|||||||
do {
|
do {
|
||||||
_ = try await ShellRunner.shared.runSudo(fullCommand, password: sessionPw)
|
_ = try await ShellRunner.shared.runSudo(fullCommand, password: sessionPw)
|
||||||
} catch {
|
} catch {
|
||||||
|
print("Sudo command error: \(error)")
|
||||||
print("Session password failed: \(error)")
|
print("Session password failed: \(error)")
|
||||||
await MainActor.run { AuthContext.shared.clear() }
|
|
||||||
// Trigger re-auth on failure
|
if case ShellError.authenticationFailed = error {
|
||||||
|
await MainActor.run {
|
||||||
|
AuthContext.shared.clear()
|
||||||
|
AuthContext.shared.needsPassword = true
|
||||||
|
self.currentLog = "Password Incorrect/Expired"
|
||||||
|
self.isCleaning = false
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Ignore other errors (e.g. command execution failed)
|
||||||
|
// but continue the flow or handle gracefully without clearing password
|
||||||
|
print("Non-auth error in cleanup: \(error)")
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
AuthContext.shared.needsPassword = true
|
self.currentLog = "Error: \(error.localizedDescription)"
|
||||||
self.currentLog = "Password Incorrect/Expired"
|
|
||||||
self.isCleaning = false
|
self.isCleaning = false
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ import Foundation
|
|||||||
enum ShellError: Error, LocalizedError {
|
enum ShellError: Error, LocalizedError {
|
||||||
case commandFailed(output: String)
|
case commandFailed(output: String)
|
||||||
case executionError(error: Error)
|
case executionError(error: Error)
|
||||||
|
case authenticationFailed
|
||||||
|
|
||||||
var errorDescription: String? {
|
var errorDescription: String? {
|
||||||
switch self {
|
switch self {
|
||||||
case .commandFailed(let output): return output
|
case .commandFailed(let output): return output
|
||||||
case .executionError(let error): return error.localizedDescription
|
case .executionError(let error): return error.localizedDescription
|
||||||
|
case .authenticationFailed: return "Authentication failed - incorrect password"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,10 +100,15 @@ class ShellRunner {
|
|||||||
if process.terminationStatus == 0 {
|
if process.terminationStatus == 0 {
|
||||||
continuation.resume(returning: output)
|
continuation.resume(returning: output)
|
||||||
} else {
|
} else {
|
||||||
// If 1, it might be wrong password or command fail.
|
// Check for password failure
|
||||||
// sudo usually complains to stderr.
|
let combined = (output + errorOutput).lowercased()
|
||||||
continuation.resume(
|
if combined.contains("try again") || combined.contains("incorrect") {
|
||||||
throwing: ShellError.commandFailed(output: errorOutput.isEmpty ? output : errorOutput))
|
continuation.resume(throwing: ShellError.authenticationFailed)
|
||||||
|
} else {
|
||||||
|
continuation.resume(
|
||||||
|
throwing: ShellError.commandFailed(output: errorOutput.isEmpty ? output : errorOutput)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,4 +124,11 @@ class ShellRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Escapes a string for safe use in bash commands
|
||||||
|
private func bashEscape(_ str: String) -> String {
|
||||||
|
// Use single quotes and escape any single quotes within the string
|
||||||
|
let escaped = str.replacingOccurrences(of: "'", with: "'\"'\"'")
|
||||||
|
return "'\(escaped)'"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user