Implement keychain groups

This commit is contained in:
Maurice Parker 2019-09-22 16:00:06 -05:00
parent 0e12f0192a
commit 20fa5d9e48
8 changed files with 47 additions and 11 deletions

View File

@ -72,6 +72,14 @@ public final class AccountManager: UnreadCountProvider {
return CombinedRefreshProgress(downloadProgressArray: downloadProgressArray)
}
public convenience init() {
let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as! String
let accountsURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup)
let accountsFolder = accountsURL!.appendingPathComponent("Accounts").absoluteString
let accountsFolderPath = accountsFolder.suffix(from: accountsFolder.index(accountsFolder.startIndex, offsetBy: 7))
self.init(accountsFolder: String(accountsFolderPath))
}
public init(accountsFolder: String) {
self.accountsFolder = accountsFolder

View File

@ -10,6 +10,15 @@ import Foundation
public struct CredentialsManager {
private static var keychainGroup: String? = {
guard let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as? String else {
return nil
}
let appIdentifierPrefix = Bundle.main.object(forInfoDictionaryKey: "AppIdentifierPrefix") as! String
let appGroupSuffix = appGroup.suffix(appGroup.count - 6)
return "\(appIdentifierPrefix)\(appGroupSuffix)"
}()
public static func storeCredentials(_ credentials: Credentials, server: String) throws {
var query: [String: Any] = [kSecClass as String: kSecClassInternetPassword,
@ -20,6 +29,10 @@ public struct CredentialsManager {
query[kSecAttrSecurityDomain as String] = credentials.type.rawValue
}
if let securityGroup = keychainGroup {
query[kSecAttrAccessGroup as String] = securityGroup
}
let secretData = credentials.secret.data(using: String.Encoding.utf8)!
let attributes: [String: Any] = [kSecValueData as String: secretData]
let status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary)
@ -59,6 +72,10 @@ public struct CredentialsManager {
query[kSecAttrSecurityDomain as String] = type.rawValue
}
if let securityGroup = keychainGroup {
query[kSecAttrAccessGroup as String] = securityGroup
}
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
@ -93,6 +110,10 @@ public struct CredentialsManager {
query[kSecAttrSecurityDomain as String] = type.rawValue
}
if let securityGroup = keychainGroup {
query[kSecAttrAccessGroup as String] = securityGroup
}
let status = SecItemDelete(query as CFDictionary)
guard status == errSecSuccess || status == errSecItemNotFound else {
throw CredentialsError.unhandledError(status: status)

View File

@ -55,12 +55,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
// Force lazy initialization of the web view provider so that it can warm up the queue of prepared web views
let _ = DetailViewControllerWebViewProvider.shared
let accountsURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.\(Bundle.main.bundleIdentifier!)")
let accountsFolder = accountsURL!.appendingPathComponent("Accounts").absoluteString
let accountsFolderPath = accountsFolder.suffix(from: accountsFolder.index(accountsFolder.startIndex, offsetBy: 7))
AccountManager.shared = AccountManager(accountsFolder: String(accountsFolderPath))
AccountManager.shared = AccountManager()
AppDefaults.shared = UserDefaults.init(suiteName: "group.\(Bundle.main.bundleIdentifier!)")!
registerBackgroundTasks()

View File

@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AppGroup</key>
<string>group.$(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS</string>
<key>AppIdentifierPrefix</key>
<string>$(AppIdentifierPrefix)</string>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>com.ranchero.NetNewsWire.FeedRefresh</string>

View File

@ -6,5 +6,9 @@
<array>
<string>group.$(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)$(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS</string>
</array>
</dict>
</plist>

View File

@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AppGroup</key>
<string>group.$(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS</string>
<key>AppIdentifierPrefix</key>
<string>$(AppIdentifierPrefix)</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>

View File

@ -6,5 +6,9 @@
<array>
<string>group.$(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)$(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS</string>
</array>
</dict>
</plist>

View File

@ -23,11 +23,7 @@ class ShareViewController: SLComposeServiceViewController, ShareFolderPickerCont
override func viewDidLoad() {
let rootID = Bundle.main.bundleIdentifier!.replacingOccurrences(of: ".Share-Extension", with: "")
let accountsURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.\(rootID)")
let accountsFolder = accountsURL!.appendingPathComponent("Accounts").absoluteString
let accountsFolderPath = accountsFolder.suffix(from: accountsFolder.index(accountsFolder.startIndex, offsetBy: 7))
AccountManager.shared = AccountManager(accountsFolder: String(accountsFolderPath))
AccountManager.shared = AccountManager()
pickerData = FlattenedAccountFolderPickerData()