mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 13:26:16 +00:00
simplified logic by saving Keypairs as an array to defaults, but without the privateKey and passphrase for obvious reasons
added codingkeys, omitting the sensitive ones like privatekey and keypair added init from decoder to skip privatekey and passphrase removed keyTypes and keyNames, vastly simplifying logic
This commit is contained in:
@@ -16,9 +16,11 @@ class KeyManager: ObservableObject {
|
||||
private let passwordStore = GenericPasswordStore()
|
||||
|
||||
@Published var keypairs: [Keypair] = []
|
||||
|
||||
@Published var keyTypes: [UUID: KeyType] = [:]
|
||||
@Published var keyNames: [UUID: String] = [:]
|
||||
var keyIDs: [UUID] {
|
||||
keypairs.map { $0.id }
|
||||
}
|
||||
// @Published var keyTypes: [UUID: KeyType] = [:]
|
||||
// @Published var keyNames: [UUID: String] = [:]
|
||||
private let baseTag = "com.neon443.ShhShell.keys".data(using: .utf8)!
|
||||
|
||||
init() {
|
||||
@@ -26,50 +28,28 @@ class KeyManager: ObservableObject {
|
||||
}
|
||||
|
||||
func loadKeypairs() {
|
||||
loadKeyIDs()
|
||||
keypairs = []
|
||||
for id in keyTypes.keys {
|
||||
guard let keypair = getFromKeychain(keyID: id) else { continue }
|
||||
keypairs.append(keypair)
|
||||
userdefaults.synchronize()
|
||||
guard let data = userdefaults.data(forKey: "keypairs") else { return }
|
||||
guard let decoded = try? JSONDecoder().decode([Keypair].self, from: data) else { return }
|
||||
withAnimation { self.keypairs = decoded }
|
||||
for kp in keypairs {
|
||||
guard let KeychainKeypair = getFromKeychain(kp) else { continue }
|
||||
guard let index = keypairs.firstIndex(where: { $0.id == kp.id }) else { continue }
|
||||
withAnimation { keypairs[index] = KeychainKeypair }
|
||||
}
|
||||
}
|
||||
|
||||
func saveKeypairs() {
|
||||
guard let coded = try? JSONEncoder().encode(keypairs) else { return }
|
||||
userdefaults.set(coded, forKey: "keypairs")
|
||||
userdefaults.synchronize()
|
||||
for keypair in keypairs {
|
||||
keyTypes.updateValue(keypair.type, forKey: keypair.id)
|
||||
keyNames.updateValue(keypair.name, forKey: keypair.id)
|
||||
saveToKeychain(keypair)
|
||||
}
|
||||
saveKeyIDs()
|
||||
loadKeypairs()
|
||||
}
|
||||
|
||||
func loadKeyIDs() {
|
||||
userdefaults.synchronize()
|
||||
let decoder = JSONDecoder()
|
||||
guard let data = userdefaults.data(forKey: "keyIDs") else { return }
|
||||
guard let decoded = try? decoder.decode([UUID:KeyType].self, from: data) else { return }
|
||||
keyTypes = decoded
|
||||
|
||||
guard let dataNames = userdefaults.data(forKey: "keyNames") else { return }
|
||||
guard let decodedNames = try? decoder.decode([UUID:String].self, from: dataNames) else { return }
|
||||
keyNames = decodedNames
|
||||
}
|
||||
|
||||
func saveKeyIDs() {
|
||||
let encoder = JSONEncoder()
|
||||
guard let encoded = try? encoder.encode(keyTypes) else { return }
|
||||
userdefaults.set(encoded, forKey: "keyIDs")
|
||||
|
||||
guard let encodedNames = try? encoder.encode(keyNames) else { return }
|
||||
userdefaults.set(encodedNames, forKey: "keyNames")
|
||||
userdefaults.synchronize()
|
||||
loadKeypairs()
|
||||
}
|
||||
|
||||
func saveToKeychain(_ keypair: Keypair) {
|
||||
keyTypes.updateValue(keypair.type, forKey: keypair.id)
|
||||
keyNames.updateValue(keypair.name, forKey: keypair.id)
|
||||
if keypair.type == .ed25519 {
|
||||
let curve25519 = try! Curve25519.Signing.PrivateKey(rawRepresentation: keypair.privateKey)
|
||||
let readKey: Curve25519.Signing.PrivateKey?
|
||||
@@ -83,16 +63,14 @@ class KeyManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func getFromKeychain(keyID: UUID) -> Keypair? {
|
||||
guard let keyType = keyTypes[keyID] else { return nil }
|
||||
guard let keyName = keyNames[keyID] else { return nil }
|
||||
if keyType == .ed25519 {
|
||||
func getFromKeychain(_ keypair: Keypair) -> Keypair? {
|
||||
if keypair.type == .ed25519 {
|
||||
var key: Curve25519.Signing.PrivateKey?
|
||||
key = try? passwordStore.readKey(account: keyID.uuidString)
|
||||
key = try? passwordStore.readKey(account: keypair.id.uuidString)
|
||||
guard let key else { return nil }
|
||||
return Keypair(id: keyID, type: keyType, name: keyName, privateKey: key.rawRepresentation)
|
||||
return Keypair(id: keypair.id, type: keypair.type, name: keypair.name, privateKey: key.rawRepresentation)
|
||||
} else {
|
||||
let tag = baseTag+keyID.uuidString.data(using: .utf8)!
|
||||
let tag = baseTag+keypair.id.uuidString.data(using: .utf8)!
|
||||
let getQuery: [String: Any] = [kSecClass as String: kSecClassKey,
|
||||
kSecAttrApplicationTag as String: tag,
|
||||
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
|
||||
@@ -101,8 +79,8 @@ class KeyManager: ObservableObject {
|
||||
let status = SecItemCopyMatching(getQuery as CFDictionary, &item)
|
||||
guard status == errSecSuccess else { fatalError() }
|
||||
return Keypair(
|
||||
type: keyType,
|
||||
name: keyName,
|
||||
type: keypair.type,
|
||||
name: keypair.name,
|
||||
privateKey: item as! Data
|
||||
)
|
||||
}
|
||||
@@ -116,9 +94,7 @@ class KeyManager: ObservableObject {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
keyNames.removeValue(forKey: keypair.id)
|
||||
keyTypes.removeValue(forKey: keypair.id)
|
||||
saveKeyIDs()
|
||||
saveKeypairs()
|
||||
}
|
||||
|
||||
func renameKey(keypair: Keypair, newName: String) {
|
||||
@@ -278,10 +254,6 @@ class KeyManager: ObservableObject {
|
||||
return content
|
||||
}
|
||||
|
||||
func getPubkey(_ privateKey: SecKey) -> SecKey? {
|
||||
return SecKeyCopyPublicKey(privateKey)
|
||||
}
|
||||
|
||||
static func encode(str: String) -> Data {
|
||||
guard let utf8 = str.data(using: .utf8) else {
|
||||
return Data()
|
||||
|
||||
@@ -26,7 +26,8 @@ struct Keypair: KeypairProtocol {
|
||||
var name: String = ""
|
||||
var publicKey: Data {
|
||||
if privateKey.isEmpty {
|
||||
return Data()
|
||||
print("not a valid ed25519 key")
|
||||
fatalError()
|
||||
} else {
|
||||
return (try? Curve25519.Signing.PrivateKey(rawRepresentation: privateKey).publicKey.rawRepresentation) ?? Data()
|
||||
}
|
||||
@@ -34,6 +35,15 @@ struct Keypair: KeypairProtocol {
|
||||
var privateKey: Data
|
||||
var passphrase: String = ""
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id = "id"
|
||||
case type = "type"
|
||||
case name = "name"
|
||||
|
||||
// case privateKey = "privateKey"
|
||||
// case passphrase = "passphrase"
|
||||
}
|
||||
|
||||
var label: String {
|
||||
if name.isEmpty {
|
||||
return openSshPubkey
|
||||
@@ -82,6 +92,17 @@ struct Keypair: KeypairProtocol {
|
||||
self.passphrase = passphrase
|
||||
}
|
||||
|
||||
init(from decoder: any Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.id = try container.decode(UUID.self, forKey: .id)
|
||||
self.type = try container.decode(KeyType.self, forKey: .type)
|
||||
self.name = try container.decode(String.self, forKey: .name)
|
||||
// self.privateKey = try container.decode(Data.self, forKey: .privateKey)
|
||||
// self.passphrase = try container.decode(String.self, forKey: .passphrase)
|
||||
self.privateKey = Data()
|
||||
self.passphrase = ""
|
||||
}
|
||||
|
||||
static func ==(lhs: Keypair, rhs: Keypair) -> Bool {
|
||||
if lhs.publicKey.base64EncodedString() == rhs.publicKey.base64EncodedString()
|
||||
&& lhs.privateKey.base64EncodedString() == rhs.privateKey.base64EncodedString() {
|
||||
|
||||
Reference in New Issue
Block a user