From 1078dc1e90856d199281c8d611dde3c271d242af Mon Sep 17 00:00:00 2001 From: Milton Moura Date: Thu, 26 Feb 2026 11:42:04 -0100 Subject: [PATCH 1/4] Replace KeychainAccess with Valet for Data Protection Keychain usage Signed-off-by: Milton Moura --- Mactrix.xcodeproj/project.pbxproj | 28 +++++++++------ .../xcshareddata/swiftpm/Package.resolved | 20 +++++------ Mactrix/Mactrix.entitlements | 10 ++++++ Mactrix/Models/HomeserverLogin.swift | 6 +++- Mactrix/Models/MatrixClient.swift | 35 ++++++++++++------- .../Models/MatrixClientSessionDelegate.swift | 1 - 6 files changed, 64 insertions(+), 36 deletions(-) create mode 100644 Mactrix/Mactrix.entitlements diff --git a/Mactrix.xcodeproj/project.pbxproj b/Mactrix.xcodeproj/project.pbxproj index d354a95..d4b6a89 100644 --- a/Mactrix.xcodeproj/project.pbxproj +++ b/Mactrix.xcodeproj/project.pbxproj @@ -12,7 +12,7 @@ 348E99882F40ABC3009F57A9 /* AsyncAlgorithms in Frameworks */ = {isa = PBXBuildFile; productRef = 348E99872F40ABC3009F57A9 /* AsyncAlgorithms */; }; 34913F6E2EC0F532003034CB /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 34913F6D2EC0F532003034CB /* MatrixRustSDK */; }; 34913F702EC0F59F003034CB /* Models in Frameworks */ = {isa = PBXBuildFile; productRef = 34913F6F2EC0F59F003034CB /* Models */; }; - 34F7225F2EB531F40007B2A4 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 34F7225E2EB531F40007B2A4 /* KeychainAccess */; }; + C26CE1FD2F4FADF0002A50A7 /* Valet in Frameworks */ = {isa = PBXBuildFile; productRef = C26CE1FC2F4FADF0002A50A7 /* Valet */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -46,11 +46,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C26CE1FD2F4FADF0002A50A7 /* Valet in Frameworks */, 3409F4EC2EBFD8D4009537B4 /* UI in Frameworks */, 34913F6E2EC0F532003034CB /* MatrixRustSDK in Frameworks */, 345E77E82ED9F309002E5B9A /* Utils in Frameworks */, 34913F702EC0F59F003034CB /* Models in Frameworks */, - 34F7225F2EB531F40007B2A4 /* KeychainAccess in Frameworks */, 348E99882F40ABC3009F57A9 /* AsyncAlgorithms in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -103,12 +103,12 @@ ); name = Mactrix; packageProductDependencies = ( - 34F7225E2EB531F40007B2A4 /* KeychainAccess */, 3409F4EB2EBFD8D4009537B4 /* UI */, 34913F6D2EC0F532003034CB /* MatrixRustSDK */, 34913F6F2EC0F59F003034CB /* Models */, 345E77E72ED9F309002E5B9A /* Utils */, 348E99872F40ABC3009F57A9 /* AsyncAlgorithms */, + C26CE1FC2F4FADF0002A50A7 /* Valet */, ); productName = Mactrix; productReference = 343858422EB394590010922A /* Mactrix.app */; @@ -140,9 +140,9 @@ minimizedProjectReferenceProxies = 1; packageReferences = ( 342C624C2EB4DDE600E2426A /* XCRemoteSwiftPackageReference "matrix-rust-components-swift" */, - 34F7225D2EB531F40007B2A4 /* XCRemoteSwiftPackageReference "KeychainAccess" */, 3409F4E82EBFD8D4009537B4 /* XCLocalSwiftPackageReference "MactrixLibrary" */, 348E99862F40ABC3009F57A9 /* XCRemoteSwiftPackageReference "swift-async-algorithms" */, + C26CE1FB2F4FADF0002A50A7 /* XCRemoteSwiftPackageReference "Valet" */, ); preferredProjectObjectVersion = 77; productRefGroup = 343858432EB394590010922A /* Products */; @@ -303,10 +303,13 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; AUTOMATION_APPLE_EVENTS = NO; + CODE_SIGN_ENTITLEMENTS = Mactrix/Mactrix.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = ""; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_INCOMING_NETWORK_CONNECTIONS = NO; @@ -356,10 +359,13 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; AUTOMATION_APPLE_EVENTS = NO; + CODE_SIGN_ENTITLEMENTS = Mactrix/Mactrix.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = ""; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_INCOMING_NETWORK_CONNECTIONS = NO; @@ -450,12 +456,12 @@ minimumVersion = 1.1.2; }; }; - 34F7225D2EB531F40007B2A4 /* XCRemoteSwiftPackageReference "KeychainAccess" */ = { + C26CE1FB2F4FADF0002A50A7 /* XCRemoteSwiftPackageReference "Valet" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess"; + repositoryURL = "https://github.com/square/Valet"; requirement = { - branch = master; - kind = branch; + kind = upToNextMajorVersion; + minimumVersion = 5.1.0; }; }; /* End XCRemoteSwiftPackageReference section */ @@ -483,10 +489,10 @@ isa = XCSwiftPackageProductDependency; productName = Models; }; - 34F7225E2EB531F40007B2A4 /* KeychainAccess */ = { + C26CE1FC2F4FADF0002A50A7 /* Valet */ = { isa = XCSwiftPackageProductDependency; - package = 34F7225D2EB531F40007B2A4 /* XCRemoteSwiftPackageReference "KeychainAccess" */; - productName = KeychainAccess; + package = C26CE1FB2F4FADF0002A50A7 /* XCRemoteSwiftPackageReference "Valet" */; + productName = Valet; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/Mactrix.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mactrix.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c65f2ed..18b6bb4 100644 --- a/Mactrix.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mactrix.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,15 +1,6 @@ { - "originHash" : "d084e0c9b1d3b8ac948908f0ca98de1cca938f342f749686b8062637737a5cf4", + "originHash" : "84591e187e18eae1ade044e76490d68c9217ea50912987cebe430eb6fa4babe7", "pins" : [ - { - "identity" : "keychainaccess", - "kind" : "remoteSourceControl", - "location" : "https://github.com/kishikawakatsumi/KeychainAccess", - "state" : { - "branch" : "master", - "revision" : "e0c7eebc5a4465a3c4680764f26b7a61f567cdaf" - } - }, { "identity" : "matrix-rust-components-swift", "kind" : "remoteSourceControl", @@ -36,6 +27,15 @@ "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", "version" : "1.3.0" } + }, + { + "identity" : "valet", + "kind" : "remoteSourceControl", + "location" : "https://github.com/square/Valet", + "state" : { + "revision" : "246baf6be3f9e3ff116dc05251a08f69dd7c7b9d", + "version" : "5.1.0" + } } ], "version" : 3 diff --git a/Mactrix/Mactrix.entitlements b/Mactrix/Mactrix.entitlements new file mode 100644 index 0000000..47bf92a --- /dev/null +++ b/Mactrix/Mactrix.entitlements @@ -0,0 +1,10 @@ + + + + + keychain-access-groups + + $(AppIdentifierPrefix)dk.qpqp.mactrix + + + diff --git a/Mactrix/Models/HomeserverLogin.swift b/Mactrix/Models/HomeserverLogin.swift index d79fc7d..6fe8b96 100644 --- a/Mactrix/Models/HomeserverLogin.swift +++ b/Mactrix/Models/HomeserverLogin.swift @@ -49,7 +49,11 @@ struct HomeserverLogin { let matrixClient = await MatrixClient(storeID: storeID, client: unauthenticatedClient) let userSession = try matrixClient.userSession() - try userSession.saveUserToKeychain() + do { + try userSession.saveUserToKeychain() + } catch { + print(error.localizedDescription) + } return matrixClient } diff --git a/Mactrix/Models/MatrixClient.swift b/Mactrix/Models/MatrixClient.swift index 8988476..1140120 100644 --- a/Mactrix/Models/MatrixClient.swift +++ b/Mactrix/Models/MatrixClient.swift @@ -1,6 +1,6 @@ import AsyncAlgorithms import Foundation -import KeychainAccess +import Valet import MatrixRustSDK import OSLog import SwiftUI @@ -40,21 +40,27 @@ struct UserSession: Codable { fileprivate static var keychainKey: String { "UserSession" } func saveUserToKeychain() throws { + guard let identifier = Identifier(nonEmpty: Bundle.main.bundleIdentifier) else { + fatalError("Unable to generate keychain identifier") + } + let valet = Valet.valet(with: identifier, accessibility: .whenUnlocked) let keychainData = try JSONEncoder().encode(self) - let keychain = Keychain(service: applicationID) - try keychain.set(keychainData, key: Self.keychainKey) + try valet.setObject(keychainData, forKey: Self.keychainKey) } static func loadUserFromKeychain() throws -> Self? { Logger.matrixClient.debug("Load user from keychain") - /* #if DEBUG - if true { - return try JSONDecoder().decode(Self.self, from: DevSecrets.matrixSession.data(using: .utf8)!) - } - #endif */ - let keychain = Keychain(service: applicationID) - guard let keychainData = try keychain.getData(keychainKey) else { return nil } - return try JSONDecoder().decode(Self.self, from: keychainData) + guard let identifier = Identifier(nonEmpty: Bundle.main.bundleIdentifier) else { + fatalError("Unable to generate keychain identifier") + } + let valet = Valet.valet(with: identifier, accessibility: .whenUnlocked) + if let keychainData = try valet.object(forKey: Self.keychainKey) as Data? { + let sessionData = try JSONDecoder().decode(Self.self, + from: keychainData) + return sessionData + } else { + return nil + } } } @@ -148,8 +154,11 @@ class MatrixClient { try? await client.logout() try? FileManager.default.removeItem(at: .sessionData(for: storeID)) try? FileManager.default.removeItem(at: .sessionCaches(for: storeID)) - let keychain = Keychain(service: applicationID) - try keychain.removeAll() + guard let identifier = Identifier(nonEmpty: Bundle.main.bundleIdentifier) else { + fatalError("Unable to generate keychain identifier") + } + let valet = Valet.valet(with: identifier, accessibility: .whenUnlocked) + try valet.removeAllObjects() Logger.matrixClient.debug("matrix client sign out complete") } diff --git a/Mactrix/Models/MatrixClientSessionDelegate.swift b/Mactrix/Models/MatrixClientSessionDelegate.swift index e0db0e3..455d357 100644 --- a/Mactrix/Models/MatrixClientSessionDelegate.swift +++ b/Mactrix/Models/MatrixClientSessionDelegate.swift @@ -1,5 +1,4 @@ import Foundation -import KeychainAccess import MatrixRustSDK import OSLog import SwiftUI From a1ff085d76bce69ab844520684cae7149d413a72 Mon Sep 17 00:00:00 2001 From: Milton Moura Date: Sun, 1 Mar 2026 15:49:37 -0100 Subject: [PATCH 2/4] Removed Valet, added Keychain wrapper Signed-off-by: Milton Moura --- Mactrix.xcodeproj/project.pbxproj | 27 ++------ .../xcshareddata/swiftpm/Package.resolved | 11 +--- Mactrix/Mactrix.entitlements | 7 +- Mactrix/Models/AppKeychain.swift | 64 +++++++++++++++++++ Mactrix/Models/MatrixClient.swift | 26 ++------ 5 files changed, 77 insertions(+), 58 deletions(-) create mode 100644 Mactrix/Models/AppKeychain.swift diff --git a/Mactrix.xcodeproj/project.pbxproj b/Mactrix.xcodeproj/project.pbxproj index d4b6a89..95dc53d 100644 --- a/Mactrix.xcodeproj/project.pbxproj +++ b/Mactrix.xcodeproj/project.pbxproj @@ -12,7 +12,6 @@ 348E99882F40ABC3009F57A9 /* AsyncAlgorithms in Frameworks */ = {isa = PBXBuildFile; productRef = 348E99872F40ABC3009F57A9 /* AsyncAlgorithms */; }; 34913F6E2EC0F532003034CB /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 34913F6D2EC0F532003034CB /* MatrixRustSDK */; }; 34913F702EC0F59F003034CB /* Models in Frameworks */ = {isa = PBXBuildFile; productRef = 34913F6F2EC0F59F003034CB /* Models */; }; - C26CE1FD2F4FADF0002A50A7 /* Valet in Frameworks */ = {isa = PBXBuildFile; productRef = C26CE1FC2F4FADF0002A50A7 /* Valet */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -46,7 +45,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C26CE1FD2F4FADF0002A50A7 /* Valet in Frameworks */, 3409F4EC2EBFD8D4009537B4 /* UI in Frameworks */, 34913F6E2EC0F532003034CB /* MatrixRustSDK in Frameworks */, 345E77E82ED9F309002E5B9A /* Utils in Frameworks */, @@ -108,7 +106,6 @@ 34913F6F2EC0F59F003034CB /* Models */, 345E77E72ED9F309002E5B9A /* Utils */, 348E99872F40ABC3009F57A9 /* AsyncAlgorithms */, - C26CE1FC2F4FADF0002A50A7 /* Valet */, ); productName = Mactrix; productReference = 343858422EB394590010922A /* Mactrix.app */; @@ -142,7 +139,6 @@ 342C624C2EB4DDE600E2426A /* XCRemoteSwiftPackageReference "matrix-rust-components-swift" */, 3409F4E82EBFD8D4009537B4 /* XCLocalSwiftPackageReference "MactrixLibrary" */, 348E99862F40ABC3009F57A9 /* XCRemoteSwiftPackageReference "swift-async-algorithms" */, - C26CE1FB2F4FADF0002A50A7 /* XCRemoteSwiftPackageReference "Valet" */, ); preferredProjectObjectVersion = 77; productRefGroup = 343858432EB394590010922A /* Products */; @@ -304,8 +300,8 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; AUTOMATION_APPLE_EVENTS = NO; CODE_SIGN_ENTITLEMENTS = Mactrix/Mactrix.entitlements; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; @@ -337,6 +333,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = dk.qpqp.mactrix; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; REGISTER_APP_GROUPS = YES; RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES = NO; RUNTIME_EXCEPTION_ALLOW_JIT = NO; @@ -360,8 +357,8 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; AUTOMATION_APPLE_EVENTS = NO; CODE_SIGN_ENTITLEMENTS = Mactrix/Mactrix.entitlements; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; @@ -393,6 +390,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = dk.qpqp.mactrix; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; REGISTER_APP_GROUPS = YES; RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES = NO; RUNTIME_EXCEPTION_ALLOW_JIT = NO; @@ -456,14 +454,6 @@ minimumVersion = 1.1.2; }; }; - C26CE1FB2F4FADF0002A50A7 /* XCRemoteSwiftPackageReference "Valet" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/square/Valet"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 5.1.0; - }; - }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -489,11 +479,6 @@ isa = XCSwiftPackageProductDependency; productName = Models; }; - C26CE1FC2F4FADF0002A50A7 /* Valet */ = { - isa = XCSwiftPackageProductDependency; - package = C26CE1FB2F4FADF0002A50A7 /* XCRemoteSwiftPackageReference "Valet" */; - productName = Valet; - }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 3438583A2EB394590010922A /* Project object */; diff --git a/Mactrix.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mactrix.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 18b6bb4..a672933 100644 --- a/Mactrix.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mactrix.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "84591e187e18eae1ade044e76490d68c9217ea50912987cebe430eb6fa4babe7", + "originHash" : "2e655dd159a59779ade7006421372d658386daea86b82435cbe33da36bb81efb", "pins" : [ { "identity" : "matrix-rust-components-swift", @@ -27,15 +27,6 @@ "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", "version" : "1.3.0" } - }, - { - "identity" : "valet", - "kind" : "remoteSourceControl", - "location" : "https://github.com/square/Valet", - "state" : { - "revision" : "246baf6be3f9e3ff116dc05251a08f69dd7c7b9d", - "version" : "5.1.0" - } } ], "version" : 3 diff --git a/Mactrix/Mactrix.entitlements b/Mactrix/Mactrix.entitlements index 47bf92a..0c67376 100644 --- a/Mactrix/Mactrix.entitlements +++ b/Mactrix/Mactrix.entitlements @@ -1,10 +1,5 @@ - - keychain-access-groups - - $(AppIdentifierPrefix)dk.qpqp.mactrix - - + diff --git a/Mactrix/Models/AppKeychain.swift b/Mactrix/Models/AppKeychain.swift new file mode 100644 index 0000000..cec05fd --- /dev/null +++ b/Mactrix/Models/AppKeychain.swift @@ -0,0 +1,64 @@ +import Foundation +import Security + +enum KeychainError: Error { + case unexpectedStatus(OSStatus) +} + +struct AppKeychain { + private let service: String + + init(service: String = Bundle.main.bundleIdentifier!) { + self.service = service + } + + private var baseQuery: [CFString: Any] { + [ + kSecClass: kSecClassGenericPassword, + kSecAttrService: service, + kSecUseDataProtectionKeychain: true, + ] + } + + /// Saves data for the given key, creating or updating the keychain item. + func save(_ data: Data, forKey key: String) throws { + var query = baseQuery + query[kSecAttrAccount] = key + + let updateStatus = SecItemUpdate(query as CFDictionary, [kSecValueData: data] as CFDictionary) + if updateStatus == errSecItemNotFound { + query[kSecValueData] = data + query[kSecAttrAccessible] = kSecAttrAccessibleWhenUnlocked + let addStatus = SecItemAdd(query as CFDictionary, nil) + guard addStatus == errSecSuccess else { + throw KeychainError.unexpectedStatus(addStatus) + } + } else if updateStatus != errSecSuccess { + throw KeychainError.unexpectedStatus(updateStatus) + } + } + + /// Returns the data stored for the given key, or `nil` if no item exists. + func load(forKey key: String) throws -> Data? { + var query = baseQuery + query[kSecAttrAccount] = key + query[kSecReturnData] = true + query[kSecMatchLimit] = kSecMatchLimitOne + + var result: AnyObject? + let status = unsafe SecItemCopyMatching(query as CFDictionary, &result) + if status == errSecItemNotFound { return nil } + guard status == errSecSuccess else { + throw KeychainError.unexpectedStatus(status) + } + return result as? Data + } + + /// Removes all keychain items stored under this service. + func removeAll() throws { + let status = SecItemDelete(baseQuery as CFDictionary) + guard status == errSecSuccess || status == errSecItemNotFound else { + throw KeychainError.unexpectedStatus(status) + } + } +} diff --git a/Mactrix/Models/MatrixClient.swift b/Mactrix/Models/MatrixClient.swift index 1140120..9c89a13 100644 --- a/Mactrix/Models/MatrixClient.swift +++ b/Mactrix/Models/MatrixClient.swift @@ -1,6 +1,5 @@ import AsyncAlgorithms import Foundation -import Valet import MatrixRustSDK import OSLog import SwiftUI @@ -40,27 +39,16 @@ struct UserSession: Codable { fileprivate static var keychainKey: String { "UserSession" } func saveUserToKeychain() throws { - guard let identifier = Identifier(nonEmpty: Bundle.main.bundleIdentifier) else { - fatalError("Unable to generate keychain identifier") - } - let valet = Valet.valet(with: identifier, accessibility: .whenUnlocked) let keychainData = try JSONEncoder().encode(self) - try valet.setObject(keychainData, forKey: Self.keychainKey) + try AppKeychain().save(keychainData, forKey: Self.keychainKey) } static func loadUserFromKeychain() throws -> Self? { Logger.matrixClient.debug("Load user from keychain") - guard let identifier = Identifier(nonEmpty: Bundle.main.bundleIdentifier) else { - fatalError("Unable to generate keychain identifier") - } - let valet = Valet.valet(with: identifier, accessibility: .whenUnlocked) - if let keychainData = try valet.object(forKey: Self.keychainKey) as Data? { - let sessionData = try JSONDecoder().decode(Self.self, - from: keychainData) - return sessionData - } else { - return nil + if let keychainData = try AppKeychain().load(forKey: Self.keychainKey) { + return try JSONDecoder().decode(Self.self, from: keychainData) } + return nil } } @@ -154,11 +142,7 @@ class MatrixClient { try? await client.logout() try? FileManager.default.removeItem(at: .sessionData(for: storeID)) try? FileManager.default.removeItem(at: .sessionCaches(for: storeID)) - guard let identifier = Identifier(nonEmpty: Bundle.main.bundleIdentifier) else { - fatalError("Unable to generate keychain identifier") - } - let valet = Valet.valet(with: identifier, accessibility: .whenUnlocked) - try valet.removeAllObjects() + try AppKeychain().removeAll() Logger.matrixClient.debug("matrix client sign out complete") } From 851caf01da6de32654747caf63581757c6d5d108 Mon Sep 17 00:00:00 2001 From: Milton Moura Date: Sun, 1 Mar 2026 15:53:57 -0100 Subject: [PATCH 3/4] Revert changes to xcode project files Signed-off-by: Milton Moura --- Mactrix.xcodeproj/project.pbxproj | 12 ++---------- Mactrix/Mactrix.entitlements | 5 ----- 2 files changed, 2 insertions(+), 15 deletions(-) delete mode 100644 Mactrix/Mactrix.entitlements diff --git a/Mactrix.xcodeproj/project.pbxproj b/Mactrix.xcodeproj/project.pbxproj index 95dc53d..591f0ef 100644 --- a/Mactrix.xcodeproj/project.pbxproj +++ b/Mactrix.xcodeproj/project.pbxproj @@ -299,13 +299,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; AUTOMATION_APPLE_EVENTS = NO; - CODE_SIGN_ENTITLEMENTS = Mactrix/Mactrix.entitlements; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; - DEVELOPMENT_TEAM = ""; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_INCOMING_NETWORK_CONNECTIONS = NO; @@ -333,7 +330,6 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = dk.qpqp.mactrix; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; REGISTER_APP_GROUPS = YES; RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES = NO; RUNTIME_EXCEPTION_ALLOW_JIT = NO; @@ -356,13 +352,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; AUTOMATION_APPLE_EVENTS = NO; - CODE_SIGN_ENTITLEMENTS = Mactrix/Mactrix.entitlements; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; - DEVELOPMENT_TEAM = ""; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_INCOMING_NETWORK_CONNECTIONS = NO; @@ -390,7 +383,6 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = dk.qpqp.mactrix; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; REGISTER_APP_GROUPS = YES; RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES = NO; RUNTIME_EXCEPTION_ALLOW_JIT = NO; diff --git a/Mactrix/Mactrix.entitlements b/Mactrix/Mactrix.entitlements deleted file mode 100644 index 0c67376..0000000 --- a/Mactrix/Mactrix.entitlements +++ /dev/null @@ -1,5 +0,0 @@ - - - - - From 49ebdfd7b044835251a55d606466e7660e349e00 Mon Sep 17 00:00:00 2001 From: Milton Moura Date: Sun, 1 Mar 2026 15:59:35 -0100 Subject: [PATCH 4/4] Disable Data Protection and add comments Signed-off-by: Milton Moura --- Mactrix/Models/AppKeychain.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Mactrix/Models/AppKeychain.swift b/Mactrix/Models/AppKeychain.swift index cec05fd..53b9bdb 100644 --- a/Mactrix/Models/AppKeychain.swift +++ b/Mactrix/Models/AppKeychain.swift @@ -16,7 +16,8 @@ struct AppKeychain { [ kSecClass: kSecClassGenericPassword, kSecAttrService: service, - kSecUseDataProtectionKeychain: true, + /// change to true for Data Protection keychain mode + kSecUseDataProtectionKeychain: false, ] } @@ -34,6 +35,9 @@ struct AppKeychain { throw KeychainError.unexpectedStatus(addStatus) } } else if updateStatus != errSecSuccess { + /// with kSecUseDataProtectionKeychain set to true, this will throw with error -34018, which according to + /// https://github.com/apple-oss-distributions/Security/blob/09becc8fb155462f0853f99cd09c26b10a38e2f4/sec/Security/SecBasePriv.h#L113 + /// is the error "Internal error when a required entitlement isn't present" throw KeychainError.unexpectedStatus(updateStatus) } }