diff --git a/Admin's Manual.md b/Admin's Manual.md index 7d0f6f8b..1c97012f 100644 --- a/Admin's Manual.md +++ b/Admin's Manual.md @@ -66,6 +66,22 @@ kick If running these commands makes Devbot complain about authorization, you need to add your ID under the `admins` key in your config file (`devzat-config.yml` by default). +### Enabling a user allowlist + +Devzat can use be used as a private chatroom. Add this to your config: + +```yaml +private: true # enable allowlist checking +allowlist: + 272b326d7d5e9a6b1d98a10b453bdc8cc950fc15cae2c2e858e30645c72ae7c0: 'John Doe' + ... +``` + +The `whitelist` has the same format as the `admins` list. Add the IDs of the allowed user and some info about that user (this is to make IDs easier to identify when editing the config file, and isn't used by Devzat) + +All admins are allowed even if their ID is not in the whitelist. So, if everyone on the private server is an admin, a whitelist isn't necessary, just enable private mode. + +Message backlog on `#main` is disabled in private chats. Only those logged in at the same time as you can read your messages. ### Enabling integrations @@ -130,3 +146,4 @@ There are 4 environment variables you can set to quickly disable integrations on * `DEVZAT_OFFLINE_SLACK=true` will disable Slack * `DEVZAT_OFFLINE_RPC=true` will disable the gRPC server * `DEVZAT_OFFLINE=true` will disable all integrations. + diff --git a/config.go b/config.go index d8e40a37..9cc6e50c 100644 --- a/config.go +++ b/config.go @@ -16,6 +16,8 @@ type ConfigType struct { KeyFile string `yaml:"key_file"` Admins map[string]string `yaml:"admins"` Censor bool `yaml:"censor,omitempty"` + Private bool `yaml:"private,omitempty"` + Allowlist map[string]string `yaml:"allowlist,omitempty"` IntegrationConfig string `yaml:"integration_config"` } @@ -61,7 +63,6 @@ var ( ProfilePort: 5555, DataDir: "devzat-data", KeyFile: "devzat-sshkey", - Censor: false, IntegrationConfig: "", } diff --git a/main.go b/main.go index 764e9283..2582dbdb 100644 --- a/main.go +++ b/main.go @@ -168,15 +168,21 @@ func main() { u.repl() }) - fmt.Printf("Starting chat server on port %d and profiling on port %d\n", Config.Port, Config.ProfilePort) + if Config.Private { + Log.Printf("Starting a private Devzat server on port %d and profiling on port %d\n Edit your config to change who's allowed entry.", Config.Port, Config.ProfilePort) + } else { + Log.Printf("Starting a Devzat server on port %d and profiling on port %d\n", Config.Port, Config.ProfilePort) + } go getMsgsFromSlack() - go func() { - fmt.Println("Also starting chat server on port", Config.AltPort) - err := ssh.ListenAndServe(fmt.Sprintf(":%d", Config.AltPort), nil, ssh.HostKeyFile(Config.KeyFile)) - if err != nil { - fmt.Println(err) - } - }() + if !Config.Private { // allow non-sshkey logins on a non-private server + go func() { + fmt.Println("Also serving on port", Config.AltPort) + err := ssh.ListenAndServe(fmt.Sprintf(":%d", Config.AltPort), nil, ssh.HostKeyFile(Config.KeyFile)) + if err != nil { + fmt.Println(err) + } + }() + } err = ssh.ListenAndServe(fmt.Sprintf(":%d", Config.Port), nil, ssh.HostKeyFile(Config.KeyFile), ssh.PublicKeyAuth(func(ctx ssh.Context, key ssh.PublicKey) bool { return true // allow all keys, this lets us hash pubkeys later @@ -316,11 +322,23 @@ func newUser(s ssh.Session) *User { Log.Println("Connected " + u.Name + " [" + u.id + "]") if bansContains(Bans, u.addr, u.id) { - Log.Println("Rejected " + u.Name + " [" + host + "]") + Log.Println("Rejected " + u.Name + " [" + host + "] (banned)") u.writeln(Devbot, "**You are banned**. If you feel this was a mistake, please reach out at github.com/quackduck/devzat/issues or email igoel.mail@gmail.com. Please include the following information: [ID "+u.id+"]") u.closeQuietly() return nil } + + if Config.Private { + _, isOnAllowlist := Config.Allowlist[u.id] + _, isAdmin := Config.Admins[u.id] + if !(isAdmin || isOnAllowlist) { + Log.Println("Rejected " + u.Name + " [" + u.id + "] (not on allowlist)") + u.writeln(Devbot, "You are not on the allowlist of this private server. If this is a mistake, send your id ("+u.id+") to the admin so that they can whitelist you.") + u.closeQuietly() + return nil + } + } + IDsInMinToTimes[u.id]++ time.AfterFunc(60*time.Second, func() { IDsInMinToTimes[u.id]-- @@ -354,15 +372,17 @@ func newUser(s ssh.Session) *User { Log.Println("Could not load user:", err) } - if len(Backlog) > 0 { - lastStamp := Backlog[0].timestamp - u.rWriteln(fmtTime(u, lastStamp)) - for i := range Backlog { - if Backlog[i].timestamp.Sub(lastStamp) > time.Minute { - lastStamp = Backlog[i].timestamp - u.rWriteln(fmtTime(u, lastStamp)) + if !Config.Private { // sensitive info might be shared on a private server + if len(Backlog) > 0 { + lastStamp := Backlog[0].timestamp + u.rWriteln(fmtTime(u, lastStamp)) + for i := range Backlog { + if Backlog[i].timestamp.Sub(lastStamp) > time.Minute { + lastStamp = Backlog[i].timestamp + u.rWriteln(fmtTime(u, lastStamp)) + } + u.writeln(Backlog[i].senderName, Backlog[i].text) } - u.writeln(Backlog[i].senderName, Backlog[i].text) } }