modularize telegram bot and log watcher
This commit is contained in:
parent
d57c6ea6aa
commit
5dcb467842
98
server/internal/log_watcher/log_watcher.go
Normal file
98
server/internal/log_watcher/log_watcher.go
Normal file
|
@ -0,0 +1,98 @@
|
|||
package log_watcher
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/Vomitblood/cspj-application/server/internal/telegram"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
tg "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
const (
|
||||
// TODO: add config for user to specify log location
|
||||
modsecLogFile = "/home/vomitblood/build/cspj-application/docker/chungus/logs/host-fs-auditlog.log"
|
||||
)
|
||||
|
||||
var lastReadPosition int64 = 0
|
||||
|
||||
type LogEntry struct {
|
||||
AuditData struct {
|
||||
Messages []string `json:"messages"`
|
||||
} `json:"audit_data"`
|
||||
}
|
||||
|
||||
func watchLogFile(bot *tg.BotAPI) {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to initialize watcher:", err)
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
// add log file to watcher
|
||||
err = watcher.Add(modsecLogFile)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to watch log file:", err)
|
||||
}
|
||||
|
||||
log.Println("Monitoring log file for changes...")
|
||||
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||
log.Println("Log file updated, reading new entries...")
|
||||
readNewLines(bot)
|
||||
}
|
||||
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log.Println("Watcher error:", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readNewLines(bot *tg.BotAPI) {
|
||||
file, err := os.Open(modsecLogFile)
|
||||
if err != nil {
|
||||
log.Println("Failed to reopen log file:", err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// move to the last read position
|
||||
file.Seek(lastReadPosition, os.SEEK_SET)
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
var logEntry LogEntry
|
||||
|
||||
// try to parse json
|
||||
if err := json.Unmarshal([]byte(line), &logEntry); err != nil {
|
||||
log.Println("⚠️ Failed to parse JSON:", err)
|
||||
// skip invalid json lines
|
||||
// very crucial as modsecurity does not respect the json spec
|
||||
continue
|
||||
}
|
||||
|
||||
// send index 0 element will do
|
||||
if len(logEntry.AuditData.Messages) > 0 {
|
||||
telegram.SendTelegramAlert(bot, logEntry.AuditData.Messages[0])
|
||||
}
|
||||
}
|
||||
|
||||
// update last read position
|
||||
lastReadPosition, _ = file.Seek(0, os.SEEK_CUR)
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Println("Error reading log file:", err)
|
||||
}
|
||||
}
|
|
@ -1,32 +1,24 @@
|
|||
package telegram
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
tg "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
const (
|
||||
// TODO: add config for user to specify log location
|
||||
modsecLogFile = "/home/vomitblood/build/cspj-application/docker/chungus/logs/host-fs-auditlog.log"
|
||||
telegramToken = "7215466800:AAGwjZnXEfbbjQiA0y7qtSzbSZNUWQJnyjo"
|
||||
telegramChatID = 622943829
|
||||
)
|
||||
|
||||
var lastReadPosition int64 = 0
|
||||
|
||||
type LogEntry struct {
|
||||
AuditData struct {
|
||||
Messages []string `json:"messages"`
|
||||
} `json:"audit_data"`
|
||||
}
|
||||
|
||||
func TelegramBotInit() {
|
||||
func TelegramBotInit() (*tg.BotAPI, error) {
|
||||
bot, err := tg.NewBotAPI(telegramToken)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create Telegram bot:", err)
|
||||
|
@ -41,84 +33,10 @@ func TelegramBotInit() {
|
|||
log.Fatal("Failed to send test message:", err)
|
||||
}
|
||||
|
||||
// start watching the log file for changes
|
||||
watchLogFile(bot)
|
||||
return bot, nil
|
||||
}
|
||||
|
||||
func watchLogFile(bot *tg.BotAPI) {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to initialize watcher:", err)
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
// add log file to watcher
|
||||
err = watcher.Add(modsecLogFile)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to watch log file:", err)
|
||||
}
|
||||
|
||||
log.Println("Monitoring log file for changes...")
|
||||
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||
log.Println("Log file updated, reading new entries...")
|
||||
readNewLines(bot)
|
||||
}
|
||||
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log.Println("Watcher error:", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readNewLines(bot *tg.BotAPI) {
|
||||
file, err := os.Open(modsecLogFile)
|
||||
if err != nil {
|
||||
log.Println("Failed to reopen log file:", err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// move to the last read position
|
||||
file.Seek(lastReadPosition, os.SEEK_SET)
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
var logEntry LogEntry
|
||||
|
||||
// try to parse json
|
||||
if err := json.Unmarshal([]byte(line), &logEntry); err != nil {
|
||||
log.Println("⚠️ Failed to parse JSON:", err)
|
||||
// skip invalid json lines
|
||||
// very crucial as modsecurity does not respect the json spec
|
||||
continue
|
||||
}
|
||||
|
||||
// send index 0 element will do
|
||||
if len(logEntry.AuditData.Messages) > 0 {
|
||||
sendTelegramAlert(bot, logEntry.AuditData.Messages[0])
|
||||
}
|
||||
}
|
||||
|
||||
// update last read position
|
||||
lastReadPosition, _ = file.Seek(0, os.SEEK_CUR)
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Println("Error reading log file:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func sendTelegramAlert(bot *tg.BotAPI, message string) {
|
||||
func SendTelegramAlert(bot *tg.BotAPI, message string) {
|
||||
msg := tg.NewMessage(telegramChatID, fmt.Sprintf("🚨 *WEEWOO ALERT* 🚨\n%s", message))
|
||||
_, err := bot.Send(msg)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in a new issue