From e8ce9bfcff142a9a13d375222847227fefe8714b Mon Sep 17 00:00:00 2001 From: "J. Stuart McMurray" Date: Sat, 13 Dec 2014 04:00:35 -0500 Subject: [PATCH 1/4] Ding on nick mention --- server.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server.go b/server.go index abdd61e..bba6a0e 100644 --- a/server.go +++ b/server.go @@ -84,6 +84,13 @@ func (s *Server) Broadcast(msg string, except *Client) { if except != nil && client == except { continue } + /* Add an ascii BEL to ding clients when they're mentioned */ + if strings.Contains(msg, client.Name) { + client.Msg <- msg + "\007" + } else { + client.Msg <- msg + } + client.Msg <- msg } } From 867b1ecde3e623b64654ba3fd3ca5df111d9c92c Mon Sep 17 00:00:00 2001 From: "J. Stuart McMurray" Date: Sat, 13 Dec 2014 04:23:48 -0500 Subject: [PATCH 2/4] Rate-limiting --- client.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/client.go b/client.go index 33bd4f7..3941716 100644 --- a/client.go +++ b/client.go @@ -30,6 +30,8 @@ const ABOUT_TEXT string = `-> ssh-chat is made by @shazow. For more, visit shazow.net or follow at twitter.com/shazow ` +const REQUIRED_WAIT time.Duration = time.Second / 2 + type Client struct { Server *Server Conn *ssh.ServerConn @@ -42,6 +44,7 @@ type Client struct { termWidth int termHeight int silencedUntil time.Time + lastTX time.Time } func NewClient(server *Server, conn *ssh.ServerConn) *Client { @@ -52,11 +55,12 @@ func NewClient(server *Server, conn *ssh.ServerConn) *Client { Color: RandomColor(), Msg: make(chan string, MSG_BUFFER), ready: make(chan struct{}, 1), + lastTX: time.Now(), } } func (c *Client) ColoredName() string { - return ColorString(c.Color, c.Name) + return ColorString(c.Color, c.Name) } func (c *Client) Write(msg string) { @@ -229,11 +233,17 @@ func (c *Client) handleShell(channel ssh.Channel) { } msg := fmt.Sprintf("%s: %s", c.ColoredName(), line) + /* Rate limit */ + if time.Now().Sub(c.lastTX) < REQUIRED_WAIT { + c.Msg <- fmt.Sprintf("-> Rate limiting in effect.") + continue + } if c.IsSilenced() || len(msg) > 1000 { c.Msg <- fmt.Sprintf("-> Message rejected.") continue } c.Server.Broadcast(msg, c) + c.lastTX = time.Now() } } From 46d3d7575a79fca0e3e1256a6b9233684c5b9f55 Mon Sep 17 00:00:00 2001 From: "J. Stuart McMurray" Date: Sat, 13 Dec 2014 04:24:05 -0500 Subject: [PATCH 3/4] Better SSH versions --- server.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/server.go b/server.go index bba6a0e..ce4d4dc 100644 --- a/server.go +++ b/server.go @@ -16,7 +16,7 @@ import ( const MAX_NAME_LENGTH = 32 const HISTORY_LEN = 20 -var RE_STRIP_TEXT = regexp.MustCompile("[^0-9A-Za-z_]") +var RE_STRIP_TEXT = regexp.MustCompile("[^0-9A-Za-z_.-]") type Clients map[string]*Client @@ -90,8 +90,6 @@ func (s *Server) Broadcast(msg string, except *Client) { } else { client.Msg <- msg } - - client.Msg <- msg } } From ee23c1617ad96cbed4c9f48d0c98dbf640810e0e Mon Sep 17 00:00:00 2001 From: "J. Stuart McMurray" Date: Sat, 13 Dec 2014 05:25:54 -0500 Subject: [PATCH 4/4] Implement private messages --- client.go | 15 +++++++++++++++ server.go | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/client.go b/client.go index 3941716..b433262 100644 --- a/client.go +++ b/client.go @@ -18,6 +18,7 @@ const HELP_TEXT string = `-> Available commands: /list /nick $NAME /whois $NAME + /msg $NAME $MESSAGE ` const ABOUT_TEXT string = `-> ssh-chat is made by @shazow. @@ -226,6 +227,20 @@ func (c *Client) handleShell(channel ssh.Channel) { client.Write(fmt.Sprintf("-> Silenced for %s by %s.", duration, c.ColoredName())) } } + case "/msg": /* Send a PM */ + /* Make sure we have a recipient and a message */ + if len(parts) < 2 { + c.Msg <- fmt.Sprintf("-> Missing $NAME from: /msg $NAME $MESSAGE") + break + } else if len(parts) < 3 { + c.Msg <- fmt.Sprintf("-> Missing $MESSAGE from: /msg $NAME $MESSAGE") + break + } + /* Ask the server to send the message */ + if err := c.Server.Privmsg(parts[1], parts[2], c); nil != err { + c.Msg <- fmt.Sprintf("Unable to send message to %v: %v", parts[1], err) + } + default: c.Msg <- fmt.Sprintf("-> Invalid command: %s", line) } diff --git a/server.go b/server.go index ce4d4dc..6343148 100644 --- a/server.go +++ b/server.go @@ -93,6 +93,19 @@ func (s *Server) Broadcast(msg string, except *Client) { } } +/* Send a message to a particular nick, if it exists */ +func (s *Server) Privmsg(nick, message string, sender *Client) error { + /* Get the recipient */ + target, ok := s.clients[nick] + if !ok { + return fmt.Errorf("no client with that nick") + } + /* Send the message */ + target.Msg <- fmt.Sprintf("\007[PM from %v] %v", sender.Name, message) + logger.Debugf("PM from %v to %v: %v", sender.Name, nick, message) + return nil +} + func (s *Server) Add(client *Client) { go func() { client.WriteLines(s.history.Get(10))