diff --git a/Design.txt b/Design.txt index ebc88c0..4bbed4f 100644 --- a/Design.txt +++ b/Design.txt @@ -61,8 +61,3 @@ Cуществует несколько видов пинга: ------------------------------------------------------------------------------------------------------------------------ Причину бана можно только включить или выключить в конфиге на per-chat основе. Фразу настроить невозможно. (не хотелось реализовывать парсинг темплейтов, как минимум даты-времени) - - -Парсинг списка и бан здобеев на моменте входа в комнату ------------------------------------------------------------------------------------------------------------------------- -Бан реализован только для real jid-ов, но не для nick-ов. Пока непонятно, как изящно хранить и то и другое. diff --git a/buny.go b/buny.go index 8aa626e..518f2fd 100644 --- a/buny.go +++ b/buny.go @@ -58,6 +58,7 @@ func buny(v xmpp.Presence) error { //nolint:gocognit,gocyclo evilJid := strings.SplitN(v.JID, "/", 2)[0] evilNick := "" evilNicks := strings.SplitN(v.From, "/", 2) + // Давайте-ка похэндлим нонсенс - когда у нас в строке нету разделителя if len(evilNicks) > 1 { evilNick = evilNicks[1] @@ -77,11 +78,13 @@ func buny(v xmpp.Presence) error { //nolint:gocognit,gocyclo re, err := regexp.Compile(jidRegexp) if err != nil { - log.Errorf("Incorrect regexp in blacklist: %s, skipping", jidRegexp) + log.Errorf("Incorrect regexp in global blacklist: %s, skipping", jidRegexp) continue } + log.Debugf("Checking jid %s vs global blacklist regex %s", evilJid, jidRegexp) + if re.MatchString(evilJid) { if id, err := squash(room, evilJid, bEntry.ReasonEnable, v.Type); err != nil { err := fmt.Errorf( @@ -107,11 +110,13 @@ func buny(v xmpp.Presence) error { //nolint:gocognit,gocyclo re, err := regexp.Compile(nickRegexp) if err != nil { - log.Errorf("Incorrect regexp in blacklist: %s, skipping", nickRegexp) + log.Errorf("Incorrect regexp in global blacklist: %s, skipping", nickRegexp) continue } + log.Debugf("Checking nick %s vs global blacklist regex %s", evilNick, nickRegexp) + if re.MatchString(evilNick) { // Баним именно jid if id, err := squash(room, evilJid, bEntry.ReasonEnable, v.Type); err != nil { @@ -143,11 +148,13 @@ func buny(v xmpp.Presence) error { //nolint:gocognit,gocyclo re, err := regexp.Compile(jidRegexp) if err != nil { - log.Errorf("Incorrect regexp in blacklist: %s, skipping", jidRegexp) + log.Errorf("Incorrect regexp in room %s blacklist: %s, skipping", room, jidRegexp) continue } + log.Debugf("Checking jid %s vs room %s blacklist regex %s", evilJid, room, jidRegexp) + if re.MatchString(evilJid) { if id, err := squash(room, evilJid, bEntry.ReasonEnable, v.Type); err != nil { err := fmt.Errorf( @@ -174,11 +181,12 @@ func buny(v xmpp.Presence) error { //nolint:gocognit,gocyclo re, err := regexp.Compile(nickRegexp) if err != nil { - log.Errorf("Incorrect regexp in blacklist: %s, skipping", nickRegexp) + log.Errorf("Incorrect regexp in room %s blacklist: %s, skipping", room, nickRegexp) continue } + log.Debugf("Checking nick %s vs room %s blacklist regex %s", evilJid, room, nickRegexp) if re.MatchString(evilNick) { // Баним именно jid if id, err := squash(room, evilJid, bEntry.ReasonEnable, v.Type); err != nil { diff --git a/event_parser.go b/event_parser.go index f32b9d9..f2d67af 100644 --- a/event_parser.go +++ b/event_parser.go @@ -1,6 +1,7 @@ package main import ( + "encoding/json" "encoding/xml" "fmt" "sort" @@ -490,7 +491,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo // Однако, это не значит, что такую ситуацию мы не должны корректным образом обрабатывать. if v.Type == "unavailable" { // Считаем, что мы больше не в комнате, поэтому не знаем, кто там есть - roomPresencesJid.Delete(v.From) + roomPresences.Delete(v.From) log.Error("Presence notification - looks like another instance of client leaves room") @@ -530,34 +531,35 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo switch v.Role { // Участник ушёл case "none": - if namesInterface, present := roomPresencesJid.Get(room); present { - var newNames []string - names := interfaceToStringSlice(namesInterface) + if presenceJSONInterface, present := roomPresences.Get(room); present { + presenceJSONStrings := interfaceToStringSlice(presenceJSONInterface) + var newPresenceJSONStrings []string - for _, name := range names { - if name != v.JID { - newNames = append(newNames, name) + for _, presenceJSONstring := range presenceJSONStrings { + var p xmpp.Presence + _ = json.Unmarshal([]byte(presenceJSONstring), &p) + + if p.JID == v.JID { + continue } + + newPresenceJSONStrings = append(newPresenceJSONStrings, presenceJSONstring) } - if len(newNames) == 0 { - roomPresencesJid.Delete(room) - } else { - roomPresencesJid.Set(room, newNames) - } + roomPresences.Set(room, newPresenceJSONStrings) } // Участник пришёл default: - var newNames []string + var presenceJSONStrings []string + var presenceJSONBytes []byte - if namesInterface, present := roomPresencesJid.Get(room); present { - names := interfaceToStringSlice(namesInterface) - names = append(names, v.JID) - roomPresencesJid.Set(room, names) - } else { - newNames = append(newNames, v.JID) - roomPresencesJid.Set(room, newNames) + if presenceJSONInterface, present := roomPresences.Get(room); present { + presenceJSONStrings = interfaceToStringSlice(presenceJSONInterface) } + + presenceJSONBytes, _ = json.Marshal(v) + presenceJSONStrings = append(presenceJSONStrings, string(presenceJSONBytes)) + roomPresences.Set(room, presenceJSONStrings) } // Проверяем, а не злодей ли зашёл? Сделать это мы можем, только если мы находимся в комнате. diff --git a/globals.go b/globals.go index d6e4140..0757ef0 100644 --- a/globals.go +++ b/globals.go @@ -66,7 +66,7 @@ var serverPingTimestampRx int64 // Объектик для хранения стейта утилизатора горутинок. var gTomb tomb.Tomb -// sync.Map-ка со списком участников конференций. -var roomPresencesJid *Collection +// sync.Map-ка со списком участников конференций (в json-формате, согласно структуре xmpp.Presence, "room".[]json). +var roomPresences *Collection /* vim: set ft=go noet ai ts=4 sw=4 sts=4: */ diff --git a/lib.go b/lib.go index 421b13e..d9f4be9 100644 --- a/lib.go +++ b/lib.go @@ -583,28 +583,19 @@ func joinMuc(room string) { go RotateStatus(room) // Время прoверить участников на предмет злобности - namesInterface, present := roomPresencesJid.Get(room) + namesInterface, present := roomPresences.Get(room) // Если room есть в списке presence-ов, то фигачим. room там должен быть, просто обязан. if present { for _, name := range interfaceToStringSlice(namesInterface) { var v xmpp.Presence - v.From = name - v.To = fmt.Sprintf("%s/%s", room, config.Jabber.Nick) - v.ID = "fake_id" - v.JID = v.From - v.Affiliation = "member" - v.Role = "participant" - v.Priority = "" - v.Show = "" - v.Status = "" + _ = json.Unmarshal([]byte(name), &v) + log.Infof("Fake presence forged for %s just for on-enter check", name) // Оно там внутри всё само обработает, если вдруг возникнет wire error, то зарекконетится. _ = buny(v) } } - - // TODO: тоже самое и для nick-ов } // probeServerLiveness проверяет живость соединения с сервером. Для многих серверов обязательная штука, без которой @@ -719,8 +710,6 @@ func probeServerLiveness() { //nolint:gocognit // probeMUCLiveness Пингует MUC-и, нужно для проверки, что клиент ещё находится в MUC-е. func probeMUCLiveness() { //nolint:gocognit - defer gTomb.Done() - for { select { case <-gTomb.Dying(): @@ -773,6 +762,7 @@ func probeMUCLiveness() { //nolint:gocognit log.Debugf("Sending MUC ping from %s to %s", talk.JID(), room) if err := talk.PingS2S(talk.JID(), room); err != nil { + err := fmt.Errorf("Unable to ping MUC %s: %v", room, err) gTomb.Kill(err) } }(room) diff --git a/main.go b/main.go index 53a649d..a1cd56f 100644 --- a/main.go +++ b/main.go @@ -128,7 +128,7 @@ func myLoop() { mucCapsList = NewCollection() serverPingTimestampTx = 0 serverPingTimestampRx = 0 - roomPresencesJid = NewCollection() + roomPresences = NewCollection() // Установим коннект establishConnection()