diff --git a/auth.go b/auth.go index 8cb1ba2..1491e05 100644 --- a/auth.go +++ b/auth.go @@ -18,9 +18,9 @@ import ( "golang.org/x/crypto/ssh" ) -// ErrNotWhitelisted Is the error returned when a key is checked that is not whitelisted, -// when whitelisting is enabled. -var ErrNotWhitelisted = errors.New("not whitelisted") +// ErrNotAllowlisted Is the error returned when a key is checked that is not allowlisted, +// when allowlisting is enabled. +var ErrNotAllowlisted = errors.New("not allowlisted") // ErrBanned is the error returned when a client is banned. var ErrBanned = errors.New("banned") @@ -50,19 +50,19 @@ func newAuthAddr(addr net.Addr) string { return host } -// Auth stores lookups for bans, whitelists, and ops. It implements the sshd.Auth interface. -// If the contained passphrase is not empty, it complements a whitelist. +// Auth stores lookups for bans, allowlists, and ops. It implements the sshd.Auth interface. +// If the contained passphrase is not empty, it complements a allowlist. type Auth struct { passphraseHash []byte - whitelistModeMu sync.RWMutex - whitelistMode bool + allowlistModeMu sync.RWMutex + allowlistMode bool bannedAddr *set.Set bannedClient *set.Set banned *set.Set - whitelist *set.Set + allowlist *set.Set ops *set.Set opFile string - whitelistFile string + allowlistFile string } // NewAuth creates a new empty Auth. @@ -71,21 +71,21 @@ func NewAuth() *Auth { bannedAddr: set.New(), bannedClient: set.New(), banned: set.New(), - whitelist: set.New(), + allowlist: set.New(), ops: set.New(), } } -func (a *Auth) WhitelistMode() bool { - a.whitelistModeMu.RLock() - defer a.whitelistModeMu.RUnlock() - return a.whitelistMode +func (a *Auth) AllowlistMode() bool { + a.allowlistModeMu.RLock() + defer a.allowlistModeMu.RUnlock() + return a.allowlistMode } -func (a *Auth) SetWhitelistMode(value bool) { - a.whitelistModeMu.Lock() - defer a.whitelistModeMu.Unlock() - a.whitelistMode = value +func (a *Auth) SetAllowlistMode(value bool) { + a.allowlistModeMu.Lock() + defer a.allowlistModeMu.Unlock() + a.allowlistMode = value } // SetPassphrase enables passphrase authentication with the given passphrase. @@ -101,7 +101,7 @@ func (a *Auth) SetPassphrase(passphrase string) { // AllowAnonymous determines if anonymous users are permitted. func (a *Auth) AllowAnonymous() bool { - return !a.WhitelistMode() && a.passphraseHash == nil + return !a.AllowlistMode() && a.passphraseHash == nil } // AcceptPassphrase determines if passphrase authentication is accepted. @@ -134,11 +134,11 @@ func (a *Auth) CheckBans(addr net.Addr, key ssh.PublicKey, clientVersion string) // CheckPubkey determines if a pubkey fingerprint is permitted. func (a *Auth) CheckPublicKey(key ssh.PublicKey) error { authkey := newAuthKey(key) - whitelisted := a.whitelist.In(authkey) - if a.AllowAnonymous() || whitelisted || a.IsOp(key) { + allowlisted := a.allowlist.In(authkey) + if a.AllowAnonymous() || allowlisted || a.IsOp(key) { return nil } else { - return ErrNotWhitelisted + return ErrNotAllowlisted } } @@ -180,29 +180,29 @@ func (a *Auth) LoadOpsFromFile(path string) error { return fromFile(path, func(key ssh.PublicKey) { a.Op(key, 0) }) } -// Whitelist will set a public key as a whitelisted user. -func (a *Auth) Whitelist(key ssh.PublicKey, d time.Duration) { +// Allowlist will set a public key as a allowlisted user. +func (a *Auth) Allowlist(key ssh.PublicKey, d time.Duration) { if key == nil { return } var err error authItem := newAuthItem(key) if d != 0 { - err = a.whitelist.Set(set.Expire(authItem, d)) + err = a.allowlist.Set(set.Expire(authItem, d)) } else { - err = a.whitelist.Set(authItem) + err = a.allowlist.Set(authItem) } if err == nil { - logger.Debugf("Added to whitelist: %q (for %s)", authItem.Key(), d) + logger.Debugf("Added to allowlist: %q (for %s)", authItem.Key(), d) } else { - logger.Errorf("Error adding %q to whitelist for %s: %s", authItem.Key(), d, err) + logger.Errorf("Error adding %q to allowlist for %s: %s", authItem.Key(), d, err) } } -// LoadWhitelistFromFile reads a file in authorized_keys format and whitelists public keys -func (a *Auth) LoadWhitelistFromFile(path string) error { - a.whitelistFile = path - return fromFile(path, func(key ssh.PublicKey) { a.Whitelist(key, 0) }) +// LoadAllowlistFromFile reads a file in authorized_keys format and allowlists public keys +func (a *Auth) LoadAllowlistFromFile(path string) error { + a.allowlistFile = path + return fromFile(path, func(key ssh.PublicKey) { a.Allowlist(key, 0) }) } // Ban will set a public key as banned. diff --git a/auth_test.go b/auth_test.go index 4f05a64..b7c55e3 100644 --- a/auth_test.go +++ b/auth_test.go @@ -21,7 +21,7 @@ func ClonePublicKey(key ssh.PublicKey) (ssh.PublicKey, error) { return ssh.ParsePublicKey(key.Marshal()) } -func TestAuthWhitelist(t *testing.T) { +func TestAuthAllowlist(t *testing.T) { key, err := NewRandomPublicKey(512) if err != nil { t.Fatal(err) @@ -33,8 +33,8 @@ func TestAuthWhitelist(t *testing.T) { t.Error("Failed to permit in default state:", err) } - auth.Whitelist(key, 0) - auth.SetWhitelistMode(true) + auth.Allowlist(key, 0) + auth.SetAllowlistMode(true) keyClone, err := ClonePublicKey(key) if err != nil { @@ -47,7 +47,7 @@ func TestAuthWhitelist(t *testing.T) { err = auth.CheckPublicKey(keyClone) if err != nil { - t.Error("Failed to permit whitelisted:", err) + t.Error("Failed to permit allowlisted:", err) } key2, err := NewRandomPublicKey(512) @@ -57,7 +57,7 @@ func TestAuthWhitelist(t *testing.T) { err = auth.CheckPublicKey(key2) if err == nil { - t.Error("Failed to restrict not whitelisted:", err) + t.Error("Failed to restrict not allowlisted:", err) } } diff --git a/cmd/ssh-chat/cmd.go b/cmd/ssh-chat/cmd.go index b967132..0aef593 100644 --- a/cmd/ssh-chat/cmd.go +++ b/cmd/ssh-chat/cmd.go @@ -34,8 +34,8 @@ type Options struct { Pprof int `long:"pprof" description:"Enable pprof http server for profiling."` Verbose []bool `short:"v" long:"verbose" description:"Show verbose logging."` Version bool `long:"version" description:"Print version and exit."` - Whitelist string `long:"whitelist" description:"Optional file of public keys who are allowed to connect."` - Passphrase string `long:"unsafe-passphrase" description:"Require an interactive passphrase to connect. Whitelist feature is more secure."` + Allowlist string `long:"allowlist" description:"Optional file of public keys who are allowed to connect."` + Passphrase string `long:"unsafe-passphrase" description:"Require an interactive passphrase to connect. Allowlist feature is more secure."` } const extraHelp = `There are hidden options and easter eggs in ssh-chat. The source code is a good @@ -144,11 +144,11 @@ func main() { fail(5, "Failed to load admins: %v\n", err) } - err = auth.LoadWhitelistFromFile(options.Whitelist) + err = auth.LoadAllowlistFromFile(options.Allowlist) if err != nil { - fail(6, "Failed to load whitelist: %v\n", err) + fail(6, "Failed to load allowlist: %v\n", err) } - auth.SetWhitelistMode(options.Whitelist != "") + auth.SetAllowlistMode(options.Allowlist != "") if options.Motd != "" { host.GetMOTD = func() (string, error) { diff --git a/host.go b/host.go index fa93861..fa03fab 100644 --- a/host.go +++ b/host.go @@ -780,7 +780,7 @@ func (h *Host) InitCommands(c *chat.Commands) { if pk == nil { noKeyUsers = append(noKeyUsers, user.Identifier.Name()) } else { - h.auth.Whitelist(pk, 0) + h.auth.Allowlist(pk, 0) } } return nil @@ -796,13 +796,13 @@ func (h *Host) InitCommands(c *chat.Commands) { return errors.New("must specify whether to keep or flush current entries") } if args[0] == "flush" { - h.auth.whitelist.Clear() + h.auth.allowlist.Clear() } - return h.auth.LoadWhitelistFromFile(h.auth.whitelistFile) + return h.auth.LoadAllowlistFromFile(h.auth.allowlistFile) } allowlistReverify := func(room *chat.Room) []string { - if !h.auth.WhitelistMode() { + if !h.auth.AllowlistMode() { return []string{"allowlist is disabled, so nobody will be kicked"} } var kicked []string @@ -820,32 +820,32 @@ func (h *Host) InitCommands(c *chat.Commands) { } allowlistStatus := func() (msgs []string) { - if h.auth.WhitelistMode() { + if h.auth.AllowlistMode() { msgs = []string{"The allowlist is currently enabled."} } else { msgs = []string{"The allowlist is currently disabled."} } - whitelistedUsers := []string{} - whitelistedKeys := []string{} - h.auth.whitelist.Each(func(key string, item set.Item) error { + allowlistedUsers := []string{} + allowlistedKeys := []string{} + h.auth.allowlist.Each(func(key string, item set.Item) error { keyFP := item.Key() if forConnectedUsers(func(user *chat.Member, pk ssh.PublicKey) error { if pk != nil && sshd.Fingerprint(pk) == keyFP { - whitelistedUsers = append(whitelistedUsers, user.Name()) + allowlistedUsers = append(allowlistedUsers, user.Name()) return errors.New("not an actual error, but exit early because we found the key") } return nil }) == nil { // if we land here, the key matches no users - whitelistedKeys = append(whitelistedKeys, keyFP) + allowlistedKeys = append(allowlistedKeys, keyFP) } return nil }) - if len(whitelistedUsers) != 0 { - msgs = append(msgs, fmt.Sprintf("The following connected users are on the allowlist: %v", whitelistedUsers)) + if len(allowlistedUsers) != 0 { + msgs = append(msgs, fmt.Sprintf("The following connected users are on the allowlist: %v", allowlistedUsers)) } - if len(whitelistedKeys) != 0 { - msgs = append(msgs, fmt.Sprintf("The following keys of not connected users are on the allowlist: %v", whitelistedKeys)) + if len(allowlistedKeys) != 0 { + msgs = append(msgs, fmt.Sprintf("The following keys of not connected users are on the allowlist: %v", allowlistedKeys)) } return } @@ -872,13 +872,13 @@ func (h *Host) InitCommands(c *chat.Commands) { case "help": replyLines = allowlistHelptext case "on": - h.auth.SetWhitelistMode(true) + h.auth.SetAllowlistMode(true) case "off": - h.auth.SetWhitelistMode(false) + h.auth.SetAllowlistMode(false) case "add": - replyLines = forPubkeyUser(args[1:], func(pk ssh.PublicKey) { h.auth.Whitelist(pk, 0) }) + replyLines = forPubkeyUser(args[1:], func(pk ssh.PublicKey) { h.auth.Allowlist(pk, 0) }) case "remove": - replyLines = forPubkeyUser(args[1:], func(pk ssh.PublicKey) { h.auth.Whitelist(pk, 1) }) + replyLines = forPubkeyUser(args[1:], func(pk ssh.PublicKey) { h.auth.Allowlist(pk, 1) }) case "import": replyLines, err = allowlistImport(args[1:]) case "reload": diff --git a/host_test.go b/host_test.go index d85d005..181341c 100644 --- a/host_test.go +++ b/host_test.go @@ -173,7 +173,7 @@ func TestHostNameCollision(t *testing.T) { } } -func TestHostWhitelist(t *testing.T) { +func TestHostAllowlist(t *testing.T) { auth := NewAuth() s, host := getHost(t, auth) defer s.Close() @@ -192,12 +192,12 @@ func TestHostWhitelist(t *testing.T) { } clientpubkey, _ := ssh.NewPublicKey(clientkey.Public()) - auth.Whitelist(clientpubkey, 0) - auth.SetWhitelistMode(true) + auth.Allowlist(clientpubkey, 0) + auth.SetAllowlistMode(true) err = sshd.ConnectShell(target, "foo", func(r io.Reader, w io.WriteCloser) error { return nil }) if err == nil { - t.Error("Failed to block unwhitelisted connection.") + t.Error("Failed to block unallowlisted connection.") } } @@ -268,52 +268,52 @@ func TestHostAllowlistCommand(t *testing.T) { } sendCmd("/allowlist on") - if !host.auth.WhitelistMode() { + if !host.auth.AllowlistMode() { t.Error("allowlist not enabled after /allowlist on") } sendCmd("/allowlist off") - if host.auth.WhitelistMode() { + if host.auth.AllowlistMode() { t.Error("allowlist not disabled after /allowlist off") } testKey := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPUiNw0nQku4pcUCbZcJlIEAIf5bXJYTy/DKI1vh5b+P" testKeyFP := "SHA256:GJNSl9NUcOS2pZYALn0C5Qgfh5deT+R+FfqNIUvpM9s=" - if host.auth.whitelist.Len() != 0 { + if host.auth.allowlist.Len() != 0 { t.Error("allowlist not empty before adding anyone") } sendCmd("/allowlist add ssh-invalid blah ssh-rsa wrongAsWell invalid foo bar %s", testKey) assertLineEq("users without a public key: [foo]\r") assertLineEq("invalid users: [invalid]\r") assertLineEq("invalid keys: [ssh-invalid blah ssh-rsa wrongAsWell]\r") - if !host.auth.whitelist.In(testKeyFP) || !host.auth.whitelist.In(clientKeyFP) { + if !host.auth.allowlist.In(testKeyFP) || !host.auth.allowlist.In(clientKeyFP) { t.Error("failed to add keys to allowlist") } sendCmd("/allowlist remove invalid bar") assertLineEq("invalid users: [invalid]\r") - if host.auth.whitelist.In(clientKeyFP) { + if host.auth.allowlist.In(clientKeyFP) { t.Error("failed to remove key from allowlist") } - if !host.auth.whitelist.In(testKeyFP) { + if !host.auth.allowlist.In(testKeyFP) { t.Error("removed wrong key") } sendCmd("/allowlist import 5h") - if host.auth.whitelist.In(clientKeyFP) { + if host.auth.allowlist.In(clientKeyFP) { t.Error("imporrted key not seen long enough") } sendCmd("/allowlist import") assertLineEq("users without a public key: [foo]\r") - if !host.auth.whitelist.In(clientKeyFP) { + if !host.auth.allowlist.In(clientKeyFP) { t.Error("failed to import key") } sendCmd("/allowlist reload keep") - if !host.auth.whitelist.In(testKeyFP) { + if !host.auth.allowlist.In(testKeyFP) { t.Error("cleared allowlist to be kept") } sendCmd("/allowlist reload flush") - if host.auth.whitelist.In(testKeyFP) { + if host.auth.allowlist.In(testKeyFP) { t.Error("kept allowlist to be cleared") } sendCmd("/allowlist reload thisIsWrong")