mirror of
https://github.com/shazow/ssh-chat.git
synced 2025-05-16 06:56:36 +03:00
- Added new rank: Administators (or masters). This rank can add or delete operators, but cannot add or remove another administrators. Administrators rank is designed by public key on server startup. - Added "vim mode". With this mode you can use commands as ':' instead of '/'. As you can see in the code, the Prefix parameter of Command structure was changed by a neutral parameter for future introductions of prefixes. - New Help function. This function add help for admin rank. - Added the following commands: - setnick: Administrators can change the nick of another user. - private: Users can stablish privates conversations. This conversations are permanent until they execute endprivate command. - endprivate: Finish private conversation. - welcome: Prints motd. Only admins can execute this. - whois: In whois only admins can see ip. - delop: Allow admins to delete an operator (or moderator as is mentioned in some parts of the code). - Changed historyLen and roomBuffer vars. - In cmd tool have been added fsnotify to update public key files (admin and moderator public key files). This is to prevent to restart the server everytime we want to add an administrator. - Added new prompt mode. In this mode you can see in which room you are talking. As default is 'general'. If you start private conversation the room will be the name of the another user. This part has been introduced for future implementations. - As I said before now exists private conversations (unlike msg command).
178 lines
4.1 KiB
Go
178 lines
4.1 KiB
Go
package sshchat
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/shazow/ssh-chat/set"
|
|
"github.com/shazow/ssh-chat/sshd"
|
|
"golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
// The error returned a key is checked that is not whitelisted, with whitelisting required.
|
|
var ErrNotWhitelisted = errors.New("not whitelisted")
|
|
|
|
// The error returned a key is checked that is banned.
|
|
var ErrBanned = errors.New("banned")
|
|
|
|
// newAuthKey returns string from an ssh.PublicKey used to index the key in our lookup.
|
|
func newAuthKey(key ssh.PublicKey) string {
|
|
if key == nil {
|
|
return ""
|
|
}
|
|
// FIXME: Is there a better way to index pubkeys without marshal'ing them into strings?
|
|
return sshd.Fingerprint(key)
|
|
}
|
|
|
|
func newAuthItem(key ssh.PublicKey) set.Item {
|
|
return set.StringItem(newAuthKey(key))
|
|
}
|
|
|
|
// newAuthAddr returns a string from a net.Addr used to index the address the key in our lookup.
|
|
func newAuthAddr(addr net.Addr) string {
|
|
if addr == nil {
|
|
return ""
|
|
}
|
|
host, _, _ := net.SplitHostPort(addr.String())
|
|
return host
|
|
}
|
|
|
|
// Auth stores lookups for bans, whitelists, and ops. It implements the sshd.Auth interface.
|
|
type Auth struct {
|
|
bannedAddr *set.Set
|
|
banned *set.Set
|
|
whitelist *set.Set
|
|
ops *set.Set
|
|
masters *set.Set
|
|
}
|
|
|
|
// NewAuth creates a new empty Auth.
|
|
func NewAuth() *Auth {
|
|
return &Auth{
|
|
bannedAddr: set.New(),
|
|
banned: set.New(),
|
|
whitelist: set.New(),
|
|
ops: set.New(),
|
|
masters: set.New(),
|
|
}
|
|
}
|
|
|
|
// AllowAnonymous determines if anonymous users are permitted.
|
|
func (a *Auth) AllowAnonymous() bool {
|
|
return a.whitelist.Len() == 0
|
|
}
|
|
|
|
// Check determines if a pubkey fingerprint is permitted.
|
|
func (a *Auth) Check(addr net.Addr, key ssh.PublicKey) (bool, error) {
|
|
authkey := newAuthKey(key)
|
|
|
|
if a.whitelist.Len() != 0 {
|
|
// Only check whitelist if there is something in it, otherwise it's disabled.
|
|
whitelisted := a.whitelist.In(authkey)
|
|
if !whitelisted {
|
|
return false, ErrNotWhitelisted
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
banned := a.banned.In(authkey)
|
|
if !banned {
|
|
banned = a.bannedAddr.In(newAuthAddr(addr))
|
|
}
|
|
if banned {
|
|
return false, ErrBanned
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
// Op sets a public key as a known operator.
|
|
func (a *Auth) Op(key ssh.PublicKey, d time.Duration) {
|
|
if key == nil {
|
|
return
|
|
}
|
|
authItem := newAuthItem(key)
|
|
if d != 0 {
|
|
a.ops.Add(set.Expire(authItem, d))
|
|
} else {
|
|
a.ops.Add(authItem)
|
|
}
|
|
logger.Debugf("Added to ops: %s (for %s)", authItem.Key(), d)
|
|
}
|
|
|
|
// Master sets a public key as a known admin master.
|
|
func (a *Auth) Master(key ssh.PublicKey, d time.Duration) {
|
|
if key == nil {
|
|
return
|
|
}
|
|
authItem := newAuthItem(key)
|
|
if d != 0 {
|
|
a.masters.Add(set.Expire(authItem, d))
|
|
} else {
|
|
a.masters.Add(authItem)
|
|
}
|
|
logger.Debugf("Added to masters: %s (for %s)", authItem.Key(), d)
|
|
}
|
|
|
|
// IsOp checks if a public key is an op.
|
|
func (a *Auth) IsOp(key ssh.PublicKey) bool {
|
|
if key == nil {
|
|
return false
|
|
}
|
|
authkey := newAuthKey(key)
|
|
return a.ops.In(authkey)
|
|
}
|
|
|
|
func (a *Auth) IsMaster(key ssh.PublicKey) bool {
|
|
if key == nil {
|
|
return false
|
|
}
|
|
authkey := newAuthKey(key)
|
|
return a.masters.In(authkey)
|
|
}
|
|
|
|
// Whitelist will set a public key as a whitelisted user.
|
|
func (a *Auth) Whitelist(key ssh.PublicKey, d time.Duration) {
|
|
if key == nil {
|
|
return
|
|
}
|
|
authItem := newAuthItem(key)
|
|
if d != 0 {
|
|
a.whitelist.Add(set.Expire(authItem, d))
|
|
} else {
|
|
a.whitelist.Add(authItem)
|
|
}
|
|
logger.Debugf("Added to whitelist: %s (for %s)", authItem.Key(), d)
|
|
}
|
|
|
|
// Ban will set a public key as banned.
|
|
func (a *Auth) Ban(key ssh.PublicKey, d time.Duration) {
|
|
if key == nil {
|
|
return
|
|
}
|
|
a.BanFingerprint(newAuthKey(key), d)
|
|
}
|
|
|
|
// BanFingerprint will set a public key fingerprint as banned.
|
|
func (a *Auth) BanFingerprint(authkey string, d time.Duration) {
|
|
authItem := set.StringItem(authkey)
|
|
if d != 0 {
|
|
a.banned.Add(set.Expire(authItem, d))
|
|
} else {
|
|
a.banned.Add(authItem)
|
|
}
|
|
logger.Debugf("Added to banned: %s (for %s)", authItem.Key(), d)
|
|
}
|
|
|
|
// Ban will set an IP address as banned.
|
|
func (a *Auth) BanAddr(addr net.Addr, d time.Duration) {
|
|
authItem := set.StringItem(addr.String())
|
|
if d != 0 {
|
|
a.bannedAddr.Add(set.Expire(authItem, d))
|
|
} else {
|
|
a.bannedAddr.Add(authItem)
|
|
}
|
|
logger.Debugf("Added to bannedAddr: %s (for %s)", authItem.Key(), d)
|
|
}
|