Files
buny-jabber-bot/internal/jabber/black-whilte_lists.go
2025-12-21 19:07:48 +03:00

221 lines
6.8 KiB
Go

package jabber
import (
"buny-jabber-bot/internal/log"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/davecgh/go-spew/spew"
"github.com/hjson/hjson-go"
)
// ReadWhitelist читает и валидирует белые списки пользователей.
func (j *Jabber) ReadWhitelist() error {
var (
whitelistLoaded = false
err error
executablePath string
)
executablePath, err = os.Executable()
if err != nil {
err = fmt.Errorf("unable to get current executable path: %w", err)
return err
}
whitelistJSONPath := filepath.Dir(executablePath) + "/data/whitelist.json"
locations := []string{
"~/.buny-jabber-bot-whitelist.json",
"~/buny-jabber-bot-whitelist.json",
"/etc/buny-jabber-bot-whitelist.json",
whitelistJSONPath,
}
for _, location := range locations {
fileInfo, err := os.Stat(location)
// Предполагаем, что файла либо нет, либо мы не можем его прочитать, второе надо бы логгировать, но пока забьём.
if err != nil {
continue
}
// Файл белого списка длинноват для белого списка, попробуем следующего кандидата.
if fileInfo.Size() > 2097152 {
log.Warnf("Whitelist file %s is too long for whitelist, skipping", location)
continue
}
buf, err := os.ReadFile(location)
// Не удалось прочитать, попробуем следующего кандидата.
if err != nil {
log.Warnf("Skip reading whitelist file %s: %s", location, err)
continue
}
// Исходя из документации, hjson какбы умеет парсить "кривой" json, но парсит его в map-ку.
// Интереснее на выходе получить структурку: то есть мы вначале конфиг преобразуем в map-ку, затем эту map-ку
// сериализуем в json, а потом json превращаем в структурку. Не очень эффективно, но он и нечасто требуется.
var (
sampleWhitelist MyWhiteList
tmp map[string]any
)
err = hjson.Unmarshal(buf, &tmp)
// Не удалось распарсить - попробуем следующего кандидата.
if err != nil {
log.Warnf("Skip parsing whitelist file %s: %s", location, err)
continue
}
tmpJSON, err := json.Marshal(tmp)
// Не удалось преобразовать map-ку в json.
if err != nil {
log.Warnf("Skip parsing whitelist file %s: %s", location, err)
continue
}
if err := json.Unmarshal(tmpJSON, &sampleWhitelist); err != nil {
log.Warnf("Skip parsing whitelist file %s: %s", location, err)
continue
}
j.WhiteList = sampleWhitelist
whitelistLoaded = true
log.Infof("Using %s as whiteList file", location)
break
}
if !whitelistLoaded {
return errors.New("whitelist was not loaded") //nolint:goerr113
}
return err
}
// ReadBlacklist читает и валидирует чёрные списки пользователей.
func (j *Jabber) ReadBlacklist() error {
var (
blacklistLoaded = false
err error
executablePath string
)
executablePath, err = os.Executable()
if err != nil {
err = fmt.Errorf("unable to get current executable path: %w", err)
return err
}
blacklistJSONPath := filepath.Dir(executablePath) + "/data/blacklist.json"
locations := []string{
"~/.buny-jabber-bot-blacklist.json",
"~/buny-jabber-bot-blacklist.json",
"/etc/buny-jabber-bot-blacklist.json",
blacklistJSONPath,
}
for _, location := range locations {
fileInfo, err := os.Stat(location)
// Предполагаем, что файла либо нет, либо мы не можем его прочитать, второе надо бы логгировать, но пока забьём.
if err != nil {
continue
}
// Файл чёрного списка длинноват для чёрного списка, попробуем следующего кандидата.
if fileInfo.Size() > 16777216 {
log.Warnf("Blacklist file %s is too long for blacklist, skipping", location)
continue
}
buf, err := os.ReadFile(location)
// Не удалось прочитать, попробуем следующего кандидата.
if err != nil {
log.Warnf("Skip reading blacklist file %s: %s", location, err)
continue
}
// Исходя из документации, hjson какбы умеет парсить "кривой" json, но парсит его в map-ку.
// Интереснее на выходе получить структурку: то есть мы вначале конфиг преобразуем в map-ку, затем эту map-ку
// сериализуем в json, а потом json превращаем в структурку. Не очень эффективно, но он и нечасто требуется.
var (
sampleBlacklist MyBlackList
tmp map[string]any
)
err = hjson.Unmarshal(buf, &tmp)
// Не удалось распарсить - попробуем следующего кандидата.
if err != nil {
log.Warnf("Skip parsing blacklist file %s: %s", location, err)
continue
}
tmpJSON, err := json.Marshal(tmp)
// Не удалось преобразовать map-ку в json.
if err != nil {
log.Warnf("Skip parsing blacklist file %s: %s", location, err)
continue
}
if err := json.Unmarshal(tmpJSON, &sampleBlacklist); err != nil {
log.Warnf("Skip parsing whitelist file %s: %s", location, err)
continue
}
for _, entry := range sampleBlacklist.Blacklist {
for str := range strings.SplitSeq(spew.Sdump(entry), "\n") {
log.Debug(str)
}
}
// Вообще говоря, нас уверяют, что простого "=" хватает, но на практике оказывается, что вложенные стуктуры
// могут и не скопироваться.
tmpjson, _ := json.Marshal(sampleBlacklist) //nolint: errchkjson // Да блять, сколько можно
// доёбываться, эти данные 100500 раз перекодировались, там ошибка возможна только если есть ошибка в
// encoding/json, но в этом случае мы в любом случае ничего поделать не можем, вот всяком случае в рантайме.
_ = json.Unmarshal(tmpjson, &j.BlackList)
blacklistLoaded = true
log.Infof("Using %s as blacklist file", location)
break
}
if !blacklistLoaded {
return errors.New("blacklist was not loaded") //nolint:goerr113
}
return err
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */