import Foundation /// 一条 Keychain 凭据(元数据部分,**不含机密**)。 /// 机密(密码/私钥材料/passphrase)经 `CredentialStore.secret(for:)` 按需单条取, /// 列表 UI 只碰这里的 meta,永不为渲染而加载机密(对齐签名后 Keychain 后端的天然分层)。 struct Credential: Identifiable, Codable, Equatable { var id: UUID = UUID() var name: String var username: String var kind: Kind var createdAt: Date = Date() enum Kind: Codable, Equatable { /// 用户名 + 密码。 case password /// SSH 私钥。`publicKeyBlob` 冗余存 SSH 线格式公钥,供列表展示指纹/复制 authorized_keys 而不碰机密。 case privateKey(keyType: KeyType, source: Source, hasPassphrase: Bool, publicKeyBlob: Data) /// Secure Enclave(Face ID)密钥——机密不出 SE,只存 tag 引用。未签名构建下建不出,UI 占位。 case secureEnclave(keyTag: String) } /// 私钥来源。 enum Source: String, Codable { case pasted, imported, generated } /// 私钥算法。libssh2 无 Ed25519、有 ECDSA;"生成新的"默认 P-256。 enum KeyType: String, Codable { case ecdsaP256, ecdsaP384, ecdsaP521, rsa, unknown var displayName: String { switch self { case .ecdsaP256: "ECDSA P-256" case .ecdsaP384: "ECDSA P-384" case .ecdsaP521: "ECDSA P-521" case .rsa: "RSA" case .unknown: "SSH 私钥" } } } // MARK: - 展示辅助 var kindLabel: String { switch kind { case .password: "密码" case .privateKey(let t, _, _, _): t.displayName case .secureEnclave: "Face ID 密钥" } } var iconName: String { switch kind { case .password: "key.fill" case .privateKey: "lock.doc.fill" case .secureEnclave: "faceid" } } /// SSH 线格式公钥 blob(仅私钥类凭据有)。 var publicKeyBlob: Data? { if case .privateKey(_, _, _, let blob) = kind { return blob } return nil } /// authorized_keys 行(生成/导入的私钥可复制到服务器)。 var authorizedKeysLine: String? { guard let blob = publicKeyBlob, !blob.isEmpty else { return nil } // 目前生成的都是 ecdsa-sha2-nistp256;导入的按 keyType 推断算法名。 let algo: String if case .privateKey(let t, _, _, _) = kind { switch t { case .ecdsaP256: algo = "ecdsa-sha2-nistp256" case .ecdsaP384: algo = "ecdsa-sha2-nistp384" case .ecdsaP521: algo = "ecdsa-sha2-nistp521" case .rsa: algo = "ssh-rsa" case .unknown: return nil } } else { return nil } return "\(algo) \(blob.base64EncodedString()) \(username)@terminalx" } } /// 凭据机密(按需加载,自描述解释方式)。 enum CredentialSecret: Codable, Equatable { /// 密码 → `.password` 认证。 case password(String) /// PEM / PKCS#8 私钥文本(导入/粘贴)→ libssh2 `publickey_frommemory`(路径 B)。 case pemPrivateKey(pem: Data, passphrase: String?) /// SecKey 外部表示(生成的软件 P-256 私钥)→ 重建 SecKey → SSHSigner(路径 A)。 case rawECPrivateKey(x963: Data) /// 无机密(Secure Enclave:机密不出安全域)。 case none }