Restructure project folders
This commit is contained in:
94
ABS Client Mac/Audiobookshelf swift/Services/AuthStore.swift
Normal file
94
ABS Client Mac/Audiobookshelf swift/Services/AuthStore.swift
Normal file
@@ -0,0 +1,94 @@
|
||||
import Foundation
|
||||
import Observation
|
||||
|
||||
enum AuthError: LocalizedError {
|
||||
case invalidURL
|
||||
case badResponse(Int)
|
||||
case noToken
|
||||
case unknown(String)
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case .invalidURL: return "Ungültige Server-URL."
|
||||
case .badResponse(let code): return "Server antwortete mit Status \(code)."
|
||||
case .noToken: return "Login fehlgeschlagen: kein Token erhalten."
|
||||
case .unknown(let msg): return msg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Observable
|
||||
@MainActor
|
||||
final class AuthStore {
|
||||
var isLoggedIn: Bool = false
|
||||
var serverURL: String = ""
|
||||
var username: String = ""
|
||||
var token: String = ""
|
||||
var errorMessage: String?
|
||||
|
||||
func restoreSession() {
|
||||
guard let creds = KeychainStore.load() else { return }
|
||||
self.serverURL = creds.serverURL
|
||||
self.username = creds.username
|
||||
self.token = creds.token
|
||||
self.isLoggedIn = true
|
||||
}
|
||||
|
||||
func login(serverURL rawURL: String, username: String, password: String, remember: Bool) async {
|
||||
errorMessage = nil
|
||||
let normalized = Self.normalizeURL(rawURL)
|
||||
guard let url = URL(string: normalized + "/login") else {
|
||||
errorMessage = AuthError.invalidURL.errorDescription
|
||||
return
|
||||
}
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "POST"
|
||||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
let body = ["username": username, "password": password]
|
||||
request.httpBody = try? JSONEncoder().encode(body)
|
||||
|
||||
do {
|
||||
let (data, response) = try await URLSession.shared.data(for: request)
|
||||
guard let http = response as? HTTPURLResponse else {
|
||||
errorMessage = "Keine HTTP-Antwort vom Server."
|
||||
return
|
||||
}
|
||||
guard (200..<300).contains(http.statusCode) else {
|
||||
errorMessage = AuthError.badResponse(http.statusCode).errorDescription
|
||||
return
|
||||
}
|
||||
let decoded = try JSONDecoder().decode(LoginResponseDTO.self, from: data)
|
||||
self.serverURL = normalized
|
||||
self.username = decoded.user.username ?? username
|
||||
self.token = decoded.user.token
|
||||
self.isLoggedIn = true
|
||||
|
||||
if remember {
|
||||
try? KeychainStore.save(StoredCredentials(
|
||||
serverURL: normalized,
|
||||
username: self.username,
|
||||
token: self.token
|
||||
))
|
||||
} else {
|
||||
KeychainStore.delete()
|
||||
}
|
||||
} catch {
|
||||
errorMessage = "Login fehlgeschlagen: \(error.localizedDescription)"
|
||||
}
|
||||
}
|
||||
|
||||
func logout() {
|
||||
KeychainStore.delete()
|
||||
token = ""
|
||||
isLoggedIn = false
|
||||
}
|
||||
|
||||
static func normalizeURL(_ raw: String) -> String {
|
||||
var s = raw.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
while s.hasSuffix("/") { s.removeLast() }
|
||||
if !s.lowercased().hasPrefix("http://") && !s.lowercased().hasPrefix("https://") {
|
||||
s = "https://" + s
|
||||
}
|
||||
return s
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user