Skip to content

Commit 7c400bb

Browse files
committed
Move Keychain to its own package, remove KeychainAccess
1 parent a060715 commit 7c400bb

File tree

7 files changed

+101
-40
lines changed

7 files changed

+101
-40
lines changed

Copilot for Xcode.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Core/Package.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ let package = Package(
4545
.package(url: "https://github.com/apple/swift-async-algorithms", from: "0.1.0"),
4646
.package(url: "https://github.com/gonzalezreal/swift-markdown-ui", from: "2.1.0"),
4747
.package(url: "https://github.com/sparkle-project/Sparkle", from: "2.0.0"),
48-
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.2"),
4948
.package(url: "https://github.com/pointfreeco/swift-parsing", from: "0.12.1"),
5049
.package(url: "https://github.com/pointfreeco/swift-dependencies", from: "0.5.1"),
5150
.package(
@@ -297,7 +296,7 @@ let package = Package(
297296
name: "CodeiumService",
298297
dependencies: [
299298
"LanguageClient",
300-
"KeychainAccess",
299+
.product(name: "Keychain", package: "Tool"),
301300
.product(name: "SuggestionModel", package: "Tool"),
302301
.product(name: "AppMonitoring", package: "Tool"),
303302
.product(name: "Preferences", package: "Tool"),

Core/Sources/CodeiumService/CodeiumAuthService.swift

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,19 @@
11
import Configs
22
import Foundation
3-
import KeychainAccess
3+
import Keychain
44

55
public final class CodeiumAuthService {
66
public init() {}
77
let codeiumKeyKey = "codeiumAuthKey"
8-
let keychain: Keychain = {
9-
let info = Bundle.main.infoDictionary
10-
return Keychain(service: keychainService, accessGroup: keychainAccessGroup)
11-
.attributes([
12-
kSecUseDataProtectionKeychain as String: true,
13-
])
14-
}()
8+
let keychain = Keychain()
159

16-
var key: String? { try? keychain.getString(codeiumKeyKey) }
10+
var key: String? { try? keychain.get(codeiumKeyKey) }
1711

1812
public var isSignedIn: Bool { return key != nil }
1913

2014
public func signIn(token: String) async throws {
2115
let key = try await generate(token: token)
22-
try keychain.set(key, key: codeiumKeyKey)
16+
try keychain.update(key, key: codeiumKeyKey)
2317
}
2418

2519
public func signOut() async throws {

Core/Sources/ServiceUpdateMigration/ServiceUpdateMigrator.swift

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import Configs
22
import Foundation
33
import GitHubCopilotService
4-
import KeychainAccess
54
import Preferences
65

76
extension UserDefaultPreferenceKeys {
@@ -28,10 +27,6 @@ public struct ServiceUpdateMigrator {
2827
if old <= 135 {
2928
try migrateFromLowerThanOrEqualToVersion135()
3029
}
31-
32-
if old < 170 {
33-
try migrateFromLowerThanOrEqualToVersion170()
34-
}
3530
}
3631
}
3732

@@ -79,16 +74,3 @@ func migrateFromLowerThanOrEqualToVersion135() throws {
7974
)
8075
}
8176

82-
func migrateFromLowerThanOrEqualToVersion170() throws {
83-
let oldKeychain = Keychain(service: keychainService, accessGroup: keychainAccessGroup)
84-
let newKeychain = oldKeychain.attributes([
85-
kSecUseDataProtectionKeychain as String: true,
86-
])
87-
88-
if (try? oldKeychain.contains("codeiumKey")) ?? false,
89-
let key = try? oldKeychain.getString("codeiumKey")
90-
{
91-
try newKeychain.set(key, key: "codeiumAuthKey")
92-
}
93-
}
94-

Pro

Submodule Pro updated from e7fd25b to 751d7c6

Tool/Package.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let package = Package(
1717
.library(name: "Environment", targets: ["Environment"]),
1818
.library(name: "SuggestionModel", targets: ["SuggestionModel"]),
1919
.library(name: "Toast", targets: ["Toast"]),
20+
.library(name: "Keychain", targets: ["Keychain"]),
2021
.library(name: "SharedUIComponents", targets: ["SharedUIComponents"]),
2122
.library(
2223
name: "AppMonitoring",
@@ -57,6 +58,11 @@ let package = Package(
5758

5859
.target(name: "ObjectiveCExceptionHandling"),
5960

61+
.target(
62+
name: "Keychain",
63+
dependencies: ["Configs"]
64+
),
65+
6066
.target(
6167
name: "Toast",
6268
dependencies: [.product(
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import Configs
2+
import Foundation
3+
import Security
4+
5+
public struct Keychain {
6+
let service = keychainService
7+
let accessGroup = keychainAccessGroup
8+
9+
public enum Error: Swift.Error {
10+
case failedToDeleteFromKeyChain
11+
case failedToUpdateOrSetItem
12+
}
13+
14+
public init() {}
15+
16+
func query(_ key: String) -> [String: Any] {
17+
[
18+
kSecClass as String: kSecClassGenericPassword as String,
19+
kSecAttrService as String: service,
20+
kSecAttrAccessGroup as String: accessGroup,
21+
kSecAttrAccount as String: key,
22+
kSecUseDataProtectionKeychain as String: true,
23+
]
24+
}
25+
26+
func set(_ value: String, key: String) throws {
27+
let query = query(key).merging([
28+
kSecValueData as String: value.data(using: .utf8) ?? Data(),
29+
], uniquingKeysWith: { _, b in b })
30+
31+
let result = SecItemAdd(query as CFDictionary, nil)
32+
33+
switch result {
34+
case noErr:
35+
return
36+
default:
37+
throw Error.failedToUpdateOrSetItem
38+
}
39+
}
40+
41+
public func update(_ value: String, key: String) throws {
42+
let query = query(key).merging([
43+
kSecMatchLimit as String: kSecMatchLimitOne,
44+
kSecReturnData as String: true,
45+
], uniquingKeysWith: { _, b in b })
46+
47+
let attributes: [String: Any] =
48+
[kSecValueData as String: value.data(using: .utf8) ?? Data()]
49+
50+
let result = SecItemUpdate(query as CFDictionary, attributes as CFDictionary)
51+
52+
switch result {
53+
case noErr:
54+
return
55+
case errSecItemNotFound:
56+
try set(value, key: key)
57+
default:
58+
throw Error.failedToUpdateOrSetItem
59+
}
60+
}
61+
62+
public func get(_ key: String) throws -> String? {
63+
let query = query(key).merging([
64+
kSecMatchLimit as String: kSecMatchLimitOne,
65+
kSecReturnData as String: true,
66+
kSecReturnAttributes as String: true,
67+
], uniquingKeysWith: { _, b in b })
68+
69+
var item: CFTypeRef?
70+
if SecItemCopyMatching(query as CFDictionary, &item) == noErr {
71+
if let existingItem = item as? [String: Any],
72+
let passwordData = existingItem[kSecValueData as String] as? Data,
73+
let password = String(data: passwordData, encoding: .utf8)
74+
{
75+
return password
76+
}
77+
return nil
78+
} else {
79+
return nil
80+
}
81+
}
82+
83+
public func remove(_ key: String) throws {
84+
if SecItemDelete(query(key) as CFDictionary) == noErr {
85+
return
86+
}
87+
throw Error.failedToDeleteFromKeyChain
88+
}
89+
}

0 commit comments

Comments
 (0)