1
0
Files
card/ios/AiCard/AiCard/Services/AuthManager.swift
2025-06-09 01:51:15 +09:00

138 lines
4.5 KiB
Swift

import Foundation
import Combine
import SwiftUI
class AuthManager: ObservableObject {
@Published var isAuthenticated = false
@Published var currentUser: User?
@Published var isLoading = false
@Published var errorMessage: String?
@Published var authMode: AuthMode = .oauth
private var cancellables = Set<AnyCancellable>()
private let apiClient = APIClient.shared
private let oauthService = AtprotoOAuthService.shared
enum AuthMode {
case oauth
case legacy
}
init() {
// Monitor OAuth service
oauthService.$isAuthenticated
.receive(on: DispatchQueue.main)
.sink { [weak self] isAuth in
if isAuth, let session = self?.oauthService.session {
self?.isAuthenticated = true
self?.currentUser = User(did: session.did, handle: session.handle)
}
}
.store(in: &cancellables)
checkAuthStatus()
}
private func checkAuthStatus() {
isLoading = true
// Check OAuth session first
if oauthService.isAuthenticated, let session = oauthService.session {
isAuthenticated = true
currentUser = User(did: session.did, handle: session.handle)
isLoading = false
return
}
// Fallback to legacy auth
apiClient.verify()
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { [weak self] completion in
self?.isLoading = false
if case .failure = completion {
self?.isAuthenticated = false
self?.currentUser = nil
}
},
receiveValue: { [weak self] user in
self?.isAuthenticated = true
self?.currentUser = user
}
)
.store(in: &cancellables)
}
func loginWithOAuth() {
isLoading = true
errorMessage = nil
oauthService.initiateOAuthFlow()
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { [weak self] completion in
self?.isLoading = false
if case .failure(let error) = completion {
self?.errorMessage = error.localizedDescription
}
},
receiveValue: { [weak self] session in
self?.isAuthenticated = true
self?.currentUser = User(did: session.did, handle: session.handle)
}
)
.store(in: &cancellables)
}
func loginWithPassword(identifier: String, password: String) {
isLoading = true
errorMessage = nil
apiClient.login(identifier: identifier, password: password)
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { [weak self] completion in
self?.isLoading = false
if case .failure(let error) = completion {
self?.errorMessage = self?.getErrorMessage(from: error)
}
},
receiveValue: { [weak self] response in
self?.isAuthenticated = true
self?.currentUser = User(did: response.did, handle: response.handle)
}
)
.store(in: &cancellables)
}
func logout() {
isLoading = true
// Logout from both services
oauthService.logout()
apiClient.logout()
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { [weak self] _ in
self?.isLoading = false
self?.isAuthenticated = false
self?.currentUser = nil
UserDefaults.standard.removeObject(forKey: "authToken")
},
receiveValue: { _ in }
)
.store(in: &cancellables)
}
private func getErrorMessage(from error: APIError) -> String {
switch error {
case .unauthorized:
return "認証情報が正しくありません"
case .networkError:
return "ネットワークエラーが発生しました"
default:
return "エラーが発生しました"
}
}
}