Fix filling presence db, fix ban by useragent

This commit is contained in:
eleksir
2025-12-21 19:07:48 +03:00
parent 9ea444f365
commit de3db48d47
7 changed files with 273 additions and 103 deletions

View File

@@ -632,8 +632,8 @@ func (j *Jabber) ParseEvent(e any) { //nolint:maintidx,gocognit,gocyclo
}
} else {
log.Infof(
"Presence notification, Type: %s, From: %s, To: %s Show: %s, Status: %s, Affiliation: %s, Role: %s, JID: %s",
v.Type, v.From, v.To, v.Show, v.Status, v.Affiliation, v.Role, v.JID,
"Presence notification, Type: %s, From: %s, To: %s Show: %s, Status: %s, Affiliation: %s, Role: %s, JID: %s, Priority: %s",
v.Type, v.From, v.To, v.Show, v.Status, v.Affiliation, v.Role, v.JID, v.Priority,
)
if !strings.Contains(v.From, "/") {
@@ -642,6 +642,12 @@ func (j *Jabber) ParseEvent(e any) { //nolint:maintidx,gocognit,gocyclo
return
}
if v.JID == "" {
log.Info("Useless presence notification without JID field, skipping")
return
}
room := strings.SplitN(v.From, "/", 2)[0]
nick := strings.SplitN(v.From, "/", 2)[1]
@@ -651,68 +657,167 @@ func (j *Jabber) ParseEvent(e any) { //nolint:maintidx,gocognit,gocyclo
return
}
// Это наш собственный Presence.
if v.Show == "" && v.Status == "" {
if nick == j.GetBotNickFromRoomConfig(room) {
j.RoomsConnected = append(j.RoomsConnected, room)
// На всякий случай дедуплицируем список комнат, к которым мы заджойнились.
sort.Strings(j.RoomsConnected)
// На всякий случай добавим комнату, из которой пришло уведомление в список тех, в которые вхож бот.
if nick == j.GetBotNickFromRoomConfig(room) {
j.RoomsConnected = append(j.RoomsConnected, room)
// На всякий случай дедуплицируем список комнат, к которым мы заджойнились.
sort.Strings(j.RoomsConnected)
j.RoomsConnected = slices.Compact(j.RoomsConnected)
}
j.RoomsConnected = slices.Compact(j.RoomsConnected)
}
switch v.Role {
// Участник ушёл.
case "none":
var (
newPresences = make([]xmpp.Presence, 0)
presenceJSON []byte
ok bool
presences []xmpp.Presence
)
// Обновлять базу имеет смысл только если есть хоть какая-то запись о комнате в ней.
if presenceJSONInterface, present := j.RoomPresences.Get(room); present {
presenceJSONStrings := InterfaceToStringSlice(presenceJSONInterface)
presenceJSON, ok = presenceJSONInterface.([]byte)
var newPresenceJSONStrings []string
if !ok {
log.Errorf("Looks like we have corrupted entry in presence db")
for _, presenceJSONstring := range presenceJSONStrings {
var p xmpp.Presence
return
}
_ = json.Unmarshal([]byte(presenceJSONstring), &p)
if err := json.Unmarshal(presenceJSON, &presences); err != nil {
log.Errorf("Looks like we have corrupted entry in presence db")
return
}
for _, p := range presences { //nolint: gocritic // Развели тут, блять, страну советов, напиши что надо сделать кодом, сука.
// Если находим, что у нас уже есть клиент с таким же From, то есть полным nick-ом (для groupchat)
// пропускаем его.
if p.From == v.From {
if j.C.Debug.PresenceDB {
log.Debugf("Skipping presence for %s in room %s", v.JID, room)
}
continue
}
newPresenceJSONStrings = append(newPresenceJSONStrings, presenceJSONstring)
if j.C.Debug.PresenceDB {
log.Debugf("Appending presence for %s in room %s", v.JID, room)
}
newPresences = append(newPresences, p)
}
j.RoomPresences.Set(room, newPresenceJSONStrings)
presenceJSON, _ = json.Marshal(newPresences) //nolint: errchkjson
if j.C.Debug.PresenceDB {
log.Debugf("Updating presence db for room %s", room)
}
j.RoomPresences.Set(room, presenceJSON)
// Больше нам, похоже с этим уведомлением нечего.
return
}
// Участник пришёл.
// Участник пришёл или изменил свой статус.
default:
var (
presenceJSONStrings []string
newPresenceJSONStrings []string
presenceJSONBytes []byte
newPresences = make([]xmpp.Presence, 0)
presenceJSON []byte
ok bool
presences []xmpp.Presence
skip bool
)
if presenceJSONInterface, present := j.RoomPresences.Get(room); present {
presenceJSONStrings = InterfaceToStringSlice(presenceJSONInterface)
}
presenceJSON, ok = presenceJSONInterface.([]byte)
if !ok {
log.Errorf("Looks like we have corrupted entry in presence db")
for _, presenceJSONString := range presenceJSONStrings {
var p xmpp.Presence
_ = json.Unmarshal([]byte(presenceJSONString), &p)
// Если находим, что у нас уже есть клиент с таким же From, то есть полным nick-ом (для groupchat)
// просто замещаем его.
if p.From == v.From {
continue
return
}
newPresenceJSONStrings = append(newPresenceJSONStrings, presenceJSONString)
// Если мы нашли запись о комнате, то её надо обновить.
if err := json.Unmarshal(presenceJSON, &presences); err != nil {
log.Errorf("Looks like we have corrupted entry in presence db")
return
}
for _, p := range presences { //nolint: gocritic // Развели тут, блять, страну советов, напиши что надо сделать кодом, сука.
// Если находим, что у нас уже есть клиент с таким же From, то есть полным nick-ом (для groupchat)
// запоминаем его и добавим позднее.
if p.From == v.From {
// Запоминаем участника только если его роль не поменялась на outcast. (То есть если это не
// бан.)
if v.Role == "outcast" {
if j.C.Debug.PresenceDB {
log.Debugf("Let's forget about %s because it is outcast/banned", p.JID)
}
skip = true
} else if j.C.Debug.PresenceDB {
log.Debugf("Skip adding %s to presences for %s, add as last one", p.JID, room)
}
continue
}
if j.C.Debug.PresenceDB {
log.Debugf("Appending presence for %s in room %s", v.JID, room)
}
newPresences = append(newPresences, p)
}
}
presenceJSONBytes, _ = json.Marshal(v) //nolint:errchkjson
newPresenceJSONStrings = append(newPresenceJSONStrings, string(presenceJSONBytes))
j.RoomPresences.Set(room, newPresenceJSONStrings)
if !skip {
if j.C.Debug.PresenceDB {
log.Debugf("Appending presence for %s in room %s", v.JID, room)
}
newPresences = append(newPresences, v)
} else if j.C.Debug.PresenceDB {
log.Debugf("Skip Appending outcast presence for %s in room %s", v.JID, room)
}
presenceJSON, _ = json.Marshal(newPresences) //nolint: errchkjson
if j.C.Debug.PresenceDB {
log.Debugf("Updating presence db for room %s", room)
}
j.RoomPresences.Set(room, presenceJSON)
}
if j.C.Debug.PresenceDB {
log.Debugf("List of presence entries in presence db of %s:", room)
if presenceJSONInterface, present := j.RoomPresences.Get(room); present {
var presences []xmpp.Presence
presenceJSON, ok := presenceJSONInterface.([]byte)
if !ok {
log.Debugf("Looks like we have corrupted entry in presence db")
return
}
// Если мы нашли запись о комнате, то её надо обновить.
if err := json.Unmarshal(presenceJSON, &presences); err != nil {
log.Debugf("Looks like we have corrupted entry in presence db")
return
}
for _, p := range presences { //nolint: gocritic // Развели тут, блять, страну советов, напиши что надо сделать кодом, сука.
log.Debugf("Found presence for %s from %s", p.JID, room)
}
}
}
// Проверяем, а не злодей ли зашёл? Сделать это мы можем, только если мы находимся в комнате.