Files
openclaw/apps/macos/Tests/OpenClawIPCTests/GatewayTLSFakeKeychain.swift
Peter Steinberger 62a6dfb082 fix(macos): direct Gateway TLS pins protect operator traffic (#112353)
* fix(macos): enforce direct Gateway TLS pins

* fix(macos): preserve existing TLS pin owner keys

* fix(macos): reuse localized TLS error labels

* test(macos): avoid nested Swift Testing require

* test(macos): isolate TLS Keychain tests

* test(macos): isolate TLS integration Keychain

* chore(i18n): update native source inventory
2026-07-22 03:38:10 -07:00

88 lines
3.4 KiB
Swift

import Foundation
import Security
@testable import OpenClawKit
private final class MacGatewayTLSFakeKeychain: @unchecked Sendable {
private let lock = NSLock()
private var items: [String: [String: Any]] = [:]
var operations: GatewayTLSKeychainOperations {
GatewayTLSKeychainOperations(
copyMatching: { [self] query, result in self.copyMatching(query, result: result) },
add: { [self] query in self.add(query) },
update: { [self] query, updates in self.update(query, updates: updates) },
delete: { [self] query in self.delete(query) })
}
private func copyMatching(
_ query: CFDictionary,
result: UnsafeMutablePointer<CFTypeRef?>?) -> OSStatus
{
let query = query as NSDictionary as! [String: Any]
guard let account = query[kSecAttrAccount as String] as? String else { return errSecParam }
self.lock.lock()
defer { self.lock.unlock() }
guard let item = self.items[account] else { return errSecItemNotFound }
if query[kSecReturnAttributes as String] as? Bool == true {
result?.pointee = item as CFDictionary
} else {
guard let data = item[kSecValueData as String] as? Data else { return errSecDecode }
result?.pointee = data as CFData
}
return errSecSuccess
}
private func add(_ query: CFDictionary) -> OSStatus {
let query = query as NSDictionary as! [String: Any]
guard let account = query[kSecAttrAccount as String] as? String else { return errSecParam }
self.lock.lock()
defer { self.lock.unlock() }
guard self.items[account] == nil else { return errSecDuplicateItem }
self.items[account] = query
return errSecSuccess
}
private func update(_ query: CFDictionary, updates: CFDictionary) -> OSStatus {
let query = query as NSDictionary as! [String: Any]
let updates = updates as NSDictionary as! [String: Any]
guard let account = query[kSecAttrAccount as String] as? String else { return errSecParam }
self.lock.lock()
defer { self.lock.unlock() }
guard var item = self.items[account] else { return errSecItemNotFound }
if let expected = query[kSecAttrGeneric as String] as? Data,
item[kSecAttrGeneric as String] as? Data != expected
{
return errSecItemNotFound
}
item.merge(updates) { _, replacement in replacement }
self.items[account] = item
return errSecSuccess
}
private func delete(_ query: CFDictionary) -> OSStatus {
let query = query as NSDictionary as! [String: Any]
self.lock.lock()
defer { self.lock.unlock() }
guard let account = query[kSecAttrAccount as String] as? String else {
self.items.removeAll()
return errSecSuccess
}
self.items[account] = nil
return errSecSuccess
}
}
func withFakeGatewayTLSKeychain<T>(_ operation: () throws -> T) rethrows -> T {
let keychain = MacGatewayTLSFakeKeychain()
return try GatewayTLSStore.$keychainOperations.withValue(keychain.operations) {
try operation()
}
}
func withFakeGatewayTLSKeychain<T>(_ operation: () async throws -> T) async rethrows -> T {
let keychain = MacGatewayTLSFakeKeychain()
return try await GatewayTLSStore.$keychainOperations.withValue(keychain.operations) {
try await operation()
}
}