Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better bans #230

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,13 +549,15 @@ func banCMD(line string, u *User) {
}
var victim *User
var ok bool
bannedByDevbot := false
banner := u.Name
banReason := "" // Initial ban reason is an empty string

if split[0] == "devbot" {
u.room.broadcast(Devbot, "Do you really think you can ban me, puny human?")
victim = u // mwahahahaha - devbot
banner = Devbot
bannedByDevbot = true
} else if !auth(u) {
u.room.broadcast(Devbot, "Not authorized")
return
Expand All @@ -564,24 +566,23 @@ func banCMD(line string, u *User) {
return
}

if len(split) > 1 {
dur, err := time.ParseDuration(split[len(split)-1])
if err != nil {
split[len(split)-1] = "" // there's no duration so don't trim anything from the reason
if len(split) > 1 || bannedByDevbot {
dur, err := time.ParseDuration("1m")
if !bannedByDevbot {
dur, err = time.ParseDuration(split[len(split)-1])
if err != nil {
split[len(split)-1] = "" // there's no duration so don't trim anything from the reason
}
}
if len(split) > 2 {
banReason = strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(line, split[0]), split[len(split)-1]))
}
if err == nil { // there was a duration
victim.ban(victim.Name + " has been banned by " + banner + " for " + dur.String() + " " + banReason)
go func(id string) {
time.Sleep(dur)
unbanIDorIP(id)
}(victim.id) // evaluate id now, call unban with that value later
victim.banTemporarily(victim.Name+" has been banned by "+banner+" for "+dur.String()+" "+banReason, dur)
return
}
}
victim.ban(victim.Name + " has been banned by " + banner + " " + banReason)
victim.banForever(victim.Name + " has been banned by " + banner + " " + banReason)
}

func kickCMD(line string, u *User) {
Expand Down
2 changes: 1 addition & 1 deletion devzat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func performTestBan(t *testing.T, id0 string, id1 string, id2 string, id3 string
r.users[1].id = id1
r.users[2].id = id2
r.users[3].id = id3
r.users[0].ban("Tim is a meany")
r.users[0].banForever("Tim is a meany")
if len(r.users) != 4-usersBanned {
t.Log("Error,", usersBanned, "users should have been kicked but", 4-len(r.users), "have been kicked.")
t.Fail()
Expand Down
58 changes: 42 additions & 16 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ const (
)

type Ban struct {
quackduck marked this conversation as resolved.
Show resolved Hide resolved
Addr string
ID string
Addr string
ID string
UseTime bool
UnbanTime time.Time
}

type Room struct {
Expand Down Expand Up @@ -410,13 +412,28 @@ func newUser(s ssh.Session) *User {

Log.Println("Connected " + u.Name + " [" + u.id + "]")

if bansContains(Bans, u.addr, u.id) || TORIPs[u.addr] {
Log.Println("Rejected " + u.Name + " [" + host + "] (banned)")
u.writeln(Devbot, "**You are banned**. If you feel this was a mistake, please reach out to the server admin. Include the following information: [ID "+u.id+"]")
if TORIPs[u.addr] {
Log.Println("Rejected " + u.Name + " [" + host + "] (Tor IP)")
u.writeln(Devbot, "**You are not allowed to join as you are using a Tor IP**")
s.Close()
return nil
}

banInfo := getBan(Bans, u.addr, u.id)
if banInfo != nil {
if banInfo.UseTime && banInfo.UnbanTime.Before(time.Now()) {
unbanIDorIP(banInfo.ID)
} else {
Log.Println("Rejected " + u.Name + " [" + host + "] (banned)")
u.writeln(Devbot, "**You are banned**. If you feel this was a mistake, please reach out to the server admin. Include the following information: [ID "+u.id+"]")
if banInfo.UseTime {
u.writeln(Devbot, "You will be unbaned on "+banInfo.UnbanTime.Format(time.RFC3339))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use a duration here instead of an absolute time

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like that:

devbot: You will be unbaned in 41 days, 15 hours, 56 minutes, and 8 seconds.

or like that:

devbot: You will be unbaned in 13 seconds.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's quite verbose. Which could be fine. But we do also have a pretty duration printer here: https://github.com/Arkaeriit/devzat/blob/c98c58e03fd3703f5d500424e886e5f06fe0768d/util.go#L420

what do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ho right, I didn't remember this function. printPrettyDuration is not very suitable for duration longer than a day, so not great for bans.
But maybe we can merge printPrettyDuration and formatDuration to prevent code duplication.
I'll make a proposition of it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with full unit names. So it changes the way the relative time display is. If you don't like it, I will go back to units symbols.
image

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean. maybe it's better to keep it short but add ability to display days using the unit 'd'

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted back to using 1 letter units with no space between the numeric value and the unit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like that now:
image

}
s.Close()
return nil
}
}

if Config.Private {
_, isOnAllowlist := Config.Allowlist[u.id]
_, isAdmin := Config.Admins[u.id]
Expand All @@ -435,7 +452,7 @@ func newUser(s ssh.Session) *User {
IDandIPsToTimesJoinedInMin[u.id]--
})
if IDandIPsToTimesJoinedInMin[u.addr] > 6 || IDandIPsToTimesJoinedInMin[u.id] > 6 {
u.ban("")
u.banForever("")
MainRoom.broadcast(Devbot, u.Name+" has been banned automatically. ID: "+u.id)
return nil
}
Expand Down Expand Up @@ -586,14 +603,23 @@ func (u *User) close(msg string) {
u.room.broadcast("", Red.Paint(" <-- ")+msg)
}

func (u *User) ban(banner string) {
func (u *User) banForever(banMsg string) {
u.ban(banMsg, false, time.Now())
}

func (u *User) banTemporarily(banMsg string, banDuration time.Duration) {
unbanTime := time.Now().Add(banDuration)
u.ban(banMsg, true, unbanTime)
}

func (u *User) ban(banMsg string, useTime bool, unbanTime time.Time) {
if u.addr == "" && u.id == "" {
return
}
Bans = append(Bans, Ban{u.addr, u.id})
Bans = append(Bans, Ban{u.addr, u.id, useTime, unbanTime})
saveBans()
uid := u.id
u.close(banner)
u.close(banMsg)
for i := range Rooms { // close all users that have this id (including this user)
for j := 0; j < len(Rooms[i].users); j++ {
if Rooms[i].users[j].id == uid {
Expand Down Expand Up @@ -875,9 +901,9 @@ func (u *User) repl() {
u.room.broadcast(Devbot, u.Name+", stop spamming or you could get banned.")
}
if AntispamMessages[u.id] >= 50 {
if !bansContains(Bans, u.addr, u.id) {
Bans = append(Bans, Ban{u.addr, u.id})
saveBans()
if getBan(Bans, u.addr, u.id) == nil {
oneMonth, _ := time.ParseDuration("730h")
u.banTemporarily("", oneMonth)
}
u.writeln(Devbot, "anti-spam triggered")
u.close(Red.Paint(u.Name + " has been banned for spamming"))
Expand Down Expand Up @@ -911,12 +937,12 @@ func calculateLinesTaken(u *User, s string, width int) {
//return lines
}

// bansContains reports if the addr or id is found in the bans list
func bansContains(b []Ban, addr string, id string) bool {
// getBan returns the ban element it it exist or nil otherwise
func getBan(b []Ban, addr string, id string) *Ban {
for i := 0; i < len(b); i++ {
if b[i].Addr == addr || b[i].ID == id {
return true
return &b[i]
}
}
return false
return nil
}
Loading