mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 13:26:16 +00:00
fix picker on connectionview
using trimmingchars whitespaces and newlines to remove any trailing "\n"s added padding to the button publickey data uses a switch now reorganised keymanager and used //MARKs added header into KeyType for easier expansion of key types in the future improved default key comment to use "at" between chunks and exclude time
This commit is contained in:
@@ -46,11 +46,49 @@ class KeyManager: ObservableObject {
|
||||
for keypair in keypairs {
|
||||
saveToKeychain(keypair)
|
||||
}
|
||||
}
|
||||
|
||||
func renameKey(keypair: Keypair, newName: String) {
|
||||
guard !newName.isEmpty else { return }
|
||||
let keyID = keypair.id
|
||||
guard let index = keypairs.firstIndex(where: { $0.id == keyID }) else { return }
|
||||
var keypairWithNewName = keypair
|
||||
keypairWithNewName.name = newName
|
||||
withAnimation { keypairs[index] = keypairWithNewName }
|
||||
saveKeypairs()
|
||||
}
|
||||
|
||||
func deleteKey(_ keypair: Keypair) {
|
||||
removeFromKeycahin(keypair: keypair)
|
||||
let keyID = keypair.id
|
||||
withAnimation { keypairs.removeAll(where: { $0.id == keyID }) }
|
||||
saveKeypairs()
|
||||
}
|
||||
|
||||
func importKey(type: KeyType, priv: String, name: String) {
|
||||
if type == .ed25519 {
|
||||
guard let importedKeypair = KeyManager.importSSHPrivkey(priv: priv) else { return }
|
||||
saveToKeychain(importedKeypair)
|
||||
} else { fatalError() }
|
||||
}
|
||||
|
||||
func generateKey(type: KeyType, comment: String) {
|
||||
switch type {
|
||||
case .ed25519:
|
||||
let keypair = Keypair(
|
||||
type: .ed25519,
|
||||
name: comment,
|
||||
privateKey: Curve25519.Signing.PrivateKey().rawRepresentation
|
||||
)
|
||||
saveToKeychain(keypair)
|
||||
}
|
||||
loadKeypairs()
|
||||
}
|
||||
|
||||
//MARK: keychain
|
||||
func saveToKeychain(_ keypair: Keypair) {
|
||||
if keypair.type == .ed25519 {
|
||||
switch keypair.type {
|
||||
case .ed25519:
|
||||
let curve25519 = try! Curve25519.Signing.PrivateKey(rawRepresentation: keypair.privateKey)
|
||||
let readKey: Curve25519.Signing.PrivateKey?
|
||||
readKey = try! passwordStore.readKey(account: keypair.id.uuidString)
|
||||
@@ -58,8 +96,10 @@ class KeyManager: ObservableObject {
|
||||
try! passwordStore.deleteKey(account: keypair.id.uuidString)
|
||||
}
|
||||
try! passwordStore.storeKey(curve25519.genericKeyRepresentation, account: keypair.id.uuidString)
|
||||
} else {
|
||||
|
||||
}
|
||||
if !keypairs.contains(keypair) {
|
||||
keypairs.append(keypair)
|
||||
saveKeypairs()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,46 +137,7 @@ class KeyManager: ObservableObject {
|
||||
saveKeypairs()
|
||||
}
|
||||
|
||||
func renameKey(keypair: Keypair, newName: String) {
|
||||
guard !newName.isEmpty else { return }
|
||||
let keyID = keypair.id
|
||||
guard let index = keypairs.firstIndex(where: { $0.id == keyID }) else { return }
|
||||
var keypairWithNewName = keypair
|
||||
keypairWithNewName.name = newName
|
||||
withAnimation { keypairs[index] = keypairWithNewName }
|
||||
saveKeypairs()
|
||||
}
|
||||
|
||||
func deleteKey(_ keypair: Keypair) {
|
||||
removeFromKeycahin(keypair: keypair)
|
||||
let keyID = keypair.id
|
||||
withAnimation { keypairs.removeAll(where: { $0.id == keyID }) }
|
||||
saveKeypairs()
|
||||
}
|
||||
|
||||
func importKey(type: KeyType, priv: String, name: String) {
|
||||
if type == .ed25519 {
|
||||
guard let importedKeypair = KeyManager.importSSHPrivkey(priv: priv) else { return }
|
||||
saveToKeychain(importedKeypair)
|
||||
saveKeypairs()
|
||||
} else { fatalError() }
|
||||
}
|
||||
|
||||
//MARK: generate keys
|
||||
func generateKey(type: KeyType, comment: String) {
|
||||
switch type {
|
||||
case .ed25519:
|
||||
let keypair = Keypair(
|
||||
type: .ed25519,
|
||||
name: comment,
|
||||
privateKey: Curve25519.Signing.PrivateKey().rawRepresentation
|
||||
)
|
||||
saveToKeychain(keypair)
|
||||
saveKeypairs()
|
||||
}
|
||||
loadKeypairs()
|
||||
}
|
||||
|
||||
//MARK: openssh converters/importers
|
||||
static func importSSHPubkey(pub: String) -> Data {
|
||||
let split = pub.split(separator: " ")
|
||||
guard split.count == 3 else { return Data() }
|
||||
@@ -150,15 +151,14 @@ class KeyManager: ObservableObject {
|
||||
}
|
||||
|
||||
static func makeSSHPubkey(_ keypair: Keypair) -> Data {
|
||||
let header = "ssh-ed25519"
|
||||
var keyBlob: Data = Data()
|
||||
//key type bit
|
||||
keyBlob += encode(str: header)
|
||||
keyBlob += encode(str: keypair.type.header)
|
||||
//base64 blob bit
|
||||
keyBlob += encode(data: keypair.publicKey)
|
||||
|
||||
let b64key = keyBlob.base64EncodedString()
|
||||
let pubkeyline = "\(header) \(b64key) \(keypair.name)\n"
|
||||
let pubkeyline = "\(keypair.type.header) \(b64key) \(keypair.name)\n"
|
||||
return Data(pubkeyline.utf8)
|
||||
}
|
||||
|
||||
@@ -254,6 +254,7 @@ class KeyManager: ObservableObject {
|
||||
return content
|
||||
}
|
||||
|
||||
//MARK: openssh conversion helpers
|
||||
static func encode(str: String) -> Data {
|
||||
guard let utf8 = str.data(using: .utf8) else {
|
||||
return Data()
|
||||
|
||||
@@ -16,4 +16,11 @@ enum KeyType: Codable, Equatable, Hashable, CustomStringConvertible, CaseIterabl
|
||||
return "Ed25519"
|
||||
}
|
||||
}
|
||||
|
||||
var header: String {
|
||||
switch self {
|
||||
case .ed25519:
|
||||
"ssh-ed25519"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,9 @@ struct Keypair: KeypairProtocol {
|
||||
var type: KeyType = .ed25519
|
||||
var name: String = ""
|
||||
var publicKey: Data {
|
||||
if privateKey.isEmpty {
|
||||
print("not a valid ed25519 key")
|
||||
fatalError()
|
||||
} else {
|
||||
guard !privateKey.isEmpty else { return Data() }
|
||||
switch type {
|
||||
case .ed25519:
|
||||
return (try? Curve25519.Signing.PrivateKey(rawRepresentation: privateKey).publicKey.rawRepresentation) ?? Data()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,9 +82,10 @@ struct ConnectionView: View {
|
||||
Picker("Private key", selection: $handler.host.privateKeyID) {
|
||||
Text("None")
|
||||
.tag(nil as UUID?)
|
||||
Divider()
|
||||
ForEach(keyManager.keypairs) { keypair in
|
||||
Text(keypair.label)
|
||||
.tag(keypair.id)
|
||||
.tag(keypair.id as UUID?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,14 +90,14 @@ struct KeyDetailView: View {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Public key")
|
||||
.bold()
|
||||
Text(keypair.openSshPubkey.dropLast(2))
|
||||
Text(keypair.openSshPubkey.trimmingCharacters(in: .whitespacesAndNewlines))
|
||||
}
|
||||
VStack(alignment: .leading) {
|
||||
Text("Private key")
|
||||
.bold()
|
||||
.frame(maxWidth: .infinity)
|
||||
ZStack(alignment: .center) {
|
||||
Text(keypair.openSshPrivkey.dropLast(2))
|
||||
Text(keypair.openSshPrivkey.trimmingCharacters(in: .whitespacesAndNewlines))
|
||||
.blur(radius: reveal ? 0 : 5)
|
||||
VStack {
|
||||
Image(systemName: "eye.slash.fill")
|
||||
|
||||
@@ -12,7 +12,7 @@ struct KeyImporterView: View {
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
@State var keyName: String = UIDevice().model + " " + Date().formatted()
|
||||
@State var keyName: String = UIDevice().model + " at " + Date().formatted(date: .numeric, time: .omitted)
|
||||
@State var privkeyStr: String = ""
|
||||
@State var keyType: KeyType = .ed25519
|
||||
|
||||
@@ -24,25 +24,33 @@ struct KeyImporterView: View {
|
||||
List {
|
||||
TextBox(label: "Name", text: $keyName, prompt: "A name for your key")
|
||||
|
||||
Picker("Key type", selection: $keyType) {
|
||||
ForEach(KeyType.allCases, id: \.self) { type in
|
||||
Text(type.description)
|
||||
.tag(type)
|
||||
}
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
|
||||
HStack {
|
||||
Text("Private Key")
|
||||
Spacer()
|
||||
Text("Required")
|
||||
.foregroundStyle(.red)
|
||||
Text("Key Type")
|
||||
Picker("Key type", selection: $keyType) {
|
||||
ForEach(KeyType.allCases, id: \.self) { type in
|
||||
Text(type.description)
|
||||
.tag(type)
|
||||
}
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
}
|
||||
|
||||
TextEditor(text: $privkeyStr)
|
||||
Section {
|
||||
HStack {
|
||||
Text("Private Key")
|
||||
Spacer()
|
||||
Text("Required")
|
||||
.foregroundStyle(.red)
|
||||
}
|
||||
.listRowSeparator(.hidden)
|
||||
|
||||
TextEditor(text: $privkeyStr)
|
||||
.background(.black)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
}
|
||||
|
||||
if !keypair.openSshPubkey.isEmpty {
|
||||
TextEditor(text: .constant(keypair.openSshPubkey))
|
||||
Text(keypair.openSshPubkey.trimmingCharacters(in: .whitespacesAndNewlines))
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
|
||||
@@ -53,11 +61,14 @@ struct KeyImporterView: View {
|
||||
dismiss()
|
||||
} label: {
|
||||
Text("Import")
|
||||
.font(.title)
|
||||
.bold()
|
||||
}
|
||||
.onTapGesture {
|
||||
UINotificationFeedbackGenerator().notificationOccurred(.success)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ struct KeyManagerView: View {
|
||||
}
|
||||
|
||||
Button("Generate a new Ed25519 Key") {
|
||||
let comment = UIDevice().model + " " + Date().formatted()
|
||||
let comment = UIDevice().model + " at " + Date().formatted(date: .numeric, time: .omitted)
|
||||
keyManager.generateKey(type: .ed25519, comment: comment)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user