Commit 047a132c authored by Jose Blaya's avatar Jose Blaya
Browse files

Merge branch 'release/1.1.7' into release/2.0.0

parents e03783b4 16ef6db3
......@@ -65,9 +65,10 @@ public protocol AccountProvider: class {
- Postcondition:
- Posts `Notification.Name.PIAAccountDidUpdate` on success.
- Parameter request: The account update request.
- Parameter password: The credentials to perform the operation.
- Parameter callback: Returns the updated `AccountInfo`.
*/
func update(with request: UpdateAccountRequest, _ callback: LibraryCallback<AccountInfo>?)
func update(with request: UpdateAccountRequest, andPassword password: String, _ callback: LibraryCallback<AccountInfo>?)
/**
Logs out of the system.
......
......@@ -11,9 +11,7 @@ import Foundation
protocol PlainStore: class {
// MARK: Account
var publicUsername: String? { get set }
var accountInfo: AccountInfo? { get set }
var lastSignupEmail: String? { get set }
......
......@@ -17,6 +17,10 @@ protocol SecureStore: class {
func setUsername(_ username: String?)
func publicUsername() -> String?
func setPublicUsername(_ username: String?)
func password(for username: String) -> String?
func setPassword(_ password: String?, for username: String)
......
......@@ -48,7 +48,7 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
}
var publicUsername: String? {
guard let username = accessedDatabase.plain.publicUsername else {
guard let username = accessedDatabase.secure.publicUsername() else {
return nil
}
return username
......@@ -69,7 +69,7 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
}
set {
if let user = newValue {
accessedDatabase.plain.publicUsername = user.credentials.username
accessedDatabase.secure.setPublicUsername(user.credentials.username)
accessedDatabase.secure.setPassword(user.credentials.password, for: user.credentials.username)
accessedDatabase.plain.accountInfo = user.info
} else {
......@@ -77,7 +77,7 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
accessedDatabase.secure.setPassword(nil, for: username)
accessedDatabase.secure.setUsername(nil)
}
accessedDatabase.plain.publicUsername = nil
accessedDatabase.secure.setPublicUsername(nil)
accessedDatabase.plain.accountInfo = nil
}
}
......@@ -111,7 +111,7 @@ 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.publicUsername = username
self.accessedDatabase.secure.setPublicUsername(username)
self.accessedDatabase.secure.setUsername(first)
self.accessedDatabase.secure.setToken(token,
for: self.accessedDatabase.secure.tokenKey(for: first))
......@@ -193,11 +193,13 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
}
}
func update(with request: UpdateAccountRequest, _ callback: ((AccountInfo?, Error?) -> Void)?) {
func update(with request: UpdateAccountRequest, andPassword password: String, _ callback: ((AccountInfo?, Error?) -> Void)?) {
guard let user = currentUser else {
preconditionFailure()
}
webServices.update(credentials: user.credentials, email: request.email) { (error) in
let credentials = Credentials(username: Client.providers.accountProvider.publicUsername ?? "",
password: password)
webServices.update(credentials: credentials, email: request.email) { (error) in
if let _ = error {
callback?(nil, error)
return
......@@ -298,7 +300,7 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
self.accessedStore.finishTransaction(transaction, success: true)
}
self.accessedDatabase.plain.lastSignupEmail = nil
self.accessedDatabase.plain.publicUsername = credentials.username
self.accessedDatabase.secure.setPublicUsername(credentials.username)
self.accessedDatabase.secure.setPassword(credentials.password, for: credentials.username)
let user = UserAccount(credentials: credentials, info: nil)
......@@ -335,7 +337,7 @@ 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.publicUsername = credentials.username
self.accessedDatabase.secure.setPublicUsername(credentials.username)
self.accessedDatabase.secure.setUsername(first)
self.accessedDatabase.secure.setToken(token,
for: self.accessedDatabase.secure.tokenKey(for: first))
......@@ -444,7 +446,7 @@ class DefaultAccountProvider: AccountProvider, ConfigurationAccess, DatabaseAcce
accessedDatabase.secure.setUsername(nil)
accessedDatabase.secure.setToken(nil, for: accessedDatabase.secure.tokenKey(for: username))
}
accessedDatabase.plain.publicUsername = nil
accessedDatabase.secure.setPublicUsername(nil)
accessedDatabase.plain.accountInfo = nil
}
#endif
......
......@@ -57,9 +57,6 @@ extension Client {
- Returns: `self`
*/
@discardableResult public func truncate() -> Self {
if let username = plain.publicUsername {
secure.clear(for: username)
}
plain.clear()
transient = MemoryStore()
return self
......
......@@ -78,6 +78,21 @@ extension KeychainStore {
}
}
extension KeychainStore {
func publicUsername() -> String? {
return try? backend.publicUsername()
}
func setPublicUsername(_ username: String?) {
if let username = username {
try? backend.set(publicUsername: username)
} else {
backend.removePublicUsername()
}
}
}
extension KeychainStore {
func token(for username: String) -> String? {
......
......@@ -20,7 +20,9 @@ enum ClientEndpoint: String, Endpoint {
case token = "v2/token"
case account = "v2/account"
case updateAccount = "account"
case payment
case status
......
......@@ -71,11 +71,11 @@ class PIAWebServices: WebServices, ConfigurationAccess {
}
func update(credentials: Credentials, email: String, _ callback: SuccessLibraryCallback?) {
let endpoint = ClientEndpoint.account
let endpoint = ClientEndpoint.updateAccount
let parameters = ["email": email]
let status = [200]
req(credentials, .post, endpoint, parameters, status, JSONRequestExecutor() { (json, status, error) in
req(credentials, .post, endpoint, useAuthToken: false, parameters, status, JSONRequestExecutor() { (json, status, error) in
if let error = error {
callback?(error)
return
......
......@@ -160,8 +160,8 @@ public class MockAccountProvider: AccountProvider, WebServicesConsumer {
}
/// :nodoc:
public func update(with request: UpdateAccountRequest, _ callback: ((AccountInfo?, Error?) -> Void)?) {
delegate.update(with: request, callback)
public func update(with request: UpdateAccountRequest, andPassword password: String, _ callback: LibraryCallback<AccountInfo>?) {
delegate.update(with: request, andPassword: password, callback)
}
/// :nodoc:
......
......@@ -298,7 +298,7 @@ class EphemeralAccountProvider: AccountProvider, ProvidersAccess, InAppAccess {
fatalError("Not implemented")
}
func update(with request: UpdateAccountRequest, _ callback: ((AccountInfo?, Error?) -> Void)?) {
func update(with request: UpdateAccountRequest, andPassword password: String, _ callback: ((AccountInfo?, Error?) -> Void)?) {
fatalError("Not implemented")
}
......
......@@ -28,6 +28,7 @@ public class Keychain {
private let accessGroup: String?
private let usernameKey = "USERNAME_KEY"
private let publicUsernameKey = "PUBLIC_USERNAME_KEY"
/**
Default initializer. Uses the default keychain associated with the main bundle identifier.
......@@ -287,6 +288,64 @@ extension Keychain {
}
extension Keychain {
// MARK: Public Username
/// :nodoc:
public func set(publicUsername: String) throws {
removePublicUsername()
var query = [String: Any]()
setScope(query: &query)
query[kSecClass as String] = kSecClassGenericPassword
query[kSecAttrAccount as String] = publicUsernameKey
query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
query[kSecValueData as String] = publicUsername.data(using: .utf8)
let status = SecItemAdd(query as CFDictionary, nil)
guard (status == errSecSuccess) else {
throw KeychainError.add
}
}
/// :nodoc:
@discardableResult public func removePublicUsername() -> Bool {
var query = [String: Any]()
setScope(query: &query)
query[kSecClass as String] = kSecClassGenericPassword
query[kSecAttrAccount as String] = publicUsernameKey
let status = SecItemDelete(query as CFDictionary)
return (status == errSecSuccess)
}
/// :nodoc:
public func publicUsername() throws -> String {
var query = [String: Any]()
setScope(query: &query)
query[kSecClass as String] = kSecClassGenericPassword
query[kSecAttrAccount as String] = publicUsernameKey
//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