package main import ( "encoding/json" "fmt" "io/ioutil" "math/rand" "net/http" "os" "regexp" "sync" "time" "log" irc "github.com/thoj/go-ircevent" ) const channel = "#ctf" const ( pattern = "(?i)\\b(cat|gato|miau|meow|garfield|lolcat)[s|z]{0,1}\\b" nyastat = "nyastat" msgPrefix = "I love cats! Here's a fact: %s ^_^" gifPrefix = "Meow! Here's a gif: %s ^_^" ) type catFact struct { Fact string `json:"fact"` Length int `json:"length"` } var ( re = regexp.MustCompile(pattern) catFactsURL = "http://catfact.ninja/fact" ) type stats struct { userMessages map[string]uint mux *sync.Mutex } func newStats() *stats { return &stats{ userMessages: make(map[string]uint), mux: &sync.Mutex{}, } } func (s *stats) addUser(user string) { s.mux.Lock() defer s.mux.Unlock() if v, ok := s.userMessages[user]; ok { log.Printf("User %s writes %d message", user, v+1) s.userMessages[user]++ return } log.Printf("First message from user %s", user) s.userMessages[user] = 1 } func (s *stats) online(e *irc.Event) int { e.Connection.Mutex.Lock() defer e.Connection.Mutex.Unlock() return -1 } func (s *stats) realStats(e *irc.Event) { e.Connection.Privmsg(channel, "🙀🙀🙀 WoW 🙀🙀🙀 NYAStat 🙀🙀🙀") t := "User %s sent %d messages" for u, v := range s.userMessages { e.Connection.Privmsg(channel, fmt.Sprintf(t, u, v)) } } func (s *stats) printStats(e *irc.Event) { s.online(e) s.realStats(e) } func main() { nick := os.Getenv("CTF2021NICK") irccon := irc.IRC(nick, os.Getenv("CTF2021USER")) s := newStats() irccon.VerboseCallbackHandler = false irccon.Debug = false irccon.UseTLS = false irccon.AddCallback("001", func(e *irc.Event) { log.Println("Welcome message:", e.Message()) e.Connection.Privmsg("nickserv", "identify "+os.Getenv("CTF2021PASS")) e.Connection.Join(channel) e.Connection.Privmsg(channel, `I'm a cat bot!`) e.Connection.Privmsg(channel, `Inspired from https://github.com/go-chat-bot/plugins/blob/master/catfacts/catfacts.go`) e.Connection.Privmsg(channel, `Try cat /etc/passwd :p`) e.Connection.Privmsg(channel, `Source code and issue tracker: https://gitea.difrex.ru/CTF2021/irc_bot`) e.Connection.Privmsg(channel, `Now with gifs! ^_^`) }) irccon.AddCallback("MODE", func(e *irc.Event) { log.Println(e.Message()) }) irccon.AddCallback("PRIVMSG", func(e *irc.Event) { log.Printf("Message from %s received: %s", e.Nick, e.Message()) s.addUser(e.Nick) doCommand(e.Message(), e, s) }) err := irccon.Connect(os.Getenv("CTF2021URL")) if err != nil { fmt.Printf("Err %s", err) return } irccon.Loop() } func doCommand(command string, e *irc.Event, s *stats) { if ok := statCommand(command); ok { s.printStats(e) return } if ok := checkCommad(command, e.Connection); !ok { return } rand.Seed(time.Now().UnixNano()) i := rand.Intn(50) fmt.Println(i) if i > 30 { catGif(e.Connection) return } catFacts(e.Connection) } func statCommand(command string) bool { if command == nyastat { return true } return false } func checkCommad(command string, con *irc.Connection) bool { if !re.MatchString(command) { return false } return true } func catGif(con *irc.Connection) (string, error) { res, err := http.Get("http://thecatapi.com/api/images/get?format=src&type=gif") if err != nil { return "", err } con.Privmsg(channel, fmt.Sprintf(gifPrefix, res.Request.URL.String())) return fmt.Sprintf(gifPrefix, res.Request.URL.String()), nil } func getJson(url string, v interface{}) error { res, err := http.Get(url) if err != nil { return err } defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { return err } return json.Unmarshal(body, v) } func catFacts(con *irc.Connection) (string, error) { data := &catFact{} err := getJson(catFactsURL, data) if err != nil { return "", err } if len(data.Fact) == 0 { return "", nil } con.Privmsg(channel, fmt.Sprintf(msgPrefix, data.Fact)) return fmt.Sprintf(msgPrefix, data.Fact), nil }