1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-04 20:54:50 +00:00

refactor: improve sudo error handling to distinguish authentication failures and adjust scene view rotation speed.

This commit is contained in:
Tw93
2025-12-15 15:09:40 +08:00
parent 4547f5819e
commit 4c18957aae
4 changed files with 55 additions and 11 deletions

View File

@@ -165,7 +165,7 @@ struct MoleSceneView: NSViewRepresentable {
// Slower, majestic rotation
// Auto Rotation Speed
// 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
let dragInfluence = Double(parent.rotationVelocity.width) * 0.0005

View File

@@ -24,11 +24,30 @@ class OptimizerService: ObservableObject {
_ = try await ShellRunner.shared.runSudo(command, password: pw)
return
} 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 {
AuthContext.shared.needsPassword = true
self.statusMessage = "Waiting for Password..."

View File

@@ -144,12 +144,23 @@ class ScannerService: ObservableObject {
do {
_ = try await ShellRunner.shared.runSudo(fullCommand, password: sessionPw)
} catch {
print("Sudo command error: \(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 {
AuthContext.shared.needsPassword = true
self.currentLog = "Password Incorrect/Expired"
self.currentLog = "Error: \(error.localizedDescription)"
self.isCleaning = false
}
return 0

View File

@@ -3,11 +3,13 @@ import Foundation
enum ShellError: Error, LocalizedError {
case commandFailed(output: String)
case executionError(error: Error)
case authenticationFailed
var errorDescription: String? {
switch self {
case .commandFailed(let output): return output
case .executionError(let error): return error.localizedDescription
case .authenticationFailed: return "Authentication failed - incorrect password"
}
}
}
@@ -98,10 +100,15 @@ class ShellRunner {
if process.terminationStatus == 0 {
continuation.resume(returning: output)
} else {
// If 1, it might be wrong password or command fail.
// sudo usually complains to stderr.
continuation.resume(
throwing: ShellError.commandFailed(output: errorOutput.isEmpty ? output : errorOutput))
// Check for password failure
let combined = (output + errorOutput).lowercased()
if combined.contains("try again") || combined.contains("incorrect") {
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)'"
}
}