From e4f02f581227a66bd358e9f69f7d36c34e95cc80 Mon Sep 17 00:00:00 2001 From: Vanshaj <79518089+V4NSH4J@users.noreply.github.com> Date: Sun, 17 Apr 2022 19:57:51 +0530 Subject: [PATCH] Major update DMDGO v1.9.0 1) Added DM on React [Beta] 2) Added Hypesquad changer 3) Added token changer 4) Added anti-captcha support (They now support Hcaptcha enterprise and it works pretty well) 5) Major Restructure of code to make it more easily updatable 6) Added subscription to guilds so that op 14 scraper does not return 0 members on larger servers --- config.yml | 22 +- discord/dm_react.go | 607 +++++++ discord/get_message.go | 37 + discord/guild_leaver.go | 62 + discord/invite_joiner.go | 132 ++ discord/mass_dm.go | 649 +++++++ discord/profile_changer.go | 302 ++++ discord/reaction_adder.go | 103 ++ discord/scraper.go | 374 ++++ discord/server_checker.go | 64 + discord/token_checker.go | 67 + discord/token_formatter.go | 43 + discord/token_onliner.go | 52 + input/changed_tokens.txt | 0 input/completed.txt | 1 + input/proxies.txt | 1 - input/tokens.txt | 1 - {utilities => instance}/captcha.go | 69 +- instance/client.go | 59 + instance/config.go | 150 ++ {utilities => instance}/direct_messages.go | 203 +-- {utilities => instance}/extra.go | 123 +- {utilities => instance}/headers.go | 103 +- instance/instance.go | 187 ++ {utilities => instance}/protocol.go | 8 +- {utilities => instance}/scrape.go | 61 +- {utilities => instance}/token_util.go | 96 +- instance/types.go | 220 +++ {utilities => instance}/websocket.go | 9 +- main.go | 1906 +------------------- utilities/files.go | 252 +-- utilities/instance.go | 99 - utilities/invite.go | 247 --- utilities/misc.go | 90 +- 34 files changed, 3616 insertions(+), 2783 deletions(-) create mode 100644 discord/dm_react.go create mode 100644 discord/get_message.go create mode 100644 discord/guild_leaver.go create mode 100644 discord/invite_joiner.go create mode 100644 discord/mass_dm.go create mode 100644 discord/profile_changer.go create mode 100644 discord/reaction_adder.go create mode 100644 discord/scraper.go create mode 100644 discord/server_checker.go create mode 100644 discord/token_checker.go create mode 100644 discord/token_formatter.go create mode 100644 discord/token_onliner.go create mode 100644 input/changed_tokens.txt rename {utilities => instance}/captcha.go (82%) create mode 100644 instance/client.go create mode 100644 instance/config.go rename {utilities => instance}/direct_messages.go (68%) rename {utilities => instance}/extra.go (71%) rename {utilities => instance}/headers.go (71%) create mode 100644 instance/instance.go rename {utilities => instance}/protocol.go (96%) rename {utilities => instance}/scrape.go (58%) rename {utilities => instance}/token_util.go (60%) create mode 100644 instance/types.go rename {utilities => instance}/websocket.go (97%) delete mode 100644 utilities/instance.go delete mode 100644 utilities/invite.go diff --git a/config.yml b/config.yml index 9207892..75ccf50 100644 --- a/config.yml +++ b/config.yml @@ -18,8 +18,8 @@ direct_message_settings: close_dm_after_message: false proxy_settings: - proxy_from_file: true - proxy_for_captcha: true + proxy_from_file: false + proxy_for_captcha: false use_proxy_for_gateway: false proxy_protocol: "http" timeout: 60 @@ -31,7 +31,7 @@ scraper_settings: captcha_settings: captcha_api_key: "" - captcha_api: "capmonster.cloud" + captcha_api: "anti-captcha.com" max_captcha_wait: 60 max_captcha_retry: 3 @@ -45,3 +45,19 @@ suspicion_avoidance: typing_variation: 250 typing_speed: 450 typing_base: 200 + +dm_on_react: + observer_token: "" + change_name: true + change_avatar: true + invite: "" + server_id: "" + channel_id: "" + message_id: "" + emoji: "" + skip_completed: true + skip_failed: true + leave_token_on_ratelimit: true + rotate_tokens: true + max_anti_raid_queue: 20 + max_dms_per_token: 10 \ No newline at end of file diff --git a/discord/dm_react.go b/discord/dm_react.go new file mode 100644 index 00000000..0b2d97f --- /dev/null +++ b/discord/dm_react.go @@ -0,0 +1,607 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package discord + +import ( + "bufio" + "encoding/json" + "fmt" + "io/ioutil" + "math/rand" + "net/http" + "os" + "path" + "path/filepath" + "strings" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/instance" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" +) + +func LaunchDMReact() { + color.Cyan("DM On React") + cfg, instances, err := instance.GetEverything() + if err != nil { + color.Red("Error while obtaining config and instances: %s", err) + } + // Checking config for observer token + if cfg.DMonReact.Observer == "" { + color.Red("Set an Observer token to use DM on react") + utilities.ExitSafely() + } + if cfg.DMonReact.ServerID == "" { + color.Red("Set a Server ID to use DM on react") + utilities.ExitSafely() + } + if cfg.DMonReact.Invite == "" { + color.Red("Set an Invite to use DM on react") + utilities.ExitSafely() + } + var msg instance.Message + color.Green("[%v] Press 1 to use messages from file or press 2 to enter a message: ", time.Now().Format("15:04:05")) + var messagechoice int + fmt.Scanln(&messagechoice) + if messagechoice != 1 && messagechoice != 2 { + color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) + utilities.ExitSafely() + } + if messagechoice == 2 { + color.Green("[%v] Enter your message, use \\n for changing lines. You can also set a constant message in message.json", time.Now().Format("15:04:05")) + scanner := bufio.NewScanner(os.Stdin) + var text string + if scanner.Scan() { + text = scanner.Text() + } + + msg.Content = text + msg.Content = strings.Replace(msg.Content, "\\n", "\n", -1) + var msgs []instance.Message + msgs = append(msgs, msg) + err := instance.SetMessages(instances, msgs) + if err != nil { + color.Red("[%v] Error while setting messages: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + } else { + var msgs []instance.Message + err := instance.SetMessages(instances, msgs) + if err != nil { + color.Red("[%v] Error while setting messages: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + } + // Initializing Files & Variables + var completed []string + var failed []string + var names []string + var avatars []string + var proxies []string + if cfg.DMonReact.SkipCompleted { + completed, err = utilities.ReadLines("completed.txt") + if err != nil { + color.Red("Error while reading completed.txt: %s", err) + utilities.ExitSafely() + } + } + if cfg.DMonReact.SkipFailed { + failed, err = utilities.ReadLines("failed.txt") + if err != nil { + color.Red("Error while reading failed.txt: %s", err) + utilities.ExitSafely() + } + } + if cfg.DMonReact.ChangeAvatar { + color.Green("[%v] Loading Avatars..", time.Now().Format("15:04:05")) + ex, err := os.Executable() + if err != nil { + color.Red("Couldn't find Exe") + utilities.ExitSafely() + } + ex = filepath.ToSlash(ex) + path := path.Join(path.Dir(ex) + "/input/pfps") + + images, err := instance.GetFiles(path) + if err != nil { + color.Red("Couldn't find images in PFPs folder") + utilities.ExitSafely() + } + color.Green("%v files found", len(images)) + if len(images) == 0 { + cfg.DMonReact.ChangeAvatar = false + color.Red("[%v][!] No images found in PFPs folder - Disabling avatar change", time.Now().Format("15:04:05")) + } else { + for i := 0; i < len(images); i++ { + av, err := instance.EncodeImg(images[i]) + if err != nil { + color.Red("Couldn't encode image") + continue + } + avatars = append(avatars, av) + } + color.Green("%v avatars loaded", len(avatars)) + } + } + if cfg.DMonReact.ChangeName { + names, err = utilities.ReadLines("names.txt") + if err != nil { + color.Red("Error while reading names.txt: %s", err) + utilities.ExitSafely() + } + if len(names) == 0 { + cfg.DMonReact.ChangeName = false + color.Red("[%v][!] No names found in names.txt - Disabling name change", time.Now().Format("15:04:05")) + } + } + if cfg.DMonReact.ChangeName { + for i := 0; i < len(instances); i++ { + if instances[i].Password == "" { + cfg.DMonReact.ChangeName = false + color.Red("[%v][!] Token %v has no password, perhaps using the wrong format. Need to use email:password:token to use the name changer", time.Now().Format("15:04:05"), instances[i].Token) + break + } + } + } + if cfg.ProxySettings.ProxyFromFile { + proxies, err = utilities.ReadLines("proxies.txt") + if len(proxies) == 0 { + cfg.ProxySettings.ProxyFromFile = false + color.Red("[%v][!] No proxies found in proxies.txt - Disabling proxy usage", time.Now().Format("15:04:05")) + } + } + if cfg.CaptchaSettings.ClientKey == "" { + color.Red("[%v][!] You're not using a Captcha key, if anytime the token is met with a captcha, it will be switched.") + } + tokenPool := make(chan instance.Instance, len(instances)) + for i := 0; i < len(instances); i++ { + go func(i int) { + if instances[i].Token != cfg.DMonReact.Observer { + tokenPool <- instances[i] + } else { + color.Red("[%v][!] Skipping Observer token %v", time.Now().Format("15:04:05"), instances[i].Token) + } + }(i) + } + + // All files and variables loaded and errors handled. + color.Green("[%v][O] Initializing Observer token [%v]", time.Now().Format("15:04:05"), cfg.DMonReact.Observer) + var observerInstance instance.Instance + observerInstance.Token = cfg.DMonReact.Observer + var proxy string + if cfg.ProxySettings.ProxyFromFile { + proxy = proxies[rand.Intn(len(proxies))] + observerInstance.Proxy = proxy + if !cfg.ProxySettings.GatewayProxy { + proxy = "" + } + observerInstance.GatewayProxy = proxy + } + client, err := instance.InitClient(proxy, cfg) + if err != nil { + color.Red("[%v][!] Error while initializing client: %s Using Default client for listener token", time.Now().Format("15:04:05"), err) + client = http.DefaultClient + } + observerInstance.Client = client + observerInstance.Config = cfg + if cfg.DMonReact.ServerID != "" { + r, err := observerInstance.ServerCheck(cfg.DMonReact.ServerID) + if err != nil { + color.Red("[%v][!] Error while checking server: %s", time.Now().Format("15:04:05"), err) + } else { + if r != 200 && r != 204 { + // Token not in server or some other issue like rate limit + err := observerInstance.Invite(cfg.DMonReact.Invite) + if err != nil { + color.Red("[%v][!] Error while inviting to server: %s", time.Now().Format("15:04:05"), err) + } else { + color.Green("[%v][O] Successfully invited to server", time.Now().Format("15:04:05")) + } + + } + } + r, err = observerInstance.ServerCheck(cfg.DMonReact.ServerID) + if err != nil { + color.Red("[%v][!] Error while checking server: %s", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } else { + if r != 200 && r != 204 { + color.Red("[%v][!] Error while joining server: %v - If you meant to listen to reactions globally, make serverid an empty string", time.Now().Format("15:04:05"), r) + // Token was tried to be invited after it was found that it might not be in the server. And after checking again the listener token may still not be present + utilities.ExitSafely() + } + } + + } + color.Green("[%v][O] Successfully initialized Observer token [%v]", time.Now().Format("15:04:05"), cfg.DMonReact.Observer) + // Start Listening for reactions. + ticker := make(chan bool) + kill := make(chan bool) + filteredReacts := make(chan string, 10000) + + go func() { + for { + time.Sleep(5 * time.Minute) + ticker <- true + } + }() + go func() { + Listener: + for { + if observerInstance.Ws != nil { + if observerInstance.Ws.Conn != nil { + select { + case <-ticker: + // Closing websocket and re-opening it. + if observerInstance.Ws.Conn != nil { + observerInstance.Ws.Close() + } + if observerInstance.Ws != nil { + observerInstance.Ws = nil + } + color.Yellow("[%v][O] Disconnected Observer token to reconnect", time.Now().Format("15:04:05")) + case x := <-observerInstance.Ws.Reactions: + var event instance.Event + err := json.Unmarshal(x, &event) + if err != nil { + color.Red("[%v][!] Error while unmarshalling event: %s", time.Now().Format("15:04:05"), err) + continue Listener + } + color.Cyan("[%v][O] Event received: %v reacted [%v|%v|%v|%v]", time.Now().Format("15:04:05"), event.Data.UserID, event.Data.GuildId, event.Data.MessageID, event.Data.ChannelID, event.Data.Emoji.Name) + if cfg.DMonReact.MaxAntiRaidQueue > 0 { + if len(filteredReacts) >= cfg.DMonReact.MaxAntiRaidQueue { + color.Red("[%v][!] Anti-Raid queue is full, skipping this reaction [%v]", time.Now().Format("15:04:05"), event.Data.UserID) + continue Listener + } + } + if cfg.DMonReact.SkipCompleted { + if utilities.Contains(completed, event.Data.UserID) { + color.Cyan("[%v][O] Skipping completed user [%v]", time.Now().Format("15:04:05"), event.Data.UserID) + continue Listener + } + } + if cfg.DMonReact.SkipFailed { + if utilities.Contains(failed, event.Data.UserID) { + color.Cyan("[%v][O] Skipping failed user [%v]", time.Now().Format("15:04:05"), event.Data.UserID) + continue Listener + } + } + if cfg.DMonReact.ServerID != "" { + if event.Data.GuildId != cfg.DMonReact.ServerID { + color.Cyan("[%v][O] Skipping event from other server [%v]", time.Now().Format("15:04:05"), event.Data.GuildId) + continue Listener + } + } + if cfg.DMonReact.ChannelID != "" { + if event.Data.ChannelID != cfg.DMonReact.ChannelID { + color.Cyan("[%v][O] Skipping event from other channel [%v]", time.Now().Format("15:04:05"), event.Data.ChannelID) + continue Listener + } + } + if cfg.DMonReact.MessageID != "" { + if event.Data.MessageID != cfg.DMonReact.MessageID { + color.Cyan("[%v][O] Skipping event from other message [%v]", time.Now().Format("15:04:05"), event.Data.MessageID) + continue Listener + } + } + if cfg.DMonReact.Emoji != "" { + if event.Data.Emoji.Name != cfg.DMonReact.Emoji || fmt.Sprintf(`%v:%v`, event.Data.Emoji.Name, event.Data.Emoji.ID) != cfg.DMonReact.Emoji { + color.Cyan("[%v][O] Skipping event from other emoji [%v]", time.Now().Format("15:04:05"), event.Data.Emoji.Name) + continue Listener + } + } + // React is approved + go func() { + filteredReacts <- event.Data.UserID + }() + continue Listener + case <-kill: + break Listener + } + + } else { + err := observerInstance.StartWS() + if err != nil { + color.Red("[%v][!] Error while starting observer websocket: %s", time.Now().Format("15:04:05"), err) + time.Sleep(10 * time.Second) + continue Listener + } + if cfg.DMonReact.ServerID != "" && observerInstance.Ws != nil { + err := instance.Subscribe(observerInstance.Ws,cfg.DMonReact.ServerID) + if err != nil { + color.Red("[%v][!] Error while subscribing to server: %s", time.Now().Format("15:04:05"), err) + time.Sleep(10 * time.Second) + continue Listener + } + + } + color.Yellow("[%v][O] Reconnected Observer token", time.Now().Format("15:04:05")) + continue Listener + } + } else { + // Opening Websocket + err := observerInstance.StartWS() + if err != nil { + color.Red("[%v][!] Error while starting observer websocket: %s", time.Now().Format("15:04:05"), err) + time.Sleep(10 * time.Second) + continue Listener + } + if cfg.DMonReact.ServerID != "" && observerInstance.Ws != nil { + err := instance.Subscribe(observerInstance.Ws,cfg.DMonReact.ServerID) + if err != nil { + color.Red("[%v][!] Error while subscribing to server: %s", time.Now().Format("15:04:05"), err) + time.Sleep(10 * time.Second) + continue Listener + } + + } + color.Yellow("[%v][O] Reconnected Observer token", time.Now().Format("15:04:05")) + continue Listener + } + } + color.Red("[%v][O] Permanently disconnected Observer token", time.Now().Format("15:04:05")) + }() + // Starting token +Token: + for { + if len(tokenPool) == 0 { + color.Red("[%v][!] No more tokens available, exiting", time.Now().Format("15:04:05")) + kill <- true + break Token + } + instance := <-tokenPool + color.Yellow("[%v][X] Starting token %v", time.Now().Format("15:04:05"), instance.Token) + React: + for { + status := instance.CheckToken() + if status != 200 { + color.Red("[%v][!] Token %v may be invalid [%v], skipping!", time.Now().Format("15:04:05"), instance.Token, status) + continue Token + } + if cfg.DMonReact.Invite != "" && !instance.Invited { + err := instance.Invite(cfg.DMonReact.Invite) + if err != nil { + color.Red("[%v][!] Error while inviting Token %v: %v Switching!", time.Now().Format("15:04:05"), instance.Token, err) + continue Token + } + instance.Invited = true + } + if instance.Cookie == "" { + cookie, err := instance.GetCookieString() + if err != nil { + color.Red("[%v][!] Error while getting cookie for Token %v: %v Switching!", time.Now().Format("15:04:05"), instance.Token, err) + if cfg.DMonReact.RotateTokens { + go func() { + tokenPool <- instance + }() + } + continue Token + } + instance.Cookie = cookie + } + if (cfg.DMonReact.ChangeAvatar && !instance.ChangedAvatar) || (cfg.DMonReact.ChangeName && !instance.ChangedName) { + // Opening Websocket to change name/avatar + err := instance.StartWS() + if err != nil { + color.Red("[%v][X] Error while opening websocket %v: %v", time.Now().Format("15:04:05"), instance.Token, err) + if cfg.DMonReact.RotateTokens { + go func() { + tokenPool <- instance + }() + } + continue Token + } else { + color.Green("[%v][X] Websocket opened %v", time.Now().Format("15:04:05"), instance.Token) + } + if cfg.DMonReact.ChangeAvatar && !instance.ChangedAvatar { + + r, err := instance.AvatarChanger(avatars[rand.Intn(len(avatars))]) + if err != nil { + color.Red("[%v][X] %v Error while changing avatar: %v", time.Now().Format("15:04:05"), instance.Token, err) + if cfg.DMonReact.RotateTokens { + go func() { + tokenPool <- instance + }() + } + continue Token + } else { + if r.StatusCode == 204 || r.StatusCode == 200 { + color.Green("[%v][X] %v Avatar changed successfully", time.Now().Format("15:04:05"), instance.Token) + instance.ChangedAvatar = true + } else { + color.Red("[%v][X] %v Error while changing avatar: %v", time.Now().Format("15:04:05"), instance.Token, r.StatusCode) + if cfg.DMonReact.RotateTokens { + go func() { + tokenPool <- instance + }() + } + continue Token + } + } + + } + if cfg.DMonReact.ChangeName && !instance.ChangedName { + r, err := instance.NameChanger(names[rand.Intn(len(names))]) + if err != nil { + color.Red("[%v]][X] %v Error while changing name: %v", time.Now().Format("15:04:05"), instance.Token, err) + if cfg.DMonReact.RotateTokens { + go func() { + tokenPool <- instance + }() + } + continue Token + } + body, err := utilities.ReadBody(r) + if err != nil { + fmt.Println(err) + if cfg.DMonReact.RotateTokens { + go func() { + tokenPool <- instance + }() + } + continue Token + } + if r.StatusCode == 200 || r.StatusCode == 204 { + color.Green("[%v][X] %v Changed name successfully", time.Now().Format("15:04:05"), instance.Token) + instance.ChangedName = true + } else { + color.Red("[%v][X] %v Error while changing name: %v %v", time.Now().Format("15:04:05"), instance.Token, r.Status, string(body)) + if cfg.DMonReact.RotateTokens { + go func() { + tokenPool <- instance + }() + } + continue Token + } + } + // Closing websocket + if instance.Ws != nil { + err = instance.Ws.Close() + if err != nil { + color.Red("[%v][X] Error while closing websocket: %v", time.Now().Format("15:04:05"), err) + } else { + color.Green("[%v][X] Websocket closed %v", time.Now().Format("15:04:05"), instance.Token) + } + } + } + if cfg.DMonReact.ServerID != "" && (instance.TimeServerCheck.Second() >= 120 || instance.TimeServerCheck.IsZero()) { + r, err := instance.ServerCheck(cfg.DMonReact.ServerID) + if err != nil { + color.Red("[%v][!] Error while checking if token %v is present in server %v: %v Switching!", time.Now().Format("15:04:05"), instance.Token, cfg.DMonReact.ServerID, err) + continue Token + } else { + if r != 200 && r != 204 { + color.Red("[%v][!] Token %v is not present in server %v: %v Switching!", time.Now().Format("15:04:05"), instance.Token, cfg.DMonReact.ServerID, err) + continue Token + } + } + instance.TimeServerCheck = time.Now() + } + ticker := make(chan bool) + go func() { + for { + time.Sleep(180 * time.Second) + ticker <- true + } + }() + select { + case uuid := <-filteredReacts: + instance.Count++ + if cfg.DMonReact.MaxDMsPerToken != 0 && instance.Count >= cfg.DMonReact.MaxDMsPerToken { + color.Red("[%v] %v Max DMs reached, switching token", time.Now().Format("15:04:05"), instance.Token) + continue Token + } + t := time.Now() + snowflake, err := instance.OpenChannel(uuid) + if err != nil { + color.Red("[%v] Error while opening channel: %v", time.Now().Format("15:04:05"), err) + err = utilities.WriteLine("input/failed.txt", uuid) + if err != nil { + fmt.Println(err) + } + failed = append(failed, uuid) + continue React + } + resp, err := instance.SendMessage(snowflake, uuid) + if err != nil { + color.Red("[%v] Error while sending message: %v", time.Now().Format("15:04:05"), err) + err = utilities.WriteLine("input/failed.txt", uuid) + if err != nil { + fmt.Println(err) + } + failed = append(failed, uuid) + continue React + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + color.Red("[%v] Error while reading body: %v", time.Now().Format("15:04:05"), err) + err = utilities.WriteLine("input/failed.txt", uuid) + if err != nil { + fmt.Println(err) + } + failed = append(failed, uuid) + continue React + } + var response jsonResponse + err = json.Unmarshal(body, &response) + if err != nil { + color.Red("[%v] Error while unmarshalling body: %v", time.Now().Format("15:04:05"), err) + err = utilities.WriteLine("input/failed.txt", uuid) + if err != nil { + fmt.Println(err) + } + failed = append(failed, uuid) + continue React + } + if resp.StatusCode == 200 { + color.Green("[%v][X] Token %v DM'd %v [%vms]", time.Now().Format("15:04:05"), instance.Token, uuid, time.Since(t).Milliseconds()) + completed = append(completed, uuid) + err = utilities.WriteLine("input/completed.txt", uuid) + if err != nil { + fmt.Println(err) + } + continue React + } else if resp.StatusCode == 403 && response.Code == 40003 { + // Token is rate limited + go func() { + filteredReacts <- uuid + }() + if cfg.DMonReact.LeaveTokenOnRateLimit && cfg.DMonReact.ServerID != "" { + re := instance.Leave(cfg.DMonReact.ServerID) + if re == 200 || re == 204 { + color.Green("[%v][!] Token %v left server %v", time.Now().Format("15:04:05"), instance.Token, cfg.DMonReact.ServerID) + } else { + color.Red("[%v][!] Error while leaving server %v: %v", time.Now().Format("15:04:05"), cfg.DMonReact.ServerID, re) + } + } + if cfg.DMonReact.RotateTokens { + go func() { + tokenPool <- instance + }() + } + continue Token + } else if resp.StatusCode == 403 && response.Code == 50007 { + failed = append(failed, uuid) + err = utilities.WriteLine("input/failed.txt", uuid) + if err != nil { + fmt.Println(err) + } + color.Red("[%v][X] Token %v failed to DM %v [DMs Closed or No mutual servers] [%vms]", time.Now().Format("15:04:05"), instance.Token, uuid, time.Since(t).Milliseconds()) + continue React + } else if resp.StatusCode == 403 && response.Code == 40002 || resp.StatusCode == 401 || resp.StatusCode == 405 { + failed = append(failed, uuid) + err = utilities.WriteLine("input/failed.txt", uuid) + if err != nil { + fmt.Println(err) + } + color.Red("[%v][X] Token %v failed to DM %v [Locked/Disabled][%vms]", time.Now().Format("15:04:05"), instance.Token, uuid, time.Since(t).Milliseconds()) + continue React + } else if resp.StatusCode == 429 { + failed = append(failed, uuid) + err = utilities.WriteLine("input/failed.txt", uuid) + if err != nil { + fmt.Println(err) + } + color.Red("[%v][X] Token %v failed to DM %v [Rate Limited][%vms]", time.Now().Format("15:04:05"), instance.Token, uuid, time.Since(t).Milliseconds()) + time.Sleep(5 * time.Second) + continue React + } else { + failed = append(failed, uuid) + err = utilities.WriteLine("input/failed.txt", uuid) + if err != nil { + fmt.Println(err) + } + color.Red("[%v][X] Token %v failed to DM %v [%v][%vms]", time.Now().Format("15:04:05"), instance.Token, uuid, string(body), time.Since(t).Milliseconds()) + continue React + } + case <-ticker: + color.Yellow("[%v][X] %v Refreshing token", time.Now().Format("15:04:05"), instance.Token) + continue React + } + } + } +} diff --git a/discord/get_message.go b/discord/get_message.go new file mode 100644 index 00000000..9c1042b --- /dev/null +++ b/discord/get_message.go @@ -0,0 +1,37 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package discord + +import ( + "fmt" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/instance" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" +) + +func LaunchGetMessage() { + // Uses ?around & ?limit parameters to discord's REST API to get messages to get the exact message needed + color.Cyan("Get Message - This will get the message from Discord which you want to send.") + color.White("Enter your token: \n") + var token string + fmt.Scanln(&token) + color.White("Enter the channelID: \n") + var channelID string + fmt.Scanln(&channelID) + color.White("Enter the messageID: \n") + var messageID string + fmt.Scanln(&messageID) + message, err := instance.FindMessage(channelID, messageID, token) + if err != nil { + color.Red("Error while finding message: %v", err) + utilities.ExitSafely() + return + } + color.Green("[%v] Message: %v", time.Now().Format("15:04:05"), message) +} diff --git a/discord/guild_leaver.go b/discord/guild_leaver.go new file mode 100644 index 00000000..593b0b9 --- /dev/null +++ b/discord/guild_leaver.go @@ -0,0 +1,62 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package discord + +import ( + "fmt" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/instance" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" + "github.com/zenthangplus/goccm" +) + +func LaunchGuildLeaver() { + color.Cyan("Guild Leaver") + cfg, instances, err := instance.GetEverything() + if err != nil { + color.Red("Error while getting necessary data %v", err) + utilities.ExitSafely() + + } + color.White("Enter the number of threads (0 for unlimited): ") + var threads int + fmt.Scanln(&threads) + if threads > len(instances) { + threads = len(instances) + } + if threads == 0 { + threads = len(instances) + } + color.White("Enter delay between leaves: ") + var delay int + fmt.Scanln(&delay) + color.White("Enter serverid: ") + var serverid string + fmt.Scanln(&serverid) + c := goccm.New(threads) + for i := 0; i < len(instances); i++ { + time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) + c.Wait() + go func(i int) { + p := instances[i].Leave(serverid) + if p == 0 { + color.Red("[%v] Error while leaving", time.Now().Format("15:04:05")) + } + if p == 200 || p == 204 { + color.Green("[%v] Left server", time.Now().Format("15:04:05")) + } else { + color.Red("[%v] Error while leaving", time.Now().Format("15:04:05")) + } + time.Sleep(time.Duration(delay) * time.Second) + c.Done() + }(i) + } + c.WaitAllDone() + color.Green("[%v] All threads finished", time.Now().Format("15:04:05")) +} diff --git a/discord/invite_joiner.go b/discord/invite_joiner.go new file mode 100644 index 00000000..e88386c --- /dev/null +++ b/discord/invite_joiner.go @@ -0,0 +1,132 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package discord + +import ( + "fmt" + "math/rand" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/instance" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" + "github.com/zenthangplus/goccm" +) + +func LaunchinviteJoiner() { + var invitechoice int + color.White("Invite Menu:\n1) Single Invite\n2) Multiple Invites from file") + fmt.Scanln(&invitechoice) + if invitechoice != 1 && invitechoice != 2 { + color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) + utilities.ExitSafely() + return + } + switch invitechoice { + case 1: + color.Cyan("Single Invite Mode") + color.White("This will join your tokens from tokens.txt to a server") + _, instances, err := instance.GetEverything() + if err != nil { + color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) + } + color.White("[%v] Enter your invite CODE (The part after discord.gg/): ", time.Now().Format("15:04:05")) + var invite string + fmt.Scanln(&invite) + color.White("[%v] Enter number of Threads (0: Unlimited Threads. 1: For using proper delay. It may be a good idea to use less threads if you're looking to solve captchas): ", time.Now().Format("15:04:05")) + var threads int + fmt.Scanln(&threads) + + if threads > len(instances) { + threads = len(instances) + } + if threads == 0 { + threads = len(instances) + } + + color.White("[%v] Enter base delay for joining in seconds (0 for none)", time.Now().Format("15:04:05")) + var base int + fmt.Scanln(&base) + color.White("[%v] Enter random delay to be added upon base delay (0 for none)", time.Now().Format("15:04:05")) + var random int + fmt.Scanln(&random) + var delay int + if random > 0 { + delay = base + rand.Intn(random) + } else { + delay = base + } + c := goccm.New(threads) + for i := 0; i < len(instances); i++ { + c.Wait() + go func(i int) { + err := instances[i].Invite(invite) + if err != nil { + color.Red("[%v] Error while joining: %v", time.Now().Format("15:04:05"), err) + } + time.Sleep(time.Duration(delay) * time.Second) + c.Done() + + }(i) + } + c.WaitAllDone() + color.Green("[%v] All threads finished", time.Now().Format("15:04:05")) + + case 2: + color.Cyan("Multiple Invite Mode") + color.White("This will join your tokens from tokens.txt to servers from invite.txt") + cfg, instances, err := instance.GetEverything() + if err != nil { + color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) + } + + if len(instances) == 0 { + color.Red("[%v] Enter your tokens in tokens.txt", time.Now().Format("15:04:05")) + utilities.ExitSafely() + } + invites, err := utilities.ReadLines("invite.txt") + if err != nil { + color.Red("Error while opening invite.txt: %v", err) + utilities.ExitSafely() + return + } + if len(invites) == 0 { + color.Red("[%v] Enter your invites in invite.txt", time.Now().Format("15:04:05")) + utilities.ExitSafely() + return + } + color.White("Enter delay between 2 consecutive joins by 1 token in seconds: ") + var delay int + fmt.Scanln(&delay) + color.White("Enter number of Threads (0 for unlimited): ") + var threads int + fmt.Scanln(&threads) + if threads > len(instances) { + threads = len(instances) + } + if threads == 0 { + threads = len(instances) + } + c := goccm.New(threads) + for i := 0; i < len(instances); i++ { + time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) + c.Wait() + go func(i int) { + for j := 0; j < len(invites); j++ { + err := instances[i].Invite(invites[j]) + if err != nil { + color.Red("[%v] Error while joining: %v", time.Now().Format("15:04:05"), err) + } + time.Sleep(time.Duration(delay) * time.Second) + } + c.Done() + }(i) + } + c.WaitAllDone() + color.Green("[%v] All threads finished", time.Now().Format("15:04:05")) + } +} diff --git a/discord/mass_dm.go b/discord/mass_dm.go new file mode 100644 index 00000000..10fc739 --- /dev/null +++ b/discord/mass_dm.go @@ -0,0 +1,649 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package discord + +import ( + "bufio" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "math/rand" + "os" + "os/exec" + "strconv" + "strings" + "sync" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/instance" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" +) + +func LaunchMassDM() { + + color.Cyan("Mass DM Advertiser/Spammer") + color.White("This will DM everyone in memberids.txt from your tokens") + members, err := utilities.ReadLines("memberids.txt") + if err != nil { + color.Red("Error while opening memberids.txt: %v", err) + utilities.ExitSafely() + } + cfg, instances, err := instance.GetEverything() + if err != nil { + color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) + } + var msg instance.Message + color.White("Press 1 to use messages from file or press 2 to enter a message: ") + var messagechoice int + fmt.Scanln(&messagechoice) + if messagechoice != 1 && messagechoice != 2 { + color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) + utilities.ExitSafely() + } + if messagechoice == 2 { + color.White("Enter your message, use \\n for changing lines. You can also set a constant message in message.json") + scanner := bufio.NewScanner(os.Stdin) + var text string + if scanner.Scan() { + text = scanner.Text() + } + + msg.Content = text + msg.Content = strings.Replace(msg.Content, "\\n", "\n", -1) + var msgs []instance.Message + msgs = append(msgs, msg) + err := instance.SetMessages(instances, msgs) + if err != nil { + color.Red("[%v] Error while setting messages: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + } else { + var msgs []instance.Message + err := instance.SetMessages(instances, msgs) + if err != nil { + color.Red("[%v] Error while setting messages: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + } + color.White("[%v] Do you wish to use Advanced Settings? 0: No, 1: Yes: ", time.Now().Format("15:04:05")) + var advancedchoice int + var checkchoice int + var serverid string + var tryjoinchoice int + var invite string + var maxattempts int + fmt.Scanln(&advancedchoice) + if advancedchoice != 0 && advancedchoice != 1 { + color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) + utilities.ExitSafely() + } + if advancedchoice == 1 { + color.White("[%v] Do you wish to check if token is still in server before every DM? [0: No, 1: Yes]", time.Now().Format("15:04:05")) + fmt.Scanln(&checkchoice) + if checkchoice != 0 && checkchoice != 1 { + color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) + utilities.ExitSafely() + } + if checkchoice == 1 { + color.White("[%v] Enter Server ID", time.Now().Format("15:04:05")) + fmt.Scanln(&serverid) + color.White("[%v] Do you wish to try rejoining the server if token is not in server? [0: No, 1: Yes]", time.Now().Format("15:04:05")) + fmt.Scanln(&tryjoinchoice) + if tryjoinchoice != 0 && tryjoinchoice != 1 { + color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) + utilities.ExitSafely() + } + if tryjoinchoice == 1 { + color.White("[%v] Enter a permanent invite code", time.Now().Format("15:04:05")) + fmt.Scanln(&invite) + color.White("[%v] Enter max rejoin attempts", time.Now().Format("15:04:05")) + fmt.Scanln(&maxattempts) + } + } + } + // Also initiate variables and slices for logging and counting + var session []string + var completed []string + var failed []string + var dead []string + var failedCount = 0 + completed, err = utilities.ReadLines("completed.txt") + if err != nil { + color.Red("Error while opening completed.txt: %v", err) + utilities.ExitSafely() + } + if cfg.DirectMessage.Skip { + members = utilities.RemoveSubset(members, completed) + } + if cfg.DirectMessage.SkipFailed { + failedSkip, err := utilities.ReadLines("failed.txt") + if err != nil { + color.Red("Error while opening failed.txt: %v", err) + utilities.ExitSafely() + } + members = utilities.RemoveSubset(members, failedSkip) + } + if len(instances) == 0 { + color.Red("[%v] Enter your tokens in tokens.txt ", time.Now().Format("15:04:05")) + utilities.ExitSafely() + } + if len(members) == 0 { + color.Red("[%v] Enter your member ids in memberids.txt or ensure that all of them are not in completed.txt", time.Now().Format("15:04:05")) + utilities.ExitSafely() + } + if len(members) < len(instances) { + instances = instances[:len(members)] + } + msgs := instances[0].Messages + for i := 0; i < len(msgs); i++ { + if msgs[i].Content == "" && msgs[i].Embeds == nil { + color.Red("[%v] WARNING: Message %v is empty", time.Now().Format("15:04:05"), i) + } + } + // Send members to a channel + mem := make(chan string, len(members)) + go func() { + for i := 0; i < len(members); i++ { + mem <- members[i] + } + }() + // Setting information to windows titlebar by github.com/foxzsz + go func() { + for { + cmd := exec.Command("cmd", "/C", "title", fmt.Sprintf(`DMDGO [%d sent, %v failed, %d locked, %v avg. dms, %d tokens left]`, len(session), len(failed), len(dead), len(session)/len(instances), len(instances)-len(dead))) + _ = cmd.Run() + } + }() + var wg sync.WaitGroup + start := time.Now() + for i := 0; i < len(instances); i++ { + // Offset goroutines by a few milliseconds. Makes a big difference and allows for better concurrency + time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) + wg.Add(1) + go func(i int) { + defer wg.Done() + for { + // Get a member from the channel + if len(mem) == 0 { + break + } + member := <-mem + + // Breaking loop if maximum DMs reached + if cfg.DirectMessage.MaxDMS != 0 && instances[i].Count >= cfg.DirectMessage.MaxDMS { + color.Yellow("[%v] Maximum DMs reached for %v", time.Now().Format("15:04:05"), instances[i].Token) + break + } + // Start websocket connection if not already connected and reconnect if dead + if cfg.DirectMessage.Websocket && instances[i].Ws == nil { + err := instances[i].StartWS() + if err != nil { + color.Red("[%v] Error while opening websocket: %v", time.Now().Format("15:04:05"), err) + } else { + color.Green("[%v] Websocket opened %v", time.Now().Format("15:04:05"), instances[i].Token) + } + } + if cfg.DirectMessage.Websocket && cfg.DirectMessage.Receive && instances[i].Ws != nil && !instances[i].Receiver { + instances[i].Receiver = true + go func() { + for { + if !instances[i].Receiver { + break + } + mes := <-instances[i].Ws.Messages + if !strings.Contains(string(mes), "guild_id") { + var mar instance.Event + err := json.Unmarshal(mes, &mar) + if err != nil { + color.Red("[%v] Error while unmarshalling websocket message: %v", time.Now().Format("15:04:05"), err) + continue + } + if instances[i].ID == "" { + tokenPart := strings.Split(instances[i].Token, ".")[0] + dec, err := base64.StdEncoding.DecodeString(tokenPart) + if err != nil { + color.Red("[%v] Error while decoding token: %v", time.Now().Format("15:04:05"), err) + continue + } + instances[i].ID = string(dec) + } + if mar.Data.Author.ID == instances[i].ID { + continue + } + color.Green("[%v] %v#%v sent a message to %v : %v", time.Now().Format("15:04:05"), mar.Data.Author.Username, mar.Data.Author.Discriminator, instances[i].Token, mar.Data.Content) + newStr := "Username: " + mar.Data.Author.Username + "#" + mar.Data.Author.Discriminator + "\nID: " + mar.Data.Author.ID + "\n" + "Message: " + mar.Data.Content + "\n" + err = utilities.WriteLines("received.txt", newStr) + if err != nil { + color.Red("[%v] Error while opening received.txt: %v", time.Now().Format("15:04:05"), err) + } + } + } + }() + } + // Check if token is valid + status := instances[i].CheckToken() + if status != 200 && status != 204 && status != 429 && status != -1 { + failedCount++ + color.Red("[%v] Token %v might be locked - Stopping instance and adding members to failed list. %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, status, failedCount) + failed = append(failed, member) + dead = append(dead, instances[i].Token) + err := utilities.WriteLines("failed.txt", member) + if err != nil { + fmt.Println(err) + } + if cfg.DirectMessage.Stop { + break + } + } + // Advanced Options + if advancedchoice == 1 { + if checkchoice == 1 { + r, err := instances[i].ServerCheck(serverid) + if err != nil { + color.Red("[%v] Error while checking server: %v", time.Now().Format("15:04:05"), err) + continue + } + if r != 200 && r != 204 && r != 429 { + if tryjoinchoice == 0 { + color.Red("[%v] Stopping token %v [Not in server]", time.Now().Format("15:04:05"), instances[i].Token) + + break + } else { + if instances[i].Retry >= maxattempts { + color.Red("[%v] Stopping token %v [Max server rejoin attempts]", time.Now().Format("15:04:05"), instances[i].Token) + break + } + err := instances[i].Invite(invite) + if err != nil { + color.Red("[%v] Error while joining server: %v", time.Now().Format("15:04:05"), err) + instances[i].Retry++ + continue + } + } + } + } + } + var user string + user = member + // Check Mutual + if cfg.DirectMessage.Mutual { + info, err := instances[i].UserInfo(member) + if err != nil { + failedCount++ + color.Red("[%v] Error while getting user info: %v [%v]", time.Now().Format("15:04:05"), err, failedCount) + err = utilities.WriteLine("input/failed.txt", member) + if err != nil { + fmt.Println(err) + } + failed = append(failed, member) + + continue + } + if len(info.Mutual) == 0 { + failedCount++ + color.Red("[%v] Token %v failed to DM %v [No Mutual Server] [%v]", time.Now().Format("15:04:05"), instances[i].Token, info.User.Username+info.User.Discriminator, failedCount) + err = utilities.WriteLine("input/failed.txt", member) + if err != nil { + fmt.Println(err) + } + failed = append(failed, member) + continue + } + user = info.User.Username + "#" + info.User.Discriminator + // Used only if Websocket is enabled as Unwebsocketed Tokens get locked if they attempt to send friend requests. + if cfg.DirectMessage.Friend && cfg.DirectMessage.Websocket { + x, err := strconv.Atoi(info.User.Discriminator) + if err != nil { + color.Red("[%v] Error while adding friend: %v", time.Now().Format("15:04:05"), err) + continue + } + resp, err := instances[i].Friend(info.User.Username, x) + if err != nil { + color.Red("[%v] Error while adding friend: %v", time.Now().Format("15:04:05"), err) + continue + } + if resp.StatusCode != 204 && err != nil { + if !errors.Is(err, io.ErrUnexpectedEOF) { + body, err := utilities.ReadBody(*resp) + if err != nil { + color.Red("[%v] Error while adding friend: %v", time.Now().Format("15:04:05"), fmt.Sprintf("error reading body: %v", err)) + continue + } + color.Red("[%v] Error while adding friend: %v", time.Now().Format("15:04:05"), string(body)) + continue + } + color.Red("[%v] Error while adding friend: %v", time.Now().Format("15:04:05"), err) + continue + } else { + color.Green("[%v] Added friend %v", time.Now().Format("15:04:05"), info.User.Username+"#"+info.User.Discriminator) + } + } + } + // Open channel to get snowflake + snowflake, err := instances[i].OpenChannel(member) + if err != nil { + failedCount++ + color.Red("[%v] Error while opening DM channel: %v [%v]", time.Now().Format("15:04:05"), err, failedCount) + err = utilities.WriteLine("input/failed.txt", member) + if err != nil { + fmt.Println(err) + } + failed = append(failed, member) + continue + } + if cfg.SuspicionAvoidance.RandomDelayOpenChannel != 0 { + time.Sleep(time.Duration(rand.Intn(cfg.SuspicionAvoidance.RandomDelayOpenChannel)) * time.Second) + } + resp, err := instances[i].SendMessage(snowflake, member) + if err != nil { + failedCount++ + color.Red("[%v] Error while sending message: %v [%v]", time.Now().Format("15:04:05"), err, failedCount) + err = utilities.WriteLine("input/failed.txt", member) + if err != nil { + fmt.Println(err) + } + failed = append(failed, member) + continue + } + body, err := utilities.ReadBody(resp) + if err != nil { + failedCount++ + color.Red("[%v] Error while reading body: %v [%v]", time.Now().Format("15:04:05"), err, failedCount) + err = utilities.WriteLine("input/failed.txt", member) + if err != nil { + fmt.Println(err) + } + failed = append(failed, member) + continue + } + var response jsonResponse + errx := json.Unmarshal(body, &response) + if errx != nil { + failedCount++ + color.Red("[%v] Error while unmarshalling body: %v [%v]", time.Now().Format("15:04:05"), errx, failedCount) + err = utilities.WriteLine("input/failed.txt", member) + if err != nil { + fmt.Println(err) + } + failed = append(failed, member) + continue + } + // Everything is fine, continue as usual + if resp.StatusCode == 200 { + err = utilities.WriteLine("input/completed.txt", member) + if err != nil { + fmt.Println(err) + } + completed = append(completed, member) + session = append(session, member) + color.Green("[%v] Token %v sent DM to %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, user, len(session)) + if cfg.DirectMessage.Websocket && cfg.DirectMessage.Call && instances[i].Ws != nil { + err := instances[i].Call(snowflake) + if err != nil { + color.Red("[%v] %v Error while calling %v: %v", time.Now().Format("15:04:05"), instances[i].Token, user, err) + } + // Unfriended people can't ring. + // + // resp, err := instance.Ring(instances[i].Client, instances[i].Token, snowflake) + // if err != nil { + // color.Red("[%v] %v Error while ringing %v: %v", time.Now().Format("15:04:05"), instances[i].Token, user, err) + // } + // if resp == 200 || resp == 204 { + // color.Green("[%v] %v Ringed %v", time.Now().Format("15:04:05"), instances[i].Token, user) + // } else { + // color.Red("[%v] %v Error while ringing %v: %v", time.Now().Format("15:04:05"), instances[i].Token, user, resp) + // } + + } + if cfg.DirectMessage.Block { + r, err := instances[i].BlockUser(member) + if err != nil { + color.Red("[%v] Error while blocking user: %v", time.Now().Format("15:04:05"), err) + } else { + if r == 204 { + color.Green("[%v] Blocked %v", time.Now().Format("15:04:05"), user) + } else { + color.Red("[%v] Error while blocking user: %v", time.Now().Format("15:04:05"), r) + } + } + } + if cfg.DirectMessage.Close { + r, err := instances[i].CloseDMS(snowflake) + if err != nil { + color.Red("[%v] Error while closing DM: %v", time.Now().Format("15:04:05"), err) + } else { + if r == 200 { + color.Green("[%v] Succesfully closed DM %v", time.Now().Format("15:04:05"), user) + } else { + color.Red("[%v] Failed to close DM %v", time.Now().Format("15:04:05"), user) + } + } + } + // Forbidden - Token is being rate limited + } else if resp.StatusCode == 403 && response.Code == 40003 { + + err = utilities.WriteLine("input/failed.txt", member) + if err != nil { + fmt.Println(err) + } + mem <- member + color.Yellow("[%v] Token %v sleeping for %v minutes!", time.Now().Format("15:04:05"), instances[i].Token, int(cfg.DirectMessage.LongDelay/60)) + time.Sleep(time.Duration(cfg.DirectMessage.LongDelay) * time.Second) + if cfg.SuspicionAvoidance.RandomRateLimitDelay != 0 { + time.Sleep(time.Duration(rand.Intn(cfg.SuspicionAvoidance.RandomRateLimitDelay)) * time.Second) + } + color.Yellow("[%v] Token %v continuing!", time.Now().Format("15:04:05"), instances[i].Token) + // Forbidden - DM's are closed + } else if resp.StatusCode == 403 && response.Code == 50007 { + failedCount++ + failed = append(failed, member) + err = utilities.WriteLine("input/failed.txt", member) + if err != nil { + fmt.Println(err) + } + color.Red("[%v] Token %v failed to DM %v User has DMs closed or not present in server %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, user, string(body), failedCount) + // Forbidden - Locked or Disabled + } else if (resp.StatusCode == 403 && response.Code == 40002) || resp.StatusCode == 401 || resp.StatusCode == 405 { + failedCount++ + failed = append(failed, member) + err = utilities.WriteLine("input/failed.txt", member) + if err != nil { + fmt.Println(err) + } + color.Red("[%v] Token %v is locked or disabled. Stopping instance. %v %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, resp.StatusCode, string(body), failedCount) + dead = append(dead, instances[i].Token) + // Stop token if locked or disabled + if cfg.DirectMessage.Stop { + break + } + // Forbidden - Invalid token + } else if resp.StatusCode == 403 && response.Code == 50009 { + failedCount++ + failed = append(failed, member) + err = utilities.WriteLine("input/failed.txt", member) + if err != nil { + fmt.Println(err) + } + color.Red("[%v] Token %v can't DM %v. It may not have bypassed membership screening or it's verification level is too low or the server requires new members to wait 10 minutes before they can interact in the server. %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, user, string(body), failedCount) + // General case - Continue loop. If problem with instance, it will be stopped at start of loop. + } else if resp.StatusCode == 429 { + failed = append(failed, member) + color.Red("[%v] Token %v is being rate limited. Sleeping for 10 seconds", time.Now().Format("15:04:05"), instances[i].Token) + time.Sleep(10 * time.Second) + } else if resp.StatusCode == 400 && strings.Contains(string(body), "captcha") { + color.Red("[%v] Token %v Captcha was attempted to solve but appeared again", time.Now().Format("15:04:05"), instances[i].Token) + instances[i].Retry++ + if instances[i].Retry >= cfg.CaptchaSettings.MaxCaptcha { + color.Red("[%v] Stopping token %v max captcha solves reached", time.Now().Format("15:04:05"), instances[i].Token) + break + } + } else { + failedCount++ + failed = append(failed, member) + err = utilities.WriteLine("input/failed.txt", member) + if err != nil { + fmt.Println(err) + } + color.Red("[%v] Token %v couldn't DM %v Error Code: %v; Status: %v; Message: %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, user, response.Code, resp.Status, response.Message, failedCount) + } + time.Sleep(time.Duration(cfg.DirectMessage.Delay) * time.Second) + if cfg.SuspicionAvoidance.RandomIndividualDelay != 0 { + time.Sleep(time.Duration(rand.Intn(cfg.SuspicionAvoidance.RandomIndividualDelay)) * time.Second) + } + } + }(i) + } + wg.Wait() + + color.Green("[%v] Threads have finished! Writing to file", time.Now().Format("15:04:05")) + + elapsed := time.Since(start) + color.Green("[%v] DM advertisement took %v. Successfully sent DMs to %v IDs. Failed to send DMs to %v IDs. %v tokens are dis-functional & %v tokens are functioning", time.Now().Format("15:04:05"), elapsed.Seconds(), len(completed), len(failed), len(dead), len(instances)-len(dead)) + if cfg.DirectMessage.Remove { + var tokens []string + for i := 0; i < len(instances); i++ { + tokens = append(tokens, instances[i].Token) + } + m := utilities.RemoveSubset(tokens, dead) + err := utilities.Truncate("input/tokens.txt", m) + if err != nil { + fmt.Println(err) + } + color.Green("Updated tokens.txt") + } + if cfg.DirectMessage.RemoveM { + m := utilities.RemoveSubset(members, completed) + err := utilities.Truncate("input/memberids.txt", m) + if err != nil { + fmt.Println(err) + } + color.Green("Updated memberids.txt") + + } + if cfg.DirectMessage.Websocket { + for i := 0; i < len(instances); i++ { + if instances[i].Ws != nil { + instances[i].Ws.Close() + } + } + } + +} + +type jsonResponse struct { + Message string `json:"message"` + Code int `json:"code"` +} + +func LaunchSingleDM() { + color.Cyan("Single DM Spammer") + color.White("Enter 0 for one message; Enter 1 for continuous spam") + var choice int + fmt.Scanln(&choice) + cfg, instances, err := instance.GetEverything() + if err != nil { + fmt.Println(err) + utilities.ExitSafely() + } + var msg instance.Message + color.White("Press 1 to use message from file or press 2 to enter a message: ") + var messagechoice int + fmt.Scanln(&messagechoice) + if messagechoice != 1 && messagechoice != 2 { + color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) + utilities.ExitSafely() + } + if messagechoice == 2 { + color.White("Enter your message, use \\n for changing lines. To use an embed, put message in message.json: ") + scanner := bufio.NewScanner(os.Stdin) + var text string + if scanner.Scan() { + text = scanner.Text() + } + + msg.Content = text + msg.Content = strings.Replace(msg.Content, "\\n", "\n", -1) + var msgs []instance.Message + msgs = append(msgs, msg) + err := instance.SetMessages(instances, msgs) + if err != nil { + color.Red("[%v] Error while setting messages: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + } else { + var msgs []instance.Message + err := instance.SetMessages(instances, msgs) + if err != nil { + color.Red("[%v] Error while setting messages: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + } + + color.White("Ensure a common link and enter victim's ID: ") + var victim string + fmt.Scanln(&victim) + var wg sync.WaitGroup + wg.Add(len(instances)) + if choice == 0 { + for i := 0; i < len(instances); i++ { + time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) + + go func(i int) { + defer wg.Done() + snowflake, err := instances[i].OpenChannel(victim) + if err != nil { + fmt.Println(err) + } + resp, err := instances[i].SendMessage(snowflake, victim) + if err != nil { + fmt.Println(err) + } + body, err := utilities.ReadBody(resp) + if err != nil { + fmt.Println(err) + } + if resp.StatusCode == 200 { + color.Green("[%v] Token %v DM'd %v", time.Now().Format("15:04:05"), instances[i].Token, victim) + } else { + color.Red("[%v] Token %v failed to DM %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, victim, string(body)) + } + }(i) + } + wg.Wait() + } + if choice == 1 { + for i := 0; i < len(instances); i++ { + time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) + go func(i int) { + defer wg.Done() + + var c int + for { + snowflake, err := instances[i].OpenChannel(victim) + if err != nil { + fmt.Println(err) + } + resp, err := instances[i].SendMessage(snowflake, victim) + if err != nil { + fmt.Println(err) + } + if resp.StatusCode == 200 { + color.Green("[%v] Token %v DM'd %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, victim, c) + } else { + color.Red("[%v] Token %v failed to DM %v", time.Now().Format("15:04:05"), instances[i].Token, victim) + } + c++ + } + }(i) + wg.Wait() + } + } + color.Green("[%v] Threads have finished!", time.Now().Format("15:04:05")) +} diff --git a/discord/profile_changer.go b/discord/profile_changer.go new file mode 100644 index 00000000..7259015 --- /dev/null +++ b/discord/profile_changer.go @@ -0,0 +1,302 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package discord + +import ( + "bufio" + "fmt" + "math/rand" + "os" + "path" + "path/filepath" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/instance" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" + "github.com/zenthangplus/goccm" +) + +func LaunchNameChanger() { + color.Blue("Name Changer") + _, instances, err := instance.GetEverything() + if err != nil { + color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) + } + for i := 0; i < len(instances); i++ { + if instances[i].Password == "" { + color.Red("[%v] %v No password set. It may be wrongly formatted. Only supported format is email:pass:token", time.Now().Format("15:04:05"), instances[i].Token) + continue + } + } + color.Red("NOTE: Names are changed randomly from the file.") + users, err := utilities.ReadLines("names.txt") + if err != nil { + color.Red("[%v] Error while reading names.txt: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + color.Green("[%v] Enter number of threads: (0 for unlimited)", time.Now().Format("15:04:05")) + + var threads int + fmt.Scanln(&threads) + if threads > len(instances) || threads == 0 { + threads = len(instances) + } + + c := goccm.New(threads) + for i := 0; i < len(instances); i++ { + c.Wait() + go func(i int) { + err := instances[i].StartWS() + if err != nil { + color.Red("[%v] Error while opening websocket: %v", time.Now().Format("15:04:05"), err) + } else { + color.Green("[%v] Websocket opened %v", time.Now().Format("15:04:05"), instances[i].Token) + } + r, err := instances[i].NameChanger(users[rand.Intn(len(users))]) + if err != nil { + color.Red("[%v] %v Error while changing name: %v", time.Now().Format("15:04:05"), instances[i].Token, err) + return + } + body, err := utilities.ReadBody(r) + if err != nil { + fmt.Println(err) + } + if r.StatusCode == 200 || r.StatusCode == 204 { + color.Green("[%v] %v Changed name successfully", time.Now().Format("15:04:05"), instances[i].Token) + } else { + color.Red("[%v] %v Error while changing name: %v %v", time.Now().Format("15:04:05"), instances[i].Token, r.Status, string(body)) + } + err = instances[i].Ws.Close() + if err != nil { + color.Red("[%v] Error while closing websocket: %v", time.Now().Format("15:04:05"), err) + } else { + color.Green("[%v] Websocket closed %v", time.Now().Format("15:04:05"), instances[i].Token) + } + c.Done() + }(i) + } + c.WaitAllDone() + color.Green("[%v] All Done", time.Now().Format("15:04:05")) + +} + +func LaunchAvatarChanger() { + color.Blue("Profile Picture Changer") + _, instances, err := instance.GetEverything() + if err != nil { + color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) + } + color.Red("NOTE: Only PNG and JPEG/JPG supported. Profile Pictures are changed randomly from the folder. Use PNG format for faster results.") + color.White("Loading Avatars..") + ex, err := os.Executable() + if err != nil { + color.Red("Couldn't find Exe") + utilities.ExitSafely() + } + ex = filepath.ToSlash(ex) + path := path.Join(path.Dir(ex) + "/input/pfps") + + images, err := instance.GetFiles(path) + if err != nil { + color.Red("Couldn't find images in PFPs folder") + utilities.ExitSafely() + } + color.Green("%v files found", len(images)) + var avatars []string + + for i := 0; i < len(images); i++ { + av, err := instance.EncodeImg(images[i]) + if err != nil { + color.Red("Couldn't encode image") + continue + } + avatars = append(avatars, av) + } + color.Green("%v avatars loaded", len(avatars)) + color.Green("[%v] Enter number of threads: ", time.Now().Format("15:04:05")) + var threads int + fmt.Scanln(&threads) + if threads > len(instances) { + threads = len(instances) + } + + c := goccm.New(threads) + for i := 0; i < len(instances); i++ { + c.Wait() + go func(i int) { + err := instances[i].StartWS() + if err != nil { + color.Red("[%v] Error while opening websocket: %v", time.Now().Format("15:04:05"), err) + } else { + color.Green("[%v] Websocket opened %v", time.Now().Format("15:04:05"), instances[i].Token) + } + r, err := instances[i].AvatarChanger(avatars[rand.Intn(len(avatars))]) + if err != nil { + color.Red("[%v] %v Error while changing avatar: %v", time.Now().Format("15:04:05"), instances[i].Token, err) + } else { + if r.StatusCode == 204 || r.StatusCode == 200 { + color.Green("[%v] %v Avatar changed successfully", time.Now().Format("15:04:05"), instances[i].Token) + } else { + color.Red("[%v] %v Error while changing avatar: %v", time.Now().Format("15:04:05"), instances[i].Token, r.StatusCode) + } + } + err = instances[i].Ws.Close() + if err != nil { + color.Red("[%v] Error while closing websocket: %v", time.Now().Format("15:04:05"), err) + } else { + color.Green("[%v] Websocket closed %v", time.Now().Format("15:04:05"), instances[i].Token) + } + c.Done() + }(i) + } + c.WaitAllDone() + color.Green("[%v] All done", time.Now().Format("15:04:05")) +} + +func LaunchBioChanger() { + color.Blue("Bio changer") + bios, err := utilities.ReadLines("bios.txt") + if err != nil { + color.Red("[%v] Error while reading bios.txt: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + _, instances, err := instance.GetEverything() + if err != nil { + color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + bios = instance.ValidateBios(bios) + color.Green("[%v] Loaded %v bios, %v instances", time.Now().Format("15:04:05"), len(bios), len(instances)) + color.Green("[%v] Enter number of threads: (0 for unlimited)", time.Now().Format("15:04:05")) + var threads int + fmt.Scanln(&threads) + if threads > len(instances) || threads == 0 { + threads = len(instances) + } + c := goccm.New(threads) + for i := 0; i < len(instances); i++ { + c.Wait() + go func(i int) { + err := instances[i].StartWS() + if err != nil { + color.Red("[%v] Error while opening websocket: %v", time.Now().Format("15:04:05"), err) + } else { + color.Green("[%v] Websocket opened %v", time.Now().Format("15:04:05"), instances[i].Token) + } + err = instances[i].BioChanger(bios) + if err != nil { + color.Red("[%v] %v Error while changing bio: %v", time.Now().Format("15:04:05"), instances[i].Token, err) + } else { + color.Green("[%v] %v Bio changed successfully", time.Now().Format("15:04:05"), instances[i].Token) + } + err = instances[i].Ws.Close() + if err != nil { + color.Red("[%v] Error while closing websocket: %v", time.Now().Format("15:04:05"), err) + } else { + color.Green("[%v] Websocket closed %v", time.Now().Format("15:04:05"), instances[i].Token) + } + c.Done() + }(i) + } + c.WaitAllDone() +} + +func LaunchHypeSquadChanger() { + color.Blue("Hype squad changer") + _, instances, err := instance.GetEverything() + if err != nil { + color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + color.Green("[%v] Enter number of threads: (0 for unlimited)", time.Now().Format("15:04:05")) + var threads int + fmt.Scanln(&threads) + if threads > len(instances) || threads == 0 { + threads = len(instances) + } + c := goccm.New(threads) + for i := 0; i < len(instances); i++ { + c.Wait() + go func(i int) { + err := instances[i].RandomHypeSquadChanger() + if err != nil { + color.Red("[%v] %v Error while changing hype squad: %v", time.Now().Format("15:04:05"), instances[i].Token, err) + } else { + color.Green("[%v] %v Hype squad changed successfully", time.Now().Format("15:04:05"), instances[i].Token) + } + c.Done() + }(i) + } + c.WaitAllDone() + +} + +func LaunchTokenChanger() { + color.Blue("Token changer") + + _, instances, err := instance.GetEverything() + if err != nil { + color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) + } + for i := 0; i < len(instances); i++ { + if instances[i].Password == "" { + color.Red("[%v] %v No password set. It may be wrongly formatted. Only supported format is email:pass:token", time.Now().Format("15:04:05"), instances[i].Token) + continue + } + } + color.Green("[%v] Enter 0 to change passwords randomly and 1 to change them to a constant input", time.Now().Format("15:04:05")) + var mode int + fmt.Scanln(&mode) + if mode != 0 && mode != 1 { + color.Red("[%v] Invalid mode", time.Now().Format("15:04:05")) + utilities.ExitSafely() + } + var password string + if mode == 1 { + color.Green("[%v] Enter Password:", time.Now().Format("15:04:05")) + scanner := bufio.NewScanner(os.Stdin) + if scanner.Scan() { + password = scanner.Text() + } + } + color.Green("[%v] Enter number of threads: (0 for unlimited)", time.Now().Format("15:04:05")) + + var threads int + fmt.Scanln(&threads) + if threads > len(instances) || threads == 0 { + threads = len(instances) + } + + c := goccm.New(threads) + for i := 0; i < len(instances); i++ { + c.Wait() + go func(i int) { + if password == "" { + password = utilities.RandStringBytes(12) + } + newToken, err := instances[i].ChangeToken(password) + if err != nil { + color.Red("[%v] %v Error while changing token: %v", time.Now().Format("15:04:05"), instances[i].Token, err) + err := utilities.WriteLine("input/changed_tokens.txt", fmt.Sprintf(`%s:%s:%s`, instances[i].Email, instances[i].Password, instances[i].Token)) + if err != nil { + color.Red("[%v] Error while writing to file: %v", time.Now().Format("15:04:05"), err) + } + } else { + color.Green("[%v] %v Token changed successfully", time.Now().Format("15:04:05"), instances[i].Token) + err := utilities.WriteLine("input/changed_tokens.txt", fmt.Sprintf(`%s:%s:%s`, instances[i].Email, password, newToken)) + if err != nil { + color.Red("[%v] Error while writing to file: %v", time.Now().Format("15:04:05"), err) + } + } + c.Done() + }(i) + } + c.WaitAllDone() + color.Green("[%v] All Done", time.Now().Format("15:04:05")) + +} \ No newline at end of file diff --git a/discord/reaction_adder.go b/discord/reaction_adder.go new file mode 100644 index 00000000..5ba5219 --- /dev/null +++ b/discord/reaction_adder.go @@ -0,0 +1,103 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package discord + +import ( + "fmt" + "sync" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/instance" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" +) + +func LaunchReactionAdder() { + color.Cyan("Reaction Adder") + color.White("Note: You don't need to do this to send DMs in servers.") + color.White("Menu:\n1) From message\n2) Manually") + var choice int + fmt.Scanln(&choice) + cfg, instances, err := instance.GetEverything() + if err != nil { + fmt.Println(err) + utilities.ExitSafely() + } + var wg sync.WaitGroup + wg.Add(len(instances)) + if choice == 1 { + color.Cyan("Enter a token which can see the message:") + var token string + fmt.Scanln(&token) + color.White("Enter message ID: ") + var id string + fmt.Scanln(&id) + color.White("Enter channel ID: ") + var channel string + fmt.Scanln(&channel) + msg, err := instance.GetRxn(channel, id, token) + if err != nil { + fmt.Println(err) + } + color.White("Select Emoji") + for i := 0; i < len(msg.Reactions); i++ { + color.White("%v) %v %v", i, msg.Reactions[i].Emojis.Name, msg.Reactions[i].Count) + } + var emoji int + var send string + fmt.Scanln(&emoji) + for i := 0; i < len(instances); i++ { + time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) + go func(i int) { + defer wg.Done() + if msg.Reactions[emoji].Emojis.ID == "" { + send = msg.Reactions[emoji].Emojis.Name + + } else if msg.Reactions[emoji].Emojis.ID != "" { + send = msg.Reactions[emoji].Emojis.Name + ":" + msg.Reactions[emoji].Emojis.ID + } + err := instances[i].React(channel, id, send) + if err != nil { + fmt.Println(err) + color.Red("[%v] %v failed to react", time.Now().Format("15:04:05"), instances[i].Token) + } else { + color.Green("[%v] %v reacted to the emoji", time.Now().Format("15:04:05"), instances[i].Token) + } + + }(i) + } + wg.Wait() + color.Green("[%v] Completed all threads.", time.Now().Format("15:04:05")) + } + if choice == 2 { + color.Cyan("Enter channel ID") + var channel string + fmt.Scanln(&channel) + color.White("Enter message ID") + var id string + fmt.Scanln(&id) + color.Red("If you have a message, please use choice 1. If you want to add a custom emoji. Follow these instructions, if you don't, it won't work.\n If it's a default emoji which appears on the emoji keyboard, just copy it as TEXT not how it appears on Discord with the colons. Type it as text, it might look like 2 question marks on console but ignore.\n If it's a custom emoji (Nitro emoji) type it like this -> name:emojiID To get the emoji ID, copy the emoji link and copy the emoji ID from the URL.\nIf you do not follow this, it will not work. Don't try to do impossible things like trying to START a nitro reaction with a non-nitro account.") + color.White("Enter emoji") + var emoji string + fmt.Scanln(&emoji) + for i := 0; i < len(instances); i++ { + time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) + go func(i int) { + defer wg.Done() + err := instances[i].React(channel, id, emoji) + if err != nil { + fmt.Println(err) + color.Red("[%v] %v failed to react", time.Now().Format("15:04:05"), instances[i].Token) + } + color.Green("[%v] %v reacted to the emoji", time.Now().Format("15:04:05"), instances[i].Token) + }(i) + } + wg.Wait() + color.Green("[%v] Completed all threads.", time.Now().Format("15:04:05")) + } + +} diff --git a/discord/scraper.go b/discord/scraper.go new file mode 100644 index 00000000..50b9263 --- /dev/null +++ b/discord/scraper.go @@ -0,0 +1,374 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package discord + +import ( + "bufio" + "encoding/json" + "fmt" + "os" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/instance" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" +) + +func LaunchScraperMenu() { + color.Blue("Scraping Menu") + cfg, _, err := instance.GetEverything() + if err != nil { + color.Red("Error while getting necessary data %v", err) + } + color.White("1) Online Scraper (Opcode 14)\n2) Scrape from Reactions\n3) Offline Scraper (Opcode 8)") + var options int + fmt.Scanln(&options) + if options == 1 { + var token string + color.White("Enter token: ") + fmt.Scanln(&token) + var serverid string + color.White("Enter serverid: ") + fmt.Scanln(&serverid) + var channelid string + color.White("Enter channelid: ") + fmt.Scanln(&channelid) + + Is := instance.Instance{Token: token} + t := 0 + for { + if t >= 5 { + color.Red("[%v] Couldn't connect to websocket after retrying.", time.Now().Format("15:04:05")) + break + } + err := Is.StartWS() + if err != nil { + color.Red("[%v] Error while opening websocket: %v", time.Now().Format("15:04:05"), err) + } else { + break + } + t++ + } + + color.Green("[%v] Websocket opened %v", time.Now().Format("15:04:05"), Is.Token) + if Is.Ws != nil { + err := instance.Subscribe(Is.Ws, serverid) + if err != nil { + color.Red("[%v][!] Error while subscribing to server: %s", time.Now().Format("15:04:05"), err) + } + } + i := 0 + for { + err := instance.Scrape(Is.Ws, serverid, channelid, i) + if err != nil { + color.Red("[%v] Error while scraping: %v", time.Now().Format("15:04:05"), err) + } + color.Green("[%v] Token %v Scrape Count: %v", time.Now().Format("15:04:05"), Is.Token, len(Is.Ws.Members)) + if Is.Ws.Complete { + break + } + i++ + time.Sleep(time.Duration(cfg.ScraperSettings.SleepSc) * time.Millisecond) + } + if Is.Ws != nil { + Is.Ws.Close() + } + color.Green("[%v] Scraping finished. Scraped %v members", time.Now().Format("15:04:05"), len(Is.Ws.Members)) + clean := utilities.RemoveDuplicateStr(Is.Ws.Members) + color.Green("[%v] Removed Duplicates. Scraped %v members", time.Now().Format("15:04:05"), len(clean)) + color.Green("[%v] Write to memberids.txt? (y/n)", time.Now().Format("15:04:05")) + + var write string + fmt.Scanln(&write) + if write == "y" { + for k := 0; k < len(clean); k++ { + err := utilities.WriteLines("memberids.txt", clean[k]) + if err != nil { + color.Red("[%v] Error while writing to memberids.txt: %v", time.Now().Format("15:04:05"), err) + } + } + color.Green("[%v] Wrote to memberids.txt", time.Now().Format("15:04:05")) + err := utilities.WriteFile("scraped/"+serverid+".txt", clean) + if err != nil { + color.Red("[%v] Error while writing to file: %v", time.Now().Format("15:04:05"), err) + } + } + + } + if options == 2 { + var token string + color.White("Enter token: ") + fmt.Scanln(&token) + var messageid string + color.White("Enter messageid: ") + fmt.Scanln(&messageid) + var channelid string + color.White("Enter channelid: ") + fmt.Scanln(&channelid) + color.White("1) Get Emoji from Message\n2) Enter Emoji manually") + var option int + var send string + fmt.Scanln(&option) + var emoji string + if option == 2 { + color.White("Enter emoji [For Native Discord Emojis, just copy and paste emoji as unicode. For Custom/Nitro Emojis enter Name:EmojiID exactly in this format]: ") + fmt.Scanln(&emoji) + send = emoji + } else { + msg, err := instance.GetRxn(channelid, messageid, token) + if err != nil { + fmt.Println(err) + } + color.White("Select Emoji") + for i := 0; i < len(msg.Reactions); i++ { + color.White("%v) %v %v", i, msg.Reactions[i].Emojis.Name, msg.Reactions[i].Count) + } + var index int + fmt.Scanln(&index) + if msg.Reactions[index].Emojis.ID == "" { + send = msg.Reactions[index].Emojis.Name + + } else if msg.Reactions[index].Emojis.ID != "" { + send = msg.Reactions[index].Emojis.Name + ":" + msg.Reactions[index].Emojis.ID + } + } + + var allUIDS []string + var m string + for { + if len(allUIDS) == 0 { + m = "" + } else { + m = allUIDS[len(allUIDS)-1] + } + rxn, err := instance.GetReactions(channelid, messageid, token, send, m) + if err != nil { + fmt.Println(err) + continue + } + if len(rxn) == 0 { + break + } + fmt.Println(rxn) + allUIDS = append(allUIDS, rxn...) + + } + color.Green("[%v] Scraping finished. Scraped %v lines - Removing Duplicates", time.Now().Format("15:04:05"), len(allUIDS)) + clean := utilities.RemoveDuplicateStr(allUIDS) + color.Green("[%v] Write to memberids.txt? (y/n)", time.Now().Format("15:04:05")) + var write string + fmt.Scanln(&write) + if write == "y" { + for k := 0; k < len(clean); k++ { + err := utilities.WriteLines("memberids.txt", clean[k]) + if err != nil { + color.Red("[%v] Error while writing to memberids.txt: %v", time.Now().Format("15:04:05"), err) + } + } + color.Green("[%v] Wrote to memberids.txt", time.Now().Format("15:04:05")) + err := utilities.WriteFile("scraped/"+messageid+".txt", allUIDS) + if err != nil { + color.Red("[%v] Error while writing to file: %v", time.Now().Format("15:04:05"), err) + } + } + fmt.Println("Done") + } + if options == 3 { + // Query Brute. This is a test function. Try using the compressed stream to appear legit. + // Make a list of possible characters - Space can only come once, double spaces are counted as single ones and Name can't start from space. Queries are NOT case-sensitive. + // Start from a character, check the returns. If it's less than 100, that query is complete and no need to go further down the rabbit hole. + // If it's more than 100 or 100 and the last name starts from the query, pick the letter after our query and go down the rabbit hole. + // Wait 0.5s (Or better, needs testing) Between scrapes and systematically connect and disconnect from websocket to avoid rate limiting. + // Global var where members get appended (even repeats, will be cleared later) list of queries completed, list of queries left to complete and last query the instance searched to be in struct + // Scan line for user input to stop at any point and proceed with the memberids scraped at hand. + // Multiple instance support. Division of queries and hence completes in lesser time. + // Might not need to worry about spaces at all as @ uses no spaces. + // Starting Websocket(s) Appending to a slice. 1 for now, add more later. + color.Cyan("Opcode 8 Scraper (Offline Scraper)") + color.White("This feature is intentionally slowed down with high delays. Please use multiple tokens and ensure they are in the server before starting to complete it quick.") + cfg, instances, err := instance.GetEverything() + if err != nil { + color.Red("[%v] Error while getting config: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + var scraped []string + // Input the number of tokens to be used + color.Green("[%v] How many tokens do you wish to use? You have %v ", time.Now().Format("15:04:05"), len(instances)) + var numTokens int + quit := make(chan bool) + var allQueries []string + fmt.Scanln(&numTokens) + + chars := " !\"#$%&'()*+,-./0123456789:;<=>?@[]^_`abcdefghijklmnopqrstuvwxyz{|}~" + queriesLeft := make(chan string) + var queriesCompleted []string + + for i := 0; i < len(chars); i++ { + go func(i int) { + queriesLeft <- string(chars[i]) + }(i) + } + + if numTokens > len(instances) { + color.Red("[%v] You only have %v tokens in your tokens.txt Using the maximum number of tokens possible", time.Now().Format("15:04:05"), len(instances)) + } else if numTokens <= 0 { + color.Red("[%v] You must atleast use 1 token", time.Now().Format("15:04:05")) + utilities.ExitSafely() + } else if numTokens <= len(instances) { + color.Green("[%v] You have %v tokens in your tokens.txt Using %v tokens", time.Now().Format("15:04:05"), len(instances), numTokens) + instances = instances[:numTokens] + } else { + color.Red("[%v] Invalid input", time.Now().Format("15:04:05")) + } + + color.Green("[%v] Enter the ServerID", time.Now().Format("15:04:05")) + var serverid string + fmt.Scanln(&serverid) + color.Green("[%v] Press ENTER to START and STOP scraping", time.Now().Format("15:04:05")) + bufio.NewReader(os.Stdin).ReadBytes('\n') + var namesScraped []string + var avatarsScraped []string + // Starting the instances as GOroutines + for i := 0; i < len(instances); i++ { + go func(i int) { + instances[i].ScrapeCount = 0 + for { + + // Start websocket, reconnect if disconnected. + if instances[i].ScrapeCount%5 == 0 || instances[i].LastCount%100 == 0 { + if instances[i].Ws != nil { + instances[i].Ws.Close() + } + time.Sleep(2 * time.Second) + err := instances[i].StartWS() + if err != nil { + fmt.Println(err) + continue + } + time.Sleep(2 * time.Second) + + } + instances[i].ScrapeCount++ + + // Get a query from the channel / Await for close response + select { + case <-quit: + return + default: + query := <-queriesLeft + allQueries = append(allQueries, query) + if instances[i].Ws == nil { + continue + } + if instances[i].Ws.Conn == nil { + continue + } + err := instance.ScrapeOffline(instances[i].Ws, serverid, query) + if err != nil { + color.Red("[%v] %v Error while scraping: %v", time.Now().Format("15:04:05"), instances[i].Token, err) + go func() { + queriesLeft <- query + }() + continue + } + + memInfo := <-instances[i].Ws.OfflineScrape + queriesCompleted = append(queriesCompleted, query) + var MemberInfo instance.Event + err = json.Unmarshal(memInfo, &MemberInfo) + if err != nil { + color.Red("[%v] Error while unmarshalling: %v", time.Now().Format("15:04:05"), err) + queriesLeft <- query + continue + } + + if len(MemberInfo.Data.Members) == 0 { + instances[i].LastCount = -1 + continue + } + instances[i].LastCount = len(MemberInfo.Data.Members) + for _, member := range MemberInfo.Data.Members { + // Avoiding Duplicates + if !utilities.Contains(scraped, member.User.ID) { + scraped = append(scraped, member.User.ID) + } + } + color.Green("[%v] Token %v Query %v Scraped %v [+%v]", time.Now().Format("15:04:05"), instances[i].Token, query, len(scraped), len(MemberInfo.Data.Members)) + + for i := 0; i < len(MemberInfo.Data.Members); i++ { + id := MemberInfo.Data.Members[i].User.ID + err := utilities.WriteLines("memberids.txt", id) + if err != nil { + color.Red("[%v] Error while writing to file: %v", time.Now().Format("15:04:05"), err) + continue + } + if cfg.ScraperSettings.ScrapeUsernames { + nom := MemberInfo.Data.Members[i].User.Username + if !utilities.Contains(namesScraped, nom) { + err := utilities.WriteLines("names.txt", nom) + if err != nil { + color.Red("[%v] Error while writing to file: %v", time.Now().Format("15:04:05"), err) + continue + } + } + } + if cfg.ScraperSettings.ScrapeAvatars { + av := MemberInfo.Data.Members[i].User.Avatar + if !utilities.Contains(avatarsScraped, av) { + err := utilities.ProcessAvatar(av, id) + if err != nil { + color.Red("[%v] Error while processing avatar: %v", time.Now().Format("15:04:05"), err) + continue + } + } + } + } + if len(MemberInfo.Data.Members) < 100 { + time.Sleep(time.Duration(cfg.ScraperSettings.SleepSc) * time.Millisecond) + continue + } + lastName := MemberInfo.Data.Members[len(MemberInfo.Data.Members)-1].User.Username + + nextQueries := instance.FindNextQueries(query, lastName, queriesCompleted, chars) + for i := 0; i < len(nextQueries); i++ { + go func(i int) { + queriesLeft <- nextQueries[i] + }(i) + } + + } + + } + }(i) + } + + bufio.NewReader(os.Stdin).ReadBytes('\n') + color.Green("[%v] Stopping All instances", time.Now().Format("15:04:05")) + for i := 0; i < len(instances); i++ { + go func() { + quit <- true + }() + } + + color.Green("[%v] Scraping Complete. %v members scraped.", time.Now().Format("15:04:05"), len(scraped)) + color.Green("Do you wish to write to file again? (y/n) [This will remove pre-existing IDs from memberids.txt]") + var choice string + fmt.Scanln(&choice) + if choice == "y" || choice == "Y" { + clean := utilities.RemoveDuplicateStr(scraped) + err := utilities.TruncateLines("memberids.txt", clean) + if err != nil { + color.Red("[%v] Error while truncating file: %v", time.Now().Format("15:04:05"), err) + } + err = utilities.WriteFile("scraped/"+serverid, clean) + if err != nil { + color.Red("[%v] Error while writing to file: %v", time.Now().Format("15:04:05"), err) + } + } + + } +} diff --git a/discord/server_checker.go b/discord/server_checker.go new file mode 100644 index 00000000..5c2f3e8 --- /dev/null +++ b/discord/server_checker.go @@ -0,0 +1,64 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package discord + +import ( + "fmt" + "sync" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/instance" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" +) + +func LaunchServerChecker() { + color.White("Check if your tokens are still in the server") + _, instances, err := instance.GetEverything() + if err != nil { + color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + var serverid string + var inServer []string + color.Green("[%v] Enter server ID: ", time.Now().Format("15:04:05")) + fmt.Scanln(&serverid) + var wg sync.WaitGroup + wg.Add(len(instances)) + for i := 0; i < len(instances); i++ { + go func(i int) { + defer wg.Done() + r, err := instances[i].ServerCheck(serverid) + if err != nil { + color.Red("[%v] %v Error while checking server: %v", time.Now().Format("15:04:05"), instances[i].Token, err) + } else { + if r == 200 || r == 204 { + color.Green("[%v] %v is in server %v ", time.Now().Format("15:04:05"), instances[i].Token, serverid) + inServer = append(inServer, instances[i].Token) + } else if r == 429 { + color.Green("[%v] %v is rate limited", time.Now().Format("15:04:05"), instances[i].Token) + } else if r == 400 { + color.Red("[%v] Bad request - Invalid Server ID", time.Now().Format("15:04:05")) + } else { + color.Red("[%v] %v is not in server [%v] [%v]", time.Now().Format("15:04:05"), instances[i].Token, serverid, r) + } + } + }(i) + } + wg.Wait() + color.Green("[%v] All done. Do you wish to save only tokens in the server to tokens.txt ? (y/n)", time.Now().Format("15:04:05")) + var save string + fmt.Scanln(&save) + if save == "y" || save == "Y" { + err := utilities.TruncateLines("tokens.txt", inServer) + if err != nil { + color.Red("[%v] Error while saving tokens: %v", time.Now().Format("15:04:05"), err) + } else { + color.Green("[%v] Tokens saved to tokens.txt", time.Now().Format("15:04:05")) + } + } +} diff --git a/discord/token_checker.go b/discord/token_checker.go new file mode 100644 index 00000000..993cdf1 --- /dev/null +++ b/discord/token_checker.go @@ -0,0 +1,67 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package discord + +import ( + "fmt" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/instance" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" + "github.com/zenthangplus/goccm" +) + +func LaunchTokenChecker() { + color.Cyan("Token checker") + _, instances, err := instance.GetEverything() + if err != nil { + color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) + utilities.ExitSafely() + } + color.White("Enter the number of threads: (0 for Unlimited)\n") + var threads int + fmt.Scanln(&threads) + if threads > len(instances) { + threads = len(instances) + } + if threads == 0 { + threads = len(instances) + } + c := goccm.New(threads) + var working []instance.Instance + for i := 0; i < len(instances); i++ { + c.Wait() + go func(i int) { + err := instances[i].CheckToken() + if err != 200 { + color.Red("[%v] Token Invalid %v", time.Now().Format("15:04:05"), instances[i].Token) + } else { + color.Green("[%v] Token Valid %v", time.Now().Format("15:04:05"), instances[i].Token) + working = append(working, instances[i]) + } + c.Done() + }(i) + } + c.WaitAllDone() + var workingTokens []string + for i := 0; i < len(working); i++ { + if working[i].Password != "" && working[i].Email != "" { + workingTokens = append(workingTokens, fmt.Sprintf(`%v:%v:%v`, working[i].Email, working[i].Password, working[i].Token)) + } else { + workingTokens = append(workingTokens, fmt.Sprintf(`%v`, working[i].Token)) + } + } + t := utilities.TruncateLines("tokens.txt", workingTokens) + if t != nil { + color.Red("[%v] Error while truncating tokens.txt: %v", time.Now().Format("15:04:05"), t) + utilities.ExitSafely() + return + } + + color.Green("[%v] All threads finished", time.Now().Format("15:04:05")) +} diff --git a/discord/token_formatter.go b/discord/token_formatter.go new file mode 100644 index 00000000..149f262 --- /dev/null +++ b/discord/token_formatter.go @@ -0,0 +1,43 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package discord + +import ( + "strings" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" +) + +func LaunchTokenFormatter() { + color.Cyan("Email:Password:Token to Token") + Tokens, err := utilities.ReadLines("tokens.txt") + if err != nil { + color.Red("Error while opening tokens.txt: %v", err) + utilities.ExitSafely() + return + } + if len(Tokens) == 0 { + color.Red("[%v] Enter your tokens in tokens.txt", time.Now().Format("15:04:05")) + utilities.ExitSafely() + return + } + var onlytokens []string + for i := 0; i < len(Tokens); i++ { + if strings.Contains(Tokens[i], ":") { + token := strings.Split(Tokens[i], ":")[2] + onlytokens = append(onlytokens, token) + } + } + t := utilities.TruncateLines("tokens.txt", onlytokens) + if t != nil { + color.Red("[%v] Error while truncating tokens.txt: %v", time.Now().Format("15:04:05"), t) + utilities.ExitSafely() + return + } +} diff --git a/discord/token_onliner.go b/discord/token_onliner.go new file mode 100644 index 00000000..a6cc2e6 --- /dev/null +++ b/discord/token_onliner.go @@ -0,0 +1,52 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package discord + +import ( + "bufio" + "os" + "sync" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/instance" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" +) + +func LaunchTokenOnliner() { + color.Blue("Token Onliner") + _, instances, err := instance.GetEverything() + if err != nil { + color.Red("Error while getting necessary data %v", err) + utilities.ExitSafely() + } + var wg sync.WaitGroup + wg.Add(len(instances)) + for i := 0; i < len(instances); i++ { + go func(i int) { + err := instances[i].StartWS() + if err != nil { + color.Red("[%v] Error while opening websocket: %v", time.Now().Format("15:04:05"), err) + } else { + color.Green("[%v] Websocket opened %v", time.Now().Format("15:04:05"), instances[i].Token) + } + wg.Done() + }(i) + } + wg.Wait() + color.Green("[%v] All Token online. Press ENTER to disconnect and continue the program", time.Now().Format("15:04:05")) + bufio.NewReader(os.Stdin).ReadBytes('\n') + wg.Add(len(instances)) + for i := 0; i < len(instances); i++ { + go func(i int) { + instances[i].Ws.Close() + wg.Done() + }(i) + } + wg.Wait() + color.Green("[%v] All Token offline", time.Now().Format("15:04:05")) +} diff --git a/input/changed_tokens.txt b/input/changed_tokens.txt new file mode 100644 index 00000000..e69de29 diff --git a/input/completed.txt b/input/completed.txt index e69de29..e594318 100644 --- a/input/completed.txt +++ b/input/completed.txt @@ -0,0 +1 @@ +960997722104660069 diff --git a/input/proxies.txt b/input/proxies.txt index 8b13789..e69de29 100644 --- a/input/proxies.txt +++ b/input/proxies.txt @@ -1 +0,0 @@ - diff --git a/input/tokens.txt b/input/tokens.txt index 8b13789..e69de29 100644 --- a/input/tokens.txt +++ b/input/tokens.txt @@ -1 +0,0 @@ - diff --git a/utilities/captcha.go b/instance/captcha.go similarity index 82% rename from utilities/captcha.go rename to instance/captcha.go index 56b6d83..eafadca 100644 --- a/utilities/captcha.go +++ b/instance/captcha.go @@ -1,4 +1,10 @@ -package utilities +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package instance import ( "bytes" @@ -10,13 +16,15 @@ import ( "strconv" "strings" "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" ) func (in *Instance) SolveCaptcha(sitekey string, cookie string, rqData string, rqToken string, url string) (string, error) { switch true { - case Contains([]string{"capmonster.cloud", "anti-captcha.com", "anycaptcha.com"}, in.Config.CaptchaSettings.CaptchaAPI): + case utilities.Contains([]string{"capmonster.cloud", "anti-captcha.com"}, in.Config.CaptchaSettings.CaptchaAPI): return in.Capmonster(sitekey, url, rqData, cookie) - case Contains([]string{"2captcha.com", "rucaptcha.com"}, in.Config.CaptchaSettings.CaptchaAPI): + case utilities.Contains([]string{"2captcha.com", "rucaptcha.com"}, in.Config.CaptchaSettings.CaptchaAPI): return in.twoCaptcha(sitekey, rqData, url) default: return "", fmt.Errorf("unsupported captcha api: %s", in.Config.CaptchaSettings.CaptchaAPI) @@ -27,11 +35,6 @@ func (in *Instance) SolveCaptcha(sitekey string, cookie string, rqData string, r 2Captcha/RuCaptcha */ -type twoCaptchaSubmitResponse struct { - Status int `json:"status"` - Request string `json:"request"` -} - func (in *Instance) twoCaptcha(sitekey, rqdata, site string) (string, error) { var solvedKey string inEndpoint := "https://2captcha.com/in.php" @@ -53,7 +56,7 @@ func (in *Instance) twoCaptcha(sitekey, rqdata, site string) (string, error) { q.Set("soft_id", "3359") if rqdata != "" { q.Set("data", rqdata) - q.Set("invisible", "1") + q.Set("invisible", "0") } if in.Config.ProxySettings.ProxyForCaptcha { q.Set("proxy", in.Proxy) @@ -146,43 +149,6 @@ func (in *Instance) twoCaptcha(sitekey, rqdata, site string) (string, error) { Capmonster */ -type CapmonsterPayload struct { - ClientKey string `json:"clientKey,omitempty"` - Task Task `json:"task,omitempty"` - TaskId int `json:"taskId,omitempty"` -} - -type Task struct { - CaptchaType string `json:"type,omitempty"` - WebsiteURL string `json:"websiteURL,omitempty"` - WebsiteKey string `json:"websiteKey,omitempty"` - IsInvisible bool `json:"isInvisible,omitempty"` - Data string `json:"data,omitempty"` - ProxyType string `json:"proxyType,omitempty"` - ProxyAddress string `json:"proxyAddress,omitempty"` - ProxyPort int `json:"proxyPort,omitempty"` - ProxyLogin string `json:"proxyLogin,omitempty"` - ProxyPassword string `json:"proxyPassword,omitempty"` - UserAgent string `json:"userAgent,omitempty"` - Cookies string `json:"cookies,omitempty"` -} - -type CapmonsterSubmitResponse struct { - ErrorID int `json:"errorId,omitempty"` - TaskID int `json:"taskId,omitempty"` -} - -type CapmonsterOutResponse struct { - ErrorID int `json:"errorId,omitempty"` - ErrorCode string `json:"errorCode,omitempty"` - Status string `json:"status,omitempty"` - Solution Solution `json:"solution"` -} - -type Solution struct { - CaptchaResponse string `json:"gRecaptchaResponse,omitempty"` -} - func (in *Instance) Capmonster(sitekey, website, rqdata, cookies string) (string, error) { var solvedKey string inEndpoint, outEndpoint := fmt.Sprintf("https://api.%s/createTask", in.Config.CaptchaSettings.CaptchaAPI), fmt.Sprintf("https://api.%s/getTaskResult", in.Config.CaptchaSettings.CaptchaAPI) @@ -224,7 +190,16 @@ func (in *Instance) Capmonster(sitekey, website, rqdata, cookies string) (string } else { submitCaptcha.Task.CaptchaType = "HCaptchaTaskProxyless" } - submitCaptcha.Task.WebsiteURL, submitCaptcha.Task.WebsiteKey, submitCaptcha.Task.Data, submitCaptcha.Task.Cookies, submitCaptcha.Task.IsInvisible, submitCaptcha.Task.UserAgent = website, sitekey, rqdata, cookies, true, UserAgent + submitCaptcha.Task.WebsiteURL, submitCaptcha.Task.WebsiteKey, submitCaptcha.Task.Cookies, submitCaptcha.Task.UserAgent = website, sitekey, cookies, UserAgent + if rqdata != "" && in.Config.CaptchaSettings.CaptchaAPI == "capmonster.cloud" { + submitCaptcha.Task.Data = rqdata + // Try with true too + submitCaptcha.Task.IsInvisible = false + } else if rqdata != "" && in.Config.CaptchaSettings.CaptchaAPI == "anti-captcha.com" { + submitCaptcha.Task.IsInvisible = false + submitCaptcha.Task.Enterprise.RqData = rqdata + submitCaptcha.Task.Enterprise.Sentry = true + } payload, err := json.Marshal(submitCaptcha) if err != nil { return solvedKey, fmt.Errorf("error while marshalling payload %v", err) diff --git a/instance/client.go b/instance/client.go new file mode 100644 index 00000000..70c8cbd --- /dev/null +++ b/instance/client.go @@ -0,0 +1,59 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package instance + +import ( + "crypto/tls" + "net/http" + "net/url" + "strings" + "time" +) + +func InitClient(proxy string, cfg Config) (*http.Client, error) { + // If proxy is empty, return a default client (if proxy from file is false) + if proxy == "" { + return http.DefaultClient, nil + } + switch cfg.ProxySettings.ProxyProtocol { + case "http": + if !strings.Contains(proxy, "http://") { + proxy = "http://" + proxy + } + case "socks5": + if !strings.Contains(proxy, "socks5://") { + proxy = "socks5://" + proxy + } + case "socks4": + if !strings.Contains(proxy, "socks4://") { + proxy = "socks4://" + proxy + } + } + // Error while converting proxy string to url.url would result in default client being returned + proxyURL, err := url.Parse(proxy) + if err != nil { + return http.DefaultClient, err + } + // Creating a client and modifying the transport. + + Client := &http.Client{ + Timeout: time.Second * time.Duration(cfg.ProxySettings.Timeout), + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + MinVersion: tls.VersionTLS12, + CipherSuites: []uint16{0x1301, 0x1303, 0x1302, 0xc02b, 0xc02f, 0xcca9, 0xcca8, 0xc02c, 0xc030, 0xc00a, 0xc009, 0xc013, 0xc014, 0x009c, 0x009d, 0x002f, 0x0035}, + InsecureSkipVerify: true, + CurvePreferences: []tls.CurveID{tls.CurveID(0x001d), tls.CurveID(0x0017), tls.CurveID(0x0018), tls.CurveID(0x0019), tls.CurveID(0x0100), tls.CurveID(0x0101)}, + }, + DisableKeepAlives: cfg.OtherSettings.DisableKL, + ForceAttemptHTTP2: true, + Proxy: http.ProxyURL(proxyURL), + }, + } + return Client, nil + +} diff --git a/instance/config.go b/instance/config.go new file mode 100644 index 00000000..f1370cf --- /dev/null +++ b/instance/config.go @@ -0,0 +1,150 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package instance + +import ( + "encoding/json" + "fmt" + "io" + "os" + "path" + "path/filepath" + + "github.com/fatih/color" + + "gopkg.in/yaml.v3" +) + +type Config struct { + DirectMessage DirectMessage `yaml:"direct_message_settings"` + ProxySettings ProxySettings `yaml:"proxy_settings"` + ScraperSettings ScraperSettings `yaml:"scraper_settings"` + CaptchaSettings CaptchaSettings `yaml:"captcha_settings"` + OtherSettings OtherSettings `yaml:"other_settings"` + SuspicionAvoidance SuspicionAvoidance `yaml:"suspicion_avoidance"` + DMonReact DMonReact `yaml:"dm_on_react"` +} +type DirectMessage struct { + Delay int `yaml:"individual_delay"` + LongDelay int `yaml:"rate_limit_delay"` + Offset int `yaml:"offset"` + Skip bool `yaml:"skip_completed"` + Call bool `yaml:"call"` + Remove bool `yaml:"remove_dead_tokens"` + RemoveM bool `yaml:"remove_completed_members"` + Stop bool `yaml:"stop_dead_tokens"` + Mutual bool `yaml:"check_mutual"` + Friend bool `yaml:"friend_before_DM"` + Websocket bool `yaml:"online_tokens"` + MaxDMS int `yaml:"max_dms_per_token"` + Receive bool `yaml:"receive_messages"` + SkipFailed bool `yaml:"skip_failed"` + Block bool `yaml:"block_after_dm"` + Close bool `yaml:"close_dm_after_message"` +} +type ProxySettings struct { + Proxy string `yaml:"proxy"` + ProxyFromFile bool `yaml:"proxy_from_file"` + ProxyForCaptcha bool `yaml:"proxy_for_captcha"` + ProxyProtocol string `yaml:"proxy_protocol"` + GatewayProxy bool `yaml:"use_proxy_for_gateway"` + Timeout int `yaml:"timeout"` +} + +type ScraperSettings struct { + SleepSc int `yaml:"online_scraper_delay"` + ScrapeUsernames bool `yaml:"scrape_usernames"` + ScrapeAvatars bool `yaml:"scrape_avatars"` +} + +type CaptchaSettings struct { + ClientKey string `yaml:"captcha_api_key"` + CaptchaAPI string `yaml:"captcha_api"` + Timeout int `yaml:"max_captcha_wait"` + MaxCaptcha int `yaml:"max_captcha_retry"` +} + +type OtherSettings struct { + DisableKL bool `yaml:"disable_keep_alives"` +} + +type SuspicionAvoidance struct { + RandomIndividualDelay int `yaml:"random_individual_delay"` + RandomRateLimitDelay int `yaml:"random_rate_limit_delay"` + RandomDelayOpenChannel int `yaml:"random_delay_before_dm"` + TypingVariation int `yaml:"typing_variation"` + TypingSpeed int `yaml:"typing_speed"` + TypingBase int `yaml:"typing_base"` +} + +type DMonReact struct { + Observer string `yaml:"observer_token"` + ChangeName bool `yaml:"change_name"` + ChangeAvatar bool `yaml:"change_avatar"` + Invite string `yaml:"invite"` + ServerID string `yaml:"server_id"` + ChannelID string `yaml:"channel_id"` + MessageID string `yaml:"message_id"` + SkipCompleted bool `yaml:"skip_completed"` + SkipFailed bool `yaml:"skip_failed"` + LeaveTokenOnRateLimit bool `yaml:"leave_token_on_rate_limit"` + Emoji string `yaml:"emoji"` + RotateTokens bool `yaml:"rotate_tokens"` + MaxAntiRaidQueue int `yaml:"max_anti_raid_queue"` + MaxDMsPerToken int `yaml:"max_dms_per_token"` +} + +func GetConfig() (Config, error) { + ex, err := os.Executable() + if err != nil { + color.Red("Error while finding executable") + return Config{}, err + } + ex = filepath.ToSlash(ex) + var file *os.File + file, err = os.Open(path.Join(path.Dir(ex) + "/" + "config.yml")) + if err != nil { + color.Red("Error while Opening Config") + return Config{}, err + } else { + defer file.Close() + var config Config + bytes, _ := io.ReadAll(file) + err = yaml.Unmarshal(bytes, &config) + if err != nil { + fmt.Println(err) + return Config{}, err + } + return config, nil + } +} + +func GetMessage() ([]Message, error) { + var messages []Message + ex, err := os.Executable() + if err != nil { + color.Red("Error while finding executable") + return []Message{}, err + } + ex = filepath.ToSlash(ex) + file, err := os.Open(path.Join(path.Dir(ex) + "/" + "message.json")) + if err != nil { + color.Red("Error while Opening message.json") + fmt.Println(err) + return []Message{}, err + } + defer file.Close() + bytes, _ := io.ReadAll(file) + errr := json.Unmarshal(bytes, &messages) + if errr != nil { + fmt.Println(errr) + + return []Message{}, errr + } + + return messages, nil +} diff --git a/utilities/direct_messages.go b/instance/direct_messages.go similarity index 68% rename from utilities/direct_messages.go rename to instance/direct_messages.go index 6465117..d1f555d 100644 --- a/utilities/direct_messages.go +++ b/instance/direct_messages.go @@ -4,7 +4,7 @@ // License v3.0. A copy of this license is available at // https://www.gnu.org/licenses/agpl-3.0.en.html -package utilities +package instance import ( "bytes" @@ -12,22 +12,16 @@ import ( "fmt" "io/ioutil" "math" - - //"regexp" - - // "io/ioutil" "math/rand" "net/http" - - // "regexp" - "strconv" "strings" "time" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" "github.com/fatih/color" ) -// Cookies are required for legitimate looking requests, a GET request to discord.com has these required cookies in it's response along with the website HTML +// Cookies are required for legitimate looking requests, a GET request to instance.com has these required cookies in it's response along with the website HTML // We can use this to get the cookies & arrange them in a string func (in *Instance) GetCookieString() (string, error) { @@ -134,45 +128,6 @@ func (in *Instance) GetCfBm(m, r, cookies string) (string, error) { } -type response struct { - Fingerprint string `json:"fingerprint"` -} - -// Getting Fingerprint to use in our requests for more legitimate seeming requests. -func (in *Instance) GetFingerprintString(cookie string) (string, error) { - url := "https://discord.com/api/v9/experiments" - - req, err := http.NewRequest("GET", url, nil) - - if err != nil { - color.Red("[%v] Error while making request to get fingerprint %v", time.Now().Format("15:04:05"), err) - return "", fmt.Errorf("error while making request to get fingerprint %v", err) - } - req = in.fingerprintHeaders(req, cookie) - resp, err := in.Client.Do(req) - if err != nil { - color.Red("[%v] Error while getting response from fingerprint request %v", time.Now().Format("15:04:05"), err) - return "", fmt.Errorf("error while getting response from fingerprint request %v", err) - } - - p, err := ReadBody(*resp) - if err != nil { - color.Red("[%v] Error while reading body from fingerprint request %v", time.Now().Format("15:04:05"), err) - return "", fmt.Errorf("error while reading body %v", err) - } - - var Response response - - err = json.Unmarshal(p, &Response) - - if err != nil { - color.Red("[%v] Error while unmarshalling body from fingerprint request %v", time.Now().Format("15:04:05"), err) - return "", fmt.Errorf("error while unmarshalling response from fingerprint request %v", err) - } - - return Response.Fingerprint, nil -} - func (in *Instance) OpenChannel(recepientUID string) (string, error) { url := "https://discord.com/api/v9/users/@me/channels" @@ -183,9 +138,14 @@ func (in *Instance) OpenChannel(recepientUID string) (string, error) { fmt.Println("Error while making request") return "", fmt.Errorf("error while making open channel request %v", err) } - cookie, err := in.GetCookieString() - if err != nil { - return "", fmt.Errorf("error while getting cookie %v", err) + var cookie string + if in.Cookie == "" { + cookie, err = in.GetCookieString() + if err != nil { + return "", fmt.Errorf("error while getting cookie %v", err) + } + } else { + cookie = in.Cookie } resp, err := in.Client.Do(in.OpenChannelHeaders(req, cookie)) @@ -195,7 +155,7 @@ func (in *Instance) OpenChannel(recepientUID string) (string, error) { } defer resp.Body.Close() - body, err := ReadBody(*resp) + body, err := utilities.ReadBody(*resp) if err != nil { return "", fmt.Errorf("error while reading body from open channel request %v", err) } @@ -220,14 +180,6 @@ func (in *Instance) OpenChannel(recepientUID string) (string, error) { return channelSnowflake.ID, nil } -type captchaDetected struct { - CaptchaKey []string `json:"captcha_key"` - Sitekey string `json:"captcha_sitekey"` - Service string `json:"captcha_service"` - RqData string `json:"captcha_rqdata"` - RqToken string `json:"captcha_rqtoken"` -} - // Inputs the Channel snowflake and sends them the message; outputs the response code for error handling. func (in *Instance) SendMessage(channelSnowflake string, memberid string) (http.Response, error) { // Sending a random message incase there are multiple. @@ -242,7 +194,7 @@ func (in *Instance) SendMessage(channelSnowflake string, memberid string) (http. body, err := json.Marshal(&map[string]interface{}{ "content": x, "tts": false, - "nonce": Snowflake(), + "nonce": utilities.Snowflake(), }) if err != nil { return http.Response{}, fmt.Errorf("error while marshalling message %v %v ", index, err) @@ -254,11 +206,17 @@ func (in *Instance) SendMessage(channelSnowflake string, memberid string) (http. if err != nil { return http.Response{}, fmt.Errorf("error while making request to send message %v", err) } - cookie, err := in.GetCookieString() - if err != nil { - return http.Response{}, fmt.Errorf("error while getting cookie %v", err) + var cookie string + if in.Cookie == "" { + cookie, err = in.GetCookieString() + if err != nil { + return http.Response{}, fmt.Errorf("error while getting cookie %v", err) + } + } else { + cookie = in.Cookie } + dur := typingSpeed(x, in.Config.SuspicionAvoidance.TypingVariation, in.Config.SuspicionAvoidance.TypingSpeed, in.Config.SuspicionAvoidance.TypingBase) if dur != 0 { iterations := int((int64(dur) / int64(time.Second*10))) + 1 @@ -301,7 +259,7 @@ func (in *Instance) SendMessage(channelSnowflake string, memberid string) (http. body, err = json.Marshal(&map[string]interface{}{ "content": x, "tts": false, - "nonce": Snowflake(), + "nonce": utilities.Snowflake(), "captcha_key": solved, "captcha_rqtoken": captchaDetect.RqToken, }) @@ -321,15 +279,6 @@ func (in *Instance) SendMessage(channelSnowflake string, memberid string) (http. return *res, nil } -type UserInf struct { - User User `json:"user"` - Mutual []Guilds `json:"mutual_guilds"` -} - -type Guilds struct { - ID string `json:"id"` -} - func (in *Instance) UserInfo(userid string) (UserInf, error) { url := "https://discord.com/api/v9/users/" + userid + "/profile?with_mutual_guilds=true" @@ -341,21 +290,13 @@ func (in *Instance) UserInfo(userid string) (UserInf, error) { if err != nil { return UserInf{}, fmt.Errorf("error while getting cookie %v", err) } - fingerprint, err := in.GetFingerprintString(cookie) - if err != nil { - return UserInf{}, fmt.Errorf("error while getting fingerprint %v", err) - } - req.Header.Set("Authorization", in.Token) - req.Header.Set("Cookie", cookie) - req.Header.Set("x-fingerprint", fingerprint) - req.Header.Set("host", "discord.com") - resp, err := in.Client.Do(CommonHeaders(req)) + resp, err := in.Client.Do(in.AtMeHeaders(req, cookie)) if err != nil { return UserInf{}, err } - body, err := ReadBody(*resp) + body, err := utilities.ReadBody(*resp) if err != nil { return UserInf{}, err } @@ -374,10 +315,6 @@ func (in *Instance) UserInfo(userid string) (UserInf, error) { return info, nil } -type RingData struct { - Recipients interface{} `json:"recipients"` -} - func Ring(httpClient *http.Client, auth string, snowflake string) (int, error) { url := "https://discord.com/api/v9/channels/" + snowflake + "/call" @@ -404,59 +341,13 @@ func Ring(httpClient *http.Client, auth string, snowflake string) (int, error) { } defer resp.Body.Close() - body, err := ReadBody(*resp) + body, err := utilities.ReadBody(*resp) if err != nil { return 0, err } fmt.Println(string(body)) return resp.StatusCode, nil -} -func Snowflake() int64 { - snowflake := strconv.FormatInt((time.Now().UTC().UnixNano()/1000000)-1420070400000, 2) + "0000000000000000000000" - nonce, _ := strconv.ParseInt(snowflake, 2, 64) - return nonce -} - -func CommonHeaders(req *http.Request) *http.Request { - - req.Header.Set("X-Super-Properties", "eyJvcyI6IldpbmRvd3MiLCJicm93c2VyIjoiRGlzY29yZCBDbGllbnQiLCJyZWxlYXNlX2NoYW5uZWwiOiJzdGFibGUiLCJjbGllbnRfdmVyc2lvbiI6IjEuMC45MDAzIiwib3NfdmVyc2lvbiI6IjEwLjAuMjIwMDAiLCJvc19hcmNoIjoieDY0Iiwic3lzdGVtX2xvY2FsZSI6ImVuLVVTIiwiY2xpZW50X2J1aWxkX251bWJlciI6MTA0OTY3LCJjbGllbnRfZXZlbnRfc291cmNlIjpudWxsfQ==") - req.Header.Set("sec-fetch-dest", "empty") - //req.Header.Set("Connection", "keep-alive") - req.Header.Set("x-debug-options", "bugReporterEnabled") - req.Header.Set("sec-fetch-mode", "cors") - req.Header.Set("X-Discord-Locale", "en-US") - req.Header.Set("X-Debug-Options", "bugReporterEnabled") - req.Header.Set("sec-fetch-site", "same-origin") - req.Header.Set("accept-language", "en-US") - req.Header.Set("content-type", "application/json") - req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0") - req.Header.Set("TE", "trailers") - return req -} - -func RegisterHeaders(req *http.Request) *http.Request { - req.Header.Set("accept", "*/*") - req.Header.Set("authority", "discord.com") - req.Header.Set("method", "POST") - req.Header.Set("path", "/api/v9/auth/register") - req.Header.Set("scheme", "https") - //req.Header.Set("Connection", "keep-alive") - req.Header.Set("X-Discord-Locale", "en-US") - req.Header.Set("origin", "discord.com") - req.Header.Set("referer", "discord.com/register") - req.Header.Set("x-debug-options", "bugReporterEnabled") - req.Header.Set("accept-language", "en-US,en;q=0.9") - req.Header.Set("content-Type", "application/json") - // Imitating Discord Desktop Client - req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) discord/1.0.9003 Chrome/91.0.4472.164 Electron/13.4.0 Safari/537.36") - req.Header.Set("x-super-properties", "eyJvcyI6IldpbmRvd3MiLCJicm93c2VyIjoiRGlzY29yZCBDbGllbnQiLCJyZWxlYXNlX2NoYW5uZWwiOiJzdGFibGUiLCJjbGllbnRfdmVyc2lvbiI6IjEuMC45MDAzIiwib3NfdmVyc2lvbiI6IjEwLjAuMjIwMDAiLCJvc19hcmNoIjoieDY0Iiwic3lzdGVtX2xvY2FsZSI6ImVuLVVTIiwiY2xpZW50X2J1aWxkX251bWJlciI6MTA0OTY3LCJjbGllbnRfZXZlbnRfc291cmNlIjpudWxsfQ==") - req.Header.Set("sec-fetch-dest", "empty") - req.Header.Set("sec-fetch-mode", "cors") - req.Header.Set("sec-fetch-site", "same-origin") - - return req - } func (in *Instance) CloseDMS(snowflake string) (int, error) { @@ -469,15 +360,7 @@ func (in *Instance) CloseDMS(snowflake string) (int, error) { if err != nil { return -1, err } - fingerprint, err := in.GetFingerprintString(cookie) - if err != nil { - return -1, err - } - req.Header.Set("cookie", cookie) - req.Header.Set("X-Fingerprint", fingerprint) - req.Header.Set("Authorization", in.Token) - req = CommonHeaders(req) - resp, err := in.Client.Do(req) + resp, err := in.Client.Do(in.AtMeHeaders(req, cookie)) if err != nil { return -1, err } @@ -495,15 +378,7 @@ func (in *Instance) BlockUser(userid string) (int, error) { if err != nil { return -1, err } - fingerprint, err := in.GetFingerprintString(cookie) - if err != nil { - return -1, err - } - req.Header.Set("cookie", cookie) - req.Header.Set("X-Fingerprint", fingerprint) - req.Header.Set("Authorization", in.Token) - req = CommonHeaders(req) - resp, err := in.Client.Do(req) + resp, err := in.Client.Do(in.AtMeHeaders(req, cookie)) if err != nil { return -1, err } @@ -586,3 +461,25 @@ func typingSpeed(msg string, TypingVariation, TypingSpeed, TypingBase int) time. } return time.Duration(d) * time.Millisecond } + +func (in *Instance) Call(snowflake string) error { + if in.Ws == nil { + return fmt.Errorf("websocket is not initialized") + } + e := CallEvent{ + Op: 4, + Data: CallData{ + ChannelId: snowflake, + GuildId: nil, + SelfDeaf: false, + SelfMute: false, + SelfVideo: false, + }, + } + err := in.Ws.WriteRaw(e) + if err != nil { + return fmt.Errorf("failed to write to websocket: %s", err) + } + + return nil +} diff --git a/utilities/extra.go b/instance/extra.go similarity index 71% rename from utilities/extra.go rename to instance/extra.go index feba405..0ef4d12 100644 --- a/utilities/extra.go +++ b/instance/extra.go @@ -4,7 +4,7 @@ // License v3.0. A copy of this license is available at // https://www.gnu.org/licenses/agpl-3.0.en.html -package utilities +package instance import ( "bytes" @@ -18,13 +18,10 @@ import ( "net/http" "net/url" + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" "github.com/fatih/color" ) -type Reactionx struct { - ID string `json:"id"` -} - func GetReactions(channel string, message string, token string, emoji string, after string) ([]string, error) { encodedID := url.QueryEscape(emoji) site := "https://discord.com/api/v9/channels/" + channel + "/messages/" + message + "/reactions/" + encodedID + "?limit=100" @@ -42,7 +39,7 @@ func GetReactions(channel string, message string, token string, emoji string, af if err != nil { return nil, err } - body, err := ReadBody(*resp) + body, err := utilities.ReadBody(*resp) if err != nil { return nil, err } @@ -62,37 +59,13 @@ func GetReactions(channel string, message string, token string, emoji string, af return UIDS, nil } -type guild struct { - ID string `json:"id"` - Name string `json:"name"` -} - -type joinresponse struct { - VerificationForm bool `json:"show_verification_form"` - GuildObj guild `json:"guild"` -} - -type bypassInformation struct { - Version string `json:"version"` - FormFields []FormField `json:"form_fields"` -} - -type FormField struct { - FieldType string `json:"field_type"` - Label string `json:"label"` - Description string `json:"description"` - Required bool `json:"required"` - Values []string `json:"values"` - Response bool `json:"response"` -} - -func (in *Instance) ContextProperties(invite, cookie, fingerprint string) (string, error) { +func (in *Instance) ContextProperties(invite, cookie string) (string, error) { site := "https://discord.com/api/v9/invites/" + invite + "?inputValue=wnd&with_counts=true&with_expiration=true" req, err := http.NewRequest("GET", site, nil) if err != nil { return "", err } - req = in.xContextPropertiesHeaders(req, cookie, fingerprint) + req = in.xContextPropertiesHeaders(req, cookie) resp, err := in.Client.Do(req) if err != nil { return "", err @@ -100,7 +73,7 @@ func (in *Instance) ContextProperties(invite, cookie, fingerprint string) (strin if resp.StatusCode != 200 { return "", fmt.Errorf("Error while getting invite context %v", resp.StatusCode) } - body, err := ReadBody(*resp) + body, err := utilities.ReadBody(*resp) if err != nil { return "", err } @@ -123,13 +96,6 @@ func (in *Instance) ContextProperties(invite, cookie, fingerprint string) (strin } -type XContext struct { - Location string `json:"location"` - LocationGuildID string `json:"location_guild_id"` - LocationChannelID string `json:"location_channel_id"` - LocationChannelType float64 `json:"location_channel_type"` -} - func XContextGen(guildID string, channelID string, ChannelType float64) (string, error) { xcontext := XContext{ Location: "Join Guild", @@ -159,7 +125,7 @@ func Bypass(client *http.Client, serverid string, token string, invite string) e return err } - body, err := ReadBody(*resp) + body, err := utilities.ReadBody(*resp) if err != nil { return err } @@ -193,25 +159,20 @@ func Bypass(client *http.Client, serverid string, token string, invite string) e color.Red("Error while sending HTTP request bypass %v \n", err) return err } - body, err = ReadBody(*resp) + body, err = utilities.ReadBody(*resp) if err != nil { color.Red("[%v] Error while reading body %v \n", time.Now().Format("15:04:05"), err) return err } if resp.StatusCode == 201 || resp.StatusCode == 204 { - color.Green("[%v] Successfully bypassed token %v", time.Now().Format("15:04:05"), token) + color.Green("[%v][X] Successfully bypassed token %v", time.Now().Format("15:04:05"), token) } else { - color.Red("[%v] Failed to bypass Token %v %v %v", time.Now().Format("15:04:05"), token, resp.StatusCode, string(body)) + color.Red("[%v][X] Failed to bypass Token %v %v %v", time.Now().Format("15:04:05"), token, resp.StatusCode, string(body)) } return nil } -type invitePayload struct { - CaptchaKey string `json:"captcha_key,omitempty"` - RqToken string `json:"captcha_rqtoken,omitempty"` -} - func (in *Instance) Invite(Code string) error { var solvedKey string var payload invitePayload @@ -243,16 +204,11 @@ func (in *Instance) Invite(Code string) error { color.Red("[%v] Error while Getting cookies: %v", time.Now().Format("15:04:05"), err) continue } - fingerprint, err := in.GetFingerprintString(cookie) - if err != nil { - color.Red("[%v] Error while Getting fingerprint: %v", err) - continue - } - XContext, err := in.ContextProperties(Code, cookie, fingerprint) + XContext, err := in.ContextProperties(Code, cookie) if err != nil { XContext = "eyJsb2NhdGlvbiI6IkpvaW4gR3VpbGQiLCJsb2NhdGlvbl9ndWlsZF9pZCI6IjkyNTA2NjE3MjM0MzM5ODQyMCIsImxvY2F0aW9uX2NoYW5uZWxfaWQiOiI5MjUwNjYxNzIzNDMzOTg0MjMiLCJsb2NhdGlvbl9jaGFubmVsX3R5cGUiOjB9" } - req = in.inviteHeaders(req, cookie, fingerprint, XContext) + req = in.inviteHeaders(req, cookie, XContext) resp, err := in.Client.Do(req) if err != nil { @@ -260,7 +216,7 @@ func (in *Instance) Invite(Code string) error { continue } - body, err := ReadBody(*resp) + body, err := utilities.ReadBody(*resp) if err != nil { color.Red("Error while reading body %v \n", err) continue @@ -280,10 +236,10 @@ func (in *Instance) Invite(Code string) error { rqToken = resp["captcha_rqtoken"].(string) } if in.Config.CaptchaSettings.CaptchaAPI == "" { - color.Red("[%v] Captcha detected but no API key provided %v", time.Now().Format("15:04:05"), in.Token) + color.Red("[%v][X] Captcha detected but no API key provided %v", time.Now().Format("15:04:05"), in.Token) break } else { - color.Yellow("[%v] Captcha detected %v [%v] [%v]", time.Now().Format("15:04:05"), in.Token, cap, i) + color.Yellow("[%v][X] Captcha detected %v [%v] [%v]", time.Now().Format("15:04:05"), in.Token, cap, i) } solvedKey, err = in.SolveCaptcha(cap, cookie, rqData, rqToken, "https://discord.com/channels/@me") if err != nil { @@ -304,7 +260,7 @@ func (in *Instance) Invite(Code string) error { return err } if resp.StatusCode == 200 { - color.Green("[%v] %v joint guild", time.Now().Format("15:04:05"), in.Token) + color.Green("[%v][X] %v joint guild", time.Now().Format("15:04:05"), in.Token) if Join.VerificationForm { if len(Join.GuildObj.ID) != 0 { Bypass(in.Client, Join.GuildObj.ID, in.Token, Code) @@ -312,7 +268,7 @@ func (in *Instance) Invite(Code string) error { } } if resp.StatusCode != 200 { - color.Red("[%v] %v Failed to join guild %v", time.Now().Format("15:04:05"), resp.StatusCode, string(body)) + color.Red("[%v][X] %v Failed to join guild %v", time.Now().Format("15:04:05"), resp.StatusCode, string(body)) } return nil @@ -355,10 +311,7 @@ func (in *Instance) React(channelID string, MessageID string, Emoji string) erro if err != nil { return fmt.Errorf("error while getting cookie %v", err) } - req.Header.Set("Authorization", in.Token) - req.Header.Set("Cookie", cookie) - - resp, err := in.Client.Do(req) + resp, err := in.Client.Do(in.AtMeHeaders(req, cookie)) if err != nil { return err } @@ -369,11 +322,6 @@ func (in *Instance) React(channelID string, MessageID string, Emoji string) erro return fmt.Errorf("%s", resp.Status) } -type friendRequest struct { - Username string `json:"username"` - Discrim int `json:"discriminator"` -} - func (in *Instance) Friend(Username string, Discrim int) (*http.Response, error) { url := "https://discord.com/api/v9/users/@me/relationships" @@ -392,16 +340,8 @@ func (in *Instance) Friend(Username string, Discrim int) (*http.Response, error) if err != nil { return &http.Response{}, fmt.Errorf("error while getting cookie %v", err) } - fingerprint, err := in.GetFingerprintString(cookie) - if err != nil { - return &http.Response{}, fmt.Errorf("error while getting fingerprint %v", err) - } - - req.Header.Set("Cookie", cookie) - req.Header.Set("x-fingerprint", fingerprint) - req.Header.Set("Authorization", in.Token) - resp, err := in.Client.Do(CommonHeaders(req)) + resp, err := in.Client.Do(in.AtMeHeaders(req, cookie)) if err != nil { return &http.Response{}, err @@ -509,28 +449,3 @@ func (in *Instance) ServerCheck(serverid string) (int, error) { return resp.StatusCode, nil } - -func headersInvite(req *http.Request, cookie string, authorization string, fingerprint string) *http.Request { - req.Header.Set("Accept-Language", "en-GB,en;q=0.9") - req.Header.Set("Accept", "*/*") - req.Header.Set("Authorization", authorization) - req.Header.Set("Connection", "keep-alive") - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Cookie", cookie) - req.Header.Set("Origin", "https://discord.com") - req.Header.Set("referer", "https://discord.com/channels/@me") - req.Header.Set("Sec-Fetch-Dest", "empty") - req.Header.Set("Sec-Fetch-Mode", "cors") - req.Header.Set("Sec-Fetch-Site", "same-origin") - req.Header.Set("Sec-ch-ua-mobile", "?0") - req.Header.Set("sec-ch-ua-platform", `"Windows"`) - req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) discord/1.0.9003 Chrome/91.0.4472.164 Electron/13.4.0 Safari/537.36") - req.Header.Set("X-Debug-Options", "bugReporterEnabled") - req.Header.Set("X-Discord-Locale", "en-US") - req.Header.Set("X-Fingerprint", fingerprint) - // Constant Context properties - //req.Header.Set("X-Context-Properties", "eyJsb2NhdGlvbiI6IkpvaW4gR3VpbGQiLCJsb2NhdGlvbl9ndWlsZF9pZCI6Ijk0NDI2ODQ5MzczMjMyMzM3OCIsImxvY2F0aW9uX2NoYW5uZWxfaWQiOiI5NDQyNjg0OTM3MzIzMjMzODEiLCJsb2NhdGlvbl9jaGFubmVsX3R5cGUiOjB9") - req.Header.Set("X-Super-Properties", "eyJvcyI6IldpbmRvd3MiLCJicm93c2VyIjoiRGlzY29yZCBDbGllbnQiLCJyZWxlYXNlX2NoYW5uZWwiOiJzdGFibGUiLCJjbGllbnRfdmVyc2lvbiI6IjEuMC45MDAzIiwib3NfdmVyc2lvbiI6IjEwLjAuMjIwMDAiLCJvc19hcmNoIjoieDY0Iiwic3lzdGVtX2xvY2FsZSI6ImVuLVVTIiwiY2xpZW50X2J1aWxkX251bWJlciI6MTEzODU0LCJjbGllbnRfZXZlbnRfc291cmNlIjpudWxsfQ==") - - return req -} diff --git a/utilities/headers.go b/instance/headers.go similarity index 71% rename from utilities/headers.go rename to instance/headers.go index f21ab15..7d9ea58 100644 --- a/utilities/headers.go +++ b/instance/headers.go @@ -1,4 +1,10 @@ -package utilities +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package instance import ( "fmt" @@ -26,27 +32,6 @@ func (in *Instance) cookieHeaders(req *http.Request) *http.Request { return req } -func (in *Instance) fingerprintHeaders(req *http.Request, cookie string) *http.Request { - - for k, v := range map[string]string{ - - "Host": "discord.com", - "User-Agent": UserAgent, - "Accept": "*/*", - "Accept-Language": "en-US,en;q=0.5", - "X-Track": XTrack, - "DNT": "1", - "Referer": "https://discord.com/", - "Cookie": cookie, - "Sec-Fetch-Dest": "empty", - "Sec-Fetch-Mode": "cors", - "Sec-Fetch-Site": "same-origin", - } { - req.Header.Set(k, v) - } - return req -} - func (in *Instance) cfBmHeaders(req *http.Request, cookie string) *http.Request { for k, v := range map[string]string{ "Host": "discord.com", @@ -67,7 +52,7 @@ func (in *Instance) cfBmHeaders(req *http.Request, cookie string) *http.Request return req } -func (in *Instance) inviteHeaders(req *http.Request, cookie, fingerprint, xcontext string) *http.Request { +func (in *Instance) inviteHeaders(req *http.Request, cookie, xcontext string) *http.Request { for k, v := range map[string]string{ "Host": "discord.com", "User-Agent": UserAgent, @@ -77,7 +62,6 @@ func (in *Instance) inviteHeaders(req *http.Request, cookie, fingerprint, xconte "X-Context-Properties": xcontext, "Authorization": in.Token, "X-Super-Properties": XSuper, - "X-Fingerprint": fingerprint, "X-Discord-Locale": "en-US", "X-Debug-Options": "bugReporterEnabled", "Origin": "https://discord.com", @@ -93,7 +77,7 @@ func (in *Instance) inviteHeaders(req *http.Request, cookie, fingerprint, xconte return req } -func (in *Instance) xContextPropertiesHeaders(req *http.Request, cookie, fingerprint string) *http.Request { +func (in *Instance) xContextPropertiesHeaders(req *http.Request, cookie string) *http.Request { for k, v := range map[string]string{ "Host": `discord.com`, "User-Agent": UserAgent, @@ -101,7 +85,6 @@ func (in *Instance) xContextPropertiesHeaders(req *http.Request, cookie, fingerp "Accept-Language": `en-US,en;q=0.5`, "Authorization": in.Token, "X-Super-Properties": XSuper, - "X-Fingerprint": fingerprint, "X-Discord-Locale": `en-US`, "X-Debug-Options": `bugReporterEnabled`, "Referer": `https://discord.com/channels/@me`, @@ -165,23 +148,63 @@ func (in *Instance) SendMessageHeaders(req *http.Request, cookie, recipient stri func (in *Instance) TypingHeaders(req *http.Request, cookie, snowflake string) *http.Request { for k, v := range map[string]string{ - "Host": "discord.com", - "User-Agent": UserAgent, - "Accept": "*/*", - "Accept-Language": "en-US,en;q=0.5", - "Accept-Encoding": "gzip, deflate", - "Authorization": in.Token, + "Host": "discord.com", + "User-Agent": UserAgent, + "Accept": "*/*", + "Accept-Language": "en-US,en;q=0.5", + "Accept-Encoding": "gzip, deflate", + "Authorization": in.Token, "X-Super-Properties": XSuper, - "X-Discord-Locale": "en-US", - "X-Debug-Options": "bugReporterEnabled", - "Origin": "https://discord.com", - "Referer": fmt.Sprintf(`https://discord.com/channels/@me/%s`, snowflake), - "Cookie": cookie, - "Sec-Fetch-Dest": "empty", - "Sec-Fetch-Mode": "cors", - "Sec-Fetch-Site": "same-origin", + "X-Discord-Locale": "en-US", + "X-Debug-Options": "bugReporterEnabled", + "Origin": "https://discord.com", + "Referer": fmt.Sprintf(`https://discord.com/channels/@me/%s`, snowflake), + "Cookie": cookie, + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "same-origin", } { req.Header.Set(k, v) } return req } + +func (in *Instance) AtMeHeaders(req *http.Request, cookie string) *http.Request { + for k, v := range map[string]string{ + + "User-Agent": UserAgent, + "Accept": "*/*", + "Accept-Language": "en-US,en;q=0.5", + "Authorization": in.Token, + "X-Super-Properties": XSuper, + "X-Discord-Locale": "en-US", + "X-Debug-Options": "bugReporterEnabled", + "Origin": "https://discord.com", + "Referer": `https://discord.com/channels/@me/`, + "Content-Type": "application/json", + "Cookie": cookie, + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "same-origin", + } { + req.Header.Set(k, v) + } + return req +} + +func CommonHeaders(req *http.Request) *http.Request { + + req.Header.Set("X-Super-Properties", XSuper) + req.Header.Set("sec-fetch-dest", "empty") + req.Header.Set("x-debug-options", "bugReporterEnabled") + req.Header.Set("sec-fetch-mode", "cors") + req.Header.Set("X-Discord-Locale", "en-US") + req.Header.Set("X-Debug-Options", "bugReporterEnabled") + req.Header.Set("sec-fetch-site", "same-origin") + req.Header.Set("accept-language", "en-US") + req.Header.Set("content-type", "application/json") + req.Header.Set("user-agent", UserAgent) + req.Header.Set("TE", "trailers") + return req +} + diff --git a/instance/instance.go b/instance/instance.go new file mode 100644 index 00000000..f2f84e9 --- /dev/null +++ b/instance/instance.go @@ -0,0 +1,187 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package instance + +import ( + "fmt" + "math/rand" + "net/http" + "os" + "regexp" + "strings" + "sync" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" + "github.com/gorilla/websocket" +) + +type Instance struct { + Token string + Email string + Password string + Proxy string + Cookie string + Fingerprint string + Messages []Message + Count int + LastQuery string + LastCount int + Members []User + AllMembers []User + Retry int + ScrapeCount int + ID string + Receiver bool + Config Config + GatewayProxy string + Client *http.Client + WG *sync.WaitGroup + Ws *Connection + fatal chan error + Invited bool + TimeServerCheck time.Time + ChangedName bool + ChangedAvatar bool +} + +func (in *Instance) StartWS() error { + ws, err := in.NewConnection(in.wsFatalHandler) + if err != nil { + return fmt.Errorf("failed to create websocket connection: %s", err) + } + in.Ws = ws + return nil +} + +func (in *Instance) wsFatalHandler(err error) { + if closeErr, ok := err.(*websocket.CloseError); ok && closeErr.Code == 4004 { + in.fatal <- fmt.Errorf("websocket closed: authentication failed, try using a new token") + return + } + color.Red("Websocket closed %v %v", err, in.Token) + in.Receiver = false + in.Ws, err = in.NewConnection(in.wsFatalHandler) + if err != nil { + in.fatal <- fmt.Errorf("failed to create websocket connection: %s", err) + return + } + color.Green("Reconnected To Websocket") +} + +func GetEverything() (Config, []Instance, error) { + var cfg Config + var instances []Instance + var err error + var tokens []string + var proxies []string + var proxy string + + // Load config + cfg, err = GetConfig() + if err != nil { + return cfg, instances, err + } + supportedProtocols := []string{"http", "https", "socks4", "socks5"} + if cfg.ProxySettings.ProxyProtocol != "" && !utilities.Contains(supportedProtocols, cfg.ProxySettings.ProxyProtocol) { + color.Red("[!] You're using an unsupported proxy protocol. Assuming http by default") + cfg.ProxySettings.ProxyProtocol = "http" + } + if cfg.ProxySettings.ProxyProtocol == "https" { + cfg.ProxySettings.ProxyProtocol = "http" + } + if cfg.CaptchaSettings.CaptchaAPI == "" { + color.Red("[!] You're not using a Captcha API, some functionality like invite joining might be unavailable") + } + if cfg.ProxySettings.Proxy != "" && os.Getenv("HTTPS_PROXY") == "" { + os.Setenv("HTTPS_PROXY", cfg.ProxySettings.ProxyProtocol+"://"+cfg.ProxySettings.Proxy) + } + if !cfg.ProxySettings.ProxyFromFile && cfg.ProxySettings.ProxyForCaptcha { + color.Red("[!] You must enabe proxy_from_file to use proxy_for_captcha") + cfg.ProxySettings.ProxyForCaptcha = false + } + + // Load instances + tokens, err = utilities.ReadLines("tokens.txt") + if err != nil { + return cfg, instances, err + } + if len(tokens) == 0 { + return cfg, instances, fmt.Errorf("no tokens found in tokens.txt") + } + + if cfg.ProxySettings.ProxyFromFile { + proxies, err = utilities.ReadLines("proxies.txt") + if err != nil { + return cfg, instances, err + } + if len(proxies) == 0 { + return cfg, instances, fmt.Errorf("no proxies found in proxies.txt") + } + } + var Gproxy string + var instanceToken string + var email string + var password string + reg := regexp.MustCompile(`(.+):(.+):(.+)`) + for i := 0; i < len(tokens); i++ { + if reg.MatchString(tokens[i]) { + parts := strings.Split(tokens[i], ":") + instanceToken = parts[2] + email = parts[0] + password = parts[1] + + } + if cfg.ProxySettings.ProxyFromFile { + proxy = proxies[rand.Intn(len(proxies))] + Gproxy = proxy + } else { + proxy = "" + } + client, err := InitClient(proxy, cfg) + if err != nil { + return cfg, instances, fmt.Errorf("couldn't initialize client: %v", err) + } + // proxy is put in struct only to be used by gateway. If proxy for gateway is disabled, it will be empty + if !cfg.ProxySettings.GatewayProxy { + Gproxy = "" + } + instances = append(instances, Instance{Client: client, Token: instanceToken, Proxy: proxy, Config: cfg, GatewayProxy: Gproxy, Email: email, Password: password}) + } + if len(instances) == 0 { + color.Red("[!] You may be using 0 tokens") + } + var empty Config + if cfg == empty { + color.Red("[!] You may be using a malformed config.json") + } + return cfg, instances, nil + +} + +func SetMessages(instances []Instance, messages []Message) error { + var err error + if len(messages) == 0 { + messages, err = GetMessage() + if err != nil { + return err + } + if len(messages) == 0 { + return fmt.Errorf("no messages found in messages.txt") + } + for i := 0; i < len(instances); i++ { + instances[i].Messages = messages + } + } else { + for i := 0; i < len(instances); i++ { + instances[i].Messages = messages + } + } + + return nil +} diff --git a/utilities/protocol.go b/instance/protocol.go similarity index 96% rename from utilities/protocol.go rename to instance/protocol.go index f640e79..72cf976 100644 --- a/utilities/protocol.go +++ b/instance/protocol.go @@ -4,7 +4,7 @@ // License v3.0. A copy of this license is available at // https://www.gnu.org/licenses/agpl-3.0.en.html -package utilities +package instance const ( OpcodeDispatch = iota @@ -89,7 +89,13 @@ type Data struct { Threads bool `json:"threads,omitempty"` Activities bool `json:"activities,omitempty"` ThreadMemberLists interface{} `json:"thread_member_lists,omitempty"` + // Emoji React + UserID string `json:"user_id,omitempty"` + MessageID string `json:"message_id,omitempty"` + Emoji Emoji `json:"emoji,omitempty"` + } + type Ops struct { Items []Userinfo `json:"items,omitempty"` Range interface{} `json:"range,omitempty"` diff --git a/utilities/scrape.go b/instance/scrape.go similarity index 58% rename from utilities/scrape.go rename to instance/scrape.go index 0f93e7c..f5216d7 100644 --- a/utilities/scrape.go +++ b/instance/scrape.go @@ -4,7 +4,15 @@ // License v3.0. A copy of this license is available at // https://www.gnu.org/licenses/agpl-3.0.en.html -package utilities +package instance + +import ( + "strings" + "time" + + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" +) func Scrape(ws *Connection, Guild string, Channel string, index int) error { var x []interface{} @@ -77,3 +85,54 @@ func ScrapeOffline(c *Connection, guild string, query string) error { } return nil } + +func FindNextQueries(query string, lastName string, completedQueries []string, chars string) []string { + if query == "" { + color.Red("[%v] Query is empty", time.Now().Format("15:04:05")) + return nil + } + lastName = strings.ToLower(lastName) + indexQuery := strings.Index(lastName, query) + if indexQuery == -1 { + return nil + } + wantedCharIndex := indexQuery + len(query) + if wantedCharIndex >= len(lastName) { + + return nil + } + wantedChar := lastName[wantedCharIndex] + queryIndexDone := strings.Index(chars, string(wantedChar)) + if queryIndexDone == -1 { + + return nil + } + + var nextQueries []string + for j := queryIndexDone; j < len(chars); j++ { + newQuery := query + string(chars[j]) + if !utilities.Contains(completedQueries, newQuery) && !strings.Contains(newQuery, " ") && string(newQuery[0]) != "" { + nextQueries = append(nextQueries, newQuery) + } + } + return nextQueries +} + +func Subscribe(ws *Connection, guildid string) error { + payload := Data{ + GuildId: guildid, + Typing: true, + Threads: true, + Activities: true, + } + + err := ws.WriteJSONe(&Event{ + Op: 14, + Data: payload, + }) + if err != nil { + return err + } + return nil + +} diff --git a/utilities/token_util.go b/instance/token_util.go similarity index 60% rename from utilities/token_util.go rename to instance/token_util.go index 7ad7b29..12bfe8b 100644 --- a/utilities/token_util.go +++ b/instance/token_util.go @@ -4,7 +4,7 @@ // License v3.0. A copy of this license is available at // https://www.gnu.org/licenses/agpl-3.0.en.html -package utilities +package instance import ( "bufio" @@ -19,12 +19,9 @@ import ( "net/http" "os" "strings" -) -type NameChange struct { - Username string `json:"username"` - Password string `json:"password"` -} + "github.com/V4NSH4J/discord-mass-dm-GO/utilities" +) // @me Discord Patch request to change Username func (in *Instance) NameChanger(name string) (http.Response, error) { @@ -50,10 +47,7 @@ func (in *Instance) NameChanger(name string) (http.Response, error) { return http.Response{}, fmt.Errorf("error while getting cookie %v", err) } - req.Header.Add("Authorization", in.Token) - req.Header.Add("cookie", cookie) - - resp, err := in.Client.Do(CommonHeaders(req)) + resp, err := in.Client.Do(in.AtMeHeaders(req, cookie)) if err != nil { return http.Response{}, err } @@ -62,10 +56,6 @@ func (in *Instance) NameChanger(name string) (http.Response, error) { } -type AvatarChange struct { - Avatar string `json:"avatar"` -} - // @me Discord Patch request to change Avatar func (in *Instance) AvatarChanger(avatar string) (http.Response, error) { @@ -91,10 +81,7 @@ func (in *Instance) AvatarChanger(avatar string) (http.Response, error) { return http.Response{}, fmt.Errorf("error while getting cookie %v", err) } - req.Header.Add("Authorization", in.Token) - req.Header.Add("cookie", cookie) - - resp, err := http.DefaultClient.Do(CommonHeaders(req)) + resp, err := http.DefaultClient.Do(in.AtMeHeaders(req, cookie)) if err != nil { return http.Response{}, err } @@ -167,12 +154,12 @@ func (in *Instance) BioChanger(bios []string) error { if err != nil { return fmt.Errorf("error while getting cookie: %v", err) } - req.Header.Set("Cookie", cookie) - resp, err := in.Client.Do(CommonHeaders(req)) + + resp, err := in.Client.Do(in.AtMeHeaders(req, cookie)) if err != nil { return fmt.Errorf("error while sending request: %v", err) } - body, err := ReadBody(*resp) + body, err := utilities.ReadBody(*resp) if err != nil { return fmt.Errorf("error while reading body: %v", err) } @@ -194,3 +181,70 @@ func ValidateBios(bios []string) []string { } return validBios } + +func (in *Instance) RandomHypeSquadChanger() error { + site := "https://discord.com/api/v9/hypesquad/online" + req, err := http.NewRequest(http.MethodPost, site, strings.NewReader(fmt.Sprintf(`{"house_id": %v}`, rand.Intn(3)+1))) + if err != nil { + return fmt.Errorf("error while making request: %v", err) + } + cookie, err := in.GetCookieString() + if err != nil { + return fmt.Errorf("error while getting cookie: %v", err) + } + req = in.AtMeHeaders(req,cookie) + resp, err := in.Client.Do(req) + if err != nil { + return fmt.Errorf("error while sending request: %v", err) + } + if resp.StatusCode != 204 { + defer resp.Body.Close() + body, err := utilities.ReadBody(*resp) + if err != nil { + return fmt.Errorf("error while reading body: %v", err) + } + return fmt.Errorf("error while changing hype squad %v %v", resp.StatusCode, string(body)) + } + return nil +} + +func (in *Instance) ChangeToken(newPassword string) (string, error) { + site := "https://discord.com/api/v9/users/@me" + payload := fmt.Sprintf(` + { + "password": "%v", + "new_password": "%v" + } + `, in.Password, newPassword) + req, err := http.NewRequest(http.MethodPatch, site, strings.NewReader(payload)) + if err != nil { + return "", fmt.Errorf("error while making request: %v", err) + } + cookie, err := in.GetCookieString() + if err != nil { + return "", fmt.Errorf("error while getting cookie: %v", err) + } + req = in.AtMeHeaders(req, cookie) + resp, err := in.Client.Do(req) + if err != nil { + return "", fmt.Errorf("error while sending request: %v", err) + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("error while reading body: %v", err) + } + if resp.StatusCode != 200 { + return "", fmt.Errorf("invalid status code %v while changing token %v", resp.StatusCode, string(body)) + } + if strings.Contains(string(body), "token") { + var response map[string]interface{} + err := json.Unmarshal(body, &response) + if err != nil { + return "", fmt.Errorf("error while unmarshalling response: %v", err) + } + return response["token"].(string), nil + } else { + return "", fmt.Errorf("error while changing token %v body does not contain token", string(body)) + } +} \ No newline at end of file diff --git a/instance/types.go b/instance/types.go new file mode 100644 index 00000000..658c83d --- /dev/null +++ b/instance/types.go @@ -0,0 +1,220 @@ +// Copyright (C) 2021 github.com/V4NSH4J +// +// This source code has been released under the GNU Affero General Public +// License v3.0. A copy of this license is available at +// https://www.gnu.org/licenses/agpl-3.0.en.html + +package instance + +type twoCaptchaSubmitResponse struct { + Status int `json:"status"` + Request string `json:"request"` +} + +type CapmonsterPayload struct { + ClientKey string `json:"clientKey,omitempty"` + Task Task `json:"task,omitempty"` + TaskId int `json:"taskId,omitempty"` +} + +type Task struct { + CaptchaType string `json:"type,omitempty"` + WebsiteURL string `json:"websiteURL,omitempty"` + WebsiteKey string `json:"websiteKey,omitempty"` + IsInvisible bool `json:"isInvisible,omitempty"` + Data string `json:"data,omitempty"` + ProxyType string `json:"proxyType,omitempty"` + ProxyAddress string `json:"proxyAddress,omitempty"` + ProxyPort int `json:"proxyPort,omitempty"` + ProxyLogin string `json:"proxyLogin,omitempty"` + ProxyPassword string `json:"proxyPassword,omitempty"` + UserAgent string `json:"userAgent,omitempty"` + Cookies string `json:"cookies,omitempty"` + Enterprise Enterprise `json:"enterprisePayload,omitempty"` +} + +type Enterprise struct { + RqData string `json:"rqdata,omitempty"` + Sentry bool `json:"sentry,omitempty"` + ApiEndpoint string `json:"apiEndpoint,omitempty"` + Endpoint string `json:"endpoint,omitempty"` + ReportAPI string `json:"reportapi,omitempty"` + AssetHost string `json:"assethost,omitempty"` + ImageHost string `json:"imghost,omitempty"` + +} + +type CapmonsterSubmitResponse struct { + ErrorID int `json:"errorId,omitempty"` + TaskID int `json:"taskId,omitempty"` +} + +type CapmonsterOutResponse struct { + ErrorID int `json:"errorId,omitempty"` + ErrorCode string `json:"errorCode,omitempty"` + Status string `json:"status,omitempty"` + Solution Solution `json:"solution"` +} + +type Solution struct { + CaptchaResponse string `json:"gRecaptchaResponse,omitempty"` +} + +type UserInf struct { + User User `json:"user"` + Mutual []Guilds `json:"mutual_guilds"` +} + +type Guilds struct { + ID string `json:"id"` +} + +type captchaDetected struct { + CaptchaKey []string `json:"captcha_key"` + Sitekey string `json:"captcha_sitekey"` + Service string `json:"captcha_service"` + RqData string `json:"captcha_rqdata"` + RqToken string `json:"captcha_rqtoken"` +} + +type Reactionx struct { + ID string `json:"id"` +} + +type guild struct { + ID string `json:"id"` + Name string `json:"name"` +} + +type joinresponse struct { + VerificationForm bool `json:"show_verification_form"` + GuildObj guild `json:"guild"` +} + +type bypassInformation struct { + Version string `json:"version"` + FormFields []FormField `json:"form_fields"` +} + +type FormField struct { + FieldType string `json:"field_type"` + Label string `json:"label"` + Description string `json:"description"` + Required bool `json:"required"` + Values []string `json:"values"` + Response bool `json:"response"` +} + +type XContext struct { + Location string `json:"location"` + LocationGuildID string `json:"location_guild_id"` + LocationChannelID string `json:"location_channel_id"` + LocationChannelType float64 `json:"location_channel_type"` +} + +type RingData struct { + Recipients interface{} `json:"recipients"` +} + +type invitePayload struct { + CaptchaKey string `json:"captcha_key,omitempty"` + RqToken string `json:"captcha_rqtoken,omitempty"` +} + +type friendRequest struct { + Username string `json:"username"` + Discrim int `json:"discriminator"` +} + +type MessageEmbedImage struct { + URL string `json:"url,omitempty"` + ProxyURL string `json:"proxy_url,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` +} + +type EmbedField struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` + Inline bool `json:"inline,omitempty"` +} + +type EmbedFooter struct { + Text string `json:"text,omitempty"` + IconURL string `json:"icon_url,omitempty"` + ProxyIconURL string `json:"proxy_icon_url,omitempty"` +} + +type EmbedAuthor struct { + Name string `json:"name,omitempty"` + URL string `json:"url,omitempty"` + IconURL string `json:"icon_url,omitempty"` + ProxyIconURL string `json:"proxy_icon_url,omitempty"` +} +type MessageEmbedThumbnail struct { + URL string `json:"url,omitempty"` + ProxyURL string `json:"proxy_url,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` +} + +type EmbedProvider struct { + Name string `json:"name,omitempty"` + URL string `json:"url,omitempty"` +} +type Embed struct { + Title string `json:"title,omitempty"` + + // The type of embed. Always EmbedTypeRich for webhook embeds. + Type string `json:"type,omitempty"` + Description string `json:"description,omitempty"` + URL string `json:"url,omitempty"` + Image *MessageEmbedImage `json:"image,omitempty"` + + // The color code of the embed. + Color int `json:"color,omitempty"` + Footer EmbedFooter `json:"footer,omitempty"` + Thumbnail *MessageEmbedThumbnail `json:"thumbnail,omitempty"` + Provider EmbedProvider `json:"provider,omitempty"` + Author EmbedAuthor `json:"author,omitempty"` + Fields []EmbedField `json:"fields,omitempty"` +} +type Emoji struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Animated bool `json:"animated,omitempty"` +} +type Reaction struct { + Emojis Emoji `json:"emoji,omitempty"` + Count int `json:"count,omitempty"` +} + +type Message struct { + Content string `json:"content,omitempty"` + Embeds []Embed `json:"embeds,omitempty"` + Reactions []Reaction `json:"reactions,omitempty"` + Author User `json:"author,omitempty"` + GuildID string `json:"guild_id,omitempty"` +} + +type CallEvent struct { + Op int `json:"op"` + Data CallData `json:"d"` +} + +type CallData struct { + ChannelId string `json:"channel_id"` + GuildId interface{} `json:"guild_id"` + SelfDeaf bool `json:"self_deaf"` + SelfMute bool `json:"self_mute"` + SelfVideo bool `json:"self_video"` +} + +type NameChange struct { + Username string `json:"username"` + Password string `json:"password"` +} + +type AvatarChange struct { + Avatar string `json:"avatar"` +} diff --git a/utilities/websocket.go b/instance/websocket.go similarity index 97% rename from utilities/websocket.go rename to instance/websocket.go index 1768edc..c8d160c 100644 --- a/utilities/websocket.go +++ b/instance/websocket.go @@ -4,7 +4,7 @@ // License v3.0. A copy of this license is available at // https://www.gnu.org/licenses/agpl-3.0.en.html -package utilities +package instance import ( "encoding/json" @@ -31,6 +31,7 @@ type Connection struct { fatalHandler func(err error) seq int closeChan chan struct{} + Reactions chan []byte } // Input Discord token and start a new websocket connection @@ -72,6 +73,7 @@ func (in *Instance) NewConnection(fatalHandler func(err error)) (*Connection, er Messages: make(chan []byte), fatalHandler: fatalHandler, closeChan: make(chan struct{}), + Reactions: make(chan []byte), } // Receive Hello message interval, err := c.ReadHello() @@ -206,6 +208,11 @@ func (c *Connection) listen() { }() } + if body.EventName == "MESSAGE_REACTION_ADD" { + go func() { + c.Reactions <- b + }() + } if body.EventName == "GUILD_MEMBER_LIST_UPDATE" { for i := 0; i < len(body.Data.Ops); i++ { if len(body.Data.Ops[i].Items) == 0 && body.Data.Ops[i].Op == "SYNC" { diff --git a/main.go b/main.go index 1e165c1..95ffa8a 100644 --- a/main.go +++ b/main.go @@ -7,46 +7,32 @@ package main import ( - "bufio" - "crypto/tls" - "encoding/base64" - "encoding/json" - "errors" "fmt" - "io" - "io/ioutil" "math/rand" - "net/http" - "net/url" "os" - "os/exec" - "path" - "path/filepath" - "regexp" - "strconv" - "strings" - "sync" "time" + "github.com/V4NSH4J/discord-mass-dm-GO/discord" "github.com/V4NSH4J/discord-mass-dm-GO/utilities" + "github.com/fatih/color" - "github.com/zenthangplus/goccm" ) +var CaptchaServices []string + func main() { - version := "1.8.13" - CaptchaServices = []string{"capmonster.cloud", "anti-captcha.com", "2captcha.com", "rucaptcha.com", "deathbycaptcha.com", "anycaptcha.com", "azcaptcha.com", "solvecaptcha.com"} + version := "1.9.0" + CaptchaServices = []string{"capmonster.cloud", "2captcha.com", "rucaptcha.com", "anti-captcha.com"} rand.Seed(time.Now().UTC().UnixNano()) color.Blue(logo + " v" + version + "\n") color.Green("Made by https://github.com/V4NSH4J\nStar repository on github for updates!") - versionCheck(version) + utilities.VersionCheck(version) Options() } // Options menu func Options() { - reg := regexp.MustCompile(`(.+):(.+):(.+)`) - color.White("Menu:\n |- 01) Invite Joiner [Token]\n |- 02) Mass DM advertiser [Token]\n |- 03) Single DM spam [Token]\n |- 04) Reaction Adder [Token]\n |- 05) Get message [Input]\n |- 06) Email:Pass:Token to Token [Email:Password:Token]\n |- 07) Token Checker [Token]\n |- 08) Guild Leaver [Token]\n |- 09) Token Onliner [Token]\n |- 10) Scraping Menu [Input]\n |- 11) Name Changer [Email:Password:Token]\n |- 12) Profile Picture Changer [Token]\n |- 13) Token Servers Check [Token]\n |- 14) Bio Changer [Token]\n |- 15) Haven't thought of anything\n |- 16) Credits & Info\n |- 17) Exit") + color.White("Menu:\n |- 01) Invite Joiner [Token]\n |- 02) Mass DM advertiser [Token]\n |- 03) Single DM spam [Token]\n |- 04) Reaction Adder [Token]\n |- 05) Get message [Input]\n |- 06) Email:Pass:Token to Token [Email:Password:Token]\n |- 07) Token Checker [Token]\n |- 08) Guild Leaver [Token]\n |- 09) Token Onliner [Token]\n |- 10) Scraping Menu [Input]\n |- 11) Name Changer [Email:Password:Token]\n |- 12) Profile Picture Changer [Token]\n |- 13) Token Servers Check [Token]\n |- 14) Bio Changer [Token]\n |- 15) DM on React\n |- 16) Hypesquad Changer\n |- 17) Mass token changer\n |- 18) Credits & Info\n |- 19) Exit") color.White("\nEnter your choice: ") var choice int fmt.Scanln(&choice) @@ -55,1880 +41,48 @@ func Options() { color.Red("Invalid choice!") Options() case 1: - var invitechoice int - color.White("Invite Menu:\n1) Single Invite\n2) Multiple Invites from file") - fmt.Scanln(&invitechoice) - if invitechoice != 1 && invitechoice != 2 { - color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) - ExitSafely() - return - } - switch invitechoice { - case 1: - color.Cyan("Single Invite Mode") - color.White("This will join your tokens from tokens.txt to a server") - _, instances, err := getEverything() - if err != nil { - color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) - } - color.White("[%v] Enter your invite CODE (The part after discord.gg/): ", time.Now().Format("15:04:05")) - var invite string - fmt.Scanln(&invite) - color.White("[%v] Enter number of Threads (0: Unlimited Threads. 1: For using proper delay. It may be a good idea to use less threads if you're looking to solve captchas): ", time.Now().Format("15:04:05")) - var threads int - fmt.Scanln(&threads) - - if threads > len(instances) { - threads = len(instances) - } - if threads == 0 { - threads = len(instances) - } - - color.White("[%v] Enter base delay for joining in seconds (0 for none)", time.Now().Format("15:04:05")) - var base int - fmt.Scanln(&base) - color.White("[%v] Enter random delay to be added upon base delay (0 for none)", time.Now().Format("15:04:05")) - var random int - fmt.Scanln(&random) - var delay int - if random > 0 { - delay = base + rand.Intn(random) - } else { - delay = base - } - c := goccm.New(threads) - for i := 0; i < len(instances); i++ { - c.Wait() - go func(i int) { - err := instances[i].Invite(invite) - if err != nil { - color.Red("[%v] Error while joining: %v", time.Now().Format("15:04:05"), err) - } - time.Sleep(time.Duration(delay) * time.Second) - c.Done() - - }(i) - } - c.WaitAllDone() - color.Green("[%v] All threads finished", time.Now().Format("15:04:05")) - - case 2: - color.Cyan("Multiple Invite Mode") - color.White("This will join your tokens from tokens.txt to servers from invite.txt") - cfg, instances, err := getEverything() - if err != nil { - color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) - } - - if len(instances) == 0 { - color.Red("[%v] Enter your tokens in tokens.txt", time.Now().Format("15:04:05")) - ExitSafely() - } - invites, err := utilities.ReadLines("invite.txt") - if err != nil { - color.Red("Error while opening invite.txt: %v", err) - ExitSafely() - return - } - if len(invites) == 0 { - color.Red("[%v] Enter your invites in invite.txt", time.Now().Format("15:04:05")) - ExitSafely() - return - } - color.White("Enter delay between 2 consecutive joins by 1 token in seconds: ") - var delay int - fmt.Scanln(&delay) - color.White("Enter number of Threads (0 for unlimited): ") - var threads int - fmt.Scanln(&threads) - if threads > len(instances) { - threads = len(instances) - } - if threads == 0 { - threads = len(instances) - } - c := goccm.New(threads) - for i := 0; i < len(instances); i++ { - time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) - c.Wait() - go func(i int) { - for j := 0; j < len(invites); j++ { - err := instances[i].Invite(invites[j]) - if err != nil { - color.Red("[%v] Error while joining: %v", time.Now().Format("15:04:05"), err) - } - time.Sleep(time.Duration(delay) * time.Second) - } - c.Done() - }(i) - } - c.WaitAllDone() - color.Green("[%v] All threads finished", time.Now().Format("15:04:05")) - } + discord.LaunchinviteJoiner() case 2: - - color.Cyan("Mass DM Advertiser/Spammer") - color.White("This will DM everyone in memberids.txt from your tokens") - members, err := utilities.ReadLines("memberids.txt") - if err != nil { - color.Red("Error while opening memberids.txt: %v", err) - ExitSafely() - } - cfg, instances, err := getEverything() - if err != nil { - color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) - } - var msg utilities.Message - color.White("Press 1 to use messages from file or press 2 to enter a message: ") - var messagechoice int - fmt.Scanln(&messagechoice) - if messagechoice != 1 && messagechoice != 2 { - color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) - ExitSafely() - } - if messagechoice == 2 { - color.White("Enter your message, use \\n for changing lines. You can also set a constant message in message.json") - scanner := bufio.NewScanner(os.Stdin) - var text string - if scanner.Scan() { - text = scanner.Text() - } - - msg.Content = text - msg.Content = strings.Replace(msg.Content, "\\n", "\n", -1) - var msgs []utilities.Message - msgs = append(msgs, msg) - err := setMessages(instances, msgs) - if err != nil { - color.Red("[%v] Error while setting messages: %v", time.Now().Format("15:04:05"), err) - ExitSafely() - } - } else { - var msgs []utilities.Message - err := setMessages(instances, msgs) - if err != nil { - color.Red("[%v] Error while setting messages: %v", time.Now().Format("15:04:05"), err) - ExitSafely() - } - } - color.White("[%v] Do you wish to use Advanced Settings? 0: No, 1: Yes: ", time.Now().Format("15:04:05")) - var advancedchoice int - var checkchoice int - var serverid string - var tryjoinchoice int - var invite string - var maxattempts int - fmt.Scanln(&advancedchoice) - if advancedchoice != 0 && advancedchoice != 1 { - color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) - ExitSafely() - } - if advancedchoice == 1 { - color.White("[%v] Do you wish to check if token is still in server before every DM? [0: No, 1: Yes]", time.Now().Format("15:04:05")) - fmt.Scanln(&checkchoice) - if checkchoice != 0 && checkchoice != 1 { - color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) - ExitSafely() - } - if checkchoice == 1 { - color.White("[%v] Enter Server ID", time.Now().Format("15:04:05")) - fmt.Scanln(&serverid) - color.White("[%v] Do you wish to try rejoining the server if token is not in server? [0: No, 1: Yes]", time.Now().Format("15:04:05")) - fmt.Scanln(&tryjoinchoice) - if tryjoinchoice != 0 && tryjoinchoice != 1 { - color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) - ExitSafely() - } - if tryjoinchoice == 1 { - color.White("[%v] Enter a permanent invite code", time.Now().Format("15:04:05")) - fmt.Scanln(&invite) - color.White("[%v] Enter max rejoin attempts", time.Now().Format("15:04:05")) - fmt.Scanln(&maxattempts) - } - } - } - // Also initiate variables and slices for logging and counting - var session []string - var completed []string - var failed []string - var dead []string - var failedCount = 0 - completed, err = utilities.ReadLines("completed.txt") - if err != nil { - color.Red("Error while opening completed.txt: %v", err) - ExitSafely() - } - if cfg.DirectMessage.Skip { - members = utilities.RemoveSubset(members, completed) - } - if cfg.DirectMessage.SkipFailed { - failedSkip, err := utilities.ReadLines("failed.txt") - if err != nil { - color.Red("Error while opening failed.txt: %v", err) - ExitSafely() - } - members = utilities.RemoveSubset(members, failedSkip) - } - if len(instances) == 0 { - color.Red("[%v] Enter your tokens in tokens.txt ", time.Now().Format("15:04:05")) - ExitSafely() - } - if len(members) == 0 { - color.Red("[%v] Enter your member ids in memberids.txt or ensure that all of them are not in completed.txt", time.Now().Format("15:04:05")) - ExitSafely() - } - if len(members) < len(instances) { - instances = instances[:len(members)] - } - msgs := instances[0].Messages - for i := 0; i < len(msgs); i++ { - if msgs[i].Content == "" && msgs[i].Embeds == nil { - color.Red("[%v] WARNING: Message %v is empty", time.Now().Format("15:04:05"), i) - } - } - // Send members to a channel - mem := make(chan string, len(members)) - go func() { - for i := 0; i < len(members); i++ { - mem <- members[i] - } - }() - // Setting information to windows titlebar by github.com/foxzsz - go func() { - for { - cmd := exec.Command("cmd", "/C", "title", fmt.Sprintf(`DMDGO [%d sent, %v failed, %d locked, %v avg. dms, %d tokens left]`, len(session), len(failed), len(dead), len(session)/len(instances), len(instances)-len(dead))) - _ = cmd.Run() - } - }() - var wg sync.WaitGroup - start := time.Now() - for i := 0; i < len(instances); i++ { - // Offset goroutines by a few milliseconds. Makes a big difference and allows for better concurrency - time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) - wg.Add(1) - go func(i int) { - defer wg.Done() - for { - // Get a member from the channel - if len(mem) == 0 { - break - } - member := <-mem - - // Breaking loop if maximum DMs reached - if cfg.DirectMessage.MaxDMS != 0 && instances[i].Count >= cfg.DirectMessage.MaxDMS { - color.Yellow("[%v] Maximum DMs reached for %v", time.Now().Format("15:04:05"), instances[i].Token) - break - } - // Start websocket connection if not already connected and reconnect if dead - if cfg.DirectMessage.Websocket && instances[i].Ws == nil { - err := instances[i].StartWS() - if err != nil { - color.Red("[%v] Error while opening websocket: %v", time.Now().Format("15:04:05"), err) - } else { - color.Green("[%v] Websocket opened %v", time.Now().Format("15:04:05"), instances[i].Token) - } - } - if cfg.DirectMessage.Websocket && cfg.DirectMessage.Receive && instances[i].Ws != nil && !instances[i].Receiver { - instances[i].Receiver = true - go func() { - for { - if !instances[i].Receiver { - break - } - mes := <-instances[i].Ws.Messages - if !strings.Contains(string(mes), "guild_id") { - var mar utilities.Event - err := json.Unmarshal(mes, &mar) - if err != nil { - color.Red("[%v] Error while unmarshalling websocket message: %v", time.Now().Format("15:04:05"), err) - continue - } - if instances[i].ID == "" { - tokenPart := strings.Split(instances[i].Token, ".")[0] - dec, err := base64.StdEncoding.DecodeString(tokenPart) - if err != nil { - color.Red("[%v] Error while decoding token: %v", time.Now().Format("15:04:05"), err) - continue - } - instances[i].ID = string(dec) - } - if mar.Data.Author.ID == instances[i].ID { - continue - } - color.Green("[%v] %v#%v sent a message to %v : %v", time.Now().Format("15:04:05"), mar.Data.Author.Username, mar.Data.Author.Discriminator, instances[i].Token, mar.Data.Content) - newStr := "Username: " + mar.Data.Author.Username + "#" + mar.Data.Author.Discriminator + "\nID: " + mar.Data.Author.ID + "\n" + "Message: " + mar.Data.Content + "\n" - err = utilities.WriteLines("received.txt", newStr) - if err != nil { - color.Red("[%v] Error while opening received.txt: %v", time.Now().Format("15:04:05"), err) - } - } - } - }() - } - // Check if token is valid - status := instances[i].CheckToken() - if status != 200 && status != 204 && status != 429 && status != -1 { - failedCount++ - color.Red("[%v] Token %v might be locked - Stopping instance and adding members to failed list. %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, status, failedCount) - failed = append(failed, member) - dead = append(dead, instances[i].Token) - err := utilities.WriteLines("failed.txt", member) - if err != nil { - fmt.Println(err) - } - if cfg.DirectMessage.Stop { - break - } - } - // Advanced Options - if advancedchoice == 1 { - if checkchoice == 1 { - r, err := instances[i].ServerCheck(serverid) - if err != nil { - color.Red("[%v] Error while checking server: %v", time.Now().Format("15:04:05"), err) - continue - } - if r != 200 && r != 204 && r != 429 { - if tryjoinchoice == 0 { - color.Red("[%v] Stopping token %v [Not in server]", time.Now().Format("15:04:05"), instances[i].Token) - - break - } else { - if instances[i].Retry >= maxattempts { - color.Red("[%v] Stopping token %v [Max server rejoin attempts]", time.Now().Format("15:04:05"), instances[i].Token) - break - } - err := instances[i].Invite(invite) - if err != nil { - color.Red("[%v] Error while joining server: %v", time.Now().Format("15:04:05"), err) - instances[i].Retry++ - continue - } - } - } - } - } - var user string - user = member - // Check Mutual - if cfg.DirectMessage.Mutual { - info, err := instances[i].UserInfo(member) - if err != nil { - failedCount++ - color.Red("[%v] Error while getting user info: %v [%v]", time.Now().Format("15:04:05"), err, failedCount) - err = WriteLine("input/failed.txt", member) - if err != nil { - fmt.Println(err) - } - failed = append(failed, member) - - continue - } - if len(info.Mutual) == 0 { - failedCount++ - color.Red("[%v] Token %v failed to DM %v [No Mutual Server] [%v]", time.Now().Format("15:04:05"), instances[i].Token, info.User.Username+info.User.Discriminator, failedCount) - err = WriteLine("input/failed.txt", member) - if err != nil { - fmt.Println(err) - } - failed = append(failed, member) - continue - } - user = info.User.Username + "#" + info.User.Discriminator - // Used only if Websocket is enabled as Unwebsocketed Tokens get locked if they attempt to send friend requests. - if cfg.DirectMessage.Friend && cfg.DirectMessage.Websocket { - x, err := strconv.Atoi(info.User.Discriminator) - if err != nil { - color.Red("[%v] Error while adding friend: %v", time.Now().Format("15:04:05"), err) - continue - } - resp, err := instances[i].Friend(info.User.Username, x) - if err != nil { - color.Red("[%v] Error while adding friend: %v", time.Now().Format("15:04:05"), err) - continue - } - if resp.StatusCode != 204 && err != nil { - if !errors.Is(err, io.ErrUnexpectedEOF) { - body, err := utilities.ReadBody(*resp) - if err != nil { - color.Red("[%v] Error while adding friend: %v", time.Now().Format("15:04:05"), fmt.Sprintf("error reading body: %v", err)) - continue - } - color.Red("[%v] Error while adding friend: %v", time.Now().Format("15:04:05"), string(body)) - continue - } - color.Red("[%v] Error while adding friend: %v", time.Now().Format("15:04:05"), err) - continue - } else { - color.Green("[%v] Added friend %v", time.Now().Format("15:04:05"), info.User.Username+"#"+info.User.Discriminator) - } - } - } - // Open channel to get snowflake - snowflake, err := instances[i].OpenChannel(member) - if err != nil { - failedCount++ - color.Red("[%v] Error while opening DM channel: %v [%v]", time.Now().Format("15:04:05"), err, failedCount) - err = WriteLine("input/failed.txt", member) - if err != nil { - fmt.Println(err) - } - failed = append(failed, member) - continue - } - if cfg.SuspicionAvoidance.RandomDelayOpenChannel != 0 { - time.Sleep(time.Duration(rand.Intn(cfg.SuspicionAvoidance.RandomDelayOpenChannel)) * time.Second) - } - resp, err := instances[i].SendMessage(snowflake, member) - if err != nil { - failedCount++ - color.Red("[%v] Error while sending message: %v [%v]", time.Now().Format("15:04:05"), err, failedCount) - err = WriteLine("input/failed.txt", member) - if err != nil { - fmt.Println(err) - } - failed = append(failed, member) - continue - } - body, err := utilities.ReadBody(resp) - if err != nil { - failedCount++ - color.Red("[%v] Error while reading body: %v [%v]", time.Now().Format("15:04:05"), err, failedCount) - err = WriteLine("input/failed.txt", member) - if err != nil { - fmt.Println(err) - } - failed = append(failed, member) - continue - } - var response jsonResponse - errx := json.Unmarshal(body, &response) - if errx != nil { - failedCount++ - color.Red("[%v] Error while unmarshalling body: %v [%v]", time.Now().Format("15:04:05"), errx, failedCount) - err = WriteLine("input/failed.txt", member) - if err != nil { - fmt.Println(err) - } - failed = append(failed, member) - continue - } - // Everything is fine, continue as usual - if resp.StatusCode == 200 { - err = WriteLine("input/completed.txt", member) - if err != nil { - fmt.Println(err) - } - completed = append(completed, member) - session = append(session, member) - color.Green("[%v] Token %v sent DM to %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, user, len(session)) - if cfg.DirectMessage.Websocket && cfg.DirectMessage.Call && instances[i].Ws != nil { - err := instances[i].Call(snowflake) - if err != nil { - color.Red("[%v] %v Error while calling %v: %v", time.Now().Format("15:04:05"), instances[i].Token, user, err) - } - // Unfriended people can't ring. - // - // resp, err := utilities.Ring(instances[i].Client, instances[i].Token, snowflake) - // if err != nil { - // color.Red("[%v] %v Error while ringing %v: %v", time.Now().Format("15:04:05"), instances[i].Token, user, err) - // } - // if resp == 200 || resp == 204 { - // color.Green("[%v] %v Ringed %v", time.Now().Format("15:04:05"), instances[i].Token, user) - // } else { - // color.Red("[%v] %v Error while ringing %v: %v", time.Now().Format("15:04:05"), instances[i].Token, user, resp) - // } - - } - if cfg.DirectMessage.Block { - r, err := instances[i].BlockUser(member) - if err != nil { - color.Red("[%v] Error while blocking user: %v", time.Now().Format("15:04:05"), err) - } else { - if r == 204 { - color.Green("[%v] Blocked %v", time.Now().Format("15:04:05"), user) - } else { - color.Red("[%v] Error while blocking user: %v", time.Now().Format("15:04:05"), r) - } - } - } - if cfg.DirectMessage.Close { - r, err := instances[i].CloseDMS(snowflake) - if err != nil { - color.Red("[%v] Error while closing DM: %v", time.Now().Format("15:04:05"), err) - } else { - if r == 200 { - color.Green("[%v] Succesfully closed DM %v", time.Now().Format("15:04:05"), user) - } else { - color.Red("[%v] Failed to close DM %v", time.Now().Format("15:04:05"), user) - } - } - } - // Forbidden - Token is being rate limited - } else if resp.StatusCode == 403 && response.Code == 40003 { - - err = WriteLine("input/failed.txt", member) - if err != nil { - fmt.Println(err) - } - mem <- member - color.Yellow("[%v] Token %v sleeping for %v minutes!", time.Now().Format("15:04:05"), instances[i].Token, int(cfg.DirectMessage.LongDelay/60)) - time.Sleep(time.Duration(cfg.DirectMessage.LongDelay) * time.Second) - if cfg.SuspicionAvoidance.RandomRateLimitDelay != 0 { - time.Sleep(time.Duration(rand.Intn(cfg.SuspicionAvoidance.RandomRateLimitDelay)) * time.Second) - } - color.Yellow("[%v] Token %v continuing!", time.Now().Format("15:04:05"), instances[i].Token) - // Forbidden - DM's are closed - } else if resp.StatusCode == 403 && response.Code == 50007 { - failedCount++ - failed = append(failed, member) - err = WriteLine("input/failed.txt", member) - if err != nil { - fmt.Println(err) - } - color.Red("[%v] Token %v failed to DM %v User has DMs closed or not present in server %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, user, string(body), failedCount) - // Forbidden - Locked or Disabled - } else if (resp.StatusCode == 403 && response.Code == 40002) || resp.StatusCode == 401 || resp.StatusCode == 405 { - failedCount++ - failed = append(failed, member) - err = WriteLine("input/failed.txt", member) - if err != nil { - fmt.Println(err) - } - color.Red("[%v] Token %v is locked or disabled. Stopping instance. %v %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, resp.StatusCode, string(body), failedCount) - dead = append(dead, instances[i].Token) - // Stop token if locked or disabled - if cfg.DirectMessage.Stop { - break - } - // Forbidden - Invalid token - } else if resp.StatusCode == 403 && response.Code == 50009 { - failedCount++ - failed = append(failed, member) - err = WriteLine("input/failed.txt", member) - if err != nil { - fmt.Println(err) - } - color.Red("[%v] Token %v can't DM %v. It may not have bypassed membership screening or it's verification level is too low or the server requires new members to wait 10 minutes before they can interact in the server. %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, user, string(body), failedCount) - // General case - Continue loop. If problem with instance, it will be stopped at start of loop. - } else if resp.StatusCode == 429 { - failed = append(failed, member) - color.Red("[%v] Token %v is being rate limited. Sleeping for 10 seconds", time.Now().Format("15:04:05"), instances[i].Token) - time.Sleep(10 * time.Second) - } else if resp.StatusCode == 400 && strings.Contains(string(body), "captcha") { - color.Red("[%v] Token %v Captcha was attempted to solve but appeared again", time.Now().Format("15:04:05"), instances[i].Token) - instances[i].Retry++ - if instances[i].Retry >= cfg.CaptchaSettings.MaxCaptcha { - color.Red("[%v] Stopping token %v max captcha solves reached", time.Now().Format("15:04:05"), instances[i].Token) - break - } - } else { - failedCount++ - failed = append(failed, member) - err = WriteLine("input/failed.txt", member) - if err != nil { - fmt.Println(err) - } - color.Red("[%v] Token %v couldn't DM %v Error Code: %v; Status: %v; Message: %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, user, response.Code, resp.Status, response.Message, failedCount) - } - time.Sleep(time.Duration(cfg.DirectMessage.Delay) * time.Second) - if cfg.SuspicionAvoidance.RandomIndividualDelay != 0 { - time.Sleep(time.Duration(rand.Intn(cfg.SuspicionAvoidance.RandomIndividualDelay)) * time.Second) - } - } - }(i) - } - wg.Wait() - - color.Green("[%v] Threads have finished! Writing to file", time.Now().Format("15:04:05")) - - elapsed := time.Since(start) - color.Green("[%v] DM advertisement took %v. Successfully sent DMs to %v IDs. Failed to send DMs to %v IDs. %v tokens are dis-functional & %v tokens are functioning", time.Now().Format("15:04:05"), elapsed.Seconds(), len(completed), len(failed), len(dead), len(instances)-len(dead)) - if cfg.DirectMessage.Remove { - var tokens []string - for i := 0; i < len(instances); i++ { - tokens = append(tokens, instances[i].Token) - } - m := utilities.RemoveSubset(tokens, dead) - err := Truncate("input/tokens.txt", m) - if err != nil { - fmt.Println(err) - } - color.Green("Updated tokens.txt") - } - if cfg.DirectMessage.RemoveM { - m := utilities.RemoveSubset(members, completed) - err := Truncate("input/memberids.txt", m) - if err != nil { - fmt.Println(err) - } - color.Green("Updated memberids.txt") - - } - if cfg.DirectMessage.Websocket { - for i := 0; i < len(instances); i++ { - if instances[i].Ws != nil { - instances[i].Ws.Close() - } - } - } - + discord.LaunchMassDM() case 3: - color.Cyan("Single DM Spammer") - color.White("Enter 0 for one message; Enter 1 for continuous spam") - var choice int - fmt.Scanln(&choice) - cfg, instances, err := getEverything() - if err != nil { - fmt.Println(err) - ExitSafely() - } - var msg utilities.Message - color.White("Press 1 to use message from file or press 2 to enter a message: ") - var messagechoice int - fmt.Scanln(&messagechoice) - if messagechoice != 1 && messagechoice != 2 { - color.Red("[%v] Invalid choice", time.Now().Format("15:04:05")) - ExitSafely() - } - if messagechoice == 2 { - color.White("Enter your message, use \\n for changing lines. To use an embed, put message in message.json: ") - scanner := bufio.NewScanner(os.Stdin) - var text string - if scanner.Scan() { - text = scanner.Text() - } - - msg.Content = text - msg.Content = strings.Replace(msg.Content, "\\n", "\n", -1) - var msgs []utilities.Message - msgs = append(msgs, msg) - err := setMessages(instances, msgs) - if err != nil { - color.Red("[%v] Error while setting messages: %v", time.Now().Format("15:04:05"), err) - ExitSafely() - } - } else { - var msgs []utilities.Message - err := setMessages(instances, msgs) - if err != nil { - color.Red("[%v] Error while setting messages: %v", time.Now().Format("15:04:05"), err) - ExitSafely() - } - } - - color.White("Ensure a common link and enter victim's ID: ") - var victim string - fmt.Scanln(&victim) - var wg sync.WaitGroup - wg.Add(len(instances)) - if choice == 0 { - for i := 0; i < len(instances); i++ { - time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) - - go func(i int) { - defer wg.Done() - snowflake, err := instances[i].OpenChannel(victim) - if err != nil { - fmt.Println(err) - } - resp, err := instances[i].SendMessage(snowflake, victim) - if err != nil { - fmt.Println(err) - } - body, err := utilities.ReadBody(resp) - if err != nil { - fmt.Println(err) - } - if resp.StatusCode == 200 { - color.Green("[%v] Token %v DM'd %v", time.Now().Format("15:04:05"), instances[i].Token, victim) - } else { - color.Red("[%v] Token %v failed to DM %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, victim, string(body)) - } - }(i) - } - wg.Wait() - } - if choice == 1 { - for i := 0; i < len(instances); i++ { - time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) - go func(i int) { - defer wg.Done() - - var c int - for { - snowflake, err := instances[i].OpenChannel(victim) - if err != nil { - fmt.Println(err) - } - resp, err := instances[i].SendMessage(snowflake, victim) - if err != nil { - fmt.Println(err) - } - if resp.StatusCode == 200 { - color.Green("[%v] Token %v DM'd %v [%v]", time.Now().Format("15:04:05"), instances[i].Token, victim, c) - } else { - color.Red("[%v] Token %v failed to DM %v", time.Now().Format("15:04:05"), instances[i].Token, victim) - } - c++ - } - }(i) - wg.Wait() - } - } - color.Green("[%v] Threads have finished!", time.Now().Format("15:04:05")) - + discord.LaunchSingleDM() case 4: - color.Cyan("Reaction Adder") - color.White("Note: You don't need to do this to send DMs in servers.") - color.White("Menu:\n1) From message\n2) Manually") - var choice int - fmt.Scanln(&choice) - cfg, instances, err := getEverything() - if err != nil { - fmt.Println(err) - ExitSafely() - } - var wg sync.WaitGroup - wg.Add(len(instances)) - if choice == 1 { - color.Cyan("Enter a token which can see the message:") - var token string - fmt.Scanln(&token) - color.White("Enter message ID: ") - var id string - fmt.Scanln(&id) - color.White("Enter channel ID: ") - var channel string - fmt.Scanln(&channel) - msg, err := utilities.GetRxn(channel, id, token) - if err != nil { - fmt.Println(err) - } - color.White("Select Emoji") - for i := 0; i < len(msg.Reactions); i++ { - color.White("%v) %v %v", i, msg.Reactions[i].Emojis.Name, msg.Reactions[i].Count) - } - var emoji int - var send string - fmt.Scanln(&emoji) - for i := 0; i < len(instances); i++ { - time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) - go func(i int) { - defer wg.Done() - if msg.Reactions[emoji].Emojis.ID == "" { - send = msg.Reactions[emoji].Emojis.Name - - } else if msg.Reactions[emoji].Emojis.ID != "" { - send = msg.Reactions[emoji].Emojis.Name + ":" + msg.Reactions[emoji].Emojis.ID - } - err := instances[i].React(channel, id, send) - if err != nil { - fmt.Println(err) - color.Red("[%v] %v failed to react", time.Now().Format("15:04:05"), instances[i].Token) - } else { - color.Green("[%v] %v reacted to the emoji", time.Now().Format("15:04:05"), instances[i].Token) - } - - }(i) - } - wg.Wait() - color.Green("[%v] Completed all threads.", time.Now().Format("15:04:05")) - } - if choice == 2 { - color.Cyan("Enter channel ID") - var channel string - fmt.Scanln(&channel) - color.White("Enter message ID") - var id string - fmt.Scanln(&id) - color.Red("If you have a message, please use choice 1. If you want to add a custom emoji. Follow these instructions, if you don't, it won't work.\n If it's a default emoji which appears on the emoji keyboard, just copy it as TEXT not how it appears on Discord with the colons. Type it as text, it might look like 2 question marks on console but ignore.\n If it's a custom emoji (Nitro emoji) type it like this -> name:emojiID To get the emoji ID, copy the emoji link and copy the emoji ID from the URL.\nIf you do not follow this, it will not work. Don't try to do impossible things like trying to START a nitro reaction with a non-nitro account.") - color.White("Enter emoji") - var emoji string - fmt.Scanln(&emoji) - for i := 0; i < len(instances); i++ { - time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) - go func(i int) { - defer wg.Done() - err := instances[i].React(channel, id, emoji) - if err != nil { - fmt.Println(err) - color.Red("[%v] %v failed to react", time.Now().Format("15:04:05"), instances[i].Token) - } - color.Green("[%v] %v reacted to the emoji", time.Now().Format("15:04:05"), instances[i].Token) - }(i) - } - wg.Wait() - color.Green("[%v] Completed all threads.", time.Now().Format("15:04:05")) - } - + discord.LaunchReactionAdder() case 5: - // Uses ?around & ?limit parameters to discord's REST API to get messages to get the exact message needed - color.Cyan("Get Message - This will get the message from Discord which you want to send.") - color.White("Enter your token: \n") - var token string - fmt.Scanln(&token) - color.White("Enter the channelID: \n") - var channelID string - fmt.Scanln(&channelID) - color.White("Enter the messageID: \n") - var messageID string - fmt.Scanln(&messageID) - message, err := utilities.FindMessage(channelID, messageID, token) - if err != nil { - color.Red("Error while finding message: %v", err) - ExitSafely() - return - } - color.Green("[%v] Message: %v", time.Now().Format("15:04:05"), message) - + discord.LaunchGetMessage() case 6: - // Quick way to interconvert tokens from a popular format to the one this program supports. - color.Cyan("Email:Password:Token to Token") - Tokens, err := utilities.ReadLines("tokens.txt") - if err != nil { - color.Red("Error while opening tokens.txt: %v", err) - ExitSafely() - return - } - if len(Tokens) == 0 { - color.Red("[%v] Enter your tokens in tokens.txt", time.Now().Format("15:04:05")) - ExitSafely() - return - } - var onlytokens []string - for i := 0; i < len(Tokens); i++ { - if strings.Contains(Tokens[i], ":") { - token := strings.Split(Tokens[i], ":")[2] - onlytokens = append(onlytokens, token) - } - } - t := utilities.TruncateLines("tokens.txt", onlytokens) - if t != nil { - color.Red("[%v] Error while truncating tokens.txt: %v", time.Now().Format("15:04:05"), t) - ExitSafely() - return - } - + discord.LaunchTokenFormatter() case 7: - // Basic token checker - color.Cyan("Token checker") - _, instances, err := getEverything() - if err != nil { - color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) - ExitSafely() - } - color.White("Enter the number of threads: (0 for Unlimited)\n") - var threads int - fmt.Scanln(&threads) - if threads > len(instances) { - threads = len(instances) - } - if threads == 0 { - threads = len(instances) - } - c := goccm.New(threads) - var working []string - for i := 0; i < len(instances); i++ { - c.Wait() - go func(i int) { - err := instances[i].CheckToken() - if err != 200 { - color.Red("[%v] Token Invalid %v", time.Now().Format("15:04:05"), instances[i].Token) - } else { - color.Green("[%v] Token Valid %v", time.Now().Format("15:04:05"), instances[i].Token) - working = append(working, instances[i].Token) - } - c.Done() - }(i) - } - c.WaitAllDone() - t := utilities.TruncateLines("tokens.txt", working) - if t != nil { - color.Red("[%v] Error while truncating tokens.txt: %v", time.Now().Format("15:04:05"), t) - ExitSafely() - return - } - - color.Green("[%v] All threads finished", time.Now().Format("15:04:05")) - + discord.LaunchTokenChecker() case 8: - // Leavs tokens from a server - color.Cyan("Guild Leaver") - cfg, instances, err := getEverything() - if err != nil { - color.Red("Error while getting necessary data %v", err) - ExitSafely() - - } - color.White("Enter the number of threads (0 for unlimited): ") - var threads int - fmt.Scanln(&threads) - if threads > len(instances) { - threads = len(instances) - } - if threads == 0 { - threads = len(instances) - } - color.White("Enter delay between leaves: ") - var delay int - fmt.Scanln(&delay) - color.White("Enter serverid: ") - var serverid string - fmt.Scanln(&serverid) - c := goccm.New(threads) - for i := 0; i < len(instances); i++ { - time.Sleep(time.Duration(cfg.DirectMessage.Offset) * time.Millisecond) - c.Wait() - go func(i int) { - p := instances[i].Leave(serverid) - if p == 0 { - color.Red("[%v] Error while leaving", time.Now().Format("15:04:05")) - } - if p == 200 || p == 204 { - color.Green("[%v] Left server", time.Now().Format("15:04:05")) - } else { - color.Red("[%v] Error while leaving", time.Now().Format("15:04:05")) - } - time.Sleep(time.Duration(delay) * time.Second) - c.Done() - }(i) - } - c.WaitAllDone() - color.Green("[%v] All threads finished", time.Now().Format("15:04:05")) + discord.LaunchGuildLeaver() case 9: - - color.Blue("Token Onliner") - _, instances, err := getEverything() - if err != nil { - color.Red("Error while getting necessary data %v", err) - ExitSafely() - } - var wg sync.WaitGroup - wg.Add(len(instances)) - for i := 0; i < len(instances); i++ { - go func(i int) { - err := instances[i].StartWS() - if err != nil { - color.Red("[%v] Error while opening websocket: %v", time.Now().Format("15:04:05"), err) - } else { - color.Green("[%v] Websocket opened %v", time.Now().Format("15:04:05"), instances[i].Token) - } - wg.Done() - }(i) - } - wg.Wait() - color.Green("[%v] All Token online. Press ENTER to disconnect and continue the program", time.Now().Format("15:04:05")) - bufio.NewReader(os.Stdin).ReadBytes('\n') - wg.Add(len(instances)) - for i := 0; i < len(instances); i++ { - go func(i int) { - instances[i].Ws.Close() - wg.Done() - }(i) - } - wg.Wait() - color.Green("[%v] All Token offline", time.Now().Format("15:04:05")) - + discord.LaunchTokenOnliner() case 10: - color.Blue("Scraping Menu") - cfg, _, err := getEverything() - if err != nil { - color.Red("Error while getting necessary data %v", err) - } - color.White("1) Online Scraper (Opcode 14)\n2) Scrape from Reactions\n3) Offline Scraper (Opcode 8)") - var options int - fmt.Scanln(&options) - if options == 1 { - var token string - color.White("Enter token: ") - fmt.Scanln(&token) - var serverid string - color.White("Enter serverid: ") - fmt.Scanln(&serverid) - var channelid string - color.White("Enter channelid: ") - fmt.Scanln(&channelid) - - Is := utilities.Instance{Token: token} - t := 0 - for { - if t >= 5 { - color.Red("[%v] Couldn't connect to websocket after retrying.", time.Now().Format("15:04:05")) - break - } - err := Is.StartWS() - if err != nil { - color.Red("[%v] Error while opening websocket: %v", time.Now().Format("15:04:05"), err) - } else { - break - } - t++ - } - - color.Green("[%v] Websocket opened %v", time.Now().Format("15:04:05"), Is.Token) - - i := 0 - for { - err := utilities.Scrape(Is.Ws, serverid, channelid, i) - if err != nil { - color.Red("[%v] Error while scraping: %v", time.Now().Format("15:04:05"), err) - } - color.Green("[%v] Token %v Scrape Count: %v", time.Now().Format("15:04:05"), Is.Token, len(Is.Ws.Members)) - if Is.Ws.Complete { - break - } - i++ - time.Sleep(time.Duration(cfg.ScraperSettings.SleepSc) * time.Millisecond) - } - if Is.Ws != nil { - Is.Ws.Close() - } - color.Green("[%v] Scraping finished. Scraped %v members", time.Now().Format("15:04:05"), len(Is.Ws.Members)) - clean := utilities.RemoveDuplicateStr(Is.Ws.Members) - color.Green("[%v] Removed Duplicates. Scraped %v members", time.Now().Format("15:04:05"), len(clean)) - color.Green("[%v] Write to memberids.txt? (y/n)", time.Now().Format("15:04:05")) - - var write string - fmt.Scanln(&write) - if write == "y" { - for k := 0; k < len(clean); k++ { - err := utilities.WriteLines("memberids.txt", clean[k]) - if err != nil { - color.Red("[%v] Error while writing to memberids.txt: %v", time.Now().Format("15:04:05"), err) - } - } - color.Green("[%v] Wrote to memberids.txt", time.Now().Format("15:04:05")) - err := WriteFile("scraped/"+serverid+".txt", clean) - if err != nil { - color.Red("[%v] Error while writing to file: %v", time.Now().Format("15:04:05"), err) - } - } - - } - if options == 2 { - var token string - color.White("Enter token: ") - fmt.Scanln(&token) - var messageid string - color.White("Enter messageid: ") - fmt.Scanln(&messageid) - var channelid string - color.White("Enter channelid: ") - fmt.Scanln(&channelid) - color.White("1) Get Emoji from Message\n2) Enter Emoji manually") - var option int - var send string - fmt.Scanln(&option) - var emoji string - if option == 2 { - color.White("Enter emoji [For Native Discord Emojis, just copy and paste emoji as unicode. For Custom/Nitro Emojis enter Name:EmojiID exactly in this format]: ") - fmt.Scanln(&emoji) - send = emoji - } else { - msg, err := utilities.GetRxn(channelid, messageid, token) - if err != nil { - fmt.Println(err) - } - color.White("Select Emoji") - for i := 0; i < len(msg.Reactions); i++ { - color.White("%v) %v %v", i, msg.Reactions[i].Emojis.Name, msg.Reactions[i].Count) - } - var index int - fmt.Scanln(&index) - if msg.Reactions[index].Emojis.ID == "" { - send = msg.Reactions[index].Emojis.Name - - } else if msg.Reactions[index].Emojis.ID != "" { - send = msg.Reactions[index].Emojis.Name + ":" + msg.Reactions[index].Emojis.ID - } - } - - var allUIDS []string - var m string - for { - if len(allUIDS) == 0 { - m = "" - } else { - m = allUIDS[len(allUIDS)-1] - } - rxn, err := utilities.GetReactions(channelid, messageid, token, send, m) - if err != nil { - fmt.Println(err) - continue - } - if len(rxn) == 0 { - break - } - fmt.Println(rxn) - allUIDS = append(allUIDS, rxn...) - - } - color.Green("[%v] Scraping finished. Scraped %v lines - Removing Duplicates", time.Now().Format("15:04:05"), len(allUIDS)) - clean := utilities.RemoveDuplicateStr(allUIDS) - color.Green("[%v] Write to memberids.txt? (y/n)", time.Now().Format("15:04:05")) - var write string - fmt.Scanln(&write) - if write == "y" { - for k := 0; k < len(clean); k++ { - err := utilities.WriteLines("memberids.txt", clean[k]) - if err != nil { - color.Red("[%v] Error while writing to memberids.txt: %v", time.Now().Format("15:04:05"), err) - } - } - color.Green("[%v] Wrote to memberids.txt", time.Now().Format("15:04:05")) - err := WriteFile("scraped/"+messageid+".txt", allUIDS) - if err != nil { - color.Red("[%v] Error while writing to file: %v", time.Now().Format("15:04:05"), err) - } - } - fmt.Println("Done") - } - if options == 3 { - // Query Brute. This is a test function. Try using the compressed stream to appear legit. - // Make a list of possible characters - Space can only come once, double spaces are counted as single ones and Name can't start from space. Queries are NOT case-sensitive. - // Start from a character, check the returns. If it's less than 100, that query is complete and no need to go further down the rabbit hole. - // If it's more than 100 or 100 and the last name starts from the query, pick the letter after our query and go down the rabbit hole. - // Wait 0.5s (Or better, needs testing) Between scrapes and systematically connect and disconnect from websocket to avoid rate limiting. - // Global var where members get appended (even repeats, will be cleared later) list of queries completed, list of queries left to complete and last query the instance searched to be in struct - // Scan line for user input to stop at any point and proceed with the memberids scraped at hand. - // Multiple instance support. Division of queries and hence completes in lesser time. - // Might not need to worry about spaces at all as @ uses no spaces. - // Starting Websocket(s) Appending to a slice. 1 for now, add more later. - color.Cyan("Opcode 8 Scraper (Offline Scraper)") - color.White("This feature is intentionally slowed down with high delays. Please use multiple tokens and ensure they are in the server before starting to complete it quick.") - cfg, instances, err := getEverything() - if err != nil { - color.Red("[%v] Error while getting config: %v", time.Now().Format("15:04:05"), err) - ExitSafely() - } - var scraped []string - // Input the number of tokens to be used - color.Green("[%v] How many tokens do you wish to use? You have %v ", time.Now().Format("15:04:05"), len(instances)) - var numTokens int - quit := make(chan bool) - var allQueries []string - fmt.Scanln(&numTokens) - - chars := " !\"#$%&'()*+,-./0123456789:;<=>?@[]^_`abcdefghijklmnopqrstuvwxyz{|}~" - queriesLeft := make(chan string) - var queriesCompleted []string - - for i := 0; i < len(chars); i++ { - go func(i int) { - queriesLeft <- string(chars[i]) - }(i) - } - - if numTokens > len(instances) { - color.Red("[%v] You only have %v tokens in your tokens.txt Using the maximum number of tokens possible", time.Now().Format("15:04:05"), len(instances)) - } else if numTokens <= 0 { - color.Red("[%v] You must atleast use 1 token", time.Now().Format("15:04:05")) - ExitSafely() - } else if numTokens <= len(instances) { - color.Green("[%v] You have %v tokens in your tokens.txt Using %v tokens", time.Now().Format("15:04:05"), len(instances), numTokens) - instances = instances[:numTokens] - } else { - color.Red("[%v] Invalid input", time.Now().Format("15:04:05")) - } - - color.Green("[%v] Enter the ServerID", time.Now().Format("15:04:05")) - var serverid string - fmt.Scanln(&serverid) - color.Green("[%v] Press ENTER to START and STOP scraping", time.Now().Format("15:04:05")) - bufio.NewReader(os.Stdin).ReadBytes('\n') - var namesScraped []string - var avatarsScraped []string - // Starting the instances as GOroutines - for i := 0; i < len(instances); i++ { - go func(i int) { - instances[i].ScrapeCount = 0 - for { - - // Start websocket, reconnect if disconnected. - if instances[i].ScrapeCount%5 == 0 || instances[i].LastCount%100 == 0 { - if instances[i].Ws != nil { - instances[i].Ws.Close() - } - time.Sleep(2 * time.Second) - err := instances[i].StartWS() - if err != nil { - fmt.Println(err) - continue - } - time.Sleep(2 * time.Second) - - } - instances[i].ScrapeCount++ - - // Get a query from the channel / Await for close response - select { - case <-quit: - return - default: - query := <-queriesLeft - allQueries = append(allQueries, query) - if instances[i].Ws == nil { - continue - } - if instances[i].Ws.Conn == nil { - continue - } - err := utilities.ScrapeOffline(instances[i].Ws, serverid, query) - if err != nil { - color.Red("[%v] %v Error while scraping: %v", time.Now().Format("15:04:05"), instances[i].Token, err) - go func() { - queriesLeft <- query - }() - continue - } - - memInfo := <-instances[i].Ws.OfflineScrape - queriesCompleted = append(queriesCompleted, query) - var MemberInfo utilities.Event - err = json.Unmarshal(memInfo, &MemberInfo) - if err != nil { - color.Red("[%v] Error while unmarshalling: %v", time.Now().Format("15:04:05"), err) - queriesLeft <- query - continue - } - - if len(MemberInfo.Data.Members) == 0 { - instances[i].LastCount = -1 - continue - } - instances[i].LastCount = len(MemberInfo.Data.Members) - for _, member := range MemberInfo.Data.Members { - // Avoiding Duplicates - if !utilities.Contains(scraped, member.User.ID) { - scraped = append(scraped, member.User.ID) - } - } - color.Green("[%v] Token %v Query %v Scraped %v [+%v]", time.Now().Format("15:04:05"), instances[i].Token, query, len(scraped), len(MemberInfo.Data.Members)) - - for i := 0; i < len(MemberInfo.Data.Members); i++ { - id := MemberInfo.Data.Members[i].User.ID - err := utilities.WriteLines("memberids.txt", id) - if err != nil { - color.Red("[%v] Error while writing to file: %v", time.Now().Format("15:04:05"), err) - continue - } - if cfg.ScraperSettings.ScrapeUsernames { - nom := MemberInfo.Data.Members[i].User.Username - if !utilities.Contains(namesScraped, nom) { - err := utilities.WriteLines("names.txt", nom) - if err != nil { - color.Red("[%v] Error while writing to file: %v", time.Now().Format("15:04:05"), err) - continue - } - } - } - if cfg.ScraperSettings.ScrapeAvatars { - av := MemberInfo.Data.Members[i].User.Avatar - if !utilities.Contains(avatarsScraped, av) { - err := utilities.ProcessAvatar(av, id) - if err != nil { - color.Red("[%v] Error while processing avatar: %v", time.Now().Format("15:04:05"), err) - continue - } - } - } - } - if len(MemberInfo.Data.Members) < 100 { - time.Sleep(time.Duration(cfg.ScraperSettings.SleepSc) * time.Millisecond) - continue - } - lastName := MemberInfo.Data.Members[len(MemberInfo.Data.Members)-1].User.Username - - nextQueries := findNextQueries(query, lastName, queriesCompleted, chars) - for i := 0; i < len(nextQueries); i++ { - go func(i int) { - queriesLeft <- nextQueries[i] - }(i) - } - - } - - } - }(i) - } - - bufio.NewReader(os.Stdin).ReadBytes('\n') - color.Green("[%v] Stopping All instances", time.Now().Format("15:04:05")) - for i := 0; i < len(instances); i++ { - go func() { - quit <- true - }() - } - - color.Green("[%v] Scraping Complete. %v members scraped.", time.Now().Format("15:04:05"), len(scraped)) - color.Green("Do you wish to write to file again? (y/n) [This will remove pre-existing IDs from memberids.txt]") - var choice string - fmt.Scanln(&choice) - if choice == "y" || choice == "Y" { - clean := utilities.RemoveDuplicateStr(scraped) - err := utilities.TruncateLines("memberids.txt", clean) - if err != nil { - color.Red("[%v] Error while truncating file: %v", time.Now().Format("15:04:05"), err) - } - err = WriteFile("scraped/"+serverid, clean) - if err != nil { - color.Red("[%v] Error while writing to file: %v", time.Now().Format("15:04:05"), err) - } - } - - } + discord.LaunchScraperMenu() case 11: - color.Blue("Name Changer") - _, instances, err := getEverything() - if err != nil { - color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) - } - for i := 0; i < len(instances); i++ { - if !reg.MatchString(instances[i].Token) { - color.Red("[%v] Name changer requires tokens in email:pass:token format, there might be wrongly formatted tokens", time.Now().Format("15:04:05")) - continue - } - fullz := instances[i].Token - instances[i].Token = strings.Split(fullz, ":")[2] - instances[i].Password = strings.Split(fullz, ":")[1] - } - color.Red("NOTE: Names are changed randomly from the file.") - users, err := utilities.ReadLines("names.txt") - if err != nil { - color.Red("[%v] Error while reading names.txt: %v", time.Now().Format("15:04:05"), err) - ExitSafely() - } - color.Green("[%v] Enter number of threads: ", time.Now().Format("15:04:05")) - - var threads int - fmt.Scanln(&threads) - if threads > len(instances) { - threads = len(instances) - } - - c := goccm.New(threads) - for i := 0; i < len(instances); i++ { - c.Wait() - go func(i int) { - err := instances[i].StartWS() - if err != nil { - color.Red("[%v] Error while opening websocket: %v", time.Now().Format("15:04:05"), err) - } else { - color.Green("[%v] Websocket opened %v", time.Now().Format("15:04:05"), instances[i].Token) - } - r, err := instances[i].NameChanger(users[rand.Intn(len(users))]) - if err != nil { - color.Red("[%v] %v Error while changing name: %v", time.Now().Format("15:04:05"), instances[i].Token, err) - return - } - body, err := utilities.ReadBody(r) - if err != nil { - fmt.Println(err) - } - if r.StatusCode == 200 || r.StatusCode == 204 { - color.Green("[%v] %v Changed name successfully", time.Now().Format("15:04:05"), instances[i].Token) - } else { - color.Red("[%v] %v Error while changing name: %v %v", time.Now().Format("15:04:05"), instances[i].Token, r.Status, string(body)) - } - err = instances[i].Ws.Close() - if err != nil { - color.Red("[%v] Error while closing websocket: %v", time.Now().Format("15:04:05"), err) - } else { - color.Green("[%v] Websocket closed %v", time.Now().Format("15:04:05"), instances[i].Token) - } - c.Done() - }(i) - } - c.WaitAllDone() - color.Green("[%v] All Done", time.Now().Format("15:04:05")) - + discord.LaunchNameChanger() case 12: - color.Blue("Profile Picture Changer") - _, instances, err := getEverything() - if err != nil { - color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) - } - color.Red("NOTE: Only PNG and JPEG/JPG supported. Profile Pictures are changed randomly from the folder. Use PNG format for faster results.") - color.White("Loading Avatars..") - ex, err := os.Executable() - if err != nil { - color.Red("Couldn't find Exe") - ExitSafely() - } - ex = filepath.ToSlash(ex) - path := path.Join(path.Dir(ex) + "/input/pfps") - - images, err := utilities.GetFiles(path) - if err != nil { - color.Red("Couldn't find images in PFPs folder") - ExitSafely() - } - color.Green("%v files found", len(images)) - var avatars []string - - for i := 0; i < len(images); i++ { - av, err := utilities.EncodeImg(images[i]) - if err != nil { - color.Red("Couldn't encode image") - continue - } - avatars = append(avatars, av) - } - color.Green("%v avatars loaded", len(avatars)) - color.Green("[%v] Enter number of threads: ", time.Now().Format("15:04:05")) - var threads int - fmt.Scanln(&threads) - if threads > len(instances) { - threads = len(instances) - } - - c := goccm.New(threads) - for i := 0; i < len(instances); i++ { - c.Wait() - go func(i int) { - err := instances[i].StartWS() - if err != nil { - color.Red("[%v] Error while opening websocket: %v", time.Now().Format("15:04:05"), err) - } else { - color.Green("[%v] Websocket opened %v", time.Now().Format("15:04:05"), instances[i].Token) - } - r, err := instances[i].AvatarChanger(avatars[rand.Intn(len(avatars))]) - if err != nil { - color.Red("[%v] %v Error while changing avatar: %v", time.Now().Format("15:04:05"), instances[i].Token, err) - } else { - if r.StatusCode == 204 || r.StatusCode == 200 { - color.Green("[%v] %v Avatar changed successfully", time.Now().Format("15:04:05"), instances[i].Token) - } else { - color.Red("[%v] %v Error while changing avatar: %v", time.Now().Format("15:04:05"), instances[i].Token, r.StatusCode) - } - } - err = instances[i].Ws.Close() - if err != nil { - color.Red("[%v] Error while closing websocket: %v", time.Now().Format("15:04:05"), err) - } else { - color.Green("[%v] Websocket closed %v", time.Now().Format("15:04:05"), instances[i].Token) - } - c.Done() - }(i) - } - c.WaitAllDone() - color.Green("[%v] All done", time.Now().Format("15:04:05")) + discord.LaunchAvatarChanger() case 13: - color.White("Check if your tokens are still in the server") - _, instances, err := getEverything() - if err != nil { - color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) - ExitSafely() - } - var serverid string - var inServer []string - color.Green("[%v] Enter server ID: ", time.Now().Format("15:04:05")) - fmt.Scanln(&serverid) - var wg sync.WaitGroup - wg.Add(len(instances)) - for i := 0; i < len(instances); i++ { - go func(i int) { - defer wg.Done() - r, err := instances[i].ServerCheck(serverid) - if err != nil { - color.Red("[%v] %v Error while checking server: %v", time.Now().Format("15:04:05"), instances[i].Token, err) - } else { - if r == 200 || r == 204 { - color.Green("[%v] %v is in server %v ", time.Now().Format("15:04:05"), instances[i].Token, serverid) - inServer = append(inServer, instances[i].Token) - } else if r == 429 { - color.Green("[%v] %v is rate limited", time.Now().Format("15:04:05"), instances[i].Token) - } else if r == 400 { - color.Red("[%v] Bad request - Invalid Server ID", time.Now().Format("15:04:05")) - } else { - color.Red("[%v] %v is not in server [%v] [%v]", time.Now().Format("15:04:05"), instances[i].Token, serverid, r) - } - } - }(i) - } - wg.Wait() - color.Green("[%v] All done. Do you wish to save only tokens in the server to tokens.txt ? (y/n)", time.Now().Format("15:04:05")) - var save string - fmt.Scanln(&save) - if save == "y" || save == "Y" { - err := utilities.TruncateLines("tokens.txt", inServer) - if err != nil { - color.Red("[%v] Error while saving tokens: %v", time.Now().Format("15:04:05"), err) - } else { - color.Green("[%v] Tokens saved to tokens.txt", time.Now().Format("15:04:05")) - } - } + discord.LaunchServerChecker() case 14: - color.Blue("Bio changer") - bios, err := utilities.ReadLines("bios.txt") - if err != nil { - color.Red("[%v] Error while reading bios.txt: %v", time.Now().Format("15:04:05"), err) - ExitSafely() - } - _, instances, err := getEverything() - if err != nil { - color.Red("[%v] Error while getting necessary data: %v", time.Now().Format("15:04:05"), err) - ExitSafely() - } - bios = utilities.ValidateBios(bios) - color.Green("[%v] Loaded %v bios, %v instances", time.Now().Format("15:04:05"), len(bios), len(instances)) - color.Green("[%v] Enter number of threads: (0 for unlimited)", time.Now().Format("15:04:05")) - var threads int - fmt.Scanln(&threads) - if threads > len(instances) || threads == 0 { - threads = len(instances) - } - c := goccm.New(threads) - for i := 0; i < len(instances); i++ { - c.Wait() - go func(i int) { - err := instances[i].StartWS() - if err != nil { - color.Red("[%v] Error while opening websocket: %v", time.Now().Format("15:04:05"), err) - } else { - color.Green("[%v] Websocket opened %v", time.Now().Format("15:04:05"), instances[i].Token) - } - err = instances[i].BioChanger(bios) - if err != nil { - color.Red("[%v] %v Error while changing bio: %v", time.Now().Format("15:04:05"), instances[i].Token, err) - } else { - color.Green("[%v] %v Bio changed successfully", time.Now().Format("15:04:05"), instances[i].Token) - } - err = instances[i].Ws.Close() - if err != nil { - color.Red("[%v] Error while closing websocket: %v", time.Now().Format("15:04:05"), err) - } else { - color.Green("[%v] Websocket closed %v", time.Now().Format("15:04:05"), instances[i].Token) - } - c.Done() - }(i) - } - c.WaitAllDone() - + discord.LaunchBioChanger() + case 15: + discord.LaunchDMReact() case 16: - color.Blue("Made with <3 by github.com/V4NSH4J for free. If you were sold this program, you got scammed. Full length documentation for this is available on the github readme.") + discord.LaunchHypeSquadChanger() case 17: - // Exit without error - os.Exit(0) + discord.LaunchTokenChanger() + case 18: + color.Blue("Made with <3 by github.com/V4NSH4J - Check out the github page for detailed documentation") + case 19: + os.Exit(0) } time.Sleep(1 * time.Second) Options() } -type jsonResponse struct { - Message string `json:"message"` - Code int `json:"code"` -} - -func getEverything() (utilities.Config, []utilities.Instance, error) { - var cfg utilities.Config - var instances []utilities.Instance - var err error - var tokens []string - var proxies []string - var proxy string - - // Load config - cfg, err = utilities.GetConfig() - if err != nil { - return cfg, instances, err - } - supportedProtocols := []string{"http", "https", "socks4", "socks5"} - if cfg.ProxySettings.ProxyProtocol != "" && !utilities.Contains(supportedProtocols, cfg.ProxySettings.ProxyProtocol) { - color.Red("[!] You're using an unsupported proxy protocol. Assuming http by default") - cfg.ProxySettings.ProxyProtocol = "http" - } - if cfg.ProxySettings.ProxyProtocol == "https" { - cfg.ProxySettings.ProxyProtocol = "http" - } - if cfg.CaptchaSettings.CaptchaAPI == "" { - color.Red("[!] You're not using a Captcha API, some functionality like invite joining might be unavailable") - } - if cfg.ProxySettings.Proxy != "" && os.Getenv("HTTPS_PROXY") == "" { - os.Setenv("HTTPS_PROXY", cfg.ProxySettings.ProxyProtocol+"://"+cfg.ProxySettings.Proxy) - } - if !cfg.ProxySettings.ProxyFromFile && cfg.ProxySettings.ProxyForCaptcha { - color.Red("[!] You must enabe proxy_from_file to use proxy_for_captcha") - cfg.ProxySettings.ProxyForCaptcha = false - } - if !utilities.Contains(CaptchaServices, cfg.CaptchaSettings.CaptchaAPI) { - color.Red("[!] Captcha API %v is not supported. Please use one of the following: %v", cfg.CaptchaSettings.CaptchaAPI, CaptchaServices) - cfg.CaptchaSettings.CaptchaAPI = "" - } - - // Load instances - tokens, err = utilities.ReadLines("tokens.txt") - if err != nil { - return cfg, instances, err - } - if len(tokens) == 0 { - return cfg, instances, fmt.Errorf("no tokens found in tokens.txt") - } - if cfg.ProxySettings.ProxyFromFile { - proxies, err = utilities.ReadLines("proxies.txt") - if err != nil { - return cfg, instances, err - } - if len(proxies) == 0 { - return cfg, instances, fmt.Errorf("no proxies found in proxies.txt") - } - } - var Gproxy string - for i := 0; i < len(tokens); i++ { - if cfg.ProxySettings.ProxyFromFile { - proxy = proxies[rand.Intn(len(proxies))] - Gproxy = proxy - } else { - proxy = "" - } - client, err := initClient(proxy, cfg) - if err != nil { - return cfg, instances, fmt.Errorf("couldn't initialize client: %v", err) - } - // proxy is put in struct only to be used by gateway. If proxy for gateway is disabled, it will be empty - if !cfg.ProxySettings.GatewayProxy { - Gproxy = "" - } - instances = append(instances, utilities.Instance{Client: client, Token: tokens[i], Proxy: proxy, Config: cfg, GatewayProxy: Gproxy}) - } - if len(instances) == 0 { - color.Red("[!] You may be using 0 tokens") - } - var empty utilities.Config - if cfg == empty { - color.Red("[!] You may be using a malformed config.json") - } - return cfg, instances, nil - -} - -func setMessages(instances []utilities.Instance, messages []utilities.Message) error { - var err error - if len(messages) == 0 { - messages, err = utilities.GetMessage() - if err != nil { - return err - } - if len(messages) == 0 { - return fmt.Errorf("no messages found in messages.txt") - } - for i := 0; i < len(instances); i++ { - instances[i].Messages = messages - } - } else { - for i := 0; i < len(instances); i++ { - instances[i].Messages = messages - } - } - - return nil -} - -// Append items from slice to file -func Append(filename string, items []string) error { - file, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0644) - if err != nil { - return err - } - defer file.Close() - - for _, item := range items { - if _, err = file.WriteString(item + "\n"); err != nil { - return err - } - } - - return nil -} - -// Truncate items from slice to file -func Truncate(filename string, items []string) error { - file, err := os.OpenFile(filename, os.O_TRUNC|os.O_WRONLY, 0644) - if err != nil { - return err - } - defer file.Close() - - for _, item := range items { - if _, err = file.WriteString(item + "\n"); err != nil { - return err - } - } - - return nil -} - -// Write line to file -func WriteLine(filename string, line string) error { - file, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0644) - if err != nil { - return err - } - defer file.Close() - - if _, err = file.WriteString(line + "\n"); err != nil { - return err - } - - return nil -} - -// Create a New file and add items from a slice or append to it if it already exists -func WriteFile(filename string, items []string) error { - file, err := os.Create(filename) - if err != nil { - return err - } - defer file.Close() - - for _, item := range items { - if _, err = file.WriteString(item + "\n"); err != nil { - return err - } - } - - return nil -} - -func initClient(proxy string, cfg utilities.Config) (*http.Client, error) { - // If proxy is empty, return a default client (if proxy from file is false) - if proxy == "" { - return http.DefaultClient, nil - } - switch cfg.ProxySettings.ProxyProtocol { - case "http": - if !strings.Contains(proxy, "http://") { - proxy = "http://" + proxy - } - case "socks5": - if !strings.Contains(proxy, "socks5://") { - proxy = "socks5://" + proxy - } - case "socks4": - if !strings.Contains(proxy, "socks4://") { - proxy = "socks4://" + proxy - } - } - // Error while converting proxy string to url.url would result in default client being returned - proxyURL, err := url.Parse(proxy) - if err != nil { - return http.DefaultClient, err - } - // Creating a client and modifying the transport. - - Client := &http.Client{ - Timeout: time.Second * time.Duration(cfg.ProxySettings.Timeout), - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - MinVersion: tls.VersionTLS12, - CipherSuites: []uint16{0x1301, 0x1303, 0x1302, 0xc02b, 0xc02f, 0xcca9, 0xcca8, 0xc02c, 0xc030, 0xc00a, 0xc009, 0xc013, 0xc014, 0x009c, 0x009d, 0x002f, 0x0035}, - InsecureSkipVerify: true, - CurvePreferences: []tls.CurveID{tls.CurveID(0x001d), tls.CurveID(0x0017), tls.CurveID(0x0018), tls.CurveID(0x0019), tls.CurveID(0x0100), tls.CurveID(0x0101)}, - }, - DisableKeepAlives: cfg.OtherSettings.DisableKL, - ForceAttemptHTTP2: true, - Proxy: http.ProxyURL(proxyURL), - }, - } - return Client, nil - -} - -func ExitSafely() { - color.Red("\nPress ENTER to EXIT") - bufio.NewReader(os.Stdin).ReadBytes('\n') - os.Exit(0) -} - const logo = "\r\n\r\n\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \r\n\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\r\n\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\r\n\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\r\n\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\r\n\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \r\nDISCORD MASS DM GO" - -func findNextQueries(query string, lastName string, completedQueries []string, chars string) []string { - if query == "" { - color.Red("[%v] Query is empty", time.Now().Format("15:04:05")) - return nil - } - lastName = strings.ToLower(lastName) - indexQuery := strings.Index(lastName, query) - if indexQuery == -1 { - return nil - } - wantedCharIndex := indexQuery + len(query) - if wantedCharIndex >= len(lastName) { - - return nil - } - wantedChar := lastName[wantedCharIndex] - queryIndexDone := strings.Index(chars, string(wantedChar)) - if queryIndexDone == -1 { - - return nil - } - - var nextQueries []string - for j := queryIndexDone; j < len(chars); j++ { - newQuery := query + string(chars[j]) - if !utilities.Contains(completedQueries, newQuery) && !strings.Contains(newQuery, " ") && string(newQuery[0]) != "" { - nextQueries = append(nextQueries, newQuery) - } - } - return nextQueries -} - -var CaptchaServices []string - -func versionCheck(version string) { - link := "https://pastebin.com/raw/CCaVBSPv" - resp, err := http.Get(link) - if err != nil { - return - } - if resp.StatusCode != 200 && resp.StatusCode != 201 && resp.StatusCode != 204 { - return - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return - } - var response map[string]interface{} - err = json.Unmarshal(body, &response) - if err != nil { - return - } - v := response["version"].(string) - message := response["message"].(string) - if v != version { - color.Red("[!] You're using DMDGO V%v, but the latest version is V%v. Consider updating at https://github.com/V4NSH4J/discord-mass-DM-GO/releases", version, v) - } else { - color.Green("[O] You're Up-to-Date! You're using DMDGO V%v", version) - } - if message != "" { - color.Yellow("[!] %v", message) - } - - link = "https://pastebin.com/CCaVBSPv" - resp, err = http.Get(link) - if err != nil { - return - } - if resp.StatusCode != 200 && resp.StatusCode != 201 && resp.StatusCode != 204 { - return - } - defer resp.Body.Close() - body, err = ioutil.ReadAll(resp.Body) - if err != nil { - return - } - r := regexp.MustCompile(`