mirror of
https://github.com/shazow/ssh-chat.git
synced 2025-04-15 00:20:37 +03:00
tests: All passing again
This commit is contained in:
parent
0096404142
commit
3ef404198d
@ -25,19 +25,21 @@ func BufferedScreen(name string, screen io.WriteCloser) *bufferedScreen {
|
|||||||
|
|
||||||
func PipedScreen(name string, screen io.WriteCloser) *pipedScreen {
|
func PipedScreen(name string, screen io.WriteCloser) *pipedScreen {
|
||||||
return &pipedScreen{
|
return &pipedScreen{
|
||||||
baseScreen: &baseScreen{
|
baseScreen: Screen(name),
|
||||||
User: NewUser(name),
|
|
||||||
},
|
|
||||||
WriteCloser: screen,
|
WriteCloser: screen,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandledScreen(name string, handler func(Message) error) *handledScreen {
|
func HandledScreen(name string, handler func(Message) error) *handledScreen {
|
||||||
return &handledScreen{
|
return &handledScreen{
|
||||||
baseScreen: &baseScreen{
|
baseScreen: Screen(name),
|
||||||
User: NewUser(name),
|
handler: handler,
|
||||||
},
|
}
|
||||||
handler: handler,
|
}
|
||||||
|
|
||||||
|
func Screen(name string) *baseScreen {
|
||||||
|
return &baseScreen{
|
||||||
|
User: NewUser(name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,13 +3,19 @@ package sshchat
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/shazow/ssh-chat/chat"
|
||||||
"github.com/shazow/ssh-chat/chat/message"
|
"github.com/shazow/ssh-chat/chat/message"
|
||||||
"github.com/shazow/ssh-chat/sshd"
|
"github.com/shazow/ssh-chat/sshd"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
user *message.User
|
user chat.Member
|
||||||
conn sshd.Connection
|
conn sshd.Connection
|
||||||
|
|
||||||
timestamp time.Time
|
timestamp time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Replier interface {
|
||||||
|
ReplyTo() message.Author
|
||||||
|
SetReplyTo(message.Author)
|
||||||
|
}
|
||||||
|
37
host.go
37
host.go
@ -35,7 +35,7 @@ type Host struct {
|
|||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
motd string
|
motd string
|
||||||
count int
|
count int
|
||||||
clients map[*message.User][]Client
|
clients map[chat.Member][]Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHost creates a Host on top of an existing listener.
|
// NewHost creates a Host on top of an existing listener.
|
||||||
@ -46,7 +46,7 @@ func NewHost(listener *sshd.SSHListener, auth *Auth) *Host {
|
|||||||
listener: listener,
|
listener: listener,
|
||||||
commands: chat.Commands{},
|
commands: chat.Commands{},
|
||||||
auth: auth,
|
auth: auth,
|
||||||
clients: map[*message.User][]Client{},
|
clients: map[chat.Member][]Client{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make our own commands registry instance.
|
// Make our own commands registry instance.
|
||||||
@ -75,7 +75,7 @@ func (h *Host) SetMotd(motd string) {
|
|||||||
// Connect a specific Terminal to this host and its room.
|
// Connect a specific Terminal to this host and its room.
|
||||||
func (h *Host) Connect(term *sshd.Terminal) {
|
func (h *Host) Connect(term *sshd.Terminal) {
|
||||||
requestedName := term.Conn.Name()
|
requestedName := term.Conn.Name()
|
||||||
user := message.NewScreen(requestedName, term)
|
user := message.BufferedScreen(requestedName, term)
|
||||||
|
|
||||||
client := h.addClient(user, term.Conn)
|
client := h.addClient(user, term.Conn)
|
||||||
defer h.removeClient(user, client)
|
defer h.removeClient(user, client)
|
||||||
@ -180,7 +180,7 @@ func (h *Host) Connect(term *sshd.Terminal) {
|
|||||||
logger.Debugf("[%s] Leaving: %s", term.Conn.RemoteAddr(), user.Name())
|
logger.Debugf("[%s] Leaving: %s", term.Conn.RemoteAddr(), user.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Host) addClient(user *message.User, conn sshd.Connection) *Client {
|
func (h *Host) addClient(user chat.Member, conn sshd.Connection) *Client {
|
||||||
client := Client{
|
client := Client{
|
||||||
user: user,
|
user: user,
|
||||||
conn: conn,
|
conn: conn,
|
||||||
@ -195,7 +195,7 @@ func (h *Host) addClient(user *message.User, conn sshd.Connection) *Client {
|
|||||||
return &client
|
return &client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Host) removeClient(user *message.User, client *Client) {
|
func (h *Host) removeClient(user chat.Member, client *Client) {
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
defer h.mu.Unlock()
|
defer h.mu.Unlock()
|
||||||
|
|
||||||
@ -212,7 +212,7 @@ func (h *Host) removeClient(user *message.User, client *Client) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Host) findClients(user *message.User) []Client {
|
func (h *Host) findClients(user chat.Member) []Client {
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
defer h.mu.Unlock()
|
defer h.mu.Unlock()
|
||||||
return h.clients[user]
|
return h.clients[user]
|
||||||
@ -244,7 +244,7 @@ func (h *Host) completeCommand(partial string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AutoCompleteFunction returns a callback for terminal autocompletion
|
// AutoCompleteFunction returns a callback for terminal autocompletion
|
||||||
func (h *Host) AutoCompleteFunction(u *message.User) func(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
|
func (h *Host) AutoCompleteFunction(u Replier) func(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
|
||||||
return func(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
|
return func(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
|
||||||
if key != 9 {
|
if key != 9 {
|
||||||
return
|
return
|
||||||
@ -301,13 +301,12 @@ func (h *Host) AutoCompleteFunction(u *message.User) func(line string, pos int,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetUser returns a message.User based on a name.
|
// GetUser returns a message.User based on a name.
|
||||||
func (h *Host) GetUser(name string) (*message.User, bool) {
|
func (h *Host) GetUser(name string) (chat.Member, bool) {
|
||||||
m, ok := h.MemberByID(name)
|
m, ok := h.MemberByID(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
u, ok := m.Member.(*message.User)
|
return m.Member, true
|
||||||
return u, ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitCommands adds host-specific commands to a Commands container. These will
|
// InitCommands adds host-specific commands to a Commands container. These will
|
||||||
@ -337,7 +336,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
|
|||||||
txt := fmt.Sprintf("[Sent PM to %s]", target.Name())
|
txt := fmt.Sprintf("[Sent PM to %s]", target.Name())
|
||||||
ms := message.NewSystemMsg(txt, msg.From())
|
ms := message.NewSystemMsg(txt, msg.From())
|
||||||
room.Send(ms)
|
room.Send(ms)
|
||||||
target.SetReplyTo(msg.From())
|
target.(Replier).SetReplyTo(msg.From())
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -353,7 +352,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
|
|||||||
return errors.New("must specify message")
|
return errors.New("must specify message")
|
||||||
}
|
}
|
||||||
|
|
||||||
target := msg.From().ReplyTo()
|
target := msg.From().(Replier).ReplyTo()
|
||||||
if target == nil {
|
if target == nil {
|
||||||
return errors.New("no message to reply to")
|
return errors.New("no message to reply to")
|
||||||
}
|
}
|
||||||
@ -392,7 +391,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
|
|||||||
// FIXME: Handle many clients
|
// FIXME: Handle many clients
|
||||||
clients := h.findClients(target)
|
clients := h.findClients(target)
|
||||||
var whois string
|
var whois string
|
||||||
switch room.IsOp(msg.From()) {
|
switch room.IsOp(msg.From().(chat.Member)) {
|
||||||
case true:
|
case true:
|
||||||
whois = whoisAdmin(clients)
|
whois = whoisAdmin(clients)
|
||||||
case false:
|
case false:
|
||||||
@ -428,7 +427,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
|
|||||||
PrefixHelp: "USER [DURATION]",
|
PrefixHelp: "USER [DURATION]",
|
||||||
Help: "Set USER as admin.",
|
Help: "Set USER as admin.",
|
||||||
Handler: func(room *chat.Room, msg message.CommandMsg) error {
|
Handler: func(room *chat.Room, msg message.CommandMsg) error {
|
||||||
if !room.IsOp(msg.From()) {
|
if !room.IsOp(msg.From().(chat.Member)) {
|
||||||
return errors.New("must be op")
|
return errors.New("must be op")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,7 +470,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
|
|||||||
Help: "Ban USER from the server.",
|
Help: "Ban USER from the server.",
|
||||||
Handler: func(room *chat.Room, msg message.CommandMsg) error {
|
Handler: func(room *chat.Room, msg message.CommandMsg) error {
|
||||||
// TODO: Would be nice to specify what to ban. Key? Ip? etc.
|
// TODO: Would be nice to specify what to ban. Key? Ip? etc.
|
||||||
if !room.IsOp(msg.From()) {
|
if !room.IsOp(msg.From().(chat.Member)) {
|
||||||
return errors.New("must be op")
|
return errors.New("must be op")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,7 +497,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
|
|||||||
|
|
||||||
body := fmt.Sprintf("%s was banned by %s.", target.Name(), msg.From().Name())
|
body := fmt.Sprintf("%s was banned by %s.", target.Name(), msg.From().Name())
|
||||||
room.Send(message.NewAnnounceMsg(body))
|
room.Send(message.NewAnnounceMsg(body))
|
||||||
target.Close()
|
target.(io.Closer).Close()
|
||||||
|
|
||||||
logger.Debugf("Banned: \n-> %s", whoisAdmin(clients))
|
logger.Debugf("Banned: \n-> %s", whoisAdmin(clients))
|
||||||
|
|
||||||
@ -512,7 +511,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
|
|||||||
PrefixHelp: "USER",
|
PrefixHelp: "USER",
|
||||||
Help: "Kick USER from the server.",
|
Help: "Kick USER from the server.",
|
||||||
Handler: func(room *chat.Room, msg message.CommandMsg) error {
|
Handler: func(room *chat.Room, msg message.CommandMsg) error {
|
||||||
if !room.IsOp(msg.From()) {
|
if !room.IsOp(msg.From().(chat.Member)) {
|
||||||
return errors.New("must be op")
|
return errors.New("must be op")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,7 +527,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
|
|||||||
|
|
||||||
body := fmt.Sprintf("%s was kicked by %s.", target.Name(), msg.From().Name())
|
body := fmt.Sprintf("%s was kicked by %s.", target.Name(), msg.From().Name())
|
||||||
room.Send(message.NewAnnounceMsg(body))
|
room.Send(message.NewAnnounceMsg(body))
|
||||||
target.Close()
|
target.(io.Closer).Close()
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -550,7 +549,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
|
|||||||
room.Send(message.NewSystemMsg(motd, user))
|
room.Send(message.NewSystemMsg(motd, user))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if !room.IsOp(user) {
|
if !room.IsOp(user.(chat.Member)) {
|
||||||
return errors.New("must be OP to modify the MOTD")
|
return errors.New("must be OP to modify the MOTD")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ func stripPrompt(s string) string {
|
|||||||
func TestHostGetPrompt(t *testing.T) {
|
func TestHostGetPrompt(t *testing.T) {
|
||||||
var expected, actual string
|
var expected, actual string
|
||||||
|
|
||||||
u := message.NewUser("foo")
|
u := message.Screen("foo")
|
||||||
|
|
||||||
actual = u.Prompt()
|
actual = u.Prompt()
|
||||||
expected = "[foo] "
|
expected = "[foo] "
|
||||||
@ -40,7 +40,7 @@ func TestHostGetPrompt(t *testing.T) {
|
|||||||
Theme: &message.Themes[0],
|
Theme: &message.Themes[0],
|
||||||
})
|
})
|
||||||
actual = u.Prompt()
|
actual = u.Prompt()
|
||||||
expected = "[\033[38;05;88mfoo\033[0m] "
|
expected = "[\033[38;05;1mfoo\033[0m] "
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
t.Errorf("Got: %q; Expected: %q", actual, expected)
|
t.Errorf("Got: %q; Expected: %q", actual, expected)
|
||||||
}
|
}
|
||||||
|
9
whois.go
9
whois.go
@ -2,6 +2,7 @@ package sshchat
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
humanize "github.com/dustin/go-humanize"
|
humanize "github.com/dustin/go-humanize"
|
||||||
"github.com/shazow/ssh-chat/chat/message"
|
"github.com/shazow/ssh-chat/chat/message"
|
||||||
@ -10,6 +11,10 @@ import (
|
|||||||
|
|
||||||
// Helpers for printing whois messages
|
// Helpers for printing whois messages
|
||||||
|
|
||||||
|
type joinTimestamped interface {
|
||||||
|
Joined() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
func whoisPublic(clients []Client) string {
|
func whoisPublic(clients []Client) string {
|
||||||
// FIXME: Handle many clients
|
// FIXME: Handle many clients
|
||||||
conn, u := clients[0].conn, clients[0].user
|
conn, u := clients[0].conn, clients[0].user
|
||||||
@ -21,7 +26,7 @@ func whoisPublic(clients []Client) string {
|
|||||||
return "name: " + u.Name() + message.Newline +
|
return "name: " + u.Name() + message.Newline +
|
||||||
" > fingerprint: " + fingerprint + message.Newline +
|
" > fingerprint: " + fingerprint + message.Newline +
|
||||||
" > client: " + SanitizeData(string(conn.ClientVersion())) + message.Newline +
|
" > client: " + SanitizeData(string(conn.ClientVersion())) + message.Newline +
|
||||||
" > joined: " + humanize.Time(u.Joined())
|
" > joined: " + humanize.Time(u.(joinTimestamped).Joined())
|
||||||
}
|
}
|
||||||
|
|
||||||
func whoisAdmin(clients []Client) string {
|
func whoisAdmin(clients []Client) string {
|
||||||
@ -37,5 +42,5 @@ func whoisAdmin(clients []Client) string {
|
|||||||
" > ip: " + ip + message.Newline +
|
" > ip: " + ip + message.Newline +
|
||||||
" > fingerprint: " + fingerprint + message.Newline +
|
" > fingerprint: " + fingerprint + message.Newline +
|
||||||
" > client: " + SanitizeData(string(conn.ClientVersion())) + message.Newline +
|
" > client: " + SanitizeData(string(conn.ClientVersion())) + message.Newline +
|
||||||
" > joined: " + humanize.Time(u.Joined())
|
" > joined: " + humanize.Time(u.(joinTimestamped).Joined())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user