Skip to content

Commit 840bd2c

Browse files
committed
Add canonically-cased config options
1 parent c7f8dec commit 840bd2c

File tree

2 files changed

+149
-1
lines changed

2 files changed

+149
-1
lines changed

config.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,11 @@ type KV struct {
571571
position Position
572572
}
573573

574+
// CanonicalKey returns k's Key, using the canonical casing from https://man.openbsd.org/ssh_config.
575+
func (k *KV) CanonicalKey() string {
576+
return GetCanonicalCase(k.Key)
577+
}
578+
574579
// Pos returns k's Position.
575580
func (k *KV) Pos() Position {
576581
return k.position
@@ -586,7 +591,7 @@ func (k *KV) String() string {
586591
if k.hasEquals {
587592
equals = " = "
588593
}
589-
line := fmt.Sprintf("%s%s%s%s", strings.Repeat(" ", int(k.leadingSpace)), k.Key, equals, k.Value)
594+
line := fmt.Sprintf("%s%s%s%s", strings.Repeat(" ", k.leadingSpace), k.CanonicalKey(), equals, k.Value)
590595
if k.Comment != "" {
591596
line += " #" + k.Comment
592597
}

config_options.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package ssh_config
2+
3+
import (
4+
"strings"
5+
)
6+
7+
// Current as of OpenSSH 8.2
8+
// Source: https://man.openbsd.org/ssh_config
9+
var configOptions = []string{
10+
"Host",
11+
"Match",
12+
"AddKeysToAgent",
13+
"AddressFamily",
14+
"BatchMode",
15+
"BindAddress",
16+
"BindInterface",
17+
"CanonicalDomains",
18+
"CanonicalizeFallbackLocal",
19+
"CanonicalizeHostname",
20+
"CanonicalizeMaxDots",
21+
"CanonicalizePermittedCNAMEs",
22+
"CASignatureAlgorithms",
23+
"CertificateFile",
24+
"CheckHostIP",
25+
"Ciphers",
26+
"ClearAllForwardings",
27+
"Compression",
28+
"ConnectionAttempts",
29+
"ConnectTimeout",
30+
"ControlMaster",
31+
"ControlPath",
32+
"ControlPersist",
33+
"DynamicForward",
34+
"EnableSSHKeysign",
35+
"EscapeChar",
36+
"ExitOnForwardFailure",
37+
"FingerprintHash",
38+
"ForkAfterAuthentication",
39+
"ForwardAgent",
40+
"ForwardX11",
41+
"ForwardX11Timeout",
42+
"ForwardX11Trusted",
43+
"GatewayPorts",
44+
"GlobalKnownHostsFile",
45+
"GSSAPIAuthentication",
46+
"GSSAPIDelegateCredentials",
47+
"HashKnownHosts",
48+
"HostbasedAcceptedAlgorithms",
49+
"HostbasedAuthentication",
50+
"HostKeyAlgorithms",
51+
"HostKeyAlias",
52+
"Hostname",
53+
"IdentitiesOnly",
54+
"IdentityAgent",
55+
"IdentityFile",
56+
"IgnoreUnknown",
57+
"Include",
58+
"IPQoS",
59+
"KbdInteractiveAuthentication",
60+
"KbdInteractiveDevices",
61+
"KexAlgorithms",
62+
"KnownHostsCommand",
63+
"LocalCommand",
64+
"LocalForward",
65+
"LogLevel",
66+
"LogVerbose",
67+
"MACs",
68+
"NoHostAuthenticationForLocalhost",
69+
"NumberOfPasswordPrompts",
70+
"PasswordAuthentication",
71+
"PermitLocalCommand",
72+
"PermitRemoteOpen",
73+
"PKCS11Provider",
74+
"Port",
75+
"PreferredAuthentications",
76+
"ProxyCommand",
77+
"ProxyJump",
78+
"ProxyUseFdpass",
79+
"PubkeyAcceptedAlgorithms",
80+
"PubkeyAuthentication",
81+
"RekeyLimit",
82+
"RemoteCommand",
83+
"RemoteForward",
84+
"RequestTTY",
85+
"RevokedHostKeys",
86+
"SecurityKeyProvider",
87+
"SendEnv",
88+
"ServerAliveCountMax",
89+
"ServerAliveInterval",
90+
"SessionType",
91+
"SetEnv",
92+
"StdinNull",
93+
"StreamLocalBindMask",
94+
"StreamLocalBindUnlink",
95+
"StrictHostKeyChecking",
96+
"SyslogFacility",
97+
"TCPKeepAlive",
98+
"Tunnel",
99+
"TunnelDevice",
100+
"UpdateHostKeys",
101+
"User",
102+
"UserKnownHostsFile",
103+
"VerifyHostKeyDNS",
104+
"VisualHostKey",
105+
"XAuthLocation",
106+
}
107+
108+
// // getConfigOptions retrieves a sorted list of all the current config options
109+
// // from the official source: https://man.openbsd.org/ssh_config and filtered
110+
// // with "github.com/PuerkitoBio/goquery".
111+
// // The result is sorted and therefore may be searched with sort.SearchStrings()
112+
// func getConfigOptions() (opts []string, err error) {
113+
// SSHConfigURL := "https://man.openbsd.org/ssh_config"
114+
115+
// resp, err := http.Get(SSHConfigURL)
116+
// if err != nil {
117+
// return opts, fmt.Errorf("getting %s: %w", SSHConfigURL, err)
118+
// }
119+
// defer resp.Body.Close()
120+
121+
// doc, err := goquery.NewDocumentFromReader(resp.Body)
122+
// if err != nil {
123+
// return opts, fmt.Errorf("parsing %s: %w", SSHConfigURL, err)
124+
// }
125+
126+
// doc.Find("dt > a > code.Cm").Each(func(i int, c *goquery.Selection) {
127+
// opts = append(opts, c.Text())
128+
// })
129+
130+
// sort.Strings(opts)
131+
// return opts, nil
132+
// }
133+
134+
// GetCanonicalCase checks for the given key in the known ssh config keys
135+
// and returns with proper casing if found, otherwise returns what was given.
136+
func GetCanonicalCase(key string) string {
137+
for _, value := range configOptions {
138+
if strings.EqualFold(key, value) {
139+
return value
140+
}
141+
}
142+
return key
143+
}

0 commit comments

Comments
 (0)