-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathSharedKeychain.swift
More file actions
73 lines (68 loc) · 2.79 KB
/
Copy pathSharedKeychain.swift
File metadata and controls
73 lines (68 loc) · 2.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import BuildSettingsKit
import Foundation
import SFHFKeychainUtils
/// Keychain access scoped to the legacy cross-app shared access group
/// ("3TMU3BH3NK.org.wordpress").
///
/// The ONLY permitted users are the WordPress-to-Jetpack migration contract:
/// 1. DataMigrator.exportData (WordPress: publish the WP.com token)
/// 2. DataMigrator.deleteExportedData (WordPress: remove it on logout)
/// 3. SharedDataIssueSolver.migrateAuthKey (Jetpack: read the token)
///
/// Anything else belongs in `AppKeychain`. A new SharedKeychain call site
/// means a new cross-app data flow; treat it as a design change.
public final class SharedKeychain: KeychainAccessible {
private let group: String
private let keychainUtils: SFHFKeychainUtils.Type
/// Fails where the app has no shared-group entitlement (Reader).
public convenience init?() {
self.init(group: BuildSettings.current.sharedKeychainAccessGroup)
}
init?(group: String?, keychainUtils: SFHFKeychainUtils.Type = SFHFKeychainUtils.self) {
guard let group else { return nil }
self.group = group
self.keychainUtils = keychainUtils
}
public func getPassword(for username: String, serviceName: String) throws -> String {
do {
return try keychainUtils.getPasswordForUsername(
username,
andServiceName: serviceName,
accessGroup: group
)
} catch {
reportKeychainFailureIfNeeded(error, serviceName: serviceName, accessGroup: group)
throw error
}
}
public func setPassword(for username: String, to newValue: String?, serviceName: String) throws {
if let newValue {
do {
try keychainUtils.storeUsername(
username,
andPassword: newValue,
forServiceName: serviceName,
accessGroup: group,
updateExisting: true
)
} catch {
reportKeychainFailureIfNeeded(error, serviceName: serviceName, accessGroup: group)
throw error
}
} else {
do {
try keychainUtils.deleteItem(
forUsername: username,
andServiceName: serviceName,
accessGroup: group
)
} catch {
reportKeychainFailureIfNeeded(error, serviceName: serviceName, accessGroup: group)
// Deleting an already-absent item is success: the migration
// cleanup path removes a token that may legitimately be gone.
// Real failures must surface, same as AppKeychain.
guard !isRealKeychainFailure(error) else { throw error }
}
}
}
}