Skip to content

Improve authentication error messages that are shown to users #86

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 20 additions & 12 deletions Xcodes/AppleAPI/Sources/AppleAPI/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,10 @@ public class Client {
switch urlResponse.statusCode {
case 200..<300:
return (data, urlResponse)
case 401:
case 400, 401:
throw AuthenticationError.incorrectSecurityCode
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
Expand Down Expand Up @@ -175,28 +175,36 @@ public enum AuthenticationState: Equatable {
public enum AuthenticationError: Swift.Error, LocalizedError, Equatable {
case invalidSession
case invalidUsernameOrPassword(username: String)
case invalidPhoneNumberIndex(min: Int, max: Int, given: String?)
case incorrectSecurityCode
case unexpectedSignInResponse(statusCode: Int, message: String?)
case appleIDAndPrivacyAcknowledgementRequired
case accountUsesTwoStepAuthentication
case accountUsesUnknownAuthenticationKind(String?)
case badStatusCode(Int, Data, HTTPURLResponse)
case badStatusCode(statusCode: Int, data: Data, response: HTTPURLResponse)

public var errorDescription: String? {
switch self {
case .invalidUsernameOrPassword(let username):
return "Invalid username and password combination. Attempted to sign in with username \(username)."
case .invalidSession:
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:
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:
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:
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:"
default:
return String(describing: self)
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."
case let .badStatusCode(statusCode, _, _):
return "Received an unexpected status code: \(statusCode). If you continue to have problems, please submit a bug report in the Help menu."
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion Xcodes/Backend/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import LegibleError
import KeychainAccess
import Path
import Version
import os.log

class AppState: ObservableObject {
private let client = AppleAPI.Client()
Expand Down Expand Up @@ -181,7 +182,7 @@ class AppState: ObservableObject {
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
case .finished:
switch self.authenticationState {
Expand Down
3 changes: 2 additions & 1 deletion Xcodes/Frontend/About/AboutView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import SwiftUI

struct AboutView: View {
let showAcknowledgementsWindow: () -> Void
@SwiftUI.Environment(\.openURL) var openURL: OpenURLAction

var body: some View {
HStack {
Expand All @@ -18,7 +19,7 @@ struct AboutView: View {

HStack(spacing: 32) {
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")
}
Expand Down
20 changes: 20 additions & 0 deletions Xcodes/XcodesApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import SwiftUI
struct XcodesApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate: AppDelegate
@SwiftUI.Environment(\.scenePhase) private var scenePhase: ScenePhase
@SwiftUI.Environment(\.openURL) var openURL: OpenURLAction
@StateObject private var appState = AppState()

var body: some Scene {
Expand Down Expand Up @@ -51,6 +52,25 @@ struct XcodesApp: App {
}

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)
}
}
}
}

Expand Down