diff --git a/auth.go b/auth.go new file mode 100644 index 0000000..27a7077 --- /dev/null +++ b/auth.go @@ -0,0 +1,68 @@ +package main + +import ( + "errors" + "sync" + + "github.com/shazow/ssh-chat/sshd" +) + +// Auth stores fingerprint lookups +type Auth struct { + whitelist map[string]struct{} + banned map[string]struct{} + ops map[string]struct{} + + sshd.Auth + sync.RWMutex +} + +// AllowAnonymous determines if anonymous users are permitted. +func (a Auth) AllowAnonymous() bool { + a.RLock() + ok := len(a.whitelist) == 0 + a.RUnlock() + return ok +} + +// Check determines if a pubkey fingerprint is permitted. +func (a Auth) Check(fingerprint string) (bool, error) { + a.RLock() + defer a.RUnlock() + + if len(a.whitelist) > 0 { + // Only check whitelist if there is something in it, otherwise it's disabled. + _, whitelisted := a.whitelist[fingerprint] + if !whitelisted { + return false, errors.New("not whitelisted") + } + } + + _, banned := a.banned[fingerprint] + if banned { + return false, errors.New("banned") + } + + return true, nil +} + +// Op will set a fingerprint as a known operator. +func (a *Auth) Op(fingerprint string) { + a.Lock() + a.ops[fingerprint] = struct{}{} + a.Unlock() +} + +// Whitelist will set a fingerprint as a whitelisted user. +func (a *Auth) Whitelist(fingerprint string) { + a.Lock() + a.whitelist[fingerprint] = struct{}{} + a.Unlock() +} + +// Ban will set a fingerprint as banned. +func (a *Auth) Ban(fingerprint string) { + a.Lock() + a.banned[fingerprint] = struct{}{} + a.Unlock() +} diff --git a/chat/channel.go b/chat/channel.go index b4de26e..68fee01 100644 --- a/chat/channel.go +++ b/chat/channel.go @@ -51,8 +51,8 @@ func (ch *Channel) SetCommands(commands Commands) { func (ch *Channel) Close() { ch.closeOnce.Do(func() { ch.closed = true - ch.members.Each(func(u Item) { - u.(*User).Close() + ch.members.Each(func(m Item) { + m.(*Member).Close() }) ch.members.Clear() close(ch.broadcast) diff --git a/chat/command.go b/chat/command.go index 431ecb9..66e9446 100644 --- a/chat/command.go +++ b/chat/command.go @@ -1,6 +1,7 @@ -// FIXME: Would be sweet if we could piggyback on a cli parser or something. package chat +// FIXME: Would be sweet if we could piggyback on a cli parser or something. + import ( "errors" "fmt" @@ -93,8 +94,12 @@ func (c Commands) Help(showOp bool) string { var defaultCommands *Commands func init() { - c := Commands{} + defaultCommands = &Commands{} + InitCommands(defaultCommands) +} +// InitCommands injects default commands into a Commands registry. +func InitCommands(c *Commands) { c.Add(Command{ Prefix: "/help", Handler: func(channel *Channel, msg CommandMsg) error { @@ -217,6 +222,4 @@ func init() { return nil }, }) - - defaultCommands = &c } diff --git a/chat/help.go b/chat/help.go index 9e9cd42..0ab62c6 100644 --- a/chat/help.go +++ b/chat/help.go @@ -17,7 +17,7 @@ type help struct { } // NewCommandsHelp creates a help container from a commands container. -func NewCommandsHelp(c []*Command) *help { +func NewCommandsHelp(c []*Command) fmt.Stringer { lookup := map[string]struct{}{} h := help{ items: []helpItem{}, diff --git a/host.go b/host.go index c6c8de7..175ba11 100644 --- a/host.go +++ b/host.go @@ -14,6 +14,7 @@ import ( type Host struct { listener *sshd.SSHListener channel *chat.Channel + commands *chat.Commands motd string auth *Auth @@ -26,6 +27,12 @@ func NewHost(listener *sshd.SSHListener) *Host { listener: listener, channel: ch, } + + // Make our own commands registry instance. + commands := chat.Commands{} + chat.InitCommands(&commands) + ch.SetCommands(commands) + go ch.Serve() return &h }