mirror of
https://github.com/writeas/writefreely-swiftui-multiplatform.git
synced 2024-11-15 01:11:02 +00:00
Merge pull request #191 from writefreely/throw-keychain-errors-instead-of-crashing
Throw (and handle) Keychain error instead of crashing
This commit is contained in:
commit
b523606f6f
@ -6,6 +6,9 @@ enum AccountError: Error {
|
|||||||
case usernameNotFound
|
case usernameNotFound
|
||||||
case serverNotFound
|
case serverNotFound
|
||||||
case invalidServerURL
|
case invalidServerURL
|
||||||
|
case couldNotSaveTokenToKeychain
|
||||||
|
case couldNotFetchTokenFromKeychain
|
||||||
|
case couldNotDeleteTokenFromKeychain
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AccountError: LocalizedError {
|
extension AccountError: LocalizedError {
|
||||||
@ -31,6 +34,21 @@ extension AccountError: LocalizedError {
|
|||||||
"Please enter a valid instance domain name. It should look like \"https://example.com\" or \"write.as\".", // swiftlint:disable:this line_length
|
"Please enter a valid instance domain name. It should look like \"https://example.com\" or \"write.as\".", // swiftlint:disable:this line_length
|
||||||
comment: ""
|
comment: ""
|
||||||
)
|
)
|
||||||
|
case .couldNotSaveTokenToKeychain:
|
||||||
|
return NSLocalizedString(
|
||||||
|
"There was a problem trying to save your access token to the device, please try logging in again.",
|
||||||
|
comment: ""
|
||||||
|
)
|
||||||
|
case .couldNotFetchTokenFromKeychain:
|
||||||
|
return NSLocalizedString(
|
||||||
|
"There was a problem trying to fetch your access token from the device, please try logging in again.",
|
||||||
|
comment: ""
|
||||||
|
)
|
||||||
|
case .couldNotDeleteTokenFromKeychain:
|
||||||
|
return NSLocalizedString(
|
||||||
|
"There was a problem trying to delete your access token from the device, please try logging out again.",
|
||||||
|
comment: ""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,16 @@ extension WriteFreelyModel {
|
|||||||
let user = try result.get()
|
let user = try result.get()
|
||||||
fetchUserCollections()
|
fetchUserCollections()
|
||||||
fetchUserPosts()
|
fetchUserPosts()
|
||||||
saveTokenToKeychain(user.token, username: user.username, server: account.server)
|
do {
|
||||||
DispatchQueue.main.async {
|
try saveTokenToKeychain(user.token, username: user.username, server: account.server)
|
||||||
self.account.login(user)
|
DispatchQueue.main.async {
|
||||||
|
self.account.login(user)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.loginErrorMessage = "There was a problem storing your access token to the Keychain."
|
||||||
|
self.isPresentingLoginErrorAlert = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch WFError.notFound {
|
} catch WFError.notFound {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension WriteFreelyModel {
|
extension WriteFreelyModel {
|
||||||
func saveTokenToKeychain(_ token: String, username: String?, server: String) {
|
|
||||||
|
enum WFKeychainError: Error {
|
||||||
|
case saveToKeychainFailed
|
||||||
|
case purgeFromKeychainFailed
|
||||||
|
case fetchFromKeychainFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveTokenToKeychain(_ token: String, username: String?, server: String) throws {
|
||||||
let query: [String: Any] = [
|
let query: [String: Any] = [
|
||||||
kSecClass as String: kSecClassGenericPassword,
|
kSecClass as String: kSecClassGenericPassword,
|
||||||
kSecValueData as String: token.data(using: .utf8)!,
|
kSecValueData as String: token.data(using: .utf8)!,
|
||||||
@ -10,7 +17,7 @@ extension WriteFreelyModel {
|
|||||||
]
|
]
|
||||||
let status = SecItemAdd(query as CFDictionary, nil)
|
let status = SecItemAdd(query as CFDictionary, nil)
|
||||||
guard status == errSecDuplicateItem || status == errSecSuccess else {
|
guard status == errSecDuplicateItem || status == errSecSuccess else {
|
||||||
fatalError("Error storing in Keychain with OSStatus: \(status)")
|
throw WFKeychainError.saveToKeychainFailed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,11 +29,11 @@ extension WriteFreelyModel {
|
|||||||
]
|
]
|
||||||
let status = SecItemDelete(query as CFDictionary)
|
let status = SecItemDelete(query as CFDictionary)
|
||||||
guard status == errSecSuccess || status == errSecItemNotFound else {
|
guard status == errSecSuccess || status == errSecItemNotFound else {
|
||||||
fatalError("Error deleting from Keychain with OSStatus: \(status)")
|
throw WFKeychainError.purgeFromKeychainFailed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchTokenFromKeychain(username: String?, server: String) -> String? {
|
func fetchTokenFromKeychain(username: String?, server: String) throws -> String? {
|
||||||
let query: [String: Any] = [
|
let query: [String: Any] = [
|
||||||
kSecClass as String: kSecClassGenericPassword,
|
kSecClass as String: kSecClassGenericPassword,
|
||||||
kSecAttrAccount as String: username ?? "anonymous",
|
kSecAttrAccount as String: username ?? "anonymous",
|
||||||
@ -41,7 +48,7 @@ extension WriteFreelyModel {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
guard status == errSecSuccess else {
|
guard status == errSecSuccess else {
|
||||||
fatalError("Error fetching from Keychain with OSStatus: \(status)")
|
throw WFKeychainError.fetchFromKeychainFailed
|
||||||
}
|
}
|
||||||
guard let existingSecItem = secItem as? [String: Any],
|
guard let existingSecItem = secItem as? [String: Any],
|
||||||
let tokenData = existingSecItem[kSecValueData as String] as? Data,
|
let tokenData = existingSecItem[kSecValueData as String] as? Data,
|
||||||
@ -50,4 +57,5 @@ extension WriteFreelyModel {
|
|||||||
}
|
}
|
||||||
return token
|
return token
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -51,18 +51,25 @@ final class WriteFreelyModel: ObservableObject {
|
|||||||
print("Server URL not found")
|
print("Server URL not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let token = self.fetchTokenFromKeychain(
|
do {
|
||||||
username: self.account.username,
|
guard let token = try self.fetchTokenFromKeychain(
|
||||||
server: self.account.server
|
username: self.account.username,
|
||||||
) else {
|
server: self.account.server
|
||||||
print("Could not fetch token from Keychain")
|
) else {
|
||||||
return
|
self.loginErrorMessage = AccountError.couldNotFetchTokenFromKeychain.localizedDescription
|
||||||
|
self.isPresentingLoginErrorAlert = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.account.login(WFUser(token: token, username: self.account.username))
|
||||||
|
self.client = WFClient(for: serverURL)
|
||||||
|
self.client?.user = self.account.user
|
||||||
|
self.fetchUserCollections()
|
||||||
|
self.fetchUserPosts()
|
||||||
|
} catch {
|
||||||
|
self.loginErrorMessage = AccountError.couldNotFetchTokenFromKeychain.localizedDescription
|
||||||
|
self.isPresentingLoginErrorAlert = true
|
||||||
}
|
}
|
||||||
self.account.login(WFUser(token: token, username: self.account.username))
|
|
||||||
self.client = WFClient(for: serverURL)
|
|
||||||
self.client?.user = self.account.user
|
|
||||||
self.fetchUserCollections()
|
|
||||||
self.fetchUserPosts()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -969,7 +969,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 612;
|
CURRENT_PROJECT_VERSION = 615;
|
||||||
DEVELOPMENT_TEAM = TPPAB4YBA6;
|
DEVELOPMENT_TEAM = TPPAB4YBA6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
INFOPLIST_FILE = iOS/Info.plist;
|
INFOPLIST_FILE = iOS/Info.plist;
|
||||||
@ -978,7 +978,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.6;
|
MARKETING_VERSION = 1.0.7;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform";
|
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform";
|
||||||
PRODUCT_NAME = "WriteFreely-MultiPlatform";
|
PRODUCT_NAME = "WriteFreely-MultiPlatform";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@ -993,7 +993,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 612;
|
CURRENT_PROJECT_VERSION = 615;
|
||||||
DEVELOPMENT_TEAM = TPPAB4YBA6;
|
DEVELOPMENT_TEAM = TPPAB4YBA6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
INFOPLIST_FILE = iOS/Info.plist;
|
INFOPLIST_FILE = iOS/Info.plist;
|
||||||
@ -1002,7 +1002,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.6;
|
MARKETING_VERSION = 1.0.7;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform";
|
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform";
|
||||||
PRODUCT_NAME = "WriteFreely-MultiPlatform";
|
PRODUCT_NAME = "WriteFreely-MultiPlatform";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
Loading…
Reference in New Issue
Block a user