Fix: GetUser, Redo bans
This commit is contained in:
parent
1f4cefd972
commit
bac6cae764
39
auth/auth.go
39
auth/auth.go
|
@ -216,36 +216,41 @@ func (users *UserDB) Sync(user *RegisteredUser) error {
|
|||
}
|
||||
|
||||
// GetUser iterates through all RegisteredUser instances in the database and returns a pointer to the one that matches the requested username.
|
||||
func (users *UserDB) GetUser(user string) (usr *RegisteredUser, err error) {
|
||||
func (users *UserDB) GetUser(targetUser string) (*RegisteredUser, error) {
|
||||
var (
|
||||
usrbytes []byte
|
||||
usrbytes []byte
|
||||
err error
|
||||
userStruct = &RegisteredUser{}
|
||||
)
|
||||
|
||||
if users.DB.Len() < 1 {
|
||||
if users.DB.Len() <= 0 {
|
||||
return &RegisteredUser{}, errors.New("no users in database")
|
||||
}
|
||||
|
||||
ukeys := users.DB.Keys()
|
||||
for {
|
||||
key, ok := <-ukeys
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
err = users.DB.Fold(func(key []byte) error {
|
||||
if usrbytes, err = users.DB.Get(key); err != nil {
|
||||
continue
|
||||
log.Fatal().Err(err).Bytes("key", key).Msg("failed to get userbytes")
|
||||
// continue
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(usrbytes, &usr); err != nil {
|
||||
log.Error().Err(err).Msg("failed to unmarshal")
|
||||
continue
|
||||
if err := json.Unmarshal(usrbytes, &userStruct); err != nil {
|
||||
log.Fatal().Err(err).Msg("failed to unmarshal")
|
||||
// continue
|
||||
}
|
||||
|
||||
if usr.Username == user {
|
||||
return usr, nil
|
||||
if userStruct.Username == targetUser {
|
||||
return errors.New("done")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if err.Error() == "done" {
|
||||
return userStruct, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("user does not exist: " + user)
|
||||
|
||||
return &RegisteredUser{}, errors.New("targetUser does not exist: " + targetUser)
|
||||
}
|
||||
|
||||
// KeyExists iterates through all RegisteredUser instances in the database and returns the corresponding RegisteredUser and true if a public key is present.
|
||||
|
|
155
auth/bans.go
155
auth/bans.go
|
@ -33,26 +33,40 @@ type BanList struct {
|
|||
}
|
||||
|
||||
func init() {
|
||||
banCache = cache.New(2*time.Hour, 10*time.Minute)
|
||||
banCache = cache.New(2*time.Hour, 25*time.Minute)
|
||||
}
|
||||
|
||||
func parseBanQuery(s string) (string, BanType, error) {
|
||||
query := strings.TrimSpace(s)
|
||||
request := strings.Split(query, "=")
|
||||
bantype, err := StringToBanType(request[1])
|
||||
if err != nil {
|
||||
return "", 100, errors.New("unknown key")
|
||||
log.Debug().Err(err).Str("caller", s).
|
||||
Str("request[0]", request[0]).
|
||||
Str("request[1]", request[1]).Msg("unknown key")
|
||||
}
|
||||
return request[1], bantype, nil
|
||||
}
|
||||
|
||||
// BanQuery is used to ingest strings that contain various types of bans seperated by an equals sign.
|
||||
// e.g: /ban name=douchebag
|
||||
func (users *UserDB) BanQuery(query string) (err error) {
|
||||
request := strings.Split(query, "=")
|
||||
switch strings.ToLower(request[0]) {
|
||||
case "client":
|
||||
err = users.BanOther(request[1], Client)
|
||||
case "name":
|
||||
err = users.BanOther(request[1], Name)
|
||||
case "ip":
|
||||
err = users.BanOther(request[1], IP)
|
||||
case "key":
|
||||
err = users.BanOther(request[1], IP)
|
||||
default:
|
||||
return errors.New("unknown key")
|
||||
target, bantype, err := parseBanQuery(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
return users.BanOther(target, bantype, true)
|
||||
}
|
||||
|
||||
// UnBanQuery is used to ingest strings that contain various types of bans seperated by an equals sign.
|
||||
// e.g: /unban name=knucklehead
|
||||
func (users *UserDB) UnBanQuery(query string) (err error) {
|
||||
target, bantype, err := parseBanQuery(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return users.BanOther(target, bantype, false)
|
||||
}
|
||||
|
||||
// Banned returns the current banned items list.
|
||||
|
@ -84,6 +98,8 @@ func (users *UserDB) banned(bantype BanType) []string {
|
|||
|
||||
// CheckBans checks our ban list for the instance of any of the given elements.
|
||||
func (users *UserDB) CheckBans(user string, addr net.Addr, key ssh.PublicKey, s string) error {
|
||||
log.Debug().Caller().Msg("checkbans")
|
||||
|
||||
var (
|
||||
userRet = errors.New("user is banned")
|
||||
addrRet = errors.New("ip is banned")
|
||||
|
@ -96,52 +112,68 @@ func (users *UserDB) CheckBans(user string, addr net.Addr, key ssh.PublicKey, s
|
|||
return
|
||||
}
|
||||
|
||||
clientAddr, _, err := net.SplitHostPort(addr.String())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// check cache before we check the database
|
||||
switch {
|
||||
case present(user):
|
||||
return userRet
|
||||
case present(addr.String()):
|
||||
case present(clientAddr):
|
||||
return addrRet
|
||||
case key != nil:
|
||||
case present(s):
|
||||
return clientRet
|
||||
default:
|
||||
if key == nil {
|
||||
break
|
||||
}
|
||||
if present(string(key.Marshal())) {
|
||||
return keyRet
|
||||
}
|
||||
case present(s):
|
||||
return clientRet
|
||||
}
|
||||
|
||||
// check database, if found add to cache
|
||||
if users.CheckBanOther(addr.String(), IP) {
|
||||
banCache.Add(addr.String(), true, cache.DefaultExpiration)
|
||||
return addrRet
|
||||
}
|
||||
if users.CheckBanOther(s, Client) {
|
||||
banCache.Add(s, true, cache.DefaultExpiration)
|
||||
return clientRet
|
||||
}
|
||||
if users.CheckBanOther(user, Name) {
|
||||
banCache.Add(user, true, cache.DefaultExpiration)
|
||||
return userRet
|
||||
var toCheck = make(map[string]BanType)
|
||||
toCheck[addr.String()] = IP
|
||||
toCheck[s] = Client
|
||||
toCheck[user] = Name
|
||||
|
||||
for item, bt := range toCheck {
|
||||
if users.CheckBanOther(item, bt) {
|
||||
if err := banCache.Add(addr.String(), true, cache.DefaultExpiration); err != nil {
|
||||
log.Debug().Caller().Err(err).Msg("ban cache failure")
|
||||
}
|
||||
switch bt {
|
||||
case IP:
|
||||
return addrRet
|
||||
case Client:
|
||||
return clientRet
|
||||
case Name:
|
||||
return userRet
|
||||
default:
|
||||
log.Warn().Caller().Msg("unhandled ban")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if key == nil {
|
||||
return nil
|
||||
}
|
||||
if users.CheckBanOther(string(key.Marshal()), Key) {
|
||||
banCache.Add(string(key.Marshal()), true, cache.DefaultExpiration)
|
||||
if err := banCache.Add(string(key.Marshal()), true, cache.DefaultExpiration); err != nil {
|
||||
log.Debug().Caller().Err(err).Msg("ban cache failure")
|
||||
}
|
||||
return keyRet
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BanOther creates a ban on various types of client attributes.
|
||||
func (users *UserDB) BanOther(target string, bantype BanType) error {
|
||||
// BanOther creates a ban on various types of client attributes, or unbans them if banunban is false.
|
||||
func (users *UserDB) BanOther(target string, bantype BanType, banunban bool) error {
|
||||
bans := uint32ToBytes(uint32(bantype))
|
||||
bad := &BanList{Items: []string{}}
|
||||
|
||||
defer func() {
|
||||
print("yeet")
|
||||
}()
|
||||
|
||||
if users.DB.Has(bans) {
|
||||
badBytes, err := users.DB.Get(bans)
|
||||
if err != nil {
|
||||
|
@ -158,13 +190,43 @@ func (users *UserDB) BanOther(target string, bantype BanType) error {
|
|||
}
|
||||
}
|
||||
|
||||
bad.Items = append(bad.Items, target)
|
||||
newbads, err := json.Marshal(bad)
|
||||
var newbans []string
|
||||
|
||||
if banunban {
|
||||
bad.Items = append(bad.Items, target)
|
||||
} else {
|
||||
for _, item := range bad.Items {
|
||||
if item != target {
|
||||
newbans = append(bad.Items, item)
|
||||
}
|
||||
}
|
||||
if len(bad.Items) == len(newbans) {
|
||||
return errors.New("ban does not exist")
|
||||
}
|
||||
bad.Items = newbans
|
||||
}
|
||||
|
||||
newitems, err := json.Marshal(bad)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return users.DB.Put(bans, newitems)
|
||||
}
|
||||
|
||||
return users.DB.Put(bans, newbads)
|
||||
// StringToBanType takes a string and returns the corresponding BanType if found.
|
||||
func StringToBanType(banstr string) (BanType, error) {
|
||||
switch banstr {
|
||||
case "name":
|
||||
return Name, nil
|
||||
case "ip":
|
||||
return IP, nil
|
||||
case "client":
|
||||
return Client, nil
|
||||
case "key":
|
||||
return Key, nil
|
||||
default:
|
||||
return 100, errors.New("ban type not found")
|
||||
}
|
||||
}
|
||||
|
||||
// CheckBanOther checks a given target of bantype against our banned items.
|
||||
|
@ -215,3 +277,16 @@ func (users *UserDB) Ban(username string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnBan unbans a user from accessing their account and resets their privileges.
|
||||
// If they were previously opped you will need to re-op them.
|
||||
func (users *UserDB) UnBan(username string) error {
|
||||
user, err := users.GetUser(username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := users.SetPrivLevel(user, LevelBanned); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -79,8 +79,8 @@ func (c Commands) Run(room *Room, msg message.CommandMsg) error {
|
|||
// Help will return collated help text as one string.
|
||||
func (c Commands) Help(showOp bool) string {
|
||||
// Filter by op
|
||||
op := []*Command{}
|
||||
normal := []*Command{}
|
||||
var op []*Command
|
||||
var normal []*Command
|
||||
for _, cmd := range c {
|
||||
if cmd.Op {
|
||||
op = append(op, cmd)
|
||||
|
|
|
@ -201,7 +201,7 @@ var DefaultTheme *Theme
|
|||
var MonoTheme *Theme
|
||||
|
||||
func allColors256() *Palette {
|
||||
colors := []uint8{}
|
||||
var colors []uint8
|
||||
var i uint8
|
||||
for i = 0; i < 255; i++ {
|
||||
colors = append(colors, i)
|
||||
|
@ -210,7 +210,7 @@ func allColors256() *Palette {
|
|||
}
|
||||
|
||||
func readableColors256() *Palette {
|
||||
colors := []uint8{}
|
||||
var colors []uint8
|
||||
var i uint8
|
||||
for i = 0; i < 255; i++ {
|
||||
if _, ok := badColors[i]; ok {
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"git.tcp.direct/kayos/sh3lly/set"
|
||||
)
|
||||
|
||||
const historyLen = 20
|
||||
const roomBuffer = 10
|
||||
|
||||
var ExternalAnnouncements chan *message.AnnounceMsg
|
||||
|
@ -192,6 +191,7 @@ func (r *Room) Join(u *message.User) (*Member, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
// TODO: Remove user ID from sets, probably referring to a prior user.
|
||||
s := fmt.Sprintf("%s joined. (Connected: %d)", u.Name(), r.Members.Len())
|
||||
r.Send(message.NewAnnounceMsg(s))
|
||||
|
|
43
host/host.go
43
host/host.go
|
@ -60,8 +60,8 @@ type Host struct {
|
|||
|
||||
// NewHost creates a Host on top of an existing listener.
|
||||
func NewHost(listener *sshd.SSHListener, auth *auth.UserDB) *Host {
|
||||
|
||||
room := chat.NewRoom()
|
||||
|
||||
h := &Host{
|
||||
Room: room,
|
||||
listener: listener,
|
||||
|
@ -149,6 +149,7 @@ func (h *Host) Connect(term *sshd.Terminal) {
|
|||
member, err := h.Join(user)
|
||||
if err != nil {
|
||||
id.SetName(fmt.Sprintf("%s%d", id.Name(), count))
|
||||
|
||||
member, err = h.Join(user)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -355,6 +356,7 @@ func (h *Host) GetUser(name string) (*message.User, bool) {
|
|||
|
||||
// InitCommands adds host-specific commands to a Commands container. These will
|
||||
// override any existing commands.
|
||||
//goland:noinspection GoUnhandledErrorResult
|
||||
func (h *Host) InitCommands(c *chat.Commands) {
|
||||
sendPM := func(room *chat.Room, msg string, from *message.User, target *message.User) error {
|
||||
m := message.NewPrivateMsg(msg, from, target)
|
||||
|
@ -537,6 +539,45 @@ func (h *Host) InitCommands(c *chat.Commands) {
|
|||
},
|
||||
})
|
||||
|
||||
c.Add(chat.Command{
|
||||
Op: true,
|
||||
Prefix: "/unban",
|
||||
PrefixHelp: "QUERY",
|
||||
Help: "Unban from the server. QUERY needs to match your the query used when /ban was used.",
|
||||
Handler: func(room *chat.Room, msg message.CommandMsg) error {
|
||||
if !room.IsOp(msg.From()) {
|
||||
return errors.New("must be op")
|
||||
}
|
||||
|
||||
args := msg.Args()
|
||||
if len(args) == 0 {
|
||||
return errors.New("must specify user")
|
||||
}
|
||||
|
||||
query := args[0]
|
||||
target, ok := h.GetUser(query)
|
||||
if !ok {
|
||||
query = strings.Join(args, " ")
|
||||
if strings.Contains(query, "=") {
|
||||
return h.auth.UnBanQuery(query)
|
||||
}
|
||||
return errors.New("user not found")
|
||||
}
|
||||
|
||||
id := target.Identifier.ID()
|
||||
if err := h.auth.UnBan(id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
body := fmt.Sprintf("%s was unbanned by %s.", target.Name(), msg.From().Name())
|
||||
room.Send(message.NewAnnounceMsg(body))
|
||||
target.Close()
|
||||
|
||||
log.Debug().Msgf("UnbanList: \n-> %s", id)
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
c.Add(chat.Command{
|
||||
Op: true,
|
||||
Prefix: "/banned",
|
||||
|
|
|
@ -35,13 +35,6 @@ func (item StringItem) Value() interface{} {
|
|||
return true
|
||||
}
|
||||
|
||||
func Expire(item Item, d time.Duration) Item {
|
||||
return &ExpiringItem{
|
||||
Item: item,
|
||||
Time: time.Now().Add(d),
|
||||
}
|
||||
}
|
||||
|
||||
type ExpiringItem struct {
|
||||
Item
|
||||
time.Time
|
||||
|
|
|
@ -197,7 +197,7 @@ func (s *Set) Each(fn IterFunc) error {
|
|||
// ListPrefix returns a list of items with a prefix, normalized.
|
||||
// TODO: Add trie for efficient prefix lookup
|
||||
func (s *Set) ListPrefix(prefix string) []Item {
|
||||
r := []Item{}
|
||||
var r []Item
|
||||
prefix = s.normalize(prefix)
|
||||
|
||||
s.Each(func(key string, item Item) error {
|
||||
|
|
Loading…
Reference in New Issue