Implement ban by nick regexp (in MUCs)

* Move ban action to separate function
* Implement ban by nick regexp
This commit is contained in:
eleksir
2023-08-20 10:55:02 -07:00
parent 939ceaebfb
commit 39ac09f82a
3 changed files with 133 additions and 93 deletions

220
buny.go
View File

@@ -11,7 +11,7 @@ import (
log "github.com/sirupsen/logrus"
)
func buny(v xmpp.Presence) error { //nolint:gocognit
func buny(v xmpp.Presence) error { //nolint:gocognit,gocyclo
var err error
// Если у presence-а есть JID и presence из одной из комнат, в которой мы есть и если его домен в чёрном
@@ -54,6 +54,12 @@ func buny(v xmpp.Presence) error { //nolint:gocognit
}
evilJid := strings.SplitN(v.JID, "/", 2)[0]
evilNick := ""
evilNicks := strings.SplitN(v.From, "/", 2)
// Давайте-ка похэндлим нонсенс - когда у нас в строке нету разделителя
if len(evilNicks) > 1 {
evilNick = evilNicks[1]
}
// Обрабатываем правила чёрного списка
for _, cRoom := range roomsConnected {
@@ -71,54 +77,34 @@ func buny(v xmpp.Presence) error { //nolint:gocognit
}
if re.MatchString(evilJid) {
log.Infof("Hammer falls on %s", v.JID)
if config.Jabber.BanPhrasesEnable {
phrase := randomPhrase(config.Jabber.BanPhrases)
if _, err := talk.Send(
xmpp.Chat{ //nolint:exhaustruct
Remote: room,
Text: phrase,
Type: v.Type,
},
); err != nil {
err := fmt.Errorf("unable to send phrase to room %s: %w", room, err)
gTomb.Kill(err)
// Здесь возвращаем nil, т.к. за нас ошибку залоггирует код выше
return nil
}
}
// https://xmpp.org/extensions/xep-0045.html#ban баним вот таким сообщением
ban := "<item affiliation='outcast' jid='" + evilJid + "'>"
if bEntry.ReasonEnable {
var t = time.Now()
ban += fmt.Sprintf(
"<reason>autoban at %04d.%02d.%02d %02d:%02d:%02d</reason>",
t.Year(),
t.Month(),
t.Day(),
t.Hour(),
t.Minute(),
t.Second(),
if id, err := squash(room, evilJid, bEntry.ReasonEnable, v.Type); err != nil {
err := fmt.Errorf(
"unable to ban user: id=%s, err=%w",
id,
err,
)
} else {
ban += "<reason />"
gTomb.Kill(err)
continue
}
ban += "</item>"
return err
}
}
if id, err := talk.RawInformationQuery(
talk.JID(),
room,
"ban1",
xmpp.IQTypeSet,
"http://jabber.org/protocol/muc#admin",
ban,
); err != nil {
for _, nickRegexp := range bEntry.NickRe {
re, err := regexp.Compile(nickRegexp)
if err != nil {
log.Errorf("Incorrect regexp in blacklist: %s, skipping", nickRegexp)
continue
}
if re.MatchString(evilNick) {
// Баним именно jid
if id, err := squash(room, evilJid, bEntry.ReasonEnable, v.Type); err != nil {
err := fmt.Errorf(
"unable to ban user: id=%s, err=%w",
id,
@@ -149,54 +135,7 @@ func buny(v xmpp.Presence) error { //nolint:gocognit
}
if re.MatchString(evilJid) {
log.Infof("Hammer falls on %s", v.JID)
if config.Jabber.BanPhrasesEnable {
phrase := randomPhrase(config.Jabber.BanPhrases)
if _, err := talk.Send(
xmpp.Chat{ //nolint:exhaustruct
Remote: room,
Text: phrase,
Type: v.Type,
},
); err != nil {
err := fmt.Errorf("unable to send phrase to room %s: %w", room, err)
gTomb.Kill(err)
// Здесь возвращаем nil, т.к. за нас ошибку залоггирует код выше
return nil
}
}
// https://xmpp.org/extensions/xep-0045.html#ban баним вот таким сообщением
ban := "<item affiliation='outcast' jid='" + evilJid + "'>"
if bEntry.ReasonEnable {
var t = time.Now()
ban += fmt.Sprintf(
"<reason>autoban at %04d.%02d.%02d %02d:%02d:%02d</reason>",
t.Year(),
t.Month(),
t.Day(),
t.Hour(),
t.Minute(),
t.Second(),
)
} else {
ban += "<reason />"
}
ban += "</item>"
if id, err := talk.RawInformationQuery(
talk.JID(),
room,
"ban1",
xmpp.IQTypeSet,
"http://jabber.org/protocol/muc#admin",
ban,
); err != nil {
if id, err := squash(room, evilJid, bEntry.ReasonEnable, v.Type); err != nil {
err := fmt.Errorf(
"unable to ban user: id=%s, err=%w",
id,
@@ -212,6 +151,35 @@ func buny(v xmpp.Presence) error { //nolint:gocognit
}
}
if bEntry.RoomName == room {
for _, nickRegexp := range bEntry.NickRe {
re, err := regexp.Compile(nickRegexp)
if err != nil {
log.Errorf("Incorrect regexp in blacklist: %s, skipping", nickRegexp)
continue
}
if re.MatchString(evilNick) {
// Баним именно jid
if id, err := squash(room, evilJid, bEntry.ReasonEnable, v.Type); err != nil {
err := fmt.Errorf(
"unable to ban user: id=%s, err=%w",
id,
err,
)
gTomb.Kill(err)
continue
}
return err
}
}
}
continue
}
}
@@ -222,4 +190,70 @@ func buny(v xmpp.Presence) error { //nolint:gocognit
return err
}
// squash банит указанный jid в указанной комнате.
// reasonEnable указывает, надо ли писать дату автобана в банлисте в поле reason (это единственная причина, в которую
// умеет бот).
func squash(room, jid string, reasonEnable bool, vType string) (string, error) {
var (
id string
err error
)
log.Infof("Hammer falls on %s", jid)
if config.Jabber.BanPhrasesEnable {
phrase := randomPhrase(config.Jabber.BanPhrases)
if _, err = talk.Send(
xmpp.Chat{ //nolint:exhaustruct
Remote: room,
Text: phrase,
Type: vType,
},
); err != nil {
err = fmt.Errorf("unable to send phrase to room %s: %w", room, err)
// Здесь возвращаем nil, т.к. за нас ошибку залоггирует код выше
return id, err
}
}
// https://xmpp.org/extensions/xep-0045.html#ban баним вот таким сообщением
ban := "<item affiliation='outcast' jid='" + jid + "'>"
if reasonEnable {
var t = time.Now()
ban += fmt.Sprintf(
"<reason>autoban at %04d.%02d.%02d %02d:%02d:%02d</reason>",
t.Year(),
t.Month(),
t.Day(),
t.Hour(),
t.Minute(),
t.Second(),
)
} else {
ban += "<reason />"
}
ban += "</item>"
if id, err = talk.RawInformationQuery(
talk.JID(),
room,
"ban1",
xmpp.IQTypeSet,
"http://jabber.org/protocol/muc#admin",
ban,
); err != nil {
err = fmt.Errorf(
"unable to ban user: id=%s, err=%w",
id,
err,
)
}
return id, err
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -12,6 +12,11 @@
"^[cC]hris(topher)?@",
"^(his|her)_cat@sweet.home/.*$",
"^(her|his)_dog@.*\\.street/.*"
],
# Список регулярок nick-ов злодеев
"nick_re": [
"^(Annoying_)?[F|f]ly$",
"^Buzzing_Wasp$"
]
}
]

View File

@@ -53,6 +53,7 @@ type myBlackList struct {
RoomName string `json:"room_name,omitempty"`
ReasonEnable bool `json:"reason_enable,omitempty"`
JidRe []string `json:"jid_re,omitempty"`
NickRe []string `json:"nick_re,omitempty"`
} `json:"blacklist,omitempty"`
}