| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- import Foundation
- import Security
- // MARK: - Managed slskd API Credentials
- /// Auto-generated credentials for the managed slskd instance.
- /// Separate Keychain service from SlskdCredentials (which stores Soulseek P2P login).
- enum ManagedSlskdKeychainService {
- private static let service = "com.mixboard.slskd-managed"
- static func save(account: String, value: String) throws {
- guard let data = value.data(using: .utf8) else {
- throw KeychainService.KeychainError.saveFailed(errSecParam)
- }
- let deleteQuery: [String: Any] = [
- kSecClass as String: kSecClassGenericPassword,
- kSecAttrService as String: service,
- kSecAttrAccount as String: account,
- ]
- SecItemDelete(deleteQuery as CFDictionary)
- let addQuery: [String: Any] = [
- kSecClass as String: kSecClassGenericPassword,
- kSecAttrService as String: service,
- kSecAttrAccount as String: account,
- kSecValueData as String: data,
- kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked,
- ]
- let status = SecItemAdd(addQuery as CFDictionary, nil)
- guard status == errSecSuccess else {
- throw KeychainService.KeychainError.saveFailed(status)
- }
- }
- static func load(account: String) -> String? {
- let query: [String: Any] = [
- kSecClass as String: kSecClassGenericPassword,
- kSecAttrService as String: service,
- kSecReturnData as String: true,
- kSecMatchLimit as String: kSecMatchLimitOne,
- kSecAttrAccount as String: account,
- ]
- var result: AnyObject?
- let status = SecItemCopyMatching(query as CFDictionary, &result)
- guard status == errSecSuccess, let data = result as? Data else { return nil }
- return String(data: data, encoding: .utf8)
- }
- }
- /// Manages auto-generated API credentials for the managed slskd subprocess.
- /// On first access, generates random credentials and persists them in Keychain.
- @MainActor
- final class ManagedSlskdCredentials {
- static let shared = ManagedSlskdCredentials()
- /// Returns existing credentials or generates new ones.
- func ensureCredentials() throws -> (username: String, password: String) {
- if let u = ManagedSlskdKeychainService.load(account: "username"),
- let p = ManagedSlskdKeychainService.load(account: "password"),
- !u.isEmpty, !p.isEmpty {
- return (u, p)
- }
- let username = "mixboard"
- let password = UUID().uuidString
- try ManagedSlskdKeychainService.save(account: "username", value: username)
- try ManagedSlskdKeychainService.save(account: "password", value: password)
- return (username, password)
- }
- var username: String? { ManagedSlskdKeychainService.load(account: "username") }
- var password: String? { ManagedSlskdKeychainService.load(account: "password") }
- }
|