// // AuthenticationManager.swift // elpha-ios // // Created by Dwayne Harris on 8/25/18. // Copyright © 2018 Elpha. All rights reserved. // import Alamofire import CoreData import UIKit protocol AuthenticationDelegate: class { func authenticationSuccess(_ sender: Any) func authenticationFailure(_ sender: Any, error: Error?) } class AuthenticationManager { static var authenticationState: String? static var authenticationClient: ClientMO? static weak var authenticationDelegate: AuthenticationDelegate? static var sessions: [SessionMO] { get { do { let request = NSFetchRequest(entityName: "Session") return try CoreDataManager.shared.context.fetch(request) } catch { print("Error fetching Sessions \(error)") return [] } } } static var session: SessionMO? { get { let request = NSFetchRequest(entityName: "Session") request.predicate = NSPredicate(format: "selected = YES") do { let results = try CoreDataManager.shared.context.fetch(request) return results.first } catch { print("Error fetching Session \(error)") return nil } } } static var token: String? { get { guard let account = session?.account, let client = session?.client else { return nil } return KeychainWrapper.standard.string(forKey: "token:\(account.username!)@\(client.host!)") } } static func saveSession(client: ClientMO, account: AccountMO, token: String) -> SessionMO? { if let session = self.session { session.selected = false } let session = SessionMO(context: CoreDataManager.shared.context) session.client = client session.account = account session.order = 0 session.createdAt = Date() session.selected = true CoreDataManager.shared.saveContext() KeychainWrapper.standard.set(token, forKey: "token:\(account.username!)@\(client.host!)") return session } static func deleteSelectedSession() { guard let session = self.session else { return } KeychainWrapper.standard.removeObject(forKey: "token:\(session.account!.username!)@\(session.client!.host!)") CoreDataManager.shared.context.delete(session) } static func handle(url: URL) { guard let state = authenticationState, let client = authenticationClient else { return } if let components = URLComponents(url: url, resolvingAgainstBaseURL: false), let queryItems = components.queryItems { var code: String? for item in queryItems { switch item.name.lowercased() { case "code": code = item.value case "state": if item.value != state { self.authenticationDelegate?.authenticationFailure(self, error: nil) return } default: continue } } let parameters: Parameters = [ "client_id": client.clientID!, "client_secret": client.clientSecret!, "grant_type": "authorization_code", "code": code!, "redirect_uri": Config.clientRedirectURI, ] Alamofire.request( "https://\(client.host!)/oauth/token", method: .post, parameters: parameters, encoding: URLEncoding.default ).validate().responseJSON { response in switch response.result { case .success(let data): let serverURL = URL(string: "https://\(client.host!)") if let json = data as? [String: Any], let token = json["access_token"] as? String { MastodonAPI.currentUser(token: token, serverURL: serverURL!) { data, error in guard let data = data, error == nil else { AlertManager.shared.show(message: error!.localizedDescription, category: .error) return } let account = MastodonDataManager.upsertAccount(data) _ = AuthenticationManager.saveSession(client: client, account: account!, token: token) self.authenticationDelegate?.authenticationSuccess(self) } } case .failure(let error): self.authenticationDelegate?.authenticationFailure(self, error: error) } } } } }