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 4 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
59 changes: 43 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,29 @@ 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 {
when := time.Until(banInfo.UnbanTime)
u.writeln(Devbot, "You will be unbaned in "+formatDuration(when)+".")
}
s.Close()
return nil
}
}

if Config.Private {
_, isOnAllowlist := Config.Allowlist[u.id]
_, isAdmin := Config.Admins[u.id]
Expand All @@ -435,7 +453,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 +604,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 +902,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 +938,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
}
25 changes: 25 additions & 0 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,3 +487,28 @@ func genKey() (ed25519.PrivateKey, ssh.PublicKey, error) {
}
return priv, sshPubKey, nil
}

func formatDuration(d time.Duration) string {
seconds := int(d.Seconds())
minutes := seconds / 60
seconds = seconds % 60
ret := fmt.Sprintf("%v seconds", seconds)
if minutes == 0 {
return ret
}

hours := minutes / 60
minutes = minutes % 60
ret = fmt.Sprintf("%v minutes, and %v", minutes, ret)
if hours == 0 {
return ret
}

days := hours / 24
hours = hours % 24
ret = fmt.Sprintf("%v hours, %v", hours, ret)
if days == 0 {
return ret
}
return fmt.Sprintf("%v days, %v", days, ret)
}
Loading