Merge pull request #86 from RobotsAndPencils/improve-auth-errors

Improve authentication error messages that are shown to users
This commit is contained in:
Brandon Evans 2021-01-26 08:50:05 -07:00 committed by GitHub
commit b27b0bfb0e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 14 deletions

View file

@ -126,10 +126,10 @@ public class Client {
switch urlResponse.statusCode { switch urlResponse.statusCode {
case 200..<300: case 200..<300:
return (data, urlResponse) return (data, urlResponse)
case 401: case 400, 401:
throw AuthenticationError.incorrectSecurityCode throw AuthenticationError.incorrectSecurityCode
case let code: case let code:
throw AuthenticationError.badStatusCode(code, data, urlResponse) throw AuthenticationError.badStatusCode(statusCode: code, data: data, response: urlResponse)
} }
} }
.flatMap { (data, response) -> AnyPublisher<AuthenticationState, Error> in .flatMap { (data, response) -> AnyPublisher<AuthenticationState, Error> in
@ -175,28 +175,36 @@ public enum AuthenticationState: Equatable {
public enum AuthenticationError: Swift.Error, LocalizedError, Equatable { public enum AuthenticationError: Swift.Error, LocalizedError, Equatable {
case invalidSession case invalidSession
case invalidUsernameOrPassword(username: String) case invalidUsernameOrPassword(username: String)
case invalidPhoneNumberIndex(min: Int, max: Int, given: String?)
case incorrectSecurityCode case incorrectSecurityCode
case unexpectedSignInResponse(statusCode: Int, message: String?) case unexpectedSignInResponse(statusCode: Int, message: String?)
case appleIDAndPrivacyAcknowledgementRequired case appleIDAndPrivacyAcknowledgementRequired
case accountUsesTwoStepAuthentication case accountUsesTwoStepAuthentication
case accountUsesUnknownAuthenticationKind(String?) case accountUsesUnknownAuthenticationKind(String?)
case badStatusCode(Int, Data, HTTPURLResponse) case badStatusCode(statusCode: Int, data: Data, response: HTTPURLResponse)
public var errorDescription: String? { public var errorDescription: String? {
switch self { switch self {
case .invalidUsernameOrPassword(let username): case .invalidSession:
return "Invalid username and password combination. Attempted to sign in with username \(username)." return "Your authentication session is invalid. Try signing in again."
case .invalidUsernameOrPassword:
return "Invalid username and password combination."
case .incorrectSecurityCode:
return "The code that was entered is incorrect."
case let .unexpectedSignInResponse(statusCode, message):
return """
Received an unexpected sign in response. If you continue to have problems, please submit a bug report in the Help menu and include the following information:
Status code: \(statusCode)
\(message != nil ? ("Message: " + message!) : "")
"""
case .appleIDAndPrivacyAcknowledgementRequired: case .appleIDAndPrivacyAcknowledgementRequired:
return "You must sign in to https://appstoreconnect.apple.com and acknowledge the Apple ID & Privacy agreement." return "You must sign in to https://appstoreconnect.apple.com and acknowledge the Apple ID & Privacy agreement."
case .invalidPhoneNumberIndex(let min, let max, let given):
return "Not a valid phone number index. Expecting a whole number between \(min)-\(max), but was given \(given ?? "nothing")."
case .accountUsesTwoStepAuthentication: case .accountUsesTwoStepAuthentication:
return "Received a response from Apple that indicates this account has two-step authentication enabled. xcodes currently only supports the newer two-factor authentication, though. Please consider upgrading to two-factor authentication, or open an issue on GitHub explaining why this isn't an option for you here: https://github.com/RobotsAndPencils/xcodes/issues/new" return "Received a response from Apple that indicates this account has two-step authentication enabled. xcodes currently only supports the newer two-factor authentication, though. Please consider upgrading to two-factor authentication, or explain why this isn't an option for you by making a new feature request in the Help menu."
case .accountUsesUnknownAuthenticationKind: case .accountUsesUnknownAuthenticationKind:
return "Received a response from Apple that indicates this account has two-step or two-factor authentication enabled, but xcodes is unsure how to handle this response:" return "Received a response from Apple that indicates this account has two-step or two-factor authentication enabled, but xcodes is unsure how to handle this response. If you continue to have problems, please submit a bug report in the Help menu."
default: case let .badStatusCode(statusCode, _, _):
return String(describing: self) return "Received an unexpected status code: \(statusCode). If you continue to have problems, please submit a bug report in the Help menu."
} }
} }
} }

View file

@ -6,6 +6,7 @@ import LegibleError
import KeychainAccess import KeychainAccess
import Path import Path
import Version import Version
import os.log
class AppState: ObservableObject { class AppState: ObservableObject {
private let client = AppleAPI.Client() private let client = AppleAPI.Client()
@ -181,7 +182,7 @@ class AppState: ObservableObject {
try? Current.keychain.remove(username) try? Current.keychain.remove(username)
} }
// This error message is not user friendly... need to extract some meaningful data in the different cases Logger.appState.error("Authentication error: \(error.legibleDescription)")
self.authError = error self.authError = error
case .finished: case .finished:
switch self.authenticationState { switch self.authenticationState {

View file

@ -2,6 +2,7 @@ import SwiftUI
struct AboutView: View { struct AboutView: View {
let showAcknowledgementsWindow: () -> Void let showAcknowledgementsWindow: () -> Void
@SwiftUI.Environment(\.openURL) var openURL: OpenURLAction
var body: some View { var body: some View {
HStack { HStack {
@ -18,7 +19,7 @@ struct AboutView: View {
HStack(spacing: 32) { HStack(spacing: 32) {
Button(action: { Button(action: {
NSWorkspace.shared.open(URL(string: "https://github.com/RobotsAndPencils/XcodesApp/")!) openURL(URL(string: "https://github.com/RobotsAndPencils/XcodesApp/")!)
}) { }) {
Label("GitHub Repo", systemImage: "link") Label("GitHub Repo", systemImage: "link")
} }

View file

@ -7,6 +7,7 @@ import SwiftUI
struct XcodesApp: App { struct XcodesApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate: AppDelegate @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate: AppDelegate
@SwiftUI.Environment(\.scenePhase) private var scenePhase: ScenePhase @SwiftUI.Environment(\.scenePhase) private var scenePhase: ScenePhase
@SwiftUI.Environment(\.openURL) var openURL: OpenURLAction
@StateObject private var appState = AppState() @StateObject private var appState = AppState()
var body: some Scene { var body: some Scene {
@ -51,6 +52,25 @@ struct XcodesApp: App {
} }
XcodeCommands(appState: appState) XcodeCommands(appState: appState)
CommandGroup(replacing: CommandGroupPlacement.help) {
Button("Xcodes GitHub Repo") {
let xcodesRepoURL = URL(string: "https://github.com/RobotsAndPencils/XcodesApp/")!
openURL(xcodesRepoURL)
}
Divider()
Button("Report a Bug") {
let bugReportURL = URL(string: "https://github.com/RobotsAndPencils/XcodesApp/issues/new?assignees=&labels=bug&template=bug_report.md&title=")!
openURL(bugReportURL)
}
Button("Request a New Feature") {
let featureRequestURL = URL(string: "https://github.com/RobotsAndPencils/XcodesApp/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=")!
openURL(featureRequestURL)
}
}
} }
} }