1
0
Fork 0
forked from External/ergo

Centralise all command handlers in handlers.go

This commit is contained in:
Daniel Oaks 2018-02-03 19:28:02 +10:00
parent 29266ce80f
commit 47d2ce351c
16 changed files with 2629 additions and 2661 deletions

View file

@ -7,18 +7,11 @@ import (
"errors"
"fmt"
"net"
"sort"
"sync"
"time"
"strings"
"encoding/json"
"github.com/goshuirc/irc-go/ircfmt"
"github.com/goshuirc/irc-go/ircmsg"
"github.com/oragono/oragono/irc/custime"
"github.com/oragono/oragono/irc/sno"
"github.com/tidwall/buntdb"
)
@ -216,270 +209,6 @@ func (dm *DLineManager) CheckIP(addr net.IP) (isBanned bool, info *IPBanInfo) {
return false, nil
}
// DLINE [ANDKILL] [MYSELF] [duration] <ip>/<net> [ON <server>] [reason [| oper reason]]
// DLINE LIST
func dlineHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// check oper permissions
if !client.class.Capabilities["oper:local_ban"] {
client.Send(nil, server.name, ERR_NOPRIVS, client.nick, msg.Command, client.t("Insufficient oper privs"))
return false
}
currentArg := 0
// if they say LIST, we just list the current dlines
if len(msg.Params) == currentArg+1 && strings.ToLower(msg.Params[currentArg]) == "list" {
bans := server.dlines.AllBans()
if len(bans) == 0 {
client.Notice(client.t("No DLINEs have been set!"))
}
for key, info := range bans {
client.Notice(fmt.Sprintf(client.t("Ban - %[1]s - added by %[2]s - %[3]s"), key, info.OperName, info.BanMessage("%s")))
}
return false
}
// when setting a ban, if they say "ANDKILL" we should also kill all users who match it
var andKill bool
if len(msg.Params) > currentArg+1 && strings.ToLower(msg.Params[currentArg]) == "andkill" {
andKill = true
currentArg++
}
// when setting a ban that covers the oper's current connection, we require them to say
// "DLINE MYSELF" so that we're sure they really mean it.
var dlineMyself bool
if len(msg.Params) > currentArg+1 && strings.ToLower(msg.Params[currentArg]) == "myself" {
dlineMyself = true
currentArg++
}
// duration
duration, err := custime.ParseDuration(msg.Params[currentArg])
durationIsUsed := err == nil
if durationIsUsed {
currentArg++
}
// get host
if len(msg.Params) < currentArg+1 {
client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, msg.Command, client.t("Not enough parameters"))
return false
}
hostString := msg.Params[currentArg]
currentArg++
// check host
var hostAddr net.IP
var hostNet *net.IPNet
_, hostNet, err = net.ParseCIDR(hostString)
if err != nil {
hostAddr = net.ParseIP(hostString)
}
if hostAddr == nil && hostNet == nil {
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, msg.Command, client.t("Could not parse IP address or CIDR network"))
return false
}
if hostNet == nil {
hostString = hostAddr.String()
if !dlineMyself && hostAddr.Equal(client.IP()) {
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, msg.Command, client.t("This ban matches you. To DLINE yourself, you must use the command: /DLINE MYSELF <arguments>"))
return false
}
} else {
hostString = hostNet.String()
if !dlineMyself && hostNet.Contains(client.IP()) {
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, msg.Command, client.t("This ban matches you. To DLINE yourself, you must use the command: /DLINE MYSELF <arguments>"))
return false
}
}
// check remote
if len(msg.Params) > currentArg && msg.Params[currentArg] == "ON" {
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, msg.Command, client.t("Remote servers not yet supported"))
return false
}
// get comment(s)
reason := "No reason given"
operReason := "No reason given"
if len(msg.Params) > currentArg {
tempReason := strings.TrimSpace(msg.Params[currentArg])
if len(tempReason) > 0 && tempReason != "|" {
tempReasons := strings.SplitN(tempReason, "|", 2)
if tempReasons[0] != "" {
reason = tempReasons[0]
}
if len(tempReasons) > 1 && tempReasons[1] != "" {
operReason = tempReasons[1]
} else {
operReason = reason
}
}
}
operName := client.operName
if operName == "" {
operName = server.name
}
// assemble ban info
var banTime *IPRestrictTime
if durationIsUsed {
banTime = &IPRestrictTime{
Duration: duration,
Expires: time.Now().Add(duration),
}
}
info := IPBanInfo{
Reason: reason,
OperReason: operReason,
OperName: operName,
Time: banTime,
}
// save in datastore
err = server.store.Update(func(tx *buntdb.Tx) error {
dlineKey := fmt.Sprintf(keyDlineEntry, hostString)
// assemble json from ban info
b, err := json.Marshal(info)
if err != nil {
return err
}
tx.Set(dlineKey, string(b), nil)
return nil
})
if err != nil {
client.Notice(fmt.Sprintf(client.t("Could not successfully save new D-LINE: %s"), err.Error()))
return false
}
if hostNet == nil {
server.dlines.AddIP(hostAddr, banTime, reason, operReason, operName)
} else {
server.dlines.AddNetwork(*hostNet, banTime, reason, operReason, operName)
}
var snoDescription string
if durationIsUsed {
client.Notice(fmt.Sprintf(client.t("Added temporary (%[1]s) D-Line for %[2]s"), duration.String(), hostString))
snoDescription = fmt.Sprintf(ircfmt.Unescape("%s [%s]$r added temporary (%s) D-Line for %s"), client.nick, operName, duration.String(), hostString)
} else {
client.Notice(fmt.Sprintf(client.t("Added D-Line for %s"), hostString))
snoDescription = fmt.Sprintf(ircfmt.Unescape("%s [%s]$r added D-Line for %s"), client.nick, operName, hostString)
}
server.snomasks.Send(sno.LocalXline, snoDescription)
var killClient bool
if andKill {
var clientsToKill []*Client
var killedClientNicks []string
var toKill bool
for _, mcl := range server.clients.AllClients() {
if hostNet == nil {
toKill = hostAddr.Equal(mcl.IP())
} else {
toKill = hostNet.Contains(mcl.IP())
}
if toKill {
clientsToKill = append(clientsToKill, mcl)
killedClientNicks = append(killedClientNicks, mcl.nick)
}
}
for _, mcl := range clientsToKill {
mcl.exitedSnomaskSent = true
mcl.Quit(fmt.Sprintf(mcl.t("You have been banned from this server (%s)"), reason))
if mcl == client {
killClient = true
} else {
// if mcl == client, we kill them below
mcl.destroy(false)
}
}
// send snomask
sort.Strings(killedClientNicks)
server.snomasks.Send(sno.LocalKills, fmt.Sprintf(ircfmt.Unescape("%s [%s] killed %d clients with a DLINE $c[grey][$r%s$c[grey]]"), client.nick, operName, len(killedClientNicks), strings.Join(killedClientNicks, ", ")))
}
return killClient
}
func unDLineHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// check oper permissions
if !client.class.Capabilities["oper:local_unban"] {
client.Send(nil, server.name, ERR_NOPRIVS, client.nick, msg.Command, client.t("Insufficient oper privs"))
return false
}
// get host
hostString := msg.Params[0]
// check host
var hostAddr net.IP
var hostNet *net.IPNet
_, hostNet, err := net.ParseCIDR(hostString)
if err != nil {
hostAddr = net.ParseIP(hostString)
}
if hostAddr == nil && hostNet == nil {
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, msg.Command, client.t("Could not parse IP address or CIDR network"))
return false
}
if hostNet == nil {
hostString = hostAddr.String()
} else {
hostString = hostNet.String()
}
// save in datastore
err = server.store.Update(func(tx *buntdb.Tx) error {
dlineKey := fmt.Sprintf(keyDlineEntry, hostString)
// check if it exists or not
val, err := tx.Get(dlineKey)
if val == "" {
return errNoExistingBan
} else if err != nil {
return err
}
tx.Delete(dlineKey)
return nil
})
if err != nil {
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, msg.Command, fmt.Sprintf(client.t("Could not remove ban [%s]"), err.Error()))
return false
}
if hostNet == nil {
server.dlines.RemoveIP(hostAddr)
} else {
server.dlines.RemoveNetwork(*hostNet)
}
client.Notice(fmt.Sprintf(client.t("Removed D-Line for %s"), hostString))
server.snomasks.Send(sno.LocalXline, fmt.Sprintf(ircfmt.Unescape("%s$r removed D-Line for %s"), client.nick, hostString))
return false
}
func (s *Server) loadDLines() {
s.dlines = NewDLineManager()