mirror of
https://github.com/Adembc/lazyssh.git
synced 2026-07-14 12:13:34 +02:00
feat: Add 60+ SSH config field support with enhanced UI (#50)
This commit is contained in:
@@ -65,19 +65,230 @@ func (r *Repository) toDomainServer(cfg *ssh_config.Config) []domain.Server {
|
||||
|
||||
// mapKVToServer maps an ssh_config.KV node to the corresponding fields in domain.Server.
|
||||
func (r *Repository) mapKVToServer(server *domain.Server, kvNode *ssh_config.KV) {
|
||||
switch strings.ToLower(kvNode.Key) {
|
||||
key := strings.ToLower(kvNode.Key)
|
||||
value := kvNode.Value
|
||||
|
||||
// Try mapping in order of categories
|
||||
if r.mapBasicConfig(server, key, value) {
|
||||
return
|
||||
}
|
||||
if r.mapConnectionConfig(server, key, value) {
|
||||
return
|
||||
}
|
||||
if r.mapForwardingConfig(server, key, value) {
|
||||
return
|
||||
}
|
||||
if r.mapAuthenticationConfig(server, key, value) {
|
||||
return
|
||||
}
|
||||
if r.mapSecurityConfig(server, key, value) {
|
||||
return
|
||||
}
|
||||
if r.mapEnvironmentConfig(server, key, value) {
|
||||
return
|
||||
}
|
||||
r.mapDebugConfig(server, key, value)
|
||||
}
|
||||
|
||||
// mapBasicConfig maps basic SSH configuration fields
|
||||
func (r *Repository) mapBasicConfig(server *domain.Server, key, value string) bool {
|
||||
switch key {
|
||||
case "hostname":
|
||||
server.Host = kvNode.Value
|
||||
server.Host = value
|
||||
case "user":
|
||||
server.User = kvNode.Value
|
||||
server.User = value
|
||||
case "port":
|
||||
port, err := strconv.Atoi(kvNode.Value)
|
||||
port, err := strconv.Atoi(value)
|
||||
if err == nil {
|
||||
server.Port = port
|
||||
}
|
||||
case "identityfile":
|
||||
server.IdentityFiles = append(server.IdentityFiles, kvNode.Value)
|
||||
server.IdentityFiles = append(server.IdentityFiles, value)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// mapConnectionConfig maps connection and proxy configuration fields
|
||||
func (r *Repository) mapConnectionConfig(server *domain.Server, key, value string) bool {
|
||||
switch key {
|
||||
case "proxycommand":
|
||||
server.ProxyCommand = value
|
||||
case "proxyjump":
|
||||
server.ProxyJump = value
|
||||
case "remotecommand":
|
||||
server.RemoteCommand = value
|
||||
case "requesttty":
|
||||
server.RequestTTY = value
|
||||
case "sessiontype":
|
||||
server.SessionType = value
|
||||
case "connecttimeout":
|
||||
server.ConnectTimeout = value
|
||||
case "connectionattempts":
|
||||
server.ConnectionAttempts = value
|
||||
case "bindaddress":
|
||||
server.BindAddress = value
|
||||
case "bindinterface":
|
||||
server.BindInterface = value
|
||||
case "addressfamily":
|
||||
server.AddressFamily = value
|
||||
case "exitonforwardfailure":
|
||||
server.ExitOnForwardFailure = value
|
||||
case "ipqos":
|
||||
server.IPQoS = value
|
||||
case "canonicalizehostname":
|
||||
server.CanonicalizeHostname = value
|
||||
case "canonicaldomains":
|
||||
server.CanonicalDomains = value
|
||||
case "canonicalizefallbacklocal":
|
||||
server.CanonicalizeFallbackLocal = value
|
||||
case "canonicalizemaxdots":
|
||||
server.CanonicalizeMaxDots = value
|
||||
case "canonicalizepermittedcnames":
|
||||
server.CanonicalizePermittedCNAMEs = value
|
||||
case "serveraliveinterval":
|
||||
server.ServerAliveInterval = value
|
||||
case "serveralivecountmax":
|
||||
server.ServerAliveCountMax = value
|
||||
case "compression":
|
||||
server.Compression = value
|
||||
case "tcpkeepalive":
|
||||
server.TCPKeepAlive = value
|
||||
case "batchmode":
|
||||
server.BatchMode = value
|
||||
case "controlmaster":
|
||||
server.ControlMaster = value
|
||||
case "controlpath":
|
||||
server.ControlPath = value
|
||||
case "controlpersist":
|
||||
server.ControlPersist = value
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// mapForwardingConfig maps port forwarding and agent forwarding fields
|
||||
func (r *Repository) mapForwardingConfig(server *domain.Server, key, value string) bool {
|
||||
switch key {
|
||||
case "localforward":
|
||||
cliFormat := r.convertConfigForwardToCLIFormat(value)
|
||||
server.LocalForward = append(server.LocalForward, cliFormat)
|
||||
case "remoteforward":
|
||||
cliFormat := r.convertConfigForwardToCLIFormat(value)
|
||||
server.RemoteForward = append(server.RemoteForward, cliFormat)
|
||||
case "dynamicforward":
|
||||
server.DynamicForward = append(server.DynamicForward, value)
|
||||
case "clearallforwardings":
|
||||
server.ClearAllForwardings = value
|
||||
case "gatewayports":
|
||||
server.GatewayPorts = value
|
||||
case "forwardagent":
|
||||
server.ForwardAgent = value
|
||||
case "forwardx11":
|
||||
server.ForwardX11 = value
|
||||
case "forwardx11trusted":
|
||||
server.ForwardX11Trusted = value
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// mapAuthenticationConfig maps authentication-related fields
|
||||
func (r *Repository) mapAuthenticationConfig(server *domain.Server, key, value string) bool {
|
||||
switch key {
|
||||
case "pubkeyauthentication":
|
||||
server.PubkeyAuthentication = value
|
||||
case "pubkeyacceptedalgorithms", "pubkeyacceptedkeytypes":
|
||||
// PubkeyAcceptedKeyTypes is deprecated alias for PubkeyAcceptedAlgorithms (since OpenSSH 8.5)
|
||||
server.PubkeyAcceptedAlgorithms = value
|
||||
case "hostbasedacceptedalgorithms", "hostbasedkeytypes", "hostbasedacceptedkeytypes":
|
||||
// HostbasedKeyTypes and HostbasedAcceptedKeyTypes are deprecated aliases (since OpenSSH 8.5)
|
||||
server.HostbasedAcceptedAlgorithms = value
|
||||
case "passwordauthentication":
|
||||
server.PasswordAuthentication = value
|
||||
case "preferredauthentications":
|
||||
server.PreferredAuthentications = value
|
||||
case "identitiesonly":
|
||||
server.IdentitiesOnly = value
|
||||
case "addkeystoagent":
|
||||
server.AddKeysToAgent = value
|
||||
case "identityagent":
|
||||
server.IdentityAgent = value
|
||||
case "kbdinteractiveauthentication", "challengeresponseauthentication":
|
||||
// ChallengeResponseAuthentication is deprecated alias for KbdInteractiveAuthentication
|
||||
server.KbdInteractiveAuthentication = value
|
||||
case "numberofpasswordprompts":
|
||||
server.NumberOfPasswordPrompts = value
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// mapSecurityConfig maps security-related fields
|
||||
func (r *Repository) mapSecurityConfig(server *domain.Server, key, value string) bool {
|
||||
switch key {
|
||||
case "stricthostkeychecking":
|
||||
server.StrictHostKeyChecking = value
|
||||
case "checkhostip":
|
||||
server.CheckHostIP = value
|
||||
case "fingerprinthash":
|
||||
server.FingerprintHash = value
|
||||
case "userknownhostsfile":
|
||||
server.UserKnownHostsFile = value
|
||||
case "hostkeyalgorithms":
|
||||
server.HostKeyAlgorithms = value
|
||||
case "macs":
|
||||
server.MACs = value
|
||||
case "ciphers":
|
||||
server.Ciphers = value
|
||||
case "kexalgorithms":
|
||||
server.KexAlgorithms = value
|
||||
case "verifyhostkeydns":
|
||||
server.VerifyHostKeyDNS = value
|
||||
case "updatehostkeys":
|
||||
server.UpdateHostKeys = value
|
||||
case "hashknownhosts":
|
||||
server.HashKnownHosts = value
|
||||
case "visualhostkey":
|
||||
server.VisualHostKey = value
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// mapEnvironmentConfig maps environment and command execution fields
|
||||
func (r *Repository) mapEnvironmentConfig(server *domain.Server, key, value string) bool {
|
||||
switch key {
|
||||
case "localcommand":
|
||||
server.LocalCommand = value
|
||||
case "permitlocalcommand":
|
||||
server.PermitLocalCommand = value
|
||||
case "escapechar":
|
||||
server.EscapeChar = value
|
||||
case "sendenv":
|
||||
server.SendEnv = append(server.SendEnv, value)
|
||||
case "setenv":
|
||||
server.SetEnv = append(server.SetEnv, value)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// mapDebugConfig maps debugging-related fields
|
||||
func (r *Repository) mapDebugConfig(server *domain.Server, key, value string) bool {
|
||||
switch key {
|
||||
case "loglevel":
|
||||
server.LogLevel = value
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// mergeMetadata merges additional metadata into the servers.
|
||||
@@ -104,3 +315,19 @@ func (r *Repository) mergeMetadata(servers []domain.Server, metadata map[string]
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
// convertConfigForwardToCLIFormat converts SSH config format forwarding spec to CLI format.
|
||||
// Config format: [bind_address:]port host:hostport
|
||||
// CLI format: [bind_address:]port:host:hostport
|
||||
func (r *Repository) convertConfigForwardToCLIFormat(forward string) string {
|
||||
// Find the last space which separates the local part from the remote part
|
||||
lastSpace := strings.LastIndex(forward, " ")
|
||||
if lastSpace != -1 {
|
||||
localPart := forward[:lastSpace]
|
||||
remotePart := forward[lastSpace+1:]
|
||||
// Join them with a colon for CLI format
|
||||
return localPart + ":" + remotePart
|
||||
}
|
||||
// If no space found, return as-is (might already be in CLI format)
|
||||
return forward
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user