diff --git a/go.mod b/go.mod index 476b84b..7cf69a2 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/BurntSushi/toml v1.2.1 github.com/edwvee/exiffix v0.0.0-20210922235313-0f6cbda5e58f github.com/golang-jwt/jwt/v4 v4.4.3 + github.com/mattn/go-shellwords v1.0.12 github.com/microcosm-cc/bluemonday v1.0.22 github.com/shurcooL/github_flavored_markdown v0.0.0-20210228213109-c3a9aa474629 golang.org/x/image v0.6.0 diff --git a/go.sum b/go.sum index f1b5ac0..c6f9d72 100644 --- a/go.sum +++ b/go.sum @@ -53,6 +53,8 @@ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= +github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/microcosm-cc/bluemonday v1.0.22 h1:p2tT7RNzRdCi0qmwxG+HbqD6ILkmwter1ZwVZn1oTxA= github.com/microcosm-cc/bluemonday v1.0.22/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= diff --git a/pkg/commands.go b/pkg/commands.go index 279f25b..84e0ac5 100644 --- a/pkg/commands.go +++ b/pkg/commands.go @@ -2,8 +2,10 @@ package barertc import ( "strconv" - "strings" "time" + + "git.kirsle.net/apps/barertc/pkg/log" + "github.com/mattn/go-shellwords" ) // ProcessCommand parses a chat message for "/commands" @@ -13,8 +15,11 @@ func (s *Server) ProcessCommand(sub *Subscriber, msg Message) bool { } // Line begins with a slash, parse it apart. - words := strings.Fields(msg.Message) - if len(words) == 0 { + words, err := shellwords.Parse(msg.Message) + if err != nil { + log.Error("ProcessCommands: parsing shell words: %s", err) + return false + } else if len(words) == 0 { return false } @@ -47,7 +52,8 @@ func (s *Server) ProcessCommand(sub *Subscriber, msg Message) bool { sub.ChatServer(RenderMarkdown("Moderator commands are:\n\n" + "* `/kick ` to kick from chat\n" + "* `/nsfw ` to mark their camera NSFW\n" + - "* `/help` to show this message", + "* `/help` to show this message\n\n" + + "Note: shell-style quoting is supported, if a username has a space in it, quote the whole username, e.g.: `/kick \"username 2\"`", )) return true } @@ -60,12 +66,17 @@ func (s *Server) ProcessCommand(sub *Subscriber, msg Message) bool { // KickCommand handles the `/kick` operator command. func (s *Server) KickCommand(words []string, sub *Subscriber) { if len(words) == 1 { - sub.ChatServer("Usage: `/kick username` to remove the user from the chat room.") + sub.ChatServer(RenderMarkdown( + "Usage: `/kick username` to remove the user from the chat room.\n\nNote: if the username has spaces in it, quote the name (shell style), `/kick \"username 2\"`", + )) + return } username := words[1] other, err := s.GetSubscriber(username) if err != nil { sub.ChatServer("/kick: username not found: %s", username) + } else if other.Username == sub.Username { + sub.ChatServer("/kick: did you really mean to kick yourself?") } else { other.ChatServer("You have been kicked from the chat room by %s", sub.Username) other.SendJSON(Message{ @@ -79,10 +90,11 @@ func (s *Server) KickCommand(words []string, sub *Subscriber) { // BanCommand handles the `/ban` operator command. func (s *Server) BanCommand(words []string, sub *Subscriber) { if len(words) == 1 { - sub.ChatServer( + sub.ChatServer(RenderMarkdown( "Usage: `/ban username` to remove the user from the chat room for 24 hours (default).\n\n" + "Set another duration (in hours, fractions supported) like: `/ban username 0.5` for a 30-minute ban.", - ) + )) + return } // Parse the command. diff --git a/pkg/handlers.go b/pkg/handlers.go index 0617d55..49433a8 100644 --- a/pkg/handlers.go +++ b/pkg/handlers.go @@ -27,8 +27,6 @@ func (s *Server) OnLogin(sub *Subscriber, msg Message) { // Sanity check the username. if msg.Username != parsed.Subject { log.Error("JWT login had a different username: %s vs %s", parsed.Subject, msg.Username) - sub.ChatServer("Your authentication username did not match the expected username. Please go back and launch the chat room again.") - return } // Strict enforcement?