Skip to content

Commit a12793a

Browse files
Merge pull request #134 from woocommerce/issue/session-manager
SessionManager: Credentials + Settings storage
2 parents 9faac23 + 537861e commit a12793a

File tree

12 files changed

+315
-248
lines changed

12 files changed

+315
-248
lines changed

WooCommerce/Classes/AppDelegate.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ extension AppDelegate {
165165
/// Whenever there is no default WordPress.com Account, let's display the Authentication UI.
166166
///
167167
func displayAuthenticatorIfNeeded() {
168-
guard needsAuthentication else {
168+
guard StoresManager.shared.isAuthenticated == false else {
169169
return
170170
}
171171

@@ -181,10 +181,4 @@ extension AppDelegate {
181181

182182
authenticationManager.displayAuthentication(from: rootViewController)
183183
}
184-
185-
/// Indicates if there's a default WordPress.com account.
186-
///
187-
var needsAuthentication: Bool {
188-
return CredentialsManager.shared.needsDefaultCredentials
189-
}
190184
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import Foundation
2+
3+
4+
5+
// MARK: - WooCommerce UserDefaults Keys
6+
//
7+
extension UserDefaults {
8+
enum Key: String {
9+
case defaultUsername
10+
case defaultStoreID
11+
}
12+
}
13+
14+
15+
// MARK: - Convenience Methods
16+
//
17+
extension UserDefaults {
18+
19+
/// Returns the Object (if any) associated with the specified Key.
20+
///
21+
func object<T>(forKey key: Key) -> T? {
22+
return value(forKey: key.rawValue) as? T
23+
}
24+
25+
/// Stores the Key/Value Pair.
26+
///
27+
func set<T>(_ value: T?, forKey key: Key) {
28+
set(value, forKey: key.rawValue)
29+
}
30+
31+
/// Nukes any object associated with the specified Key.
32+
///
33+
func removeObject(forKey key: Key) {
34+
removeObject(forKey: key.rawValue)
35+
}
36+
37+
/// Subscript Accessible via our new Key type!
38+
///
39+
subscript<T>(key: Key) -> T? {
40+
get {
41+
return value(forKey: key.rawValue) as? T
42+
}
43+
set {
44+
set(newValue, forKey: key.rawValue)
45+
}
46+
}
47+
48+
/// Subscript: "Type Inference Fallback". To be used whenever the type cannot be automatically inferred!
49+
///
50+
subscript(key: Key) -> Any? {
51+
get {
52+
return value(forKey: key.rawValue)
53+
}
54+
set {
55+
set(newValue, forKey: key.rawValue)
56+
}
57+
}
58+
}

WooCommerce/Classes/System/CredentialsManager.swift

Lines changed: 0 additions & 92 deletions
This file was deleted.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import Foundation
2+
import Yosemite
3+
import KeychainAccess
4+
5+
6+
7+
/// SessionManager provides persistent storage for Session-Y Properties.
8+
///
9+
struct SessionManager {
10+
11+
/// Standard Session Manager
12+
///
13+
static var standard: SessionManager {
14+
return SessionManager(defaults: .standard, keychainServiceName: WooConstants.keychainServiceName)
15+
}
16+
17+
/// Reference to the UserDefaults Instance that should be used.
18+
///
19+
private let defaults: UserDefaults
20+
21+
/// KeychainAccess Wrapper.
22+
///
23+
private let keychain: Keychain
24+
25+
/// Active Credentials.
26+
///
27+
var credentials: Credentials? {
28+
get {
29+
return loadCredentials()
30+
}
31+
set {
32+
guard let credentials = newValue else {
33+
removeCredentials()
34+
return
35+
}
36+
37+
saveCredentials(credentials)
38+
}
39+
}
40+
41+
/// Active Store's Site ID.
42+
///
43+
var storeID: Int? {
44+
get {
45+
return defaults[.defaultStoreID]
46+
}
47+
set {
48+
defaults[.defaultStoreID] = storeID
49+
}
50+
}
51+
52+
53+
/// Designated Initializer.
54+
///
55+
init(defaults: UserDefaults, keychainServiceName: String) {
56+
self.defaults = defaults
57+
self.keychain = Keychain(service: keychainServiceName).accessibility(.afterFirstUnlock)
58+
}
59+
60+
/// Nukes all of the known Session's properties.
61+
///
62+
mutating func reset() {
63+
credentials = nil
64+
storeID = nil
65+
}
66+
}
67+
68+
69+
// MARK: - Private Methods
70+
//
71+
private extension SessionManager {
72+
73+
/// Returns the Default Credentials, if any.
74+
///
75+
func loadCredentials() -> Credentials? {
76+
guard let username = defaults[.defaultUsername] as? String, let authToken = keychain[username] else {
77+
return nil
78+
}
79+
80+
return Credentials(username: username, authToken: authToken)
81+
}
82+
83+
/// Persists the Credentials's authToken in the keychain, and username in User Settings.
84+
///
85+
func saveCredentials(_ credentials: Credentials) {
86+
defaults[.defaultUsername] = credentials.username
87+
keychain[credentials.username] = credentials.authToken
88+
}
89+
90+
/// Nukes both, the AuthToken and Default Username.
91+
///
92+
func removeCredentials() {
93+
guard let username = defaults[.defaultUsername] as? String else {
94+
return
95+
}
96+
97+
keychain[username] = nil
98+
defaults[.defaultUsername] = nil
99+
}
100+
}

WooCommerce/Classes/System/WooConstants.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import Foundation
33

44
/// WooCommerce Constants
55
///
6-
struct WooConstants {
6+
enum WooConstants {
77

8-
/// Private: No-OP!
8+
/// Keychain Access's Service Name
99
///
10-
private init() {}
10+
static let keychainServiceName = "com.automattic.woocommerce"
1111

1212
/// Jetpack Setup URL
1313
///

WooCommerce/Classes/Yosemite/AuthenticatedState.swift

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,10 @@ class AuthenticatedState: StoresManagerState {
2121
///
2222
private let services: [ActionsProcessor]
2323

24-
/// CredentialsManager: By Reference, for unit testing purposes.
25-
///
26-
private let keychain: CredentialsManager
27-
28-
2924

3025
/// Designated Initializer
3126
///
32-
init(keychain: CredentialsManager, credentials: Credentials) {
27+
init(credentials: Credentials) {
3328
let storageManager = CoreDataManager.global
3429
let network = AlamofireNetwork(credentials: credentials)
3530

@@ -39,15 +34,12 @@ class AuthenticatedState: StoresManagerState {
3934
]
4035

4136
self.credentials = credentials
42-
self.keychain = keychain
4337
}
4438

4539

4640
/// Executed whenever the state is activated.
4741
///
48-
func didEnter() {
49-
keychain.saveDefaultCredentials(credentials)
50-
}
42+
func didEnter() { }
5143

5244

5345
/// Forwards the received action to the Actions Dispatcher.

WooCommerce/Classes/Yosemite/DeauthenticatedState.swift

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,9 @@ import Yosemite
77
//
88
class DeauthenticatedState: StoresManagerState {
99

10-
/// CredentialsManager: By Reference, for unit testing purposes.
11-
///
12-
private let keychain: CredentialsManager
13-
14-
15-
/// Designated Initializer
16-
///
17-
init(keychain: CredentialsManager) {
18-
self.keychain = keychain
19-
}
20-
2110
/// This method should run only when the app got deauthenticated.
2211
///
2312
func didEnter() {
24-
keychain.removeDefaultCredentials()
2513
AppDelegate.shared.displayAuthenticator()
2614
}
2715

0 commit comments

Comments
 (0)