Commit 0b39a978 authored by Jose Blaya's avatar Jose Blaya
Browse files

Save the username in the plainStore to display the value across the views

Save the username token in the secure store
parent 88a35155
......@@ -25,6 +25,9 @@ public protocol AccountProvider: class {
/// The current auth token, or 'nil' if logged out.
var token: String? { get }
/// The public username to be displayed in the views.
var publicUsername: String? { get }
/// The password reference object associated with the currentUser, or `nil` if logged out.
var currentPasswordReference: Data? { get }
......
......@@ -12,7 +12,7 @@ protocol PlainStore: class {
// MARK: Account
var username: String? { get set }
var publicUsername: String? { get set }
var accountInfo: AccountInfo? { get set }
......
......@@ -13,6 +13,10 @@ protocol SecureStore: class {
@discardableResult func setPublicKey(withData data: Data) -> SecKey?
func username() -> String?
func setUsername(_ username: String?)
func password(for username: String) -> String?
func setPassword(_ password: String?, for username: String)
......
......@@ -41,15 +41,22 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
#endif
var isLoggedIn: Bool {
guard let username = accessedDatabase.plain.username else {
guard let username = accessedDatabase.secure.username() else {
return false
}
return (accessedDatabase.secure.password(for: username) != nil)
}
var publicUsername: String? {
guard let username = accessedDatabase.plain.publicUsername else {
return nil
}
return username
}
var currentUser: UserAccount? {
get {
guard let username = accessedDatabase.plain.username else {
guard let username = accessedDatabase.secure.username() else {
return nil
}
guard let password = accessedDatabase.secure.password(for: username) else {
......@@ -62,21 +69,22 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
}
set {
if let user = newValue {
accessedDatabase.plain.username = user.credentials.username
accessedDatabase.plain.publicUsername = user.credentials.username
accessedDatabase.secure.setPassword(user.credentials.password, for: user.credentials.username)
accessedDatabase.plain.accountInfo = user.info
} else {
if let username = accessedDatabase.plain.username {
if let username = accessedDatabase.secure.username() {
accessedDatabase.secure.setPassword(nil, for: username)
accessedDatabase.secure.setUsername(nil)
}
accessedDatabase.plain.username = nil
accessedDatabase.plain.publicUsername = nil
accessedDatabase.plain.accountInfo = nil
}
}
}
var token: String? {
guard let username = accessedDatabase.plain.username else {
guard let username = accessedDatabase.secure.username() else {
return nil
}
return accessedDatabase.secure.token(for: accessedDatabase.secure.tokenKey(for: username))
......@@ -84,7 +92,7 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
var currentPasswordReference: Data? {
guard let username = accessedDatabase.plain.username else {
guard let username = accessedDatabase.secure.username() else {
return nil
}
return accessedDatabase.secure.passwordReference(for: username)
......@@ -114,7 +122,8 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
let tokenComponents = token.split(by: token.count/2)
if let first = tokenComponents.first,
let last = tokenComponents.last {
self.accessedDatabase.plain.username = first
self.accessedDatabase.plain.publicUsername = request.credentials.username
self.accessedDatabase.secure.setUsername(first)
self.accessedDatabase.secure.setToken(token,
for: self.accessedDatabase.secure.tokenKey(for: first))
self.accessedDatabase.secure.setPassword(last,
......@@ -188,11 +197,12 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
guard isLoggedIn else {
preconditionFailure()
}
if let username = accessedDatabase.plain.username {
if let username = accessedDatabase.secure.username() {
accessedDatabase.secure.setPassword(nil, for: username)
accessedDatabase.secure.setUsername(nil)
accessedDatabase.secure.setToken(nil, for: accessedDatabase.secure.tokenKey(for: username))
}
accessedDatabase.plain.username = nil
accessedDatabase.plain.publicUsername = nil
accessedDatabase.plain.accountInfo = nil
Macros.postNotification(.PIAAccountDidLogout)
callback?(nil)
......@@ -270,7 +280,7 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
self.accessedStore.finishTransaction(transaction, success: true)
}
self.accessedDatabase.plain.lastSignupEmail = nil
self.accessedDatabase.plain.username = credentials.username
self.accessedDatabase.plain.publicUsername = credentials.username
self.accessedDatabase.secure.setPassword(credentials.password, for: credentials.username)
let user = UserAccount(credentials: credentials, info: nil)
......@@ -307,7 +317,8 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
let tokenComponents = token.split(by: token.count/2)
if let first = tokenComponents.first,
let last = tokenComponents.last {
self.accessedDatabase.plain.username = first
self.accessedDatabase.plain.publicUsername = credentials.username
self.accessedDatabase.secure.setUsername(first)
self.accessedDatabase.secure.setToken(token,
for: self.accessedDatabase.secure.tokenKey(for: first))
self.accessedDatabase.secure.setPassword(last,
......
......@@ -57,7 +57,7 @@ extension Client {
- Returns: `self`
*/
@discardableResult public func truncate() -> Self {
if let username = plain.username {
if let username = plain.publicUsername {
secure.clear(for: username)
}
plain.clear()
......
......@@ -63,6 +63,21 @@ class KeychainStore: SecureStore {
}
}
extension KeychainStore {
func username() -> String? {
return try? backend.username()
}
func setUsername(_ username: String?) {
if let username = username {
try? backend.set(username: username)
} else {
backend.removeUsername()
}
}
}
extension KeychainStore {
func token(for username: String) -> String? {
......
......@@ -76,7 +76,7 @@ class UserDefaultsStore: PlainStore, ConfigurationAccess {
// MARK: Account
var username: String? {
var publicUsername: String? {
get {
return backend.string(forKey: Entries.username)
}
......
......@@ -115,6 +115,10 @@ public class MockAccountProvider: AccountProvider, WebServicesConsumer {
public var token: String? {
return "TOKEN"
}
public var publicUsername: String? {
return "p0000000"
}
/// :nodoc:
public var currentUser: UserAccount? {
......
......@@ -330,6 +330,8 @@ class EphemeralAccountProvider: AccountProvider, ProvidersAccess, InAppAccess {
var currentUser: UserAccount?
var publicUsername: String?
var currentPasswordReference: Data? {
return nil
}
......
......@@ -26,6 +26,8 @@ public class Keychain {
private let service: String?
private let accessGroup: String?
private let usernameKey = "USERNAME_KEY"
/**
Default initializer. Uses the default keychain associated with the main bundle identifier.
......@@ -227,6 +229,64 @@ public class Keychain {
}
}
extension Keychain {
// MARK: Username
/// :nodoc:
public func set(username: String) throws {
removeUsername()
var query = [String: Any]()
setScope(query: &query)
query[kSecClass as String] = kSecClassGenericPassword
query[kSecAttrAccount as String] = usernameKey
query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
query[kSecValueData as String] = username.data(using: .utf8)
let status = SecItemAdd(query as CFDictionary, nil)
guard (status == errSecSuccess) else {
throw KeychainError.add
}
}
/// :nodoc:
@discardableResult public func removeUsername() -> Bool {
var query = [String: Any]()
setScope(query: &query)
query[kSecClass as String] = kSecClassGenericPassword
query[kSecAttrAccount as String] = usernameKey
let status = SecItemDelete(query as CFDictionary)
return (status == errSecSuccess)
}
/// :nodoc:
public func username() throws -> String {
var query = [String: Any]()
setScope(query: &query)
query[kSecClass as String] = kSecClassGenericPassword
query[kSecAttrAccount as String] = usernameKey
//query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
query[kSecMatchLimit as String] = kSecMatchLimitOne
query[kSecReturnData as String] = true
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
guard (status == errSecSuccess) else {
throw KeychainError.notFound
}
guard let data = result as? Data else {
throw KeychainError.notFound
}
guard let token = String(data: data, encoding: .utf8) else {
throw KeychainError.notFound
}
return token
}
}
extension Keychain {
// MARK: Token
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment