diff --git a/.gitignore b/.gitignore index 062b559..20556eb 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ repliesConfig.json keywordsConfig.json temp text.txt +logs \ No newline at end of file diff --git a/color.go b/color.go deleted file mode 100644 index e945ac5..0000000 --- a/color.go +++ /dev/null @@ -1,57 +0,0 @@ -package main - -import "fmt" - -//Color struct, defines the color -type Color struct{} - -var c Color - -//DarkGray color -func (c Color) DarkGray(t string) { - fmt.Print("\x1b[30;1m") //dark gray - fmt.Println(t) - fmt.Print("\x1b[0m") //defaultColor -} - -//Red color -func (c Color) Red(t string) { - fmt.Print("\x1b[31;1m") //red - fmt.Println(t) - fmt.Print("\x1b[0m") //defaultColor -} - -//Green color -func (c Color) Green(t string) { - fmt.Print("\x1b[32;1m") //green - fmt.Println(t) - fmt.Print("\x1b[0m") //defaultColor -} - -//Yellow color -func (c Color) Yellow(t string) { - fmt.Print("\x1b[33;1m") //yellow - fmt.Println(t) - fmt.Print("\x1b[0m") //defaultColor -} - -//Blue color -func (c Color) Blue(t string) { - fmt.Print("\x1b[34;1m") //blue - fmt.Println(t) - fmt.Print("\x1b[0m") //defaultColor -} - -//Purple color -func (c Color) Purple(t string) { - fmt.Print("\x1b[35;1m") //purple - fmt.Println(t) - fmt.Print("\x1b[0m") //defaultColor -} - -//Cyan color -func (c Color) Cyan(t string) { - fmt.Print("\x1b[36;1m") //cyan - fmt.Println(t) - fmt.Print("\x1b[0m") //defaultColor -} diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..e997ec1 --- /dev/null +++ b/errors.go @@ -0,0 +1,9 @@ +package main + +import "log" + +func check(err error) { + if err != nil { + log.Println(err) + } +} diff --git a/log.go b/log.go new file mode 100644 index 0000000..d12c469 --- /dev/null +++ b/log.go @@ -0,0 +1,19 @@ +package main + +import ( + "io" + "log" + "os" + "time" +) + +func savelog() { + timeS := time.Now().String() + _ = os.Mkdir("logs", os.ModePerm) + logFile, err := os.OpenFile("logs/log-"+timeS+".log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) + if err != nil { + panic(err) + } + mw := io.MultiWriter(os.Stdout, logFile) + log.SetOutput(mw) +} diff --git a/main.go b/main.go index 5c9b4ab..b540bbe 100644 --- a/main.go +++ b/main.go @@ -1,28 +1,52 @@ package main -import "fmt" +import ( + "fmt" + "log" + "strconv" + "time" + + "github.com/fatih/color" +) const version = "0.1-dev" func main() { - c.Yellow("echo-botnet") + savelog() + color.Blue("echo-botnet") fmt.Println("---------------") - c.Cyan("echo-botnet initialized") - c.Purple("https://github.com/arnaucode/echo-botnet") - fmt.Println("version " + version) + color.Cyan("echo-botnet initialized") + color.Green("https://github.com/arnaucode/echo-botnet") + log.Println("version " + version) - keywords := readKeywordsConfig() - c.Cyan("keywords configured: ") + readKeywordsConfig() + color.Cyan("keywords configured: ") fmt.Println(keywords) - replies := readRepliesConfig() - c.Cyan("replies configured: ") + readRepliesConfig() + color.Cyan("replies configured: ") fmt.Println(replies) fmt.Println("Reading botsConfig.json file") - botnet := readConfigTokensAndConnect() - c.Cyan("[list of configured bots]:") - for _, v := range botnet.ScreenNames { - c.Cyan(v) + readConfigTokensAndConnect() + color.Cyan("[list of configured bots]:") + for _, bot := range botnet { + color.Cyan(bot.Title) + } + var i int + for { + color.Red(strconv.Itoa(i)) + sinceTweeted := time.Unix(botnet[i].SinceTweeted, 0) + elapsed := time.Since(sinceTweeted) + fmt.Println(elapsed) + if elapsed.Seconds() > 60 { + log.Println("starting to use bot: " + botnet[i].Title) + startStreaming(botnet[i]) + } else { + log.Println("bot: " + botnet[i].Title + " not used due bot is in waiting time") + } + i++ + if i > len(botnet)-1 { + i = 0 + } } - streamTweets(botnet, keywords, replies) } diff --git a/readConfigTokensAndConnect.go b/readConfigTokensAndConnect.go deleted file mode 100644 index e962297..0000000 --- a/readConfigTokensAndConnect.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - - "github.com/dghubble/go-twitter/twitter" - "github.com/dghubble/oauth1" -) - -//Config stores the data from json botsConfig.json file -type Config struct { - Title string `json:"title"` - ConsumerKey string `json:"consumer_key"` - ConsumerSecret string `json:"consumer_secret"` - AccessTokenKey string `json:"access_token_key"` - AccessTokenSecret string `json:"access_token_secret"` -} - -//Botnet stores each bot configured -type Botnet struct { - ScreenNames []string - Clients []*twitter.Client -} - -func readConfigTokensAndConnect() (botnet Botnet) { - var config []Config - var clients []*twitter.Client - - file, e := ioutil.ReadFile("botsConfig.json") - if e != nil { - fmt.Println("error:", e) - } - content := string(file) - json.Unmarshal([]byte(content), &config) - fmt.Println("botnetConfig.json read comlete") - - fmt.Print("connecting to twitter api --> ") - for i := 0; i < len(config); i++ { - configu := oauth1.NewConfig(config[i].ConsumerKey, config[i].ConsumerSecret) - token := oauth1.NewToken(config[i].AccessTokenKey, config[i].AccessTokenSecret) - httpClient := configu.Client(oauth1.NoContext, token) - // twitter client - client := twitter.NewClient(httpClient) - clients = append(clients, client) - botnet.ScreenNames = append(botnet.ScreenNames, config[i].Title) - } - botnet.Clients = clients - - fmt.Println("connection successful") - - return botnet -} diff --git a/readConfigurations.go b/readConfigurations.go new file mode 100644 index 0000000..57f2540 --- /dev/null +++ b/readConfigurations.go @@ -0,0 +1,61 @@ +package main + +import ( + "encoding/json" + "io/ioutil" + "log" + + "github.com/dghubble/go-twitter/twitter" + "github.com/dghubble/oauth1" +) + +//Bot stores the data from json botsConfig.json file +type Bot struct { + Title string `json:"title"` + ConsumerKey string `json:"consumer_key"` + ConsumerSecret string `json:"consumer_secret"` + AccessTokenKey string `json:"access_token_key"` + AccessTokenSecret string `json:"access_token_secret"` + Client *twitter.Client + SinceTweeted int64 `json:"sincetweeted"` + Blocked bool `json:"blocked"` + SinceBlocked int64 `json:"sinceblocked"` +} + +var botnet []Bot +var keywords []string +var replies []string + +func readConfigTokensAndConnect() { + file, err := ioutil.ReadFile("botsConfig.json") + check(err) + content := string(file) + json.Unmarshal([]byte(content), &botnet) + log.Println("botnetConfig.json read comlete") + log.Print("connecting to twitter api") + for k, _ := range botnet { + configu := oauth1.NewConfig(botnet[k].ConsumerKey, botnet[k].ConsumerSecret) + token := oauth1.NewToken(botnet[k].AccessTokenKey, botnet[k].AccessTokenSecret) + httpClient := configu.Client(oauth1.NoContext, token) + // twitter client + client := twitter.NewClient(httpClient) + botnet[k].Client = client + botnet[k].Blocked = false + } + + log.Println("connection successful") +} + +func readKeywordsConfig() { + file, err := ioutil.ReadFile("keywordsConfig.json") + check(err) + content := string(file) + json.Unmarshal([]byte(content), &keywords) +} + +func readRepliesConfig() { + file, err := ioutil.ReadFile("repliesConfig.json") + check(err) + content := string(file) + json.Unmarshal([]byte(content), &replies) +} diff --git a/readKeywordsConfig.go b/readKeywordsConfig.go deleted file mode 100644 index 0912943..0000000 --- a/readKeywordsConfig.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" -) - -func readKeywordsConfig() []string { - var keywords []string - file, e := ioutil.ReadFile("keywordsConfig.json") - if e != nil { - fmt.Println("error:", e) - } - content := string(file) - json.Unmarshal([]byte(content), &keywords) - - return keywords -} diff --git a/readRepliesConfig.go b/readRepliesConfig.go deleted file mode 100644 index c7f2c94..0000000 --- a/readRepliesConfig.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" -) - -func readRepliesConfig() []string { - var replies []string - file, e := ioutil.ReadFile("repliesConfig.json") - if e != nil { - fmt.Println("error:", e) - } - content := string(file) - json.Unmarshal([]byte(content), &replies) - - return replies -} diff --git a/streamTweets.go b/streamTweets.go index f12e3bf..9b158b5 100644 --- a/streamTweets.go +++ b/streamTweets.go @@ -4,11 +4,11 @@ import ( "fmt" "log" "math/rand" - "strconv" "strings" "time" "github.com/dghubble/go-twitter/twitter" + "github.com/fatih/color" ) func isRT(tweet *twitter.Tweet) bool { @@ -20,9 +20,9 @@ func isRT(tweet *twitter.Tweet) bool { } return false } -func isFromOwnBot(flock Botnet, tweet *twitter.Tweet) bool { - for i := 0; i < len(flock.ScreenNames); i++ { - if flock.ScreenNames[i] == tweet.User.ScreenName { +func isFromBotnet(tweet *twitter.Tweet) bool { + for i := 0; i < len(botnet); i++ { + if botnet[i].Title == tweet.User.ScreenName { return true } } @@ -40,39 +40,33 @@ func replyTweet(client *twitter.Client, text string, inReplyToStatusID int64) { InReplyToStatusID: inReplyToStatusID, }) if err != nil { - fmt.Println(err) + log.Println(err) } if httpResp.Status != "200 OK" { - c.Red("error: " + httpResp.Status) - c.Purple("maybe twitter has blocked the account, CTRL+C, wait 15 minutes and try again") + color.Red("error: " + httpResp.Status) + log.Println("error" + httpResp.Status) + color.Cyan("maybe twitter has blocked the account, CTRL+C, wait 15 minutes and try again") + log.Println("maybe twitter has blocked the account, CTRL+C, wait 15 minutes and try again") } - fmt.Print("tweet posted: ") - c.Green(tweet.Text) + log.Println("tweet posted: " + tweet.Text) } -func startStreaming(botnet Botnet, bot *twitter.Client, botScreenName string, keywords []string, replies []string) { +func startStreaming(bot Bot) { // Convenience Demux demultiplexed stream messages demux := twitter.NewSwitchDemux() demux.Tweet = func(tweet *twitter.Tweet) { - if isRT(tweet) == false && isFromOwnBot(botnet, tweet) == false { + if isRT(tweet) == false && isFromBotnet(tweet) == false { //processTweet(botnetUser, botScreenName, keywords, tweet) - fmt.Println("[bot @" + botScreenName + "] - New tweet detected:") - c.Yellow(tweet.Text) + log.Println("[bot @" + bot.Title + "] - New tweet detected:") + log.Println(tweet.Text) reply := getRandomReplyFromReplies(replies) - fmt.Print("reply: ") - c.Green(reply) - fmt.Println(tweet.User.ScreenName) - fmt.Println(tweet.ID) - replyTweet(bot, "@"+tweet.User.ScreenName+" "+reply, tweet.ID) - waitMinutes(1) + log.Println("reply: " + reply + ", to: @" + tweet.User.ScreenName /* + ". tweet ID: " + tweet.ID*/) + + //replyTweet(bot, "@"+tweet.User.ScreenName+" "+reply, tweet.ID) + color.Green("replying tweet!") + bot.SinceTweeted = time.Now().Unix() } } - demux.DM = func(dm *twitter.DirectMessage) { - fmt.Println(dm.SenderID) - } - demux.Event = func(event *twitter.Event) { - fmt.Printf("%#v\n", event) - } fmt.Println("Starting Stream...") // FILTER @@ -80,29 +74,13 @@ func startStreaming(botnet Botnet, bot *twitter.Client, botScreenName string, ke Track: keywords, StallWarnings: twitter.Bool(true), } - stream, err := bot.Streams.Filter(filterParams) - if err != nil { - log.Fatal(err) - } + stream, err := bot.Client.Streams.Filter(filterParams) + check(err) // Receive messages until stopped or stream quits demux.HandleChan(stream.Messages) - - // Wait for SIGINT and SIGTERM (HIT CTRL-C) - /*ch := make(chan os.Signal) - signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) - log.Println(<-ch) - - fmt.Println("Stopping Stream...") - stream.Stop()*/ -} -func streamTweets(botnet Botnet, keywords []string, replies []string) { - fmt.Println("total keywords: " + strconv.Itoa(len(keywords))) - c.Purple("keywords to follow: ") - fmt.Println(keywords) - c.Green("Starting to stream tweets") - for i := 0; i < len(botnet.Clients); i++ { - go startStreaming(botnet, botnet.Clients[i], botnet.ScreenNames[i], keywords, replies) - //wait 35 seconds to start the next bot - waitSeconds(35) - } + /*for message := range stream.Messages { + demux.Handle(message) + log.Println("stopping stream") + stream.Stop() + }*/ }