Authentication working
* Updates to use new API style per discussion with Maurice * Credential validation functioning
This commit is contained in:
parent
de82f718d5
commit
0df86e5761
|
@ -252,6 +252,9 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||||
// MARK: - API
|
// MARK: - API
|
||||||
|
|
||||||
public func storeCredentials(_ credentials: Credentials) throws {
|
public func storeCredentials(_ credentials: Credentials) throws {
|
||||||
|
// The delegate may need the credentials to determine the server
|
||||||
|
delegate.credentials = credentials
|
||||||
|
|
||||||
guard let server = delegate.server else {
|
guard let server = delegate.server else {
|
||||||
throw CredentialsError.incompleteCredentials
|
throw CredentialsError.incompleteCredentials
|
||||||
}
|
}
|
||||||
|
@ -259,7 +262,9 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||||
switch credentials {
|
switch credentials {
|
||||||
case .basic(let username, _):
|
case .basic(let username, _):
|
||||||
self.username = username
|
self.username = username
|
||||||
case .googleLogin(let username, _, _, _):
|
case .googleBasicLogin(let username, _, _):
|
||||||
|
self.username = username
|
||||||
|
case .googleAuthLogin(let username, _, _):
|
||||||
self.username = username
|
self.username = username
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,7 +289,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||||
self.username = nil
|
self.username = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func validateCredentials(transport: Transport = URLSession.webserviceTransport(), type: AccountType, credentials: Credentials, completion: @escaping (Result<Bool, Error>) -> Void) {
|
public static func validateCredentials(transport: Transport = URLSession.webserviceTransport(), type: AccountType, credentials: Credentials, completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||||
switch type {
|
switch type {
|
||||||
case .onMyMac:
|
case .onMyMac:
|
||||||
LocalAccountDelegate.validateCredentials(transport: transport, credentials: credentials, completion: completion)
|
LocalAccountDelegate.validateCredentials(transport: transport, credentials: credentials, completion: completion)
|
||||||
|
|
|
@ -46,6 +46,6 @@ protocol AccountDelegate {
|
||||||
// Called at the end of account’s init method.
|
// Called at the end of account’s init method.
|
||||||
func accountDidInitialize(_ account: Account)
|
func accountDidInitialize(_ account: Account)
|
||||||
|
|
||||||
static func validateCredentials(transport: Transport, credentials: Credentials, completion: @escaping (Result<Bool, Error>) -> Void)
|
static func validateCredentials(transport: Transport, credentials: Credentials, completion: @escaping (Result<Credentials?, Error>) -> Void)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ final class FeedbinAPICaller: NSObject {
|
||||||
self.transport = transport
|
self.transport = transport
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateCredentials(completion: @escaping (Result<Bool, Error>) -> Void) {
|
func validateCredentials(completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||||
|
|
||||||
let callURL = feedbinBaseURL.appendingPathComponent("authentication.json")
|
let callURL = feedbinBaseURL.appendingPathComponent("authentication.json")
|
||||||
let request = URLRequest(url: callURL, credentials: credentials)
|
let request = URLRequest(url: callURL, credentials: credentials)
|
||||||
|
@ -50,12 +50,12 @@ final class FeedbinAPICaller: NSObject {
|
||||||
transport.send(request: request) { result in
|
transport.send(request: request) { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .success:
|
case .success:
|
||||||
completion(.success(true))
|
completion(.success(self.credentials))
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
switch error {
|
switch error {
|
||||||
case TransportError.httpError(let status):
|
case TransportError.httpError(let status):
|
||||||
if status == 401 {
|
if status == 401 {
|
||||||
completion(.success(false))
|
completion(.success(self.credentials))
|
||||||
} else {
|
} else {
|
||||||
completion(.failure(error))
|
completion(.failure(error))
|
||||||
}
|
}
|
||||||
|
|
|
@ -485,7 +485,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
accountMetadata = account.metadata
|
accountMetadata = account.metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
static func validateCredentials(transport: Transport, credentials: Credentials, completion: @escaping (Result<Bool, Error>) -> Void) {
|
static func validateCredentials(transport: Transport, credentials: Credentials, completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||||
|
|
||||||
let caller = FeedbinAPICaller(transport: transport)
|
let caller = FeedbinAPICaller(transport: transport)
|
||||||
caller.credentials = credentials
|
caller.credentials = credentials
|
||||||
|
|
|
@ -35,41 +35,43 @@ final class GoogleReaderCompatibleAPICaller: NSObject {
|
||||||
private var transport: Transport!
|
private var transport: Transport!
|
||||||
|
|
||||||
var credentials: Credentials?
|
var credentials: Credentials?
|
||||||
var apiAuthToken: String?
|
|
||||||
weak var accountMetadata: AccountMetadata?
|
weak var accountMetadata: AccountMetadata?
|
||||||
|
|
||||||
|
var server: String? {
|
||||||
|
get {
|
||||||
|
guard let localCredentials = credentials else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch localCredentials {
|
||||||
|
case .googleBasicLogin(_, _, let apiUrl):
|
||||||
|
return apiUrl.host
|
||||||
|
case .googleAuthLogin(_, _, let apiUrl):
|
||||||
|
return apiUrl.host
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
init(transport: Transport) {
|
init(transport: Transport) {
|
||||||
super.init()
|
super.init()
|
||||||
self.transport = transport
|
self.transport = transport
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateCredentials(completion: @escaping (Result<Bool, Error>) -> Void) {
|
func validateCredentials(completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||||
guard let credentials = credentials else {
|
guard let credentials = credentials else {
|
||||||
completion(.failure(CredentialsError.incompleteCredentials))
|
completion(.failure(CredentialsError.incompleteCredentials))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard case .googleLogin(let username, let password, let apiUrl, _) = credentials else {
|
guard case .googleBasicLogin(let username, _, let apiUrl) = credentials else {
|
||||||
completion(.failure(CredentialsError.incompleteCredentials))
|
completion(.failure(CredentialsError.incompleteCredentials))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard var loginURL = URLComponents(url: apiUrl.appendingPathComponent("/accounts/ClientLogin"), resolvingAgainstBaseURL: false) else {
|
let request = URLRequest(url: apiUrl.appendingPathComponent("/accounts/ClientLogin"), credentials: credentials)
|
||||||
completion(.failure(CredentialsError.incompleteCredentials))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
loginURL.queryItems = [
|
|
||||||
URLQueryItem(name: "Email", value: username),
|
|
||||||
URLQueryItem(name: "Passwd", value: password)
|
|
||||||
]
|
|
||||||
|
|
||||||
guard let callURL = loginURL.url else {
|
|
||||||
completion(.failure(CredentialsError.incompleteCredentials))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let request = URLRequest(url: callURL, credentials: credentials)
|
|
||||||
|
|
||||||
transport.send(request: request) { result in
|
transport.send(request: request) { result in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -97,20 +99,11 @@ final class GoogleReaderCompatibleAPICaller: NSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save Auth Token for later use
|
// Save Auth Token for later use
|
||||||
self.apiAuthToken = authString
|
self.credentials = .googleAuthLogin(username: username, apiKey: authString, url: apiUrl)
|
||||||
|
|
||||||
completion(.success(true))
|
completion(.success(self.credentials))
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
switch error {
|
completion(.failure(error))
|
||||||
case TransportError.httpError(let status):
|
|
||||||
if status == 401 {
|
|
||||||
completion(.success(false))
|
|
||||||
} else {
|
|
||||||
completion(.failure(error))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
completion(.failure(error))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,12 @@ final class GoogleReaderCompatibleAccountDelegate: AccountDelegate {
|
||||||
private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "GoogleReaderCompatible")
|
private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "GoogleReaderCompatible")
|
||||||
|
|
||||||
let supportsSubFolders = false
|
let supportsSubFolders = false
|
||||||
let server: String? = "api.GoogleReaderCompatible.com"
|
var server: String? {
|
||||||
|
get {
|
||||||
|
return caller.server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var opmlImportInProgress = false
|
var opmlImportInProgress = false
|
||||||
|
|
||||||
var credentials: Credentials? {
|
var credentials: Credentials? {
|
||||||
|
@ -485,7 +490,7 @@ final class GoogleReaderCompatibleAccountDelegate: AccountDelegate {
|
||||||
accountMetadata = account.metadata
|
accountMetadata = account.metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
static func validateCredentials(transport: Transport, credentials: Credentials, completion: @escaping (Result<Bool, Error>) -> Void) {
|
static func validateCredentials(transport: Transport, credentials: Credentials, completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||||
|
|
||||||
let caller = GoogleReaderCompatibleAPICaller(transport: transport)
|
let caller = GoogleReaderCompatibleAPICaller(transport: transport)
|
||||||
caller.credentials = credentials
|
caller.credentials = credentials
|
||||||
|
|
|
@ -182,8 +182,8 @@ final class LocalAccountDelegate: AccountDelegate {
|
||||||
func accountDidInitialize(_ account: Account) {
|
func accountDidInitialize(_ account: Account) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static func validateCredentials(transport: Transport, credentials: Credentials, completion: (Result<Bool, Error>) -> Void) {
|
static func validateCredentials(transport: Transport, credentials: Credentials, completion: (Result<Credentials?, Error>) -> Void) {
|
||||||
return completion(.success(false))
|
return completion(.success(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,38 +74,36 @@ class AccountsFeedbinWindowController: NSWindowController {
|
||||||
self.progressIndicator.stopAnimation(self)
|
self.progressIndicator.stopAnimation(self)
|
||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let authenticated):
|
case .success(let validatedCredentials):
|
||||||
|
|
||||||
if authenticated {
|
guard let validatedCredentials = validatedCredentials else {
|
||||||
|
self.errorMessageLabel.stringValue = NSLocalizedString("Invalid email/password combination.", comment: "Credentials Error")
|
||||||
var newAccount = false
|
return
|
||||||
if self.account == nil {
|
}
|
||||||
self.account = AccountManager.shared.createAccount(type: .feedbin)
|
var newAccount = false
|
||||||
newAccount = true
|
if self.account == nil {
|
||||||
}
|
self.account = AccountManager.shared.createAccount(type: .feedbin)
|
||||||
|
newAccount = true
|
||||||
do {
|
}
|
||||||
try self.account?.removeBasicCredentials()
|
|
||||||
try self.account?.storeCredentials(credentials)
|
do {
|
||||||
if newAccount {
|
try self.account?.removeBasicCredentials()
|
||||||
self.account?.refreshAll() { result in
|
try self.account?.storeCredentials(validatedCredentials)
|
||||||
switch result {
|
if newAccount {
|
||||||
case .success:
|
self.account?.refreshAll() { result in
|
||||||
break
|
switch result {
|
||||||
case .failure(let error):
|
case .success:
|
||||||
NSApplication.shared.presentError(error)
|
break
|
||||||
}
|
case .failure(let error):
|
||||||
|
NSApplication.shared.presentError(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
|
||||||
} catch {
|
|
||||||
self.errorMessageLabel.stringValue = NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error")
|
|
||||||
}
|
}
|
||||||
|
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
||||||
} else {
|
} catch {
|
||||||
self.errorMessageLabel.stringValue = NSLocalizedString("Invalid email/password combination.", comment: "Credentials Error")
|
self.errorMessageLabel.stringValue = NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
case .failure:
|
case .failure:
|
||||||
|
|
||||||
self.errorMessageLabel.stringValue = NSLocalizedString("Network error. Try again later.", comment: "Credentials Error")
|
self.errorMessageLabel.stringValue = NSLocalizedString("Network error. Try again later.", comment: "Credentials Error")
|
||||||
|
|
|
@ -70,7 +70,7 @@ class AccountsGoogleReaderCompatibleWindowController: NSWindowController {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let credentials = Credentials.googleLogin(username: usernameTextField.stringValue, password: passwordTextField.stringValue, apiUrl: apiURL, apiKey: nil)
|
let credentials = Credentials.googleBasicLogin(username: usernameTextField.stringValue, password: passwordTextField.stringValue, url: apiURL)
|
||||||
Account.validateCredentials(type: .googleReaderCompatible, credentials: credentials) { [weak self] result in
|
Account.validateCredentials(type: .googleReaderCompatible, credentials: credentials) { [weak self] result in
|
||||||
|
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
@ -80,42 +80,39 @@ class AccountsGoogleReaderCompatibleWindowController: NSWindowController {
|
||||||
self.progressIndicator.stopAnimation(self)
|
self.progressIndicator.stopAnimation(self)
|
||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let authenticated):
|
case .success(let validatedCredentials):
|
||||||
|
guard let validatedCredentials = validatedCredentials else {
|
||||||
|
self.errorMessageLabel.stringValue = NSLocalizedString("Invalid email/password combination.", comment: "Credentials Error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if authenticated {
|
|
||||||
|
var newAccount = false
|
||||||
var newAccount = false
|
if self.account == nil {
|
||||||
if self.account == nil {
|
self.account = AccountManager.shared.createAccount(type: .googleReaderCompatible)
|
||||||
self.account = AccountManager.shared.createAccount(type: .googleReaderCompatible)
|
newAccount = true
|
||||||
newAccount = true
|
}
|
||||||
}
|
|
||||||
|
do {
|
||||||
do {
|
try self.account?.removeBasicCredentials()
|
||||||
try self.account?.removeBasicCredentials()
|
try self.account?.storeCredentials(validatedCredentials)
|
||||||
try self.account?.storeCredentials(credentials)
|
if newAccount {
|
||||||
if newAccount {
|
self.account?.refreshAll() { result in
|
||||||
self.account?.refreshAll() { result in
|
switch result {
|
||||||
switch result {
|
case .success:
|
||||||
case .success:
|
break
|
||||||
break
|
case .failure(let error):
|
||||||
case .failure(let error):
|
NSApplication.shared.presentError(error)
|
||||||
NSApplication.shared.presentError(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
|
||||||
} catch {
|
|
||||||
self.errorMessageLabel.stringValue = NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error")
|
|
||||||
}
|
}
|
||||||
|
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
||||||
} else {
|
} catch {
|
||||||
self.errorMessageLabel.stringValue = NSLocalizedString("Invalid email/password combination.", comment: "Credentials Error")
|
self.errorMessageLabel.stringValue = NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
case .failure:
|
case .failure:
|
||||||
|
|
||||||
self.errorMessageLabel.stringValue = NSLocalizedString("Network error. Try again later.", comment: "Credentials Error")
|
self.errorMessageLabel.stringValue = NSLocalizedString("Network error. Try again later.", comment: "Credentials Error")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 261feb7537eb7c6dc425fd1c9e24b22dea8fc982
|
Subproject commit 07ec7f9179dfdf7e89fc97a4a90c4690fa71581a
|
Loading…
Reference in New Issue