Skip to content

Commit

Permalink
Fix handling of invalid refresh token
Browse files Browse the repository at this point in the history
  • Loading branch information
jstorm31 committed Mar 16, 2021
1 parent ec0057f commit 5cec908
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 8 deletions.
1 change: 1 addition & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ disabled_rules: # rule identifiers to exclude from running
- identifier_name
- trailing_whitespace
- type_name
- opening_brace
opt_in_rules: # some rules are only opt-in
- control_statement
- empty_count
Expand Down
2 changes: 2 additions & 0 deletions Grades/Generated/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ internal enum L10n {
internal enum Auth {
/// Authentication error
internal static let generic = L10n.tr("Localizable", "error.auth.generic")
/// Invalid refresh token
internal static let invalidRefreshToken = L10n.tr("Localizable", "error.auth.invalidRefreshToken")
}
}

Expand Down
3 changes: 3 additions & 0 deletions Grades/Model/Error/AuthenticationError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ import Foundation

enum AuthenticationError: Error {
case generic
case invalidRefreshToken
}

extension AuthenticationError: LocalizedError {
public var errorDescription: String? {
switch self {
case .generic:
return L10n.Error.Auth.generic
case .invalidRefreshToken:
return L10n.Error.Auth.invalidRefreshToken
}
}
}
27 changes: 25 additions & 2 deletions Grades/Service/AuthenticationService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,18 @@ final class AuthenticationService: AuthenticationServiceProtocol {
if handler.client.credential.oauthRefreshToken.isEmpty {
return Observable.just(false)
}
return renewAccessToken.execute().map { _ in true }

return renewAccessToken.execute()
.catchError { [weak self] error in
if case let ActionError.underlyingError(underlyingError) = error,
case AuthenticationError.invalidRefreshToken = underlyingError
{
Log.debug("Removed credentials")
self?.removeCredentialsFromKeychain()
}
throw error
}
.map { _ in true }
}

func logOut() {
Expand Down Expand Up @@ -154,7 +165,19 @@ final class AuthenticationService: AuthenticationServiceProtocol {
observer.onNext(())
observer.onCompleted()
} catch {
observer.onError(ApiError.unprocessableData)
if let errorDict: [String: String] = try? JSONDecoder().decode([String: String].self, from: data),
let errorType = errorDict["error"]
{
if errorType == "invalid_grant" {
observer.onError(AuthenticationError.invalidRefreshToken)
} else {
observer.onError(AuthenticationError.generic)
}
} else {
let errorDescription = String(decoding: data, as: UTF8.self)
Log.error("AuthenticationService: unprocessable data: \(errorDescription)")
observer.onError(ApiError.unprocessableData)
}
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions Grades/Utilities/Log.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@ class Log {

static func error(_ message: String) {
print("⛔️ \(message)")
SentrySDK.capture(message: message)

#if !DEBUG
SentrySDK.capture(message: message)
#endif
}

static func report(_ error: Error) {
print("⛔️ \(error) \(error.localizedDescription)")
SentrySDK.capture(error: error)

#if !DEBUG
SentrySDK.capture(error: error)
#endif
}
}
9 changes: 6 additions & 3 deletions Grades/View/ViewController/LoginViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// Copyright © 2019 jiri.zdovmka. All rights reserved.
//

import Action
import RxSwift
import SnapKit
import UIKit
Expand Down Expand Up @@ -93,7 +94,11 @@ class LoginViewController: BaseViewController, BindableType, ConfirmationModalPr

DispatchQueue.main.async {
if let view = self?.view {
view.makeCustomToast(error.localizedDescription, type: .danger)
if case let ActionError.underlyingError(underlyingError) = error {
view.makeCustomToast(underlyingError.localizedDescription, type: .danger)
} else {
view.makeCustomToast(error.localizedDescription, type: .danger)
}
}
}
})
Expand Down Expand Up @@ -127,8 +132,6 @@ class LoginViewController: BaseViewController, BindableType, ConfirmationModalPr
viewModel.authenticate(viewController: self)
.subscribeOn(MainScheduler.instance)
.subscribe(onError: { [weak self] error in
Log.report(error)

DispatchQueue.main.async {
if let view = self?.view {
view.makeCustomToast(error.localizedDescription, type: .danger)
Expand Down
11 changes: 10 additions & 1 deletion Grades/ViewModel/LoginViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,16 @@ final class LoginViewModel: BaseViewModel {
}

self?.fetching.onNext(true)
return self?.dependencies.authService.authenticateWitRefreshToken() ?? Observable.just(false)

self?.fetching.onNext(false)
return self?.dependencies.authService.authenticateWitRefreshToken().catchError { error in

guard case AuthenticationError.invalidRefreshToken = error else {
throw error
}

return Observable.just(false)
} ?? Observable.just(false)
}
.flatMap(postAuthSetup)
}
Expand Down
1 change: 1 addition & 0 deletions Grades/cs.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"appVersion" = "Verze aplikace";

"error.auth.generic" = "Nastala chyba při autentizaci";
"error.auth.invalidRefreshToken" = "Neplatný refresh token";
"error.api.generic" = "Nastala chyba při stahování dat.";

"labels.noContent" = "Není co zobrazit";
Expand Down
1 change: 1 addition & 0 deletions Grades/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"appVersion" = "App version";

"error.auth.generic" = "Authentication error";
"error.auth.invalidRefreshToken" = "Invalid refresh token";
"error.api.generic" = "Network request error";

"labels.noContent" = "Nothing to display";
Expand Down

0 comments on commit 5cec908

Please sign in to comment.