Compare commits
2 Commits
a332459b92
...
70307c7cba
Author | SHA1 | Date | |
---|---|---|---|
70307c7cba | |||
94407289db |
@@ -88,8 +88,11 @@ kport supports the SSH `Include` directive, allowing you to organize your SSH co
|
|||||||
- **Glob patterns**: `Include ~/.ssh/config.d/*`
|
- **Glob patterns**: `Include ~/.ssh/config.d/*`
|
||||||
- **Specific files**: `Include ~/.ssh/work-config`
|
- **Specific files**: `Include ~/.ssh/work-config`
|
||||||
- **Relative paths**: `Include config.d/servers`
|
- **Relative paths**: `Include config.d/servers`
|
||||||
|
- **Quoted paths**: `Include "gitpod/config"` or `Include 'path with spaces/config'`
|
||||||
- **Cycle detection**: Prevents infinite loops from circular includes
|
- **Cycle detection**: Prevents infinite loops from circular includes
|
||||||
|
|
||||||
|
Relative paths in includes are resolved relative to `~/.ssh/` directory, matching OpenSSH behavior.
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
|
|
||||||
The application supports:
|
The application supports:
|
||||||
|
@@ -77,14 +77,11 @@ func (sc *SSHConfig) loadConfigFromFileRecursive(path string, visited map[string
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := strings.Fields(line)
|
key, value, err := parseConfigLine(line)
|
||||||
if len(parts) < 2 {
|
if err != nil {
|
||||||
continue
|
continue // Skip malformed lines
|
||||||
}
|
}
|
||||||
|
|
||||||
key := strings.ToLower(parts[0])
|
|
||||||
value := strings.Join(parts[1:], " ")
|
|
||||||
|
|
||||||
switch key {
|
switch key {
|
||||||
case "include":
|
case "include":
|
||||||
// Handle include directive
|
// Handle include directive
|
||||||
@@ -142,6 +139,13 @@ func (sc *SSHConfig) processInclude(pattern string, visited map[string]bool) err
|
|||||||
return fmt.Errorf("failed to get home directory: %w", err)
|
return fmt.Errorf("failed to get home directory: %w", err)
|
||||||
}
|
}
|
||||||
pattern = filepath.Join(homeDir, pattern[2:])
|
pattern = filepath.Join(homeDir, pattern[2:])
|
||||||
|
} else if !filepath.IsAbs(pattern) {
|
||||||
|
// Relative paths are relative to ~/.ssh/
|
||||||
|
homeDir, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get home directory: %w", err)
|
||||||
|
}
|
||||||
|
pattern = filepath.Join(homeDir, ".ssh", pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle glob patterns
|
// Handle glob patterns
|
||||||
@@ -180,3 +184,28 @@ func (sc *SSHConfig) GetHostByName(name string) (*SSHHost, error) {
|
|||||||
}
|
}
|
||||||
return nil, fmt.Errorf("host '%s' not found", name)
|
return nil, fmt.Errorf("host '%s' not found", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseConfigLine parses a SSH config line, handling quoted values
|
||||||
|
func parseConfigLine(line string) (key, value string, err error) {
|
||||||
|
// Find the first whitespace to separate key from value
|
||||||
|
parts := strings.SplitN(strings.TrimSpace(line), " ", 2)
|
||||||
|
if len(parts) < 2 {
|
||||||
|
return "", "", fmt.Errorf("invalid config line")
|
||||||
|
}
|
||||||
|
|
||||||
|
key = strings.ToLower(strings.TrimSpace(parts[0]))
|
||||||
|
valueStr := strings.TrimSpace(parts[1])
|
||||||
|
|
||||||
|
// Handle quoted values
|
||||||
|
if len(valueStr) >= 2 &&
|
||||||
|
((valueStr[0] == '"' && valueStr[len(valueStr)-1] == '"') ||
|
||||||
|
(valueStr[0] == '\'' && valueStr[len(valueStr)-1] == '\'')) {
|
||||||
|
// Remove quotes
|
||||||
|
value = valueStr[1 : len(valueStr)-1]
|
||||||
|
} else {
|
||||||
|
// Handle unquoted values (may contain multiple words)
|
||||||
|
value = valueStr
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, value, nil
|
||||||
|
}
|
Reference in New Issue
Block a user