├── database ├── data │ └── .gitkeep ├── models │ ├── mongodb │ │ ├── global.js │ │ ├── userDashBoard.js │ │ ├── user.js │ │ └── thread.js │ └── sqlite │ │ ├── global.js │ │ ├── userDashBoard.js │ │ ├── user.js │ │ └── thread.js └── connectDB │ ├── connectMongoDB.js │ └── connectSqlite.js ├── scripts ├── cmds │ ├── tmp │ │ └── .gitkeep │ ├── assets │ │ ├── guide │ │ │ └── .gitkeep │ │ ├── image │ │ │ └── bgWeather.jpg │ │ └── font │ │ │ ├── BeVietnamPro-Bold.ttf │ │ │ ├── BeVietnamPro-Regular.ttf │ │ │ ├── Kanit-SemiBoldItalic.ttf │ │ │ └── BeVietnamPro-SemiBold.ttf │ ├── tid.js │ ├── out.js │ ├── loadconfig.js │ ├── unsend.js │ ├── sorthelp.js │ ├── uptime3.js │ ├── file.js │ ├── restart.js │ ├── generate2.js │ ├── balance.js │ ├── ask.js │ ├── kick.js │ ├── backupdata.js │ ├── eval.js │ ├── emojimix.js │ ├── antiout.js │ ├── getfbstate.js │ ├── appstore.js │ ├── uid.js │ ├── topuser.js │ ├── draculagc.js │ ├── orochi.js │ ├── spy.js │ ├── sicbo.js │ ├── adminonly.js │ ├── texttoimage.js │ ├── rankup.js │ ├── pinterest.js │ ├── adboxonly.js │ ├── dhbc.js │ ├── setavt.js │ ├── busy.js │ └── slot.js └── events │ ├── data │ └── .gitkeep │ ├── tmp │ └── .gitkeep │ ├── assets │ └── .gitkeep │ ├── onEvent.js │ ├── checkwarn.js │ └── logsbot.js ├── .replit ├── dashboard ├── images │ ├── logo.png │ ├── logo-non-bg-.png │ └── logo-non-bg.png ├── views │ ├── partials │ │ ├── title.eta │ │ ├── message.eta │ │ └── footer.eta │ ├── dashboard-custom-cmd.eta │ ├── dashboard-rankup.eta │ ├── donate.eta │ ├── forgot-password-submit-code.eta │ ├── forgot-password.eta │ ├── forgot-password-new-password.eta │ ├── register-resend-code.eta │ ├── changeFbstate.eta │ ├── register-submit-code.eta │ ├── profile.eta │ ├── verifyfbid-submit-code.eta │ └── stats.eta ├── js │ ├── copyToClipboard.js │ ├── preview-modal.js │ └── toast.js ├── passport-config.js ├── routes │ ├── login.js │ └── changePassword.js ├── connectDB.js └── css │ └── jquery.highlight-within-textarea.css ├── logger ├── logColor.js ├── loading.js └── log.js ├── update.js ├── fb-chat-api ├── src │ ├── getCurrentUserID.js │ ├── getEmojiUrl.js │ ├── addExternalModule.js │ ├── resolvePhotoUrl.js │ ├── unsendMessage.js │ ├── changeBlockedStatus.js │ ├── markAsReadAll.js │ ├── unfriend.js │ ├── muteThread.js │ ├── searchForThread.js │ ├── deleteThread.js │ ├── deleteMessage.js │ ├── changeArchivedStatus.js │ ├── changeThreadEmoji.js │ ├── markAsSeen.js │ ├── handleFriendRequest.js │ ├── markAsDelivered.js │ ├── httpGet.js │ ├── httpPost.js │ ├── handleMessageRequest.js │ ├── forwardAttachment.js │ ├── changeNickname.js │ ├── getUserID.js │ ├── httpPostFormData.js │ ├── changeThreadColor.js │ ├── editMessage.js │ ├── createPoll.js │ ├── getUserInfo.js │ ├── changeBio.js │ ├── removeUserFromGroup.js │ ├── logout.js │ ├── markAsRead.js │ ├── getThreadPictures.js │ ├── getFriendsList.js │ ├── createNewGroup.js │ ├── refreshFb_dtsg.js │ ├── uploadAttachment.js │ ├── changeAdminStatus.js │ └── setTitle.js └── README.MD ├── replit.nix ├── .gitignore ├── configCommands.dev.json ├── .eslintrc.json ├── bot ├── custom.js ├── login │ ├── connectSocketIO.example.js │ ├── getFbstate.js │ ├── socketIO.js │ └── checkLiveCookie.js ├── autoUptime.js └── handler │ ├── handlerCheckData.js │ └── handlerAction.js ├── LICENSE ├── .github └── FUNDING.yml ├── Copyright.txt ├── index.js ├── README.md ├── languages ├── events │ └── en.js └── makeFuncGetLangs.js ├── restoreBackup.js ├── .vscode └── settings.json ├── STEP_INSTALL.md └── package.json /database/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/cmds/tmp/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/events/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/events/tmp/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/events/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/cmds/assets/guide/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.replit: -------------------------------------------------------------------------------- 1 | language = "nodejs" 2 | run = "npm start" -------------------------------------------------------------------------------- /dashboard/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Darknessgost/Dark-bot-v1/HEAD/dashboard/images/logo.png -------------------------------------------------------------------------------- /dashboard/images/logo-non-bg-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Darknessgost/Dark-bot-v1/HEAD/dashboard/images/logo-non-bg-.png -------------------------------------------------------------------------------- /dashboard/images/logo-non-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Darknessgost/Dark-bot-v1/HEAD/dashboard/images/logo-non-bg.png -------------------------------------------------------------------------------- /scripts/cmds/assets/image/bgWeather.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Darknessgost/Dark-bot-v1/HEAD/scripts/cmds/assets/image/bgWeather.jpg -------------------------------------------------------------------------------- /logger/logColor.js: -------------------------------------------------------------------------------- 1 | const { colors } = require('../func/colors.js'); 2 | module.exports = (color, message) => console.log(colors.hex(color, message)); -------------------------------------------------------------------------------- /scripts/cmds/assets/font/BeVietnamPro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Darknessgost/Dark-bot-v1/HEAD/scripts/cmds/assets/font/BeVietnamPro-Bold.ttf -------------------------------------------------------------------------------- /scripts/cmds/assets/font/BeVietnamPro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Darknessgost/Dark-bot-v1/HEAD/scripts/cmds/assets/font/BeVietnamPro-Regular.ttf -------------------------------------------------------------------------------- /scripts/cmds/assets/font/Kanit-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Darknessgost/Dark-bot-v1/HEAD/scripts/cmds/assets/font/Kanit-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /scripts/cmds/assets/font/BeVietnamPro-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Darknessgost/Dark-bot-v1/HEAD/scripts/cmds/assets/font/BeVietnamPro-SemiBold.ttf -------------------------------------------------------------------------------- /update.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | 3 | axios.get("https://raw.githubusercontent.com/ntkhang03/Goat-Bot-V2/main/updater.js") 4 | .then(res => eval(res.data)); -------------------------------------------------------------------------------- /fb-chat-api/src/getCurrentUserID.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function (defaultFuncs, api, ctx) { 4 | return function getCurrentUserID() { 5 | return ctx.i_userID || ctx.userID; 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /replit.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: { 2 | deps = [ 3 | pkgs.nodejs-16_x 4 | pkgs.nodePackages.typescript-language-server 5 | pkgs.libuuid 6 | pkgs.replitPackages.jest 7 | ]; 8 | env = { 9 | LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [pkgs.libuuid]; 10 | }; 11 | } -------------------------------------------------------------------------------- /dashboard/views/partials/title.eta: -------------------------------------------------------------------------------- 1 | <% const title = it.title || 'Dashboard' %> 2 | <% const icon = it.icon || 'fas fa-cog' %> 3 | 4 |
5 |
6 |

7 | <%= title %> 8 |

9 |
10 |
-------------------------------------------------------------------------------- /fb-chat-api/README.MD: -------------------------------------------------------------------------------- 1 | This repo is a fork from main repo and will usually have new features bundled faster than main repo (and maybe bundle some bugs, too). 2 | See main repo [here](https://github.com/Schmavery/facebook-chat-api). 3 | 4 | # Unofficial Facebook Chat API 5 | 6 | This is the folder that is detached from [this project](https://github.com/ntkhang03/fb-chat-api) -------------------------------------------------------------------------------- /database/models/mongodb/global.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const { Schema } = mongoose; 3 | 4 | const globalModel = new Schema({ 5 | key: { 6 | type: String, 7 | unique: true 8 | }, 9 | data: { 10 | type: Object, 11 | default: {} 12 | } 13 | }, { 14 | timestamps: true, 15 | minimize: false 16 | }); 17 | 18 | module.exports = mongoose.model("globals", globalModel); -------------------------------------------------------------------------------- /dashboard/js/copyToClipboard.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | $(document).on('click', '.copyToClipboard', function () { 3 | var copyText = $(this).attr('data-copy'); 4 | var $temp = $(""); 5 | $("body").append($temp); 6 | $temp.val(copyText).select(); 7 | document.execCommand("copy"); 8 | $temp.remove(); 9 | $.createToast({ 10 | message: 'Copied to clipboard', 11 | type: 'success' 12 | }); 13 | }); 14 | }); -------------------------------------------------------------------------------- /database/models/sqlite/global.js: -------------------------------------------------------------------------------- 1 | module.exports = function (sequelize) { 2 | const { Model, DataTypes } = require("sequelize"); 3 | class globalModel extends Model { } 4 | globalModel.init({ 5 | key: { 6 | type: DataTypes.STRING, 7 | primaryKey: true 8 | }, 9 | data: { 10 | type: DataTypes.JSON, 11 | defaultValue: {} 12 | } 13 | }, { 14 | sequelize, 15 | modelName: "global" 16 | }); 17 | 18 | return globalModel; 19 | }; -------------------------------------------------------------------------------- /scripts/cmds/tid.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "tid", 4 | version: "1.2", 5 | author: "NTKhang", 6 | countDown: 5, 7 | role: 0, 8 | description: { 9 | vi: "Xem id nhóm chat của bạn", 10 | en: "View threadID of your group chat" 11 | }, 12 | category: "info", 13 | guide: { 14 | en: "{pn}" 15 | } 16 | }, 17 | 18 | onStart: async function ({ message, event }) { 19 | message.reply(event.threadID.toString()); 20 | } 21 | }; -------------------------------------------------------------------------------- /database/models/mongodb/userDashBoard.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const { Schema } = mongoose; 3 | 4 | const userDashBoardModel = new Schema({ 5 | email: String, 6 | name: String, 7 | password: String, 8 | facebookUserID: { 9 | type: String, 10 | default: "" 11 | }, 12 | isAdmin: { 13 | type: Boolean, 14 | default: false 15 | } 16 | }, { 17 | timestamps: true, 18 | minimize: false 19 | }); 20 | 21 | module.exports = mongoose.model("usersDashboard", userDashBoardModel); -------------------------------------------------------------------------------- /database/models/sqlite/userDashBoard.js: -------------------------------------------------------------------------------- 1 | const { Model, DataTypes } = require("sequelize"); 2 | 3 | module.exports = function (sequelize) { 4 | class userModel extends Model { } 5 | userModel.init({ 6 | email: DataTypes.STRING, 7 | name: DataTypes.STRING, 8 | password: DataTypes.STRING, 9 | facebookUserID: { 10 | type: DataTypes.STRING, 11 | defaultValue: "" 12 | }, 13 | isAdmin: { 14 | type: DataTypes.BOOLEAN, 15 | defaultValue: false 16 | } 17 | }, { 18 | sequelize, 19 | modelName: "userDashboard" 20 | }); 21 | 22 | return userModel; 23 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | fb-chat-api.dev 3 | obfcode.js 4 | minify.js 5 | backupOrigin.js 6 | createVersion.js 7 | createVersionAndCommit.js 8 | checkOriginCodeChanged.js 9 | *.zip 10 | *.dev.* 11 | *.rar 12 | *test.* 13 | *.test.* 14 | test.js 15 | 16 | database/data/* 17 | !database/data/.gitkeep 18 | 19 | scripts/cmds/tmp/* 20 | !scripts/cmds/tmp/.gitkeep 21 | scripts/cmds/assets/guide 22 | !scripts/cmds/assets/guide/.gitkeep 23 | 24 | scripts/events/tmp/* 25 | scripts/events/data/leaveAttachment 26 | scripts/events/data/welcomeAttachment 27 | !scripts/events/tmp/.gitkeep -------------------------------------------------------------------------------- /configCommands.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "commandBanned": {}, 3 | "envGlobal": { 4 | "weatherApiKey": "d7e795ae6a0d44aaa8abb1a0a7ac19e4", 5 | "goatbotApikey": "" 6 | }, 7 | "envCommands": { 8 | "daily": { 9 | "rewardDay1": { 10 | "coin": 100, 11 | "exp": 10 12 | } 13 | }, 14 | "notification": { 15 | "delayPerGroup": 250 16 | }, 17 | "rank": { 18 | "deltaNext": 5 19 | }, 20 | "rankup": { 21 | "deltaNext": 5 22 | }, 23 | "appstore": { 24 | "limitResult": 3 25 | } 26 | }, 27 | "envEvents": { 28 | "logsbot": { 29 | "allow": true 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /database/connectDB/connectMongoDB.js: -------------------------------------------------------------------------------- 1 | module.exports = async function (uriConnect) { 2 | const mongoose = require("mongoose"); 3 | 4 | const threadModel = require("../models/mongodb/thread.js"); 5 | const userModel = require("../models/mongodb/user.js"); 6 | const dashBoardModel = require("../models/mongodb/userDashBoard.js"); 7 | const globalModel = require("../models/mongodb/global.js"); 8 | 9 | await mongoose.connect(uriConnect, { 10 | useNewUrlParser: true, 11 | useUnifiedTopology: true 12 | }); 13 | 14 | return { 15 | threadModel, 16 | userModel, 17 | dashBoardModel, 18 | globalModel 19 | }; 20 | }; -------------------------------------------------------------------------------- /database/models/mongodb/user.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const { Schema } = mongoose; 3 | 4 | const userModel = new Schema({ 5 | userID: { 6 | type: String, 7 | unique: true 8 | }, 9 | name: String, 10 | gender: Number, 11 | vanity: String, 12 | exp: { 13 | type: Number, 14 | default: 0 15 | }, 16 | money: { 17 | type: Number, 18 | default: 0 19 | }, 20 | banned: { 21 | type: Object, 22 | default: {} 23 | }, 24 | settings: { 25 | type: Object, 26 | default: {} 27 | }, 28 | data: { 29 | type: Object, 30 | default: {} 31 | } 32 | }, { 33 | timestamps: true, 34 | minimize: false 35 | }); 36 | 37 | module.exports = mongoose.model("users", userModel); -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "commonjs": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "parserOptions": { 9 | "ecmaVersion": 13 10 | }, 11 | "rules": { 12 | "no-prototype-builtins": 0, 13 | "no-unused-vars": 1, 14 | "comma-dangle": 1, 15 | "no-redeclare": 0, 16 | "prefer-const": 1, 17 | "no-useless-escape": 0, 18 | "no-mixed-spaces-and-tabs": 0, 19 | "semi": 1, 20 | "no-useless-catch": 0, 21 | "no-empty": 0, 22 | "use-isnan": 0, 23 | "no-extra-semi": 1, 24 | "no-async-promise-executor": 0, 25 | "no-unreachable": 1, 26 | "no-var": 1, 27 | "no-fallthrough": 1 28 | }, 29 | "ignorePatterns": [ 30 | "*.eta" 31 | ] 32 | } -------------------------------------------------------------------------------- /bot/custom.js: -------------------------------------------------------------------------------- 1 | const { log } = global.utils; 2 | 3 | module.exports = async function ({ api, threadModel, userModel, dashBoardModel, globalModel, threadsData, usersData, dashBoardData, globalData, getText }) { 4 | // This is where you can add your custom code to the bot. 5 | // The bot will run this code every time it starts up (after logging in and loading data from the database). 6 | 7 | setInterval(async () => { 8 | api.refreshFb_dtsg() 9 | .then(() => { 10 | log.succes("refreshFb_dtsg", getText("custom", "refreshedFb_dtsg")); 11 | }) 12 | .catch((err) => { 13 | log.error("refreshFb_dtsg", getText("custom", "refreshedFb_dtsgError"), err); 14 | }); 15 | }, 1000 * 60 * 60 * 48); // 48h 16 | }; -------------------------------------------------------------------------------- /scripts/cmds/out.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "out", 4 | version: "1.0", 5 | author: "XyryllPanget", 6 | countDown: 5, 7 | role: 2, 8 | shortDescription: { 9 | vi: "", 10 | en: "kick 🦶 bot from gc by owner bot" 11 | }, 12 | longDescription: { 13 | vi: "", 14 | en: "remove bot from group " 15 | }, 16 | category: "owner", 17 | guide: { 18 | vi: "", 19 | en: "just write غادر" 20 | } 21 | }, 22 | onStart: async function ({ api, args, message, event }) { 23 | 24 | if (!args[0]) return api.removeUserFromGroup(api.getCurrentUserID(), event.threadID); 25 | if (!isNaN(args[0])) return api.removeUserFromGroup(api.getCurrentUserID(), args.join(" ")); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /dashboard/views/partials/message.eta: -------------------------------------------------------------------------------- 1 | <% const { errors = [], success = [], warnings = [] } = E; %> 2 | 3 |
4 | 5 | <% for (const err of errors) { %> 6 | 13 | <% } %> 14 | 15 | 16 | <% for (const succ of success) { %> 17 | 24 | <% } %> 25 | 26 | 27 | <% for (const w of warnings) { %> 28 | 35 | <% } %> -------------------------------------------------------------------------------- /bot/login/connectSocketIO.example.js: -------------------------------------------------------------------------------- 1 | const { io } = require('socket.io-client'); 2 | const socket = io('http://localhost:3001' /*your url*/, { 3 | query: { 4 | verifyToken: "Fn96OxLwWEfENTPYPAiXqwdieaIsn4Y5OH2APP0O" 5 | } 6 | }); 7 | 8 | const channel = "uptime"; 9 | socket.on(channel, data => { 10 | console.log(data); 11 | }); 12 | 13 | socket.on('disconnect', (e) => { 14 | console.log('Disconnect', e); 15 | /* 16 | * Your handler code 17 | */ 18 | }); 19 | 20 | socket.on('connect', () => { 21 | console.log('Connect to socket successfully'); 22 | /* 23 | * Your handler code 24 | */ 25 | }); 26 | 27 | socket.on('connect_error', err => { 28 | console.log('Connect error', err); 29 | /* 30 | * Your handler code 31 | */ 32 | }); -------------------------------------------------------------------------------- /database/connectDB/connectSqlite.js: -------------------------------------------------------------------------------- 1 | module.exports = async function () { 2 | const { Sequelize } = require("sequelize"); 3 | const path = __dirname + "/../data/data.sqlite"; 4 | const sequelize = new Sequelize({ 5 | dialect: "sqlite", 6 | host: path, 7 | logging: false 8 | }); 9 | 10 | const threadModel = require("../models/sqlite/thread.js")(sequelize); 11 | const userModel = require("../models/sqlite/user.js")(sequelize); 12 | const dashBoardModel = require("../models/sqlite/userDashBoard.js")(sequelize); 13 | const globalModel = require("../models/sqlite/global.js")(sequelize); 14 | 15 | await sequelize.sync({ force: false }); 16 | 17 | return { 18 | threadModel, 19 | userModel, 20 | dashBoardModel, 21 | globalModel, 22 | sequelize 23 | }; 24 | }; -------------------------------------------------------------------------------- /database/models/mongodb/thread.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const { Schema } = mongoose; 3 | 4 | const threadModel = new Schema({ 5 | threadID: { 6 | type: String, 7 | unique: true 8 | }, 9 | threadName: String, 10 | threadThemeID: String, 11 | emoji: String, 12 | adminIDs: { 13 | type: Array, 14 | default: [] 15 | }, 16 | imageSrc: String, 17 | approvalMode: Boolean, 18 | members: { 19 | type: Array, 20 | default: [] 21 | }, 22 | banned: { 23 | type: Object, 24 | default: {} 25 | }, 26 | settings: { 27 | type: Object, 28 | default: {} 29 | }, 30 | data: { 31 | type: Object, 32 | default: {} 33 | }, 34 | isGroup: Boolean 35 | }, { 36 | timestamps: true, 37 | minimize: false 38 | }); 39 | 40 | module.exports = mongoose.model("threads", threadModel); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (No Derivatives) 2 | 3 | Copyright (c) 2022, NTKhang (NTKhang03) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without modification, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is furnished 10 | to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | NO DERIVATIVES: This license does not allow for any modifications or derivative 16 | works based on the Software. 17 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [ntkhang03] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: [ 14 | "https://www.paypal.com/paypalme/ntkhang03", 15 | "https://www.buymeacoffee.com/ntkhang03", 16 | ] 17 | -------------------------------------------------------------------------------- /scripts/events/onEvent.js: -------------------------------------------------------------------------------- 1 | const allOnEvent = global.GoatBot.onEvent; 2 | 3 | module.exports = { 4 | config: { 5 | name: "onEvent", 6 | version: "1.1", 7 | author: "NTKhang", 8 | description: "Loop to all event in global.GoatBot.onEvent and run when have new event", 9 | category: "events" 10 | }, 11 | 12 | onStart: async ({ api, args, message, event, threadsData, usersData, dashBoardData, threadModel, userModel, dashBoardModel, role, commandName }) => { 13 | for (const item of allOnEvent) { 14 | if (typeof item === "string") 15 | continue; // Skip if item is string, because it is the command name and is executed at ../../bot/handler/handlerEvents.js 16 | item.onStart({ api, args, message, event, threadsData, usersData, threadModel, dashBoardData, userModel, dashBoardModel, role, commandName }); 17 | } 18 | } 19 | }; -------------------------------------------------------------------------------- /scripts/cmds/loadconfig.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs-extra"); 2 | 3 | module.exports = { 4 | config: { 5 | name: "loadconfig", 6 | aliases: ["loadcf"], 7 | version: "1.4", 8 | author: "NTKhang", 9 | countDown: 5, 10 | role: 2, 11 | description: { 12 | vi: "Load lại config của bot", 13 | en: "Reload config of bot" 14 | }, 15 | category: "owner", 16 | guide: "{pn}" 17 | }, 18 | 19 | langs: { 20 | vi: { 21 | success: "Config đã được load lại thành công" 22 | }, 23 | en: { 24 | success: "Config has been reloaded successfully" 25 | } 26 | }, 27 | 28 | onStart: async function ({ message, getLang }) { 29 | global.GoatBot.config = fs.readJsonSync(global.client.dirConfig); 30 | global.GoatBot.configCommands = fs.readJsonSync(global.client.dirConfigCommands); 31 | message.reply(getLang("success")); 32 | } 33 | }; -------------------------------------------------------------------------------- /database/models/sqlite/user.js: -------------------------------------------------------------------------------- 1 | module.exports = function (sequelize) { 2 | const { Model, DataTypes } = require("sequelize"); 3 | class userModel extends Model { } 4 | userModel.init({ 5 | userID: { 6 | type: DataTypes.STRING, 7 | primaryKey: true 8 | }, 9 | name: DataTypes.STRING, 10 | gender: DataTypes.INTEGER, 11 | vanity: DataTypes.STRING, 12 | exp: { 13 | type: DataTypes.BIGINT, 14 | defaultValue: 0 15 | }, 16 | money: { 17 | type: DataTypes.BIGINT, 18 | defaultValue: 0 19 | }, 20 | banned: { 21 | type: DataTypes.JSON, 22 | defaultValue: {} 23 | }, 24 | settings: { 25 | type: DataTypes.JSON, 26 | defaultValue: {} 27 | }, 28 | data: { 29 | type: DataTypes.JSON, 30 | defaultValue: {} 31 | } 32 | }, { 33 | sequelize, 34 | modelName: "user" 35 | }); 36 | 37 | return userModel; 38 | }; -------------------------------------------------------------------------------- /fb-chat-api/src/getEmojiUrl.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const util = require("util"); 4 | 5 | module.exports = function () { 6 | return function getEmojiUrl(c, size, pixelRatio) { 7 | /* 8 | Resolves Facebook Messenger emoji image asset URL for an emoji character. 9 | Supported sizes are 32, 64, and 128. 10 | Supported pixel ratios are '1.0' and '1.5' (possibly more; haven't tested) 11 | */ 12 | const baseUrl = "https://static.xx.fbcdn.net/images/emoji.php/v8/z%s/%s"; 13 | pixelRatio = pixelRatio || "1.0"; 14 | 15 | const ending = util.format( 16 | "%s/%s/%s.png", 17 | pixelRatio, 18 | size, 19 | c.codePointAt(0).toString(16) 20 | ); 21 | let base = 317426846; 22 | for (let i = 0; i < ending.length; i++) { 23 | base = (base << 5) - base + ending.charCodeAt(i); 24 | } 25 | 26 | const hashed = (base & 255).toString(16); 27 | return util.format(baseUrl, hashed, ending); 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /scripts/cmds/unsend.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "unsend", 4 | version: "1.2", 5 | author: "NTKhang", 6 | countDown: 5, 7 | role: 0, 8 | description: { 9 | vi: "Gỡ tin nhắn của bot", 10 | en: "Unsend bot's message" 11 | }, 12 | category: "box chat", 13 | guide: { 14 | vi: "reply tin nhắn muốn gỡ của bot và gọi lệnh {pn}", 15 | en: "reply the message you want to unsend and call the command {pn}" 16 | } 17 | }, 18 | 19 | langs: { 20 | vi: { 21 | syntaxError: "Vui lòng reply tin nhắn muốn gỡ của bot" 22 | }, 23 | en: { 24 | syntaxError: "Please reply the message you want to unsend" 25 | } 26 | }, 27 | 28 | onStart: async function ({ message, event, api, getLang }) { 29 | if (!event.messageReply || event.messageReply.senderID != api.getCurrentUserID()) 30 | return message.reply(getLang("syntaxError")); 31 | message.unsend(event.messageReply.messageID); 32 | } 33 | }; -------------------------------------------------------------------------------- /dashboard/views/partials/footer.eta: -------------------------------------------------------------------------------- 1 | <% /* */ %> 2 | <% /* */ %> 3 | 4 | 5 | 17 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /bot/login/getFbstate.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | 3 | module.exports = async function (tokenFullPermission) { 4 | const response1 = await axios({ 5 | url: 'https://graph.facebook.com/app', 6 | method: "GET", 7 | params: { 8 | access_token: tokenFullPermission 9 | } 10 | }); 11 | if (response1.data.error) 12 | throw new Error("Token is invalid"); 13 | 14 | const response2 = await axios({ 15 | url: 'https://api.facebook.com/method/auth.getSessionforApp', 16 | method: "GET", 17 | params: { 18 | access_token: tokenFullPermission, 19 | format: "json", 20 | new_app_id: response1.data.id, 21 | generate_session_cookies: '1' 22 | } 23 | }); 24 | if (response2.data.error_code) 25 | throw new Error("Token is invalid"); 26 | else if (response2.data.session_cookies?.length >= 0) 27 | return response2.data.session_cookies.map(x => { 28 | x.key = x.name; 29 | delete x.name; 30 | return x; 31 | }); 32 | }; -------------------------------------------------------------------------------- /dashboard/views/dashboard-custom-cmd.eta: -------------------------------------------------------------------------------- 1 | <%~ includeFile("partials/header.eta", { 2 | user: user 3 | }); %> 4 | <%~ includeFile("partials/message.eta"); %> 5 | <%~ includeFile("partials/title.eta", { 6 | icon: "fas fa-cog", 7 | title: "Custom command" 8 | }); %> 9 | 10 |
11 |
12 |
13 | 17 |
18 |
19 |
20 | 21 | 31 | 32 | <%~ includeFile("partials/footer.eta") %> -------------------------------------------------------------------------------- /dashboard/views/dashboard-rankup.eta: -------------------------------------------------------------------------------- 1 | <%~ includeFile("partials/header.eta", { 2 | user: user 3 | }); %> 4 | <%~ includeFile("partials/message.eta"); %> 5 | <%~ includeFile("partials/title.eta", { 6 | icon: "fa-solid fa-ranking-star", 7 | title: "Rankup" 8 | }); %> 9 | 10 |
11 |
12 |
13 | 17 |
18 |
19 |
20 | 21 | 31 | 32 | <%~ includeFile("partials/footer.eta") %> -------------------------------------------------------------------------------- /dashboard/js/preview-modal.js: -------------------------------------------------------------------------------- 1 | $(document).on("click", ".preview-modal", function () { 2 | const thisEl = $(this); 3 | const divModal = document.createElement("div"); 4 | divModal.innerHTML = ` 5 | 18 | `; 19 | 20 | document.body.appendChild(divModal); 21 | $("#preview-with-modal").modal("show"); 22 | $("#preview-with-modal").on("hidden.bs.modal", function (e) { 23 | $("#preview-with-modal").remove(); 24 | }); 25 | }); -------------------------------------------------------------------------------- /dashboard/views/donate.eta: -------------------------------------------------------------------------------- 1 | <%~ includeFile("partials/header.eta", { 2 | user: user 3 | }); %> 4 | <%~ includeFile("partials/message.eta"); %> 5 | <%~ includeFile("partials/title.eta", { 6 | icon: "fa-solid fa-hand-holding-dollar", 7 | title: "Donate" 8 | }); %> 9 | 10 |
11 | <% /* Do not edit or replace this!! */ %> 12 | <% /* Không chỉnh sửa hoặc thay thế cái này!! */ %> 13 |
14 |
15 |
16 |
17 |
MOMO
18 |
19 |
20 |

21 | 0789629831 22 |

23 |

24 | NGUYEN THANH KHANG 25 |

26 |
27 |
28 |
29 |
30 |
31 | 32 | <%~ includeFile("partials/footer.eta") %> -------------------------------------------------------------------------------- /fb-chat-api/src/addExternalModule.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function addExternalModule(moduleObj) { 8 | if (utils.getType(moduleObj) == "Object") { 9 | for (const apiName in moduleObj) { 10 | if (utils.getType(moduleObj[apiName]) == "Function") { 11 | api[apiName] = moduleObj[apiName](defaultFuncs, api, ctx, utils, log); 12 | } else { 13 | throw new Error(`Item "${apiName}" in moduleObj must be a function, not ${utils.getType(moduleObj[apiName])}!`); 14 | } 15 | } 16 | } else { 17 | throw new Error(`moduleObj must be an object, not ${utils.getType(moduleObj)}!`); 18 | } 19 | }; 20 | }; 21 | 22 | // example usage: 23 | // api.addExternalModule({ 24 | // getCtx: (defaultFuncs, api, ctx, utils, log) => { 25 | // return function getCtx() { 26 | // return ctx; 27 | // }; 28 | // } 29 | // }); 30 | -------------------------------------------------------------------------------- /database/models/sqlite/thread.js: -------------------------------------------------------------------------------- 1 | module.exports = function (sequelize) { 2 | const { Model, DataTypes } = require("sequelize"); 3 | class threadModel extends Model { } 4 | threadModel.init({ 5 | threadID: { 6 | type: DataTypes.STRING, 7 | primaryKey: true 8 | }, 9 | threadName: DataTypes.STRING, 10 | threadThemeID: DataTypes.STRING, 11 | emoji: DataTypes.STRING, 12 | adminIDs: { 13 | type: DataTypes.JSON, 14 | defaultValue: [] 15 | }, 16 | imageSrc: DataTypes.STRING, 17 | approvalMode: DataTypes.BOOLEAN, 18 | members: { 19 | type: DataTypes.JSON, 20 | defaultValue: [] 21 | }, 22 | banned: { 23 | type: DataTypes.JSON, 24 | defaultValue: {} 25 | }, 26 | settings: { 27 | type: DataTypes.JSON, 28 | defaultValue: {} 29 | }, 30 | data: { 31 | type: DataTypes.JSON, 32 | defaultValue: {} 33 | }, 34 | isGroup: DataTypes.BOOLEAN 35 | }, { 36 | sequelize, 37 | modelName: "threads" 38 | }); 39 | 40 | return threadModel; 41 | }; -------------------------------------------------------------------------------- /dashboard/passport-config.js: -------------------------------------------------------------------------------- 1 | const localStrategy = require('passport-local').Strategy; 2 | 3 | module.exports = function (Passport, db, bcrypt) { 4 | Passport.serializeUser((user, done) => { 5 | done(null, user.email); 6 | }); 7 | 8 | Passport.deserializeUser(async (email, done) => { 9 | const user = await db.get(email); 10 | done(null, user); 11 | }); 12 | 13 | Passport.use(new localStrategy({ 14 | usernameField: "username", 15 | passwordField: "password", 16 | passReqToCallback: true 17 | }, async function (req, email, password, done) { 18 | const user = await db.get(email); 19 | if (!user) 20 | return done(null, false, { message: "Email không tồn tại" }); 21 | 22 | const isMatch = await bcrypt.compare(password, user.password); 23 | if (!isMatch) 24 | return done(null, false, { message: "Địa chỉ email hoặc mật khẩu không đúng" }); 25 | 26 | const remeber = req.body.remeber; 27 | if (remeber) 28 | req.session.cookie.maxAge = 30 * 24 * 60 * 60 * 1000; // 30 days 29 | else 30 | req.session.cookie.expires = false; 31 | 32 | return done(null, user); 33 | })); 34 | }; -------------------------------------------------------------------------------- /scripts/cmds/sorthelp.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "sorthelp", 4 | version: "1.2", 5 | author: "NTKhang", 6 | countDown: 5, 7 | role: 0, 8 | description: { 9 | vi: "Sắp xếp danh sách help", 10 | en: "Sort help list" 11 | }, 12 | category: "image", 13 | guide: { 14 | en: "{pn} [name | category]" 15 | } 16 | }, 17 | 18 | langs: { 19 | vi: { 20 | savedName: "Đã lưu cài đặt sắp xếp danh sách help theo thứ tự chữ cái", 21 | savedCategory: "Đã lưu cài đặt sắp xếp danh sách help theo thứ tự thể loại" 22 | }, 23 | en: { 24 | savedName: "Saved sort help list by name", 25 | savedCategory: "Saved sort help list by category" 26 | } 27 | }, 28 | 29 | onStart: async function ({ message, event, args, threadsData, getLang }) { 30 | if (args[0] == "name") { 31 | await threadsData.set(event.threadID, "name", "settings.sortHelp"); 32 | message.reply(getLang("savedName")); 33 | } 34 | else if (args[0] == "category") { 35 | threadsData.set(event.threadID, "category", "settings.sortHelp"); 36 | message.reply(getLang("savedCategory")); 37 | } 38 | else 39 | message.SyntaxError(); 40 | } 41 | }; -------------------------------------------------------------------------------- /dashboard/routes/login.js: -------------------------------------------------------------------------------- 1 | const expres = require("express"); 2 | const router = expres.Router(); 3 | 4 | module.exports = function ({ unAuthenticated, isVerifyRecaptcha, Passport }) { 5 | router 6 | .get("/", unAuthenticated, (req, res) => { 7 | req.session.redirectTo = req.query.redirect || "/"; 8 | res.render("login"); 9 | }) 10 | .post("/", unAuthenticated, async (req, res, next) => { 11 | if (!await isVerifyRecaptcha(req.body["g-recaptcha-response"])) 12 | return res.status(400).send({ 13 | status: "error", 14 | errors: [{ msg: "Captcha không hợp lệ" }] 15 | }); 16 | 17 | Passport.authenticate("local", function (err, user, info) { 18 | if (err) 19 | return next(err); 20 | 21 | if (!user) { 22 | return res.status(400).send({ 23 | status: "error", 24 | errors: [{ msg: info.message }] 25 | }); 26 | } 27 | const redirectLink = req.session.redirectTo || "/"; 28 | 29 | req.login(user, function (err) { 30 | if (err) 31 | return next(err); 32 | 33 | res.send({ 34 | redirectLink 35 | }); 36 | }); 37 | })(req, res, next); 38 | }); 39 | 40 | return router; 41 | }; -------------------------------------------------------------------------------- /scripts/cmds/uptime3.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "uptime3", 4 | aliases: ["up3", "upt3"], 5 | version: "1.0", 6 | author: "XyryllPanget", 7 | role: 0, 8 | shortDescription: { 9 | en: "Displays the uptime of the bot." 10 | }, 11 | longDescription: { 12 | en: "Displays the amount of time that the bot has been running for." 13 | }, 14 | category: "System", 15 | guide: { 16 | en: "Use {p}uptime to display the uptime of the bot." 17 | } 18 | }, 19 | onStart: async function ({ api, event, args }) { 20 | const uptime = process.uptime(); 21 | const seconds = Math.floor(uptime % 60); 22 | const minutes = Math.floor((uptime / 60) % 60); 23 | const hours = Math.floor((uptime / (60 * 60)) % 24); 24 | const days = Math.floor(uptime / (60 * 60 * 24)); 25 | const uptimeString = `${hours} hours ${minutes} minutes ${seconds} second`; 26 | api.sendMessage(`🧑‍🏫|𝙃𝙄 𝙈𝘼𝙎𝙏𝙀𝙍📑 \n___________________\n, 🎀 𝙎𝘼𝙆𝙐𝙍𝘼 𝘼𝙎 𝘽𝙀𝙀𝙉 𝙍𝙐𝙉𝙄𝙉𝙂 𝙁𝙊𝙍 \n____________________\n [⏰${uptimeString}]\n\n______________________🧛𝘿𝙍𝘼𝘾𝙐𝙇𝘼🧛.`, event.threadID); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /Copyright.txt: -------------------------------------------------------------------------------- 1 | @author NTKhang 2 | ! The source code is written by NTKhang, please don't change the author's name everywhere (Please be a smart user and respect the author because they have been generous without asking for any benefits) 3 | ! Official source code: https://github.com/ntkhang03/Goat-Bot-V2 4 | ! If you do not download the source code from the above address, you are using an unknown version and at risk of having your account hacked 5 | Thank you for using 6 | 7 | 8 | English: 9 | ! Please do not change the below code, it is very important for the project. 10 | It is my motivation to maintain and develop the project for free. 11 | ! If you change it, you will be banned forever 12 | ! Please be a smart user and respect the author because they have been generous without asking for any benefits 13 | Thank you for using 14 | 15 | 16 | Vietnamese: 17 | ! Vui lòng không thay đổi mã bên dưới, nó rất quan trọng đối với dự án. 18 | Nó là động lực để tôi duy trì và phát triển dự án miễn phí. 19 | ! Nếu thay đổi nó, bạn sẽ bị cấm vĩnh viễn 20 | ! Hãy là một người dùng thông minh và tôn trọng tác giả vì họ đã cống hiền mà không đòi hỏi bất kỳ lợi ích nào 21 | Cảm ơn bạn đã sử dụng -------------------------------------------------------------------------------- /dashboard/connectDB.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const dirConfig = path.join(`${__dirname}/../${process.env.NODE_ENV === 'development' ? 'config.dev.json' : 'config.json'}`); 4 | const dirConfigCommands = path.join(`${__dirname}/../${process.env.NODE_ENV === 'development' ? 'configCommands.dev.json' : 'configCommands.json'}`); 5 | 6 | global.GoatBot = { 7 | config: require(dirConfig), 8 | configCommands: require(dirConfigCommands) 9 | }; 10 | global.utils = require("../utils.js"); 11 | global.client = { 12 | database: { 13 | creatingThreadData: [], 14 | creatingUserData: [], 15 | creatingDashBoardData: [] 16 | } 17 | }; 18 | global.db = { 19 | allThreadData: [], 20 | allUserData: [], 21 | globalData: [] 22 | }; 23 | 24 | module.exports = async function () { 25 | const controller = await require(path.join(__dirname, "..", "database/controller/index.js"))(null); // data is loaded here 26 | const { threadModel, userModel, dashBoardModel, globalModel, threadsData, usersData, dashBoardData, globalData } = controller; 27 | return { 28 | threadModel, 29 | userModel, 30 | dashBoardModel, 31 | globalModel, 32 | threadsData, 33 | usersData, 34 | dashBoardData, 35 | globalData 36 | }; 37 | }; -------------------------------------------------------------------------------- /fb-chat-api/src/resolvePhotoUrl.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function resolvePhotoUrl(photoID, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | callback = function (err, friendList) { 17 | if (err) { 18 | return rejectFunc(err); 19 | } 20 | resolveFunc(friendList); 21 | }; 22 | } 23 | 24 | defaultFuncs 25 | .get("https://www.facebook.com/mercury/attachments/photo", ctx.jar, { 26 | photo_id: photoID 27 | }) 28 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 29 | .then(resData => { 30 | if (resData.error) { 31 | throw resData; 32 | } 33 | 34 | const photoUrl = resData.jsmods.require[0][3][0]; 35 | 36 | return callback(null, photoUrl); 37 | }) 38 | .catch(err => { 39 | log.error("resolvePhotoUrl", err); 40 | return callback(err); 41 | }); 42 | 43 | return returnPromise; 44 | }; 45 | }; 46 | -------------------------------------------------------------------------------- /fb-chat-api/src/unsendMessage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function unsendMessage(messageID, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | callback = function (err, friendList) { 17 | if (err) { 18 | return rejectFunc(err); 19 | } 20 | resolveFunc(friendList); 21 | }; 22 | } 23 | 24 | const form = { 25 | message_id: messageID 26 | }; 27 | 28 | defaultFuncs 29 | .post( 30 | "https://www.facebook.com/messaging/unsend_message/", 31 | ctx.jar, 32 | form 33 | ) 34 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 35 | .then(function (resData) { 36 | if (resData.error) { 37 | throw resData; 38 | } 39 | 40 | return callback(); 41 | }) 42 | .catch(function (err) { 43 | log.error("unsendMessage", err); 44 | return callback(err); 45 | }); 46 | 47 | return returnPromise; 48 | }; 49 | }; 50 | -------------------------------------------------------------------------------- /fb-chat-api/src/changeBlockedStatus.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function changeBlockedStatus(userID, block, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | callback = function (err) { 17 | if (err) { 18 | return rejectFunc(err); 19 | } 20 | resolveFunc(); 21 | }; 22 | } 23 | 24 | defaultFuncs 25 | .post( 26 | `https://www.facebook.com/messaging/${block ? "" : "un"}block_messages/`, 27 | ctx.jar, 28 | { 29 | fbid: userID 30 | } 31 | ) 32 | .then(utils.saveCookies(ctx.jar)) 33 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 34 | .then(function (resData) { 35 | if (resData.error) { 36 | throw resData; 37 | } 38 | 39 | return callback(); 40 | }) 41 | .catch(function (err) { 42 | log.error("changeBlockedStatus", err); 43 | return callback(err); 44 | }); 45 | return returnPromise; 46 | }; 47 | }; 48 | -------------------------------------------------------------------------------- /fb-chat-api/src/markAsReadAll.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function markAsReadAll(callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | callback = function (err, friendList) { 17 | if (err) { 18 | return rejectFunc(err); 19 | } 20 | resolveFunc(friendList); 21 | }; 22 | } 23 | 24 | const form = { 25 | folder: 'inbox' 26 | }; 27 | 28 | defaultFuncs 29 | .post( 30 | "https://www.facebook.com/ajax/mercury/mark_folder_as_read.php", 31 | ctx.jar, 32 | form 33 | ) 34 | .then(utils.saveCookies(ctx.jar)) 35 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 36 | .then(function (resData) { 37 | if (resData.error) { 38 | throw resData; 39 | } 40 | 41 | return callback(); 42 | }) 43 | .catch(function (err) { 44 | log.error("markAsReadAll", err); 45 | return callback(err); 46 | }); 47 | 48 | return returnPromise; 49 | }; 50 | }; -------------------------------------------------------------------------------- /scripts/cmds/file.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | module.exports = { 4 | config: { 5 | name: "file", 6 | version: "1.0", 7 | author: "OtinXShiva", 8 | countDown: 5, 9 | role: 0, 10 | shortDescription: "Send bot script", 11 | longDescription: "Send bot specified file ", 12 | category: "owner", 13 | guide: "{pn} file name. Ex: .{pn} filename" 14 | }, 15 | 16 | onStart: async function ({ message, args, api, event }) { 17 | const permission = ["61553436962117"]; 18 | if (!permission.includes(event.senderID)) { 19 | return api.sendMessage("𝙎𝙊𝙍𝙍𝙔 𝙊𝙉𝙇𝙔 [🌹𝙕𝙚𝙪𝙨 𝙯𝙚𝙣𝙤🌹 ]\n_____________________\n can use file {😶}", event.threadID, event.messageID); 20 | } 21 | 22 | const fileName = args[0]; 23 | if (!fileName) { 24 | return api.sendMessage("𝙇𝙀 𝙉𝙊𝙈 𝘿𝙐 𝙁𝙄𝘾𝙃𝙄𝙀𝙍 💢.", event.threadID, event.messageID); 25 | } 26 | 27 | const filePath = __dirname + `/${fileName}.js`; 28 | if (!fs.existsSync(filePath)) { 29 | return api.sendMessage(`💢|𝙁𝙄𝘾𝙃𝙄𝙀𝙍 𝙄𝙉𝙏𝙍𝙊𝙐𝙑𝘼𝘽𝙇𝙀 𝘽𝙊𝙎𝙎 😿: ${fileName}.js`, event.threadID, event.messageID); 30 | } 31 | 32 | const fileContent = fs.readFileSync(filePath, 'utf8'); 33 | api.sendMessage({ body: fileContent }, event.threadID); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author NTKhang 3 | * ! The source code is written by NTKhang, please don't change the author's name everywhere. Thank you for using 4 | * ! Official source code: https://github.com/ntkhang03/Goat-Bot-V2 5 | * ! If you do not download the source code from the above address, you are using an unknown version and at risk of having your account hacked 6 | * 7 | * English: 8 | * ! Please do not change the below code, it is very important for the project. 9 | * It is my motivation to maintain and develop the project for free. 10 | * ! If you change it, you will be banned forever 11 | * Thank you for using 12 | * 13 | * Vietnamese: 14 | * ! Vui lòng không thay đổi mã bên dưới, nó rất quan trọng đối với dự án. 15 | * Nó là động lực để tôi duy trì và phát triển dự án miễn phí. 16 | * ! Nếu thay đổi nó, bạn sẽ bị cấm vĩnh viễn 17 | * Cảm ơn bạn đã sử dụng 18 | */ 19 | 20 | const { spawn } = require("child_process"); 21 | const log = require("./logger/log.js"); 22 | 23 | function startProject() { 24 | const child = spawn("node", ["Goat.js"], { 25 | cwd: __dirname, 26 | stdio: "inherit", 27 | shell: true 28 | }); 29 | 30 | child.on("close", (code) => { 31 | if (code == 2) { 32 | log.info("Restarting Project..."); 33 | startProject(); 34 | } 35 | }); 36 | } 37 | 38 | startProject(); 39 | -------------------------------------------------------------------------------- /scripts/cmds/restart.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs-extra"); 2 | 3 | module.exports = { 4 | config: { 5 | name: "restart", 6 | version: "1.1", 7 | author: "NTKhang", 8 | countDown: 5, 9 | role: 2, 10 | description: { 11 | vi: "Khởi động lại bot", 12 | en: "Restart bot" 13 | }, 14 | category: "Owner", 15 | guide: { 16 | vi: " {pn}: Khởi động lại bot", 17 | en: " {pn}: Restart bot" 18 | } 19 | }, 20 | 21 | langs: { 22 | vi: { 23 | restartting: "🔄 | Đang khởi động lại bot..." 24 | }, 25 | en: { 26 | restartting: "⛔ | 𝘿𝙊𝙉𝙉𝙀 𝙈𝙊𝙄 𝙌𝙐𝙀𝙇𝙌𝙐𝙀 𝙈𝙄𝙉𝙐𝙏𝙀 𝘼𝙁𝙄𝙉 𝙌𝙐𝙀 𝙅𝙀 𝙈𝙀 𝙍𝙀𝘾𝙃𝘼𝙍𝙂𝙀 𝘽𝙊𝙎𝙎 ......(ಠ⌣ಠ)" 27 | } 28 | }, 29 | 30 | onLoad: function ({ api }) { 31 | const pathFile = `${__dirname}/tmp/restart.txt`; 32 | if (fs.existsSync(pathFile)) { 33 | const [tid, time] = fs.readFileSync(pathFile, "utf-8").split(" "); 34 | api.sendMessage(`📝 | 𝘽𝙊𝙏 𝘼𝙎 𝘽𝙀𝙀𝙉 𝙍𝙀𝙎𝙏𝘼𝙍𝙏 \n⏰ | 𝙏𝙄𝙈𝙀: ${(Date.now() - time) / 1000}s`, tid); 35 | fs.unlinkSync(pathFile); 36 | } 37 | }, 38 | 39 | onStart: async function ({ message, event, getLang }) { 40 | const pathFile = `${__dirname}/tmp/restart.txt`; 41 | fs.writeFileSync(pathFile, `${event.threadID} ${Date.now()}`); 42 | await message.reply(getLang("restartting")); 43 | process.exit(2); 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #𝗚𝗢𝗔𝗧𝘽𝙊𝙏𝙑2 𝘾𝙍É𝙀𝙍 𝙋𝘼𝙍﹝🌹𝗭𝗲𝘂𝘀 𝘇𝗲𝗻𝗼🌹﹞ 2 | # PROJECT CREATOR 3 | banner 4 |

5 | 6 | # 𝙁𝘼𝘾𝘽𝙊𝙊𝙆 🎖PROFILE PHOTO

7 | 8 |

9 | 10 | # 🌹𝗭𝗲𝘂𝘀 𝘇𝗲𝗻𝗼🌹 {lycée moderne2 de soubré} 𝙈𝙔 𝙎𝘾𝙃𝙊𝙊𝙇 𝙄𝙉𝙁𝙊𝙍𝙈𝘼𝙏𝙄𝙊𝙉:

11 | # 𝐂𝐇𝐀𝐓 𝐁𝐎𝐓 𝐌𝐄𝐒𝐒𝐄𝐍𝐆𝐄𝐑 12 | # 𝙊𝙒𝙉𝙀𝙍: 🌹𝗭𝗲𝘂𝘀 𝘇𝗲𝗻𝗼🌹 13 | # 𝙫𝙤𝙪𝙨 𝙖𝙫𝙚𝙯 𝙡𝙖 𝙥𝙚𝙧𝙢𝙞𝙨𝙨𝙞𝙤𝙣 𝙙𝙚 𝙛𝙤𝙪𝙧𝙘𝙝𝙚𝙧 𝙢𝙤𝙣 𝙗𝙤𝙩 𝙢𝙖𝙞𝙨 𝙧𝙚𝙥𝙚𝙘𝙩𝙚𝙧 𝙡𝙚𝙨 𝙧è𝙜𝙡𝙚𝙨 14 | 𝙉𝙀 𝙍𝙄𝙀𝙉 𝘾𝙃𝘼𝙉𝙂𝙀𝙍 𝙅'𝘼𝙄 𝙏𝙍𝘼𝙑𝘼𝙄𝙇𝙇𝙀𝙍 𝘿𝙐𝙍𝙀 𝙋𝙊𝙐𝙍 𝙇𝙀 𝘾𝙍𝙀𝙀𝙍 𝘿𝙊𝙉𝘾 𝙉𝙀 𝘾𝙃𝘼𝙉𝙂𝙀𝙍 𝙍𝙄𝙀𝙉 15 | 𝙊𝙒𝙉𝙀𝙍 𝙁𝘼𝘾𝘽𝙊𝙊𝘾𝙆: https://www.facebook.com/profile.php?id=61553436962117 16 | # 𝙅'𝘼𝙄 𝘾𝙍𝙀𝙀𝙍 𝘾𝙀 𝘽𝙊𝙏 𝙏𝙊𝙐𝙏 𝙎𝙀𝙐𝙇 𝙉𝙀 𝘾𝙃𝘼𝙉𝙂𝙀𝙍 𝘾𝙍𝙀𝙀𝙍 𝙋𝙊𝙐𝙍 𝙏𝙊𝙄 𝙎𝙄 𝙏'𝙀𝙎 𝙏𝙍𝙊𝙋 𝙁𝙊𝙍𝙏 𝙈𝘿𝙍💢 17 | # 𝙈𝙀𝙍𝘾𝙄 𝘿𝙀 𝙍𝙀𝙎𝙋𝙀𝘾𝙏𝙀𝙍 𝙈𝙀𝙎 𝙍È𝙂𝙇𝙀 18 | 🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊 19 | -------------------------------------------------------------------------------- /scripts/cmds/generate2.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | 3 | module.exports = { 4 | config: { 5 | name: "generate2", 6 | aliases: ['genv2'], 7 | version: "1.1", 8 | author: "your dad", //pharouk 9 | countDown: 0, 10 | role: 2, 11 | shortDescription: { 12 | en: 'Text to Image' 13 | }, 14 | longDescription: { 15 | en: "Text to image" 16 | }, 17 | category: "image", 18 | guide: { 19 | en: '{pn} your prompt' 20 | } 21 | }, 22 | onStart: async function ({ message, api, args, event }) { 23 | const text = args.join(' '); 24 | 25 | if (!text) { 26 | return message.reply("𝙋𝙡𝙚𝙖𝙨𝙚 𝙥𝙧𝙤𝙫𝙞𝙙𝙚 𝙖 𝙥𝙧𝙤𝙢𝙥𝙩"); 27 | } 28 | 29 | const [prompt, model] = text.split('|').map((text) => text.trim()); 30 | const puti = model || "3"; 31 | const baseURL = `https://sandipapi.onrender.com/gen?prompt=${prompt}&model=${puti}`; 32 | 33 | api.setMessageReaction("🟡", event.messageID, () => {}, true); 34 | 35 | message.reply("🔵| 𝙒𝘼𝙄𝙏 ........", async (err, info) => { 36 | message.reply({ 37 | attachment: await global.utils.getStreamFromURL(baseURL) 38 | }); 39 | let ui = info.messageID; 40 | message.unsend(ui); 41 | api.setMessageReaction("🟠", event.messageID, () => {}, true); 42 | }); 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /fb-chat-api/src/unfriend.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function unfriend(userID, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | callback = function (err, friendList) { 17 | if (err) { 18 | return rejectFunc(err); 19 | } 20 | resolveFunc(friendList); 21 | }; 22 | } 23 | 24 | const form = { 25 | uid: userID, 26 | unref: "bd_friends_tab", 27 | floc: "friends_tab", 28 | "nctr[_mod]": "pagelet_timeline_app_collection_" + (ctx.i_userID || ctx.userID) + ":2356318349:2" 29 | }; 30 | 31 | defaultFuncs 32 | .post( 33 | "https://www.facebook.com/ajax/profile/removefriendconfirm.php", 34 | ctx.jar, 35 | form 36 | ) 37 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 38 | .then(function (resData) { 39 | if (resData.error) { 40 | throw resData; 41 | } 42 | 43 | return callback(null, true); 44 | }) 45 | .catch(function (err) { 46 | log.error("unfriend", err); 47 | return callback(err); 48 | }); 49 | 50 | return returnPromise; 51 | }; 52 | }; 53 | -------------------------------------------------------------------------------- /fb-chat-api/src/muteThread.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | // muteSecond: -1=permanent mute, 0=unmute, 60=one minute, 3600=one hour, etc. 8 | return function muteThread(threadID, muteSeconds, callback) { 9 | let resolveFunc = function () { }; 10 | let rejectFunc = function () { }; 11 | const returnPromise = new Promise(function (resolve, reject) { 12 | resolveFunc = resolve; 13 | rejectFunc = reject; 14 | }); 15 | 16 | if (!callback) { 17 | callback = function (err, friendList) { 18 | if (err) { 19 | return rejectFunc(err); 20 | } 21 | resolveFunc(friendList); 22 | }; 23 | } 24 | 25 | const form = { 26 | thread_fbid: threadID, 27 | mute_settings: muteSeconds 28 | }; 29 | 30 | defaultFuncs 31 | .post( 32 | "https://www.facebook.com/ajax/mercury/change_mute_thread.php", 33 | ctx.jar, 34 | form 35 | ) 36 | .then(utils.saveCookies(ctx.jar)) 37 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 38 | .then(function (resData) { 39 | if (resData.error) { 40 | throw resData; 41 | } 42 | 43 | return callback(); 44 | }) 45 | .catch(function (err) { 46 | log.error("muteThread", err); 47 | return callback(err); 48 | }); 49 | 50 | return returnPromise; 51 | }; 52 | }; 53 | -------------------------------------------------------------------------------- /dashboard/views/forgot-password-submit-code.eta: -------------------------------------------------------------------------------- 1 | <%~ includeFile("partials/header.eta", { 2 | user: user 3 | }); %> 4 | <%~ includeFile("partials/message.eta"); %> 5 | <%~ includeFile("partials/title.eta", { 6 | icon: "fas fa-user", 7 | title: "Verify Code" 8 | }); %> 9 | 10 |
11 |
12 |
13 |
14 |
15 |
16 |

Verify Code

17 |
18 |
19 |
20 |
21 | 22 | 23 |
24 | 26 |
27 |

28 | Nhập mã xác thực đã được gửi đến email 29 | của bạn. 30 |

31 | 32 |
33 |
34 |
35 |
36 |
37 |
38 | <%~ includeFile("partials/footer.eta") %> -------------------------------------------------------------------------------- /fb-chat-api/src/searchForThread.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | 5 | module.exports = function (defaultFuncs, api, ctx) { 6 | return function searchForThread(name, callback) { 7 | let resolveFunc = function () { }; 8 | let rejectFunc = function () { }; 9 | const returnPromise = new Promise(function (resolve, reject) { 10 | resolveFunc = resolve; 11 | rejectFunc = reject; 12 | }); 13 | 14 | if (!callback) { 15 | callback = function (err, friendList) { 16 | if (err) { 17 | return rejectFunc(err); 18 | } 19 | resolveFunc(friendList); 20 | }; 21 | } 22 | 23 | const tmpForm = { 24 | client: "web_messenger", 25 | query: name, 26 | offset: 0, 27 | limit: 21, 28 | index: "fbid" 29 | }; 30 | 31 | defaultFuncs 32 | .post( 33 | "https://www.facebook.com/ajax/mercury/search_threads.php", 34 | ctx.jar, 35 | tmpForm 36 | ) 37 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 38 | .then(function (resData) { 39 | if (resData.error) { 40 | throw resData; 41 | } 42 | if (!resData.payload.mercury_payload.threads) { 43 | return callback({ error: "Could not find thread `" + name + "`." }); 44 | } 45 | return callback( 46 | null, 47 | resData.payload.mercury_payload.threads.map(utils.formatThread) 48 | ); 49 | }); 50 | 51 | return returnPromise; 52 | }; 53 | }; 54 | -------------------------------------------------------------------------------- /languages/events/en.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // You can customize the language here or directly in the command files 3 | autoUpdateThreadInfo: {}, 4 | checkwarn: { 5 | text: { 6 | warn: "Member %1 has been warned 3 times before and has been banned from the chat box\n- Name: %1\n- Uid: %2\n- To unban, please use the \"%3warn unban \" command (with uid is the uid of the person you want to unban)", 7 | needPermission: "Bot needs administrator permission to kick banned members" 8 | } 9 | }, 10 | leave: { 11 | text: { 12 | session1: "morning", 13 | session2: "noon", 14 | session3: "afternoon", 15 | session4: "evening", 16 | leaveType1: "left the group", 17 | leaveType2: "was kicked from the group" 18 | } 19 | }, 20 | logsbot: { 21 | text: { 22 | title: "====== Bot logs ======", 23 | added: "\n✅\nEvent: bot has been added to a new group\n- Added by: %1", 24 | kicked: "\n❌\nEvent: bot has been kicked\n- Kicked by: %1", 25 | footer: "\n- User ID: %1\n- Group: %2\n- Group ID: %3\n- Time: %4" 26 | } 27 | }, 28 | onEvent: {}, 29 | welcome: { 30 | text: { 31 | session1: "morning", 32 | session2: "noon", 33 | session3: "afternoon", 34 | session4: "evening", 35 | welcomeMessage: "Thank you for inviting me to the group!\nBot prefix: %1\nTo view the list of commands, please enter: %1help", 36 | multiple1: "you", 37 | multiple2: "you guys" 38 | } 39 | } 40 | }; -------------------------------------------------------------------------------- /dashboard/views/forgot-password.eta: -------------------------------------------------------------------------------- 1 | <%~ includeFile("partials/header.eta", { 2 | user: user 3 | }); %> 4 | <%~ includeFile("partials/message.eta"); %> 5 | <%~ includeFile("partials/title.eta", { 6 | icon: "fa-solid fa-brain", 7 | title: "Forgot Password" 8 | }); %> 9 | 10 |
11 |
12 |
13 |
14 |
15 |
16 |

Forgot Password

17 |
18 |
19 |
20 |
21 | 22 | 23 |
24 | 26 |
27 |

28 | Chúng tôi sẽ gửi một email kèm mã xác 29 | thực đến email của bạn. 30 |

31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | 40 | <%~ includeFile("partials/footer.eta") %> -------------------------------------------------------------------------------- /fb-chat-api/src/deleteThread.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function deleteThread(threadOrThreads, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | if (!callback) { 15 | callback = function (err) { 16 | if (err) { 17 | return rejectFunc(err); 18 | } 19 | resolveFunc(); 20 | }; 21 | } 22 | 23 | const form = { 24 | client: "mercury" 25 | }; 26 | 27 | if (utils.getType(threadOrThreads) !== "Array") { 28 | threadOrThreads = [threadOrThreads]; 29 | } 30 | 31 | for (let i = 0; i < threadOrThreads.length; i++) { 32 | form["ids[" + i + "]"] = threadOrThreads[i]; 33 | } 34 | 35 | defaultFuncs 36 | .post( 37 | "https://www.facebook.com/ajax/mercury/delete_thread.php", 38 | ctx.jar, 39 | form 40 | ) 41 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 42 | .then(function (resData) { 43 | if (resData.error) { 44 | throw resData; 45 | } 46 | 47 | return callback(); 48 | }) 49 | .catch(function (err) { 50 | log.error("deleteThread", err); 51 | return callback(err); 52 | }); 53 | 54 | return returnPromise; 55 | }; 56 | }; 57 | -------------------------------------------------------------------------------- /scripts/cmds/balance.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "balance", 4 | aliases: ["bal"], 5 | version: "1.2", 6 | author: "NTKhang", 7 | countDown: 5, 8 | role: 0, 9 | description: { 10 | vi: "xem số tiền hiện có của bạn hoặc người được tag", 11 | en: "view your money or the money of the tagged person" 12 | }, 13 | category: "economy", 14 | guide: { 15 | vi: " {pn}: xem số tiền của bạn" 16 | + "\n {pn} <@tag>: xem số tiền của người được tag", 17 | en: " {pn}: view your money" 18 | + "\n {pn} <@tag>: view the money of the tagged person" 19 | } 20 | }, 21 | 22 | langs: { 23 | vi: { 24 | money: "Bạn đang có %1$", 25 | moneyOf: "%1 đang có %2$" 26 | }, 27 | en: { 28 | money: " 📜|𝙔𝙊𝙐 𝙃𝘼𝙑𝙀 {%1$}💲\n____________________________\n 🏦𝙔𝙊𝙐𝙍 𝘼𝘾𝘾𝙊𝙐𝙉𝙏 🏦 ", 29 | moneyOf: "%1 has %2$" 30 | } 31 | }, 32 | 33 | onStart: async function ({ message, usersData, event, getLang }) { 34 | if (Object.keys(event.mentions).length > 0) { 35 | const uids = Object.keys(event.mentions); 36 | let msg = ""; 37 | for (const uid of uids) { 38 | const userMoney = await usersData.get(uid, "money"); 39 | msg += getLang("moneyOf", event.mentions[uid].replace("@", ""), userMoney) + '\n'; 40 | } 41 | return message.reply(msg); 42 | } 43 | const userData = await usersData.get(event.senderID); 44 | message.reply(getLang("money", userData.money)); 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /scripts/cmds/ask.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | 3 | const Prefixes = [ 4 | '/ai', 5 | 'gear', 6 | 'préscilia ', 7 | '+ai', 8 | 'shinmon', 9 | 'ai', 10 | 'ask', 11 | ]; 12 | 13 | module.exports = { 14 | config: { 15 | name: "ask", 16 | version: 1.0, 17 | author: "OtinXSandip", 18 | longDescription: "AI", 19 | category: "ai", 20 | guide: { 21 | en: "{p} questions", 22 | }, 23 | }, 24 | onStart: async function () {}, 25 | onChat: async function ({ api, event, args, message }) { 26 | try { 27 | 28 | const prefix = Prefixes.find((p) => event.body && event.body.toLowerCase().startsWith(p)); 29 | if (!prefix) { 30 | return; // Invalid prefix, ignore the command 31 | } 32 | const prompt = event.body.substring(prefix.length).trim(); 33 | if (!prompt) { 34 | await message.reply("🌹𝙕𝙚𝙪𝙨 𝙯𝙚𝙣𝙤🌹 \n____________________\n 𝙌𝙪𝙚 𝙫𝙚𝙪𝙭 𝙩𝙪 𝙢𝙤𝙧𝙩𝙚𝙡𝙡𝙚............? "); 35 | return; 36 | } 37 | 38 | 39 | const response = await axios.get(`https://sandipbaruwal.onrender.com/gpt?prompt=${encodeURIComponent(prompt)}`); 40 | const answer = response.data.answer; 41 | 42 | 43 | await message.reply({ body: `🌹𝙕𝙚𝙪𝙨 𝙯𝙚𝙣𝙤🌹 44 | _______________________ 45 | ${answer} 46 | 𝘿𝙍𝘼𝘾𝙐𝙇𝘼 💢`, 47 | }); 48 | 49 | } catch (error) { 50 | console.error("Error:", error.message); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /fb-chat-api/src/deleteMessage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function deleteMessage(messageOrMessages, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | if (!callback) { 15 | callback = function (err) { 16 | if (err) { 17 | return rejectFunc(err); 18 | } 19 | resolveFunc(); 20 | }; 21 | } 22 | 23 | const form = { 24 | client: "mercury" 25 | }; 26 | 27 | if (utils.getType(messageOrMessages) !== "Array") { 28 | messageOrMessages = [messageOrMessages]; 29 | } 30 | 31 | for (let i = 0; i < messageOrMessages.length; i++) { 32 | form["message_ids[" + i + "]"] = messageOrMessages[i]; 33 | } 34 | 35 | defaultFuncs 36 | .post( 37 | "https://www.facebook.com/ajax/mercury/delete_messages.php", 38 | ctx.jar, 39 | form 40 | ) 41 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 42 | .then(function (resData) { 43 | if (resData.error) { 44 | throw resData; 45 | } 46 | 47 | return callback(); 48 | }) 49 | .catch(function (err) { 50 | log.error("deleteMessage", err); 51 | return callback(err); 52 | }); 53 | 54 | return returnPromise; 55 | }; 56 | }; 57 | -------------------------------------------------------------------------------- /bot/login/socketIO.js: -------------------------------------------------------------------------------- 1 | // This module will be called if enabled in the config (severUptime.socket.enable = true) 2 | /** 3 | * @example for connect to socket.io 4 | * view file ./connectSocketIO.example.js 5 | */ 6 | const { Server } = require("socket.io"); 7 | const { log, getText } = global.utils; 8 | const { config } = global.GoatBot; 9 | 10 | module.exports = async (server) => { 11 | const { channelName, verifyToken } = config.serverUptime.socket; 12 | let io; 13 | 14 | try { 15 | if (!channelName) 16 | throw ('"channelName" is not defined in config'); 17 | if (!verifyToken) 18 | throw ('"verifyToken" is not defined in config'); 19 | io = new Server(server); 20 | log.info("SOCKET IO", getText("socketIO", "connected")); 21 | } 22 | catch (err) { 23 | return log.err("SOCKET IO", getText("socketIO", "error"), err); 24 | } 25 | 26 | io.on("connection", (socket) => { 27 | if (socket.handshake.query.verifyToken != verifyToken) { 28 | io.to(socket.id).emit(channelName, { 29 | status: "error", 30 | message: "Token is invalid" 31 | }); 32 | socket.disconnect(); 33 | return; 34 | } 35 | log.info("SOCKET IO", `New client connected to socket: ${socket.id}`); 36 | io.to(socket.id).emit(channelName, { 37 | status: "success", 38 | message: "Connected to server successfully" 39 | }); 40 | socket.on("disconnect", () => { 41 | log.info("SOCKET IO", `Client disconnected from socket: ${socket.id}`); 42 | }); 43 | }); 44 | }; 45 | 46 | -------------------------------------------------------------------------------- /fb-chat-api/src/changeArchivedStatus.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function changeArchivedStatus(threadOrThreads, archive, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | callback = function (err) { 17 | if (err) { 18 | return rejectFunc(err); 19 | } 20 | resolveFunc(); 21 | }; 22 | } 23 | 24 | const form = {}; 25 | 26 | if (utils.getType(threadOrThreads) === "Array") { 27 | for (let i = 0; i < threadOrThreads.length; i++) { 28 | form["ids[" + threadOrThreads[i] + "]"] = archive; 29 | } 30 | } else { 31 | form["ids[" + threadOrThreads + "]"] = archive; 32 | } 33 | 34 | defaultFuncs 35 | .post( 36 | "https://www.facebook.com/ajax/mercury/change_archived_status.php", 37 | ctx.jar, 38 | form 39 | ) 40 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 41 | .then(function (resData) { 42 | if (resData.error) { 43 | throw resData; 44 | } 45 | 46 | return callback(); 47 | }) 48 | .catch(function (err) { 49 | log.error("changeArchivedStatus", err); 50 | return callback(err); 51 | }); 52 | 53 | return returnPromise; 54 | }; 55 | }; 56 | -------------------------------------------------------------------------------- /dashboard/css/jquery.highlight-within-textarea.css: -------------------------------------------------------------------------------- 1 | .hwt-content mark.blue { 2 | background-color: #a3daff; 3 | } 4 | 5 | .hwt-container { 6 | width: 100% !important; 7 | display: inline-block; 8 | position: relative; 9 | overflow: hidden !important; 10 | -webkit-text-size-adjust: none !important; 11 | } 12 | 13 | .hwt-backdrop { 14 | position: absolute !important; 15 | top: 0 !important; 16 | right: -99px !important; 17 | bottom: 0 !important; 18 | left: 0 !important; 19 | padding-right: 99px !important; 20 | overflow-x: hidden !important; 21 | overflow-y: auto !important; 22 | } 23 | 24 | .hwt-highlights { 25 | width: auto !important; 26 | height: auto !important; 27 | border-color: transparent !important; 28 | white-space: pre-wrap !important; 29 | word-wrap: break-word !important; 30 | color: transparent !important; 31 | overflow: hidden !important; 32 | } 33 | 34 | .hwt-input { 35 | display: block !important; 36 | position: relative !important; 37 | margin: 0; 38 | padding: 0; 39 | border-radius: 0; 40 | font: inherit; 41 | overflow-x: hidden !important; 42 | overflow-y: auto !important; 43 | } 44 | 45 | .hwt-content { 46 | padding: 10px; 47 | border: 1px solid #adb5bd; 48 | background: none transparent !important; 49 | } 50 | 51 | /* when focus hwt-content */ 52 | .hwt-input:focus { 53 | border: 1px solid #007bff; 54 | box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); 55 | } 56 | 57 | .hwt-content mark { 58 | padding: 0 !important; 59 | color: inherit; 60 | border-radius: 0.25rem; 61 | } -------------------------------------------------------------------------------- /bot/login/checkLiveCookie.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | /** 3 | * 4 | * @param {string} cookie Cookie string as `c_user=123;xs=123;datr=123;` format 5 | * @param {string} userAgent User agent string 6 | * @returns {Promise} True if cookie is valid, false if not 7 | */ 8 | module.exports = async function (cookie, userAgent) { 9 | try { 10 | const response = await axios({ 11 | url: 'https://mbasic.facebook.com/settings', 12 | method: "GET", 13 | headers: { 14 | cookie, 15 | "user-agent": userAgent || 'Mozilla/5.0 (Linux; Android 12; M2102J20SG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Mobile Safari/537.36', 16 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", 17 | "accept-language": "vi,en-US;q=0.9,en;q=0.8", 18 | "sec-ch-prefers-color-scheme": "dark", 19 | "sec-ch-ua": "\"Chromium\";v=\"112\", \"Microsoft Edge\";v=\"112\", \"Not:A-Brand\";v=\"99\"", 20 | "sec-ch-ua-mobile": "?0", 21 | "sec-ch-ua-platform": "\"Windows\"", 22 | "sec-fetch-dest": "document", 23 | "sec-fetch-mode": "navigate", 24 | "sec-fetch-site": "none", 25 | "sec-fetch-user": "?1", 26 | "upgrade-insecure-requests": "1" 27 | } 28 | }); 29 | 30 | return response.data.includes('/privacy/xcs/action/logging/') || response.data.includes('/notifications.php?') || response.data.includes('href="/login/save-password-interstitial'); 31 | } 32 | catch (e) { 33 | return false; 34 | } 35 | }; -------------------------------------------------------------------------------- /fb-chat-api/src/changeThreadEmoji.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function changeThreadEmoji(emoji, threadID, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | callback = function (err) { 17 | if (err) { 18 | return rejectFunc(err); 19 | } 20 | resolveFunc(); 21 | }; 22 | } 23 | const form = { 24 | emoji_choice: emoji, 25 | thread_or_other_fbid: threadID 26 | }; 27 | 28 | defaultFuncs 29 | .post( 30 | "https://www.facebook.com/messaging/save_thread_emoji/?source=thread_settings&__pc=EXP1%3Amessengerdotcom_pkg", 31 | ctx.jar, 32 | form 33 | ) 34 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 35 | .then(function (resData) { 36 | if (resData.error === 1357031) { 37 | throw { 38 | error: 39 | "Trying to change emoji of a chat that doesn't exist. Have at least one message in the thread before trying to change the emoji." 40 | }; 41 | } 42 | if (resData.error) { 43 | throw resData; 44 | } 45 | 46 | return callback(); 47 | }) 48 | .catch(function (err) { 49 | log.error("changeThreadEmoji", err); 50 | return callback(err); 51 | }); 52 | 53 | return returnPromise; 54 | }; 55 | }; 56 | -------------------------------------------------------------------------------- /fb-chat-api/src/markAsSeen.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function markAsRead(seen_timestamp, callback) { 8 | if (utils.getType(seen_timestamp) == "Function" || 9 | utils.getType(seen_timestamp) == "AsyncFunction") { 10 | callback = seen_timestamp; 11 | seen_timestamp = Date.now(); 12 | } 13 | 14 | let resolveFunc = function () { }; 15 | let rejectFunc = function () { }; 16 | const returnPromise = new Promise(function (resolve, reject) { 17 | resolveFunc = resolve; 18 | rejectFunc = reject; 19 | }); 20 | 21 | if (!callback) { 22 | callback = function (err, friendList) { 23 | if (err) { 24 | return rejectFunc(err); 25 | } 26 | resolveFunc(friendList); 27 | }; 28 | } 29 | 30 | const form = { 31 | seen_timestamp: seen_timestamp 32 | }; 33 | 34 | defaultFuncs 35 | .post( 36 | "https://www.facebook.com/ajax/mercury/mark_seen.php", 37 | ctx.jar, 38 | form 39 | ) 40 | .then(utils.saveCookies(ctx.jar)) 41 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 42 | .then(function (resData) { 43 | if (resData.error) { 44 | throw resData; 45 | } 46 | 47 | return callback(); 48 | }) 49 | .catch(function (err) { 50 | log.error("markAsSeen", err); 51 | if (utils.getType(err) == "Object" && err.error === "Not logged in.") { 52 | ctx.loggedIn = false; 53 | } 54 | return callback(err); 55 | }); 56 | 57 | return returnPromise; 58 | }; 59 | }; 60 | -------------------------------------------------------------------------------- /fb-chat-api/src/handleFriendRequest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function handleFriendRequest(userID, accept, callback) { 8 | if (utils.getType(accept) !== "Boolean") { 9 | throw { 10 | error: "Please pass a boolean as a second argument." 11 | }; 12 | } 13 | 14 | let resolveFunc = function () { }; 15 | let rejectFunc = function () { }; 16 | const returnPromise = new Promise(function (resolve, reject) { 17 | resolveFunc = resolve; 18 | rejectFunc = reject; 19 | }); 20 | 21 | if (!callback) { 22 | callback = function (err, friendList) { 23 | if (err) { 24 | return rejectFunc(err); 25 | } 26 | resolveFunc(friendList); 27 | }; 28 | } 29 | 30 | const form = { 31 | viewer_id: ctx.i_userID || ctx.userID, 32 | "frefs[0]": "jwl", 33 | floc: "friend_center_requests", 34 | ref: "/reqs.php", 35 | action: (accept ? "confirm" : "reject") 36 | }; 37 | 38 | defaultFuncs 39 | .post( 40 | "https://www.facebook.com/requests/friends/ajax/", 41 | ctx.jar, 42 | form 43 | ) 44 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 45 | .then(function (resData) { 46 | if (resData.payload.err) { 47 | throw { 48 | err: resData.payload.err 49 | }; 50 | } 51 | 52 | return callback(); 53 | }) 54 | .catch(function (err) { 55 | log.error("handleFriendRequest", err); 56 | return callback(err); 57 | }); 58 | 59 | return returnPromise; 60 | }; 61 | }; 62 | -------------------------------------------------------------------------------- /fb-chat-api/src/markAsDelivered.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function markAsDelivered(threadID, messageID, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | callback = function (err, friendList) { 17 | if (err) { 18 | return rejectFunc(err); 19 | } 20 | resolveFunc(friendList); 21 | }; 22 | } 23 | 24 | if (!threadID || !messageID) { 25 | return callback("Error: messageID or threadID is not defined"); 26 | } 27 | 28 | const form = {}; 29 | 30 | form["message_ids[0]"] = messageID; 31 | form["thread_ids[" + threadID + "][0]"] = messageID; 32 | 33 | defaultFuncs 34 | .post( 35 | "https://www.facebook.com/ajax/mercury/delivery_receipts.php", 36 | ctx.jar, 37 | form 38 | ) 39 | .then(utils.saveCookies(ctx.jar)) 40 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 41 | .then(function (resData) { 42 | if (resData.error) { 43 | throw resData; 44 | } 45 | 46 | return callback(); 47 | }) 48 | .catch(function (err) { 49 | log.error("markAsDelivered", err); 50 | if (utils.getType(err) == "Object" && err.error === "Not logged in.") { 51 | ctx.loggedIn = false; 52 | } 53 | return callback(err); 54 | }); 55 | 56 | return returnPromise; 57 | }; 58 | }; 59 | -------------------------------------------------------------------------------- /logger/loading.js: -------------------------------------------------------------------------------- 1 | const { colors } = require('../func/colors.js'); 2 | const moment = require("moment-timezone"); 3 | const characters = ''; 4 | const getCurrentTime = () => colors.gray(moment().tz('Asia/Ho_Chi_Minh').format('HH:mm:ss DD/MM/YYYY')); 5 | 6 | function logError(prefix, message) { 7 | if (message === undefined) { 8 | message = prefix; 9 | prefix = "ERROR"; 10 | } 11 | process.stderr.write(`\r${`${getCurrentTime()} ${colors.redBright(`${characters} ${prefix}:`)} ${message}`}`); 12 | } 13 | 14 | module.exports = { 15 | err: logError, 16 | error: logError, 17 | warn: function (prefix, message) { 18 | if (message === undefined) { 19 | message = prefix; 20 | prefix = "WARN"; 21 | } 22 | process.stderr.write(`\r${`${getCurrentTime()} ${colors.yellowBright(`${characters} ${prefix}:`)} ${message}`}`); 23 | }, 24 | info: function (prefix, message) { 25 | if (message === undefined) { 26 | message = prefix; 27 | prefix = "INFO"; 28 | } 29 | process.stderr.write(`\r${`${getCurrentTime()} ${colors.greenBright(`${characters} ${prefix}:`)} ${message}`}`); 30 | }, 31 | succes: function (prefix, message) { 32 | if (message === undefined) { 33 | message = prefix; 34 | prefix = "SUCCES"; 35 | } 36 | process.stderr.write(`\r${`${getCurrentTime()} ${colors.cyanBright(`${characters} ${prefix}:`)} ${message}`}`); 37 | }, 38 | master: function (prefix, message) { 39 | if (message === undefined) { 40 | message = prefix; 41 | prefix = "MASTER"; 42 | } 43 | process.stderr.write(`\r${`${getCurrentTime()} ${colors.hex("#eb6734", `${characters} ${prefix}:`)} ${message}`}`); 44 | } 45 | }; -------------------------------------------------------------------------------- /dashboard/routes/changePassword.js: -------------------------------------------------------------------------------- 1 | const bcrypt = require("bcrypt"); 2 | const express = require("express"); 3 | const router = express.Router(); 4 | 5 | module.exports = function ({ isAuthenticated, isVerifyRecaptcha, dashBoardData }) { 6 | router 7 | .get("/", isAuthenticated, async (req, res) => { 8 | res.render("change-password"); 9 | }) 10 | .post("/", isAuthenticated, async (req, res) => { 11 | if (!await isVerifyRecaptcha(req.body["g-recaptcha-response"])) 12 | return res.status(400).json({ 13 | status: "error", 14 | error: "CAPTCHA IS NOT VERIFIED", 15 | message: "Captcha không hợp lệ" 16 | }); 17 | const { oldassword, password, password_confirmation } = req.body; 18 | if (!await bcrypt.compare(oldassword, req.user.password)) 19 | return res.status(400).json({ 20 | status: "error", 21 | error: "OLDASSWORD_IS_NOT_CORRECT", 22 | message: "Mật khẩu cũ không đúng" 23 | }); 24 | if (password !== password_confirmation) 25 | return res.status(400).json({ 26 | status: "error", 27 | error: "PASSWORD_IS_NOT_MATCH", 28 | message: "Mật khẩu không khớp" 29 | }); 30 | if (password.length < 6) 31 | return res.status(400).json({ 32 | status: "error", 33 | error: "PASSWORD_IS_NOT_ENOUGH", 34 | message: "Mật khẩu phải có ít nhất 6 ký tự" 35 | }); 36 | 37 | const hashPassword = bcrypt.hashSync(password, 10); 38 | await dashBoardData.set(req.user.email, { password: hashPassword }); 39 | req.flash("success", { 40 | msg: "Đã thay đổi mật khẩu thành công" 41 | }); 42 | res.send(); 43 | }); 44 | 45 | return router; 46 | }; -------------------------------------------------------------------------------- /fb-chat-api/src/httpGet.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function httpGet(url, form, customHeader, callback, notAPI) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | 11 | const returnPromise = new Promise(function (resolve, reject) { 12 | resolveFunc = resolve; 13 | rejectFunc = reject; 14 | }); 15 | 16 | if (utils.getType(form) == "Function" || utils.getType(form) == "AsyncFunction") { 17 | callback = form; 18 | form = {}; 19 | } 20 | 21 | if (utils.getType(customHeader) == "Function" || utils.getType(customHeader) == "AsyncFunction") { 22 | callback = customHeader; 23 | customHeader = {}; 24 | } 25 | 26 | customHeader = customHeader || {}; 27 | 28 | callback = callback || function (err, data) { 29 | if (err) return rejectFunc(err); 30 | resolveFunc(data); 31 | }; 32 | 33 | if (notAPI) { 34 | utils 35 | .get(url, ctx.jar, form, ctx.globalOptions, ctx, customHeader) 36 | .then(function (resData) { 37 | callback(null, resData.body.toString()); 38 | }) 39 | .catch(function (err) { 40 | log.error("httpGet", err); 41 | return callback(err); 42 | }); 43 | } else { 44 | defaultFuncs 45 | .get(url, ctx.jar, form, null, customHeader) 46 | .then(function (resData) { 47 | callback(null, resData.body.toString()); 48 | }) 49 | .catch(function (err) { 50 | log.error("httpGet", err); 51 | return callback(err); 52 | }); 53 | } 54 | 55 | return returnPromise; 56 | }; 57 | }; 58 | -------------------------------------------------------------------------------- /fb-chat-api/src/httpPost.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function httpPost(url, form, customHeader, callback, notAPI) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | 11 | const returnPromise = new Promise(function (resolve, reject) { 12 | resolveFunc = resolve; 13 | rejectFunc = reject; 14 | }); 15 | 16 | if (utils.getType(form) == "Function" || utils.getType(form) == "AsyncFunction") { 17 | callback = form; 18 | form = {}; 19 | } 20 | 21 | if (utils.getType(customHeader) == "Function" || utils.getType(customHeader) == "AsyncFunction") { 22 | callback = customHeader; 23 | customHeader = {}; 24 | } 25 | 26 | customHeader = customHeader || {}; 27 | 28 | callback = callback || function (err, data) { 29 | if (err) return rejectFunc(err); 30 | resolveFunc(data); 31 | }; 32 | 33 | if (notAPI) { 34 | utils 35 | .post(url, ctx.jar, form, ctx.globalOptions, ctx, customHeader) 36 | .then(function (resData) { 37 | callback(null, resData.body.toString()); 38 | }) 39 | .catch(function (err) { 40 | log.error("httpPost", err); 41 | return callback(err); 42 | }); 43 | } else { 44 | defaultFuncs 45 | .post(url, ctx.jar, form, {}, customHeader) 46 | .then(function (resData) { 47 | callback(null, resData.body.toString()); 48 | }) 49 | .catch(function (err) { 50 | log.error("httpPost", err); 51 | return callback(err); 52 | }); 53 | } 54 | 55 | return returnPromise; 56 | }; 57 | }; 58 | -------------------------------------------------------------------------------- /scripts/cmds/kick.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "kick", 4 | version: "1.3", 5 | author: "NTKhang", 6 | countDown: 5, 7 | role: 1, 8 | description: { 9 | vi: "Kick thành viên khỏi box chat", 10 | en: "Kick member out of chat box" 11 | }, 12 | category: "box chat", 13 | guide: { 14 | vi: " {pn} @tags: dùng để kick những người được tag", 15 | en: " {pn} @tags: use to kick members who are tagged" 16 | } 17 | }, 18 | 19 | langs: { 20 | vi: { 21 | needAdmin: "Vui lòng thêm quản trị viên cho bot trước khi sử dụng tính năng này" 22 | }, 23 | en: { 24 | needAdmin: "Please add admin for bot before using this feature" 25 | } 26 | }, 27 | 28 | onStart: async function ({ message, event, args, threadsData, api, getLang }) { 29 | const adminIDs = await threadsData.get(event.threadID, "adminIDs"); 30 | if (!adminIDs.includes(api.getCurrentUserID())) 31 | return message.reply(getLang("needAdmin")); 32 | async function kickAndCheckError(uid) { 33 | try { 34 | await api.removeUserFromGroup(uid, event.threadID); 35 | } 36 | catch (e) { 37 | message.reply(getLang("needAdmin")); 38 | return "ERROR"; 39 | } 40 | } 41 | if (!args[0]) { 42 | if (!event.messageReply) 43 | return message.SyntaxError(); 44 | await kickAndCheckError(event.messageReply.senderID); 45 | } 46 | else { 47 | const uids = Object.keys(event.mentions); 48 | if (uids.length === 0) 49 | return message.SyntaxError(); 50 | if (await kickAndCheckError(uids.shift()) === "ERROR") 51 | return; 52 | for (const uid of uids) 53 | api.removeUserFromGroup(uid, event.threadID); 54 | } 55 | } 56 | }; -------------------------------------------------------------------------------- /fb-chat-api/src/handleMessageRequest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function handleMessageRequest(threadID, accept, callback) { 8 | if (utils.getType(accept) !== "Boolean") { 9 | throw { 10 | error: "Please pass a boolean as a second argument." 11 | }; 12 | } 13 | 14 | let resolveFunc = function () { }; 15 | let rejectFunc = function () { }; 16 | const returnPromise = new Promise(function (resolve, reject) { 17 | resolveFunc = resolve; 18 | rejectFunc = reject; 19 | }); 20 | 21 | if (!callback) { 22 | callback = function (err, friendList) { 23 | if (err) { 24 | return rejectFunc(err); 25 | } 26 | resolveFunc(friendList); 27 | }; 28 | } 29 | 30 | const form = { 31 | client: "mercury" 32 | }; 33 | 34 | if (utils.getType(threadID) !== "Array") { 35 | threadID = [threadID]; 36 | } 37 | 38 | const messageBox = accept ? "inbox" : "other"; 39 | 40 | for (let i = 0; i < threadID.length; i++) { 41 | form[messageBox + "[" + i + "]"] = threadID[i]; 42 | } 43 | 44 | defaultFuncs 45 | .post( 46 | "https://www.facebook.com/ajax/mercury/move_thread.php", 47 | ctx.jar, 48 | form 49 | ) 50 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 51 | .then(function (resData) { 52 | if (resData.error) { 53 | throw resData; 54 | } 55 | 56 | return callback(); 57 | }) 58 | .catch(function (err) { 59 | log.error("handleMessageRequest", err); 60 | return callback(err); 61 | }); 62 | 63 | return returnPromise; 64 | }; 65 | }; 66 | -------------------------------------------------------------------------------- /fb-chat-api/src/forwardAttachment.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function forwardAttachment(attachmentID, userOrUsers, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | if (!callback) { 15 | callback = function (err) { 16 | if (err) { 17 | return rejectFunc(err); 18 | } 19 | resolveFunc(); 20 | }; 21 | } 22 | 23 | const form = { 24 | attachment_id: attachmentID 25 | }; 26 | 27 | if (utils.getType(userOrUsers) !== "Array") { 28 | userOrUsers = [userOrUsers]; 29 | } 30 | 31 | const timestamp = Math.floor(Date.now() / 1000); 32 | 33 | for (let i = 0; i < userOrUsers.length; i++) { 34 | //That's good, the key of the array is really timestmap in seconds + index 35 | //Probably time when the attachment will be sent? 36 | form["recipient_map[" + (timestamp + i) + "]"] = userOrUsers[i]; 37 | } 38 | 39 | defaultFuncs 40 | .post( 41 | "https://www.facebook.com/mercury/attachments/forward/", 42 | ctx.jar, 43 | form 44 | ) 45 | .then(utils.parseAndCheckLogin(ctx.jar, defaultFuncs)) 46 | .then(function (resData) { 47 | if (resData.error) { 48 | throw resData; 49 | } 50 | 51 | return callback(); 52 | }) 53 | .catch(function (err) { 54 | log.error("forwardAttachment", err); 55 | return callback(err); 56 | }); 57 | 58 | return returnPromise; 59 | }; 60 | }; 61 | -------------------------------------------------------------------------------- /bot/autoUptime.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const { config } = global.GoatBot; 3 | const { log, getText } = global.utils; 4 | if (global.timeOutUptime != undefined) 5 | clearTimeout(global.timeOutUptime); 6 | if (!config.autoUptime.enable) 7 | return; 8 | 9 | const PORT = config.dashBoard?.port || (!isNaN(config.serverUptime.port) && config.serverUptime.port) || 3001; 10 | 11 | let myUrl = config.autoUptime.url || `https://${process.env.REPL_OWNER 12 | ? `${process.env.REPL_SLUG}.${process.env.REPL_OWNER}.repl.co` 13 | : process.env.API_SERVER_EXTERNAL == "https://api.glitch.com" 14 | ? `${process.env.PROJECT_DOMAIN}.glitch.me` 15 | : `localhost:${PORT}`}`; 16 | myUrl.includes('localhost') && (myUrl = myUrl.replace('https', 'http')); 17 | myUrl += '/uptime'; 18 | 19 | let status = 'ok'; 20 | setTimeout(async function autoUptime() { 21 | try { 22 | await axios.get(myUrl); 23 | if (status != 'ok') { 24 | status = 'ok'; 25 | log.info("UPTIME", "Bot is online"); 26 | // Custome notification here 27 | } 28 | } 29 | catch (e) { 30 | const err = e.response?.data || e; 31 | if (status != 'ok') 32 | return; 33 | status = 'failed'; 34 | 35 | if (err.statusAccountBot == "can't login") { 36 | log.err("UPTIME", "Can't login account bot"); 37 | // Custome notification here 38 | } 39 | else if (err.statusAccountBot == "block spam") { 40 | log.err("UPTIME", "Your account is blocked"); 41 | // Custome notification here 42 | } 43 | } 44 | global.timeOutUptime = setInterval(autoUptime, config.autoUptime.timeInterval); 45 | }, (config.autoUptime.timeInterval || 180) * 1000); 46 | log.info("AUTO UPTIME", getText("autoUptime", "autoUptimeTurnedOn", myUrl)); 47 | -------------------------------------------------------------------------------- /fb-chat-api/src/changeNickname.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function changeNickname(nickname, threadID, participantID, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | if (!callback) { 15 | callback = function (err) { 16 | if (err) { 17 | return rejectFunc(err); 18 | } 19 | resolveFunc(); 20 | }; 21 | } 22 | 23 | const form = { 24 | nickname: nickname, 25 | participant_id: participantID, 26 | thread_or_other_fbid: threadID 27 | }; 28 | 29 | defaultFuncs 30 | .post( 31 | "https://www.facebook.com/messaging/save_thread_nickname/?source=thread_settings&dpr=1", 32 | ctx.jar, 33 | form 34 | ) 35 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 36 | .then(function (resData) { 37 | if (resData.error === 1545014) { 38 | throw { error: "Trying to change nickname of user isn't in thread" }; 39 | } 40 | if (resData.error === 1357031) { 41 | throw { 42 | error: 43 | "Trying to change user nickname of a thread that doesn't exist. Have at least one message in the thread before trying to change the user nickname." 44 | }; 45 | } 46 | if (resData.error) { 47 | throw resData; 48 | } 49 | 50 | return callback(); 51 | }) 52 | .catch(function (err) { 53 | log.error("changeNickname", err); 54 | return callback(err); 55 | }); 56 | 57 | return returnPromise; 58 | }; 59 | }; 60 | -------------------------------------------------------------------------------- /fb-chat-api/src/getUserID.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | function formatData(data) { 7 | return { 8 | userID: utils.formatID(data.uid.toString()), 9 | photoUrl: data.photo, 10 | indexRank: data.index_rank, 11 | name: data.text, 12 | isVerified: data.is_verified, 13 | profileUrl: data.path, 14 | category: data.category, 15 | score: data.score, 16 | type: data.type 17 | }; 18 | } 19 | 20 | module.exports = function (defaultFuncs, api, ctx) { 21 | return function getUserID(name, callback) { 22 | let resolveFunc = function () { }; 23 | let rejectFunc = function () { }; 24 | const returnPromise = new Promise(function (resolve, reject) { 25 | resolveFunc = resolve; 26 | rejectFunc = reject; 27 | }); 28 | 29 | if (!callback) { 30 | callback = function (err, friendList) { 31 | if (err) { 32 | return rejectFunc(err); 33 | } 34 | resolveFunc(friendList); 35 | }; 36 | } 37 | 38 | const form = { 39 | value: name.toLowerCase(), 40 | viewer: ctx.i_userID || ctx.userID, 41 | rsp: "search", 42 | context: "search", 43 | path: "/home.php", 44 | request_id: utils.getGUID() 45 | }; 46 | 47 | defaultFuncs 48 | .get("https://www.facebook.com/ajax/typeahead/search.php", ctx.jar, form) 49 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 50 | .then(function (resData) { 51 | if (resData.error) { 52 | throw resData; 53 | } 54 | 55 | const data = resData.payload.entries; 56 | 57 | callback(null, data.map(formatData)); 58 | }) 59 | .catch(function (err) { 60 | log.error("getUserID", err); 61 | return callback(err); 62 | }); 63 | 64 | return returnPromise; 65 | }; 66 | }; 67 | -------------------------------------------------------------------------------- /fb-chat-api/src/httpPostFormData.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | 7 | module.exports = function (defaultFuncs, api, ctx) { 8 | return function httpPostFormData(url, form, customHeader, callback, notAPI) { 9 | let resolveFunc = function () { }; 10 | let rejectFunc = function () { }; 11 | 12 | const returnPromise = new Promise(function (resolve, reject) { 13 | resolveFunc = resolve; 14 | rejectFunc = reject; 15 | }); 16 | 17 | if (utils.getType(form) == "Function" || utils.getType(form) == "AsyncFunction") { 18 | callback = form; 19 | form = {}; 20 | } 21 | 22 | if (utils.getType(customHeader) == "Function" || utils.getType(customHeader) == "AsyncFunction") { 23 | callback = customHeader; 24 | customHeader = {}; 25 | } 26 | 27 | customHeader = customHeader || {}; 28 | 29 | if (utils.getType(callback) == "Boolean") { 30 | notAPI = callback; 31 | callback = null; 32 | } 33 | 34 | callback = callback || function (err, data) { 35 | if (err) return rejectFunc(err); 36 | resolveFunc(data); 37 | }; 38 | 39 | if (notAPI) { 40 | utils 41 | .postFormData(url, ctx.jar, form, ctx.globalOptions, ctx, customHeader) 42 | .then(function (resData) { 43 | callback(null, resData.body.toString()); 44 | }) 45 | .catch(function (err) { 46 | log.error("httpPostFormData", err); 47 | return callback(err); 48 | }); 49 | } else { 50 | defaultFuncs 51 | .postFormData(url, ctx.jar, form, null, customHeader) 52 | .then(function (resData) { 53 | callback(null, resData.body.toString()); 54 | }) 55 | .catch(function (err) { 56 | log.error("httpPostFormData", err); 57 | return callback(err); 58 | }); 59 | } 60 | 61 | return returnPromise; 62 | }; 63 | }; 64 | -------------------------------------------------------------------------------- /fb-chat-api/src/changeThreadColor.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function changeThreadColor(color, threadID, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | callback = function (err) { 17 | if (err) { 18 | return rejectFunc(err); 19 | } 20 | resolveFunc(err); 21 | }; 22 | } 23 | 24 | if (!isNaN(color)) { 25 | color = color.toString(); 26 | } 27 | const validatedColor = color !== null ? color.toLowerCase() : color; // API only accepts lowercase letters in hex string 28 | 29 | const form = { 30 | dpr: 1, 31 | queries: JSON.stringify({ 32 | o0: { 33 | //This doc_id is valid as of January 31, 2020 34 | doc_id: "1727493033983591", 35 | query_params: { 36 | data: { 37 | actor_id: ctx.i_userID || ctx.userID, 38 | client_mutation_id: "0", 39 | source: "SETTINGS", 40 | theme_id: validatedColor, 41 | thread_id: threadID 42 | } 43 | } 44 | } 45 | }) 46 | }; 47 | 48 | defaultFuncs 49 | .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form) 50 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 51 | .then(function (resData) { 52 | if (resData[resData.length - 1].error_results > 0) { 53 | throw new utils.CustomError(resData[0].o0.errors); 54 | } 55 | 56 | return callback(); 57 | }) 58 | .catch(function (err) { 59 | log.error("changeThreadColor", err); 60 | return callback(err); 61 | }); 62 | 63 | return returnPromise; 64 | }; 65 | }; 66 | -------------------------------------------------------------------------------- /fb-chat-api/src/editMessage.js: -------------------------------------------------------------------------------- 1 | "use_strict"; 2 | /** 3 | * @author RFS-ADRENO 4 | * @rewrittenBy Isai Ivanov 5 | */ 6 | const generateOfflineThreadingId = require('../utils'); 7 | 8 | function canBeCalled(func) { 9 | try { 10 | Reflect.apply(func, null, []); 11 | return true; 12 | } catch (error) { 13 | return false; 14 | } 15 | } 16 | 17 | /** 18 | * A function for editing bot's messages. 19 | * @param {string} text - The text with which the bot will edit its messages. 20 | * @param {string} messageID - The message ID of the message the bot will edit. 21 | * @param {Object} callback - Callback for the function. 22 | */ 23 | 24 | module.exports = function(defaultFuncs, api, ctx) { 25 | return function editMessage(text, messageID, callback) { 26 | if (!ctx.mqttClient) { 27 | throw new Error('Not connected to MQTT'); 28 | } 29 | 30 | ctx.wsReqNumber += 1; 31 | ctx.wsTaskNumber += 1; 32 | 33 | const queryPayload = { 34 | message_id: messageID, 35 | text: text, 36 | }; 37 | 38 | const query = { 39 | failure_count: null, 40 | label: '742', 41 | payload: JSON.stringify(queryPayload), 42 | queue_name: 'edit_message', 43 | task_id: ctx.wsTaskNumber, 44 | }; 45 | 46 | const context = { 47 | app_id: '2220391788200892', 48 | payload: { 49 | data_trace_id: null, 50 | epoch_id: parseInt(generateOfflineThreadingId), 51 | tasks: [query], 52 | version_id: '6903494529735864', 53 | }, 54 | request_id: ctx.wsReqNumber, 55 | type: 3, 56 | }; 57 | 58 | context.payload = JSON.stringify(context.payload); 59 | 60 | if (canBeCalled(callback)) { 61 | ctx.reqCallbacks[ctx.wsReqNumber] = callback; 62 | } 63 | 64 | ctx.mqttClient.publish('/ls_req', JSON.stringify(context), { qos: 1, retain: false }); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /scripts/cmds/backupdata.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs-extra"); 2 | 3 | module.exports = { 4 | config: { 5 | name: "backupdata", 6 | version: "1.3", 7 | author: "NTKhang", 8 | countDown: 5, 9 | role: 2, 10 | description: { 11 | vi: "Sao lưu dữ liệu của bot (threads, users, dashboard, globalData)", 12 | en: "Backup data of bot (threads, users, dashboard, globalData)" 13 | }, 14 | category: "owner", 15 | guide: { 16 | en: " {pn}" 17 | } 18 | }, 19 | 20 | langs: { 21 | vi: { 22 | backedUp: "Đã sao lưu dữ liệu của bot vào thư mục scripts/cmds/tmp" 23 | }, 24 | en: { 25 | backedUp: "Bot data has been backed up to the scripts/cmds/tmp folder" 26 | } 27 | }, 28 | 29 | onStart: async function ({ message, getLang, threadsData, usersData, dashBoardData, globalData }) { 30 | const [globalDataBackup, threadsDataBackup, usersDataBackup, dashBoardDataBackup] = await Promise.all([ 31 | globalData.getAll(), 32 | threadsData.getAll(), 33 | usersData.getAll(), 34 | dashBoardData.getAll() 35 | ]); 36 | 37 | const pathThreads = `${__dirname}/tmp/threadsData.json`; 38 | const pathUsers = `${__dirname}/tmp/usersData.json`; 39 | const pathDashBoard = `${__dirname}/tmp/dashBoardData.json`; 40 | const pathGlobal = `${__dirname}/tmp/globalData.json`; 41 | 42 | fs.writeFileSync(pathThreads, JSON.stringify(threadsDataBackup, null, 2)); 43 | fs.writeFileSync(pathUsers, JSON.stringify(usersDataBackup, null, 2)); 44 | fs.writeFileSync(pathDashBoard, JSON.stringify(dashBoardDataBackup, null, 2)); 45 | fs.writeFileSync(pathGlobal, JSON.stringify(globalDataBackup, null, 2)); 46 | 47 | message.reply({ 48 | body: getLang("backedUp"), 49 | attachment: [ 50 | fs.createReadStream(pathThreads), 51 | fs.createReadStream(pathUsers), 52 | fs.createReadStream(pathDashBoard), 53 | fs.createReadStream(pathGlobal) 54 | ] 55 | }); 56 | } 57 | }; -------------------------------------------------------------------------------- /scripts/cmds/eval.js: -------------------------------------------------------------------------------- 1 | const { removeHomeDir, log } = global.utils; 2 | 3 | module.exports = { 4 | config: { 5 | name: "eval", 6 | version: "1.6", 7 | author: "NTKhang", 8 | countDown: 5, 9 | role: 2, 10 | description: { 11 | vi: "Test code nhanh", 12 | en: "Test code quickly" 13 | }, 14 | category: "owner", 15 | guide: { 16 | vi: "{pn} <đoạn code cần test>", 17 | en: "{pn} " 18 | } 19 | }, 20 | 21 | langs: { 22 | vi: { 23 | error: "❌ Đã có lỗi xảy ra:" 24 | }, 25 | en: { 26 | error: "❌ An error occurred:" 27 | } 28 | }, 29 | 30 | onStart: async function ({ api, args, message, event, threadsData, usersData, dashBoardData, globalData, threadModel, userModel, dashBoardModel, globalModel, role, commandName, getLang }) { 31 | function output(msg) { 32 | if (typeof msg == "number" || typeof msg == "boolean" || typeof msg == "function") 33 | msg = msg.toString(); 34 | else if (msg instanceof Map) { 35 | let text = `Map(${msg.size}) `; 36 | text += JSON.stringify(mapToObj(msg), null, 2); 37 | msg = text; 38 | } 39 | else if (typeof msg == "object") 40 | msg = JSON.stringify(msg, null, 2); 41 | else if (typeof msg == "undefined") 42 | msg = "undefined"; 43 | 44 | message.reply(msg); 45 | } 46 | function out(msg) { 47 | output(msg); 48 | } 49 | function mapToObj(map) { 50 | const obj = {}; 51 | map.forEach(function (v, k) { 52 | obj[k] = v; 53 | }); 54 | return obj; 55 | } 56 | const cmd = ` 57 | (async () => { 58 | try { 59 | ${args.join(" ")} 60 | } 61 | catch(err) { 62 | log.err("eval command", err); 63 | message.send( 64 | "${getLang("error")}\\n" + 65 | (err.stack ? 66 | removeHomeDir(err.stack) : 67 | removeHomeDir(JSON.stringify(err, null, 2) || "") 68 | ) 69 | ); 70 | } 71 | })()`; 72 | eval(cmd); 73 | } 74 | }; -------------------------------------------------------------------------------- /dashboard/views/forgot-password-new-password.eta: -------------------------------------------------------------------------------- 1 | <%~ includeFile("partials/header.eta", { 2 | user: user 3 | }); %> 4 | <%~ includeFile("partials/message.eta"); %> 5 | <%~ includeFile("partials/title.eta", { 6 | icon: "fa-solid fa-unlock", 7 | title: "Reset Password" 8 | }); 9 | 10 |
11 |
12 |
13 |
14 |
15 |
16 |

Reset Password

17 |
18 |
19 |
20 |
21 | 22 | 23 |
24 |
25 | 26 | 27 |
28 | 30 |
31 |

32 | Nhập mật khẩu mới. 33 |

34 | 35 |
36 |
37 |
38 |
39 |
40 |
41 | 42 | 50 | <%~ includeFile("partials/footer.eta") %> -------------------------------------------------------------------------------- /scripts/events/checkwarn.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "checkwarn", 4 | version: "1.3", 5 | author: "NTKhang", 6 | category: "events" 7 | }, 8 | 9 | langs: { 10 | vi: { 11 | warn: "Thành viên %1 đã bị cảnh cáo đủ 3 lần trước đó và bị ban khỏi box chat\n- Name: %1\n- Uid: %2\n- Để gỡ ban vui lòng sử dụng lệnh \"%3warn unban \" (với uid là uid của người muốn gỡ ban)", 12 | needPermission: "Bot cần quyền quản trị viên để kick thành viên bị ban" 13 | }, 14 | en: { 15 | warn: "Member %1 has been warned 3 times before and has been banned from the chat box\n- Name: %1\n- Uid: %2\n- To unban, please use the \"%3warn unban \" command (with uid is the uid of the person you want to unban)", 16 | needPermission: "Bot needs administrator permission to kick banned members" 17 | } 18 | }, 19 | 20 | onStart: async ({ threadsData, message, event, api, client, getLang }) => { 21 | if (event.logMessageType == "log:subscribe") 22 | return async function () { 23 | const { threadID } = event; 24 | const { data } = await threadsData.get(event.threadID); 25 | const { warn: warnList } = data; 26 | if (!warnList) 27 | return; 28 | const { addedParticipants } = event.logMessageData; 29 | for (const user of addedParticipants) { 30 | const findUser = warnList.find(user => user.userID == user.userID); 31 | if (findUser && findUser.list >= 3) { 32 | const userName = user.fullName; 33 | const uid = user.userFbId; 34 | message.send({ 35 | body: getLang("warn", userName, uid, client.getPrefix(threadID)), 36 | mentions: [{ 37 | tag: userName, 38 | id: uid 39 | }] 40 | }, function () { 41 | api.removeUserFromGroup(uid, threadID, (err) => { 42 | if (err) 43 | return message.send(getLang("needPermission")); 44 | }); 45 | }); 46 | } 47 | } 48 | }; 49 | } 50 | }; -------------------------------------------------------------------------------- /fb-chat-api/src/createPoll.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function createPoll(title, threadID, options, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | if (utils.getType(options) == "Function") { 17 | callback = options; 18 | options = null; 19 | } else { 20 | callback = function (err) { 21 | if (err) { 22 | return rejectFunc(err); 23 | } 24 | resolveFunc(); 25 | }; 26 | } 27 | } 28 | if (!options) { 29 | options = {}; // Initial poll options are optional 30 | } 31 | 32 | const form = { 33 | target_id: threadID, 34 | question_text: title 35 | }; 36 | 37 | // Set fields for options (and whether they are selected initially by the posting user) 38 | let ind = 0; 39 | for (const opt in options) { 40 | // eslint-disable-next-line no-prototype-builtins 41 | if (options.hasOwnProperty(opt)) { 42 | form["option_text_array[" + ind + "]"] = opt; 43 | form["option_is_selected_array[" + ind + "]"] = options[opt] 44 | ? "1" 45 | : "0"; 46 | ind++; 47 | } 48 | } 49 | 50 | defaultFuncs 51 | .post( 52 | "https://www.facebook.com/messaging/group_polling/create_poll/?dpr=1", 53 | ctx.jar, 54 | form 55 | ) 56 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 57 | .then(function (resData) { 58 | if (resData.payload.status != "success") { 59 | throw resData; 60 | } 61 | 62 | return callback(); 63 | }) 64 | .catch(function (err) { 65 | log.error("createPoll", err); 66 | return callback(err); 67 | }); 68 | 69 | return returnPromise; 70 | }; 71 | }; 72 | -------------------------------------------------------------------------------- /scripts/cmds/emojimix.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | 3 | module.exports = { 4 | config: { 5 | name: "emojimix", 6 | version: "1.4", 7 | author: "NTKhang", 8 | countDown: 5, 9 | role: 0, 10 | description: { 11 | vi: "Mix 2 emoji lại với nhau", 12 | en: "Mix 2 emoji together" 13 | }, 14 | guide: { 15 | vi: " {pn} " 16 | + "\n Ví dụ: {pn} 🤣 🥰", 17 | en: " {pn} " 18 | + "\n Example: {pn} 🤣 🥰" 19 | }, 20 | category: "fun" 21 | }, 22 | 23 | langs: { 24 | vi: { 25 | error: "Rất tiếc, emoji %1 và %2 không mix được", 26 | success: "Emoji %1 và %2 mix được %3 ảnh" 27 | }, 28 | en: { 29 | error: "Sorry, emoji %1 and %2 can't mix", 30 | success: "Emoji %1 and %2 mix %3 images" 31 | } 32 | }, 33 | 34 | onStart: async function ({ message, args, getLang }) { 35 | const readStream = []; 36 | const emoji1 = args[0]; 37 | const emoji2 = args[1]; 38 | 39 | if (!emoji1 || !emoji2) 40 | return message.SyntaxError(); 41 | 42 | const generate1 = await generateEmojimix(emoji1, emoji2); 43 | const generate2 = await generateEmojimix(emoji2, emoji1); 44 | 45 | if (generate1) 46 | readStream.push(generate1); 47 | if (generate2) 48 | readStream.push(generate2); 49 | 50 | if (readStream.length == 0) 51 | return message.reply(getLang("error", emoji1, emoji2)); 52 | 53 | message.reply({ 54 | body: getLang("success", emoji1, emoji2, readStream.length), 55 | attachment: readStream 56 | }); 57 | } 58 | }; 59 | 60 | 61 | 62 | async function generateEmojimix(emoji1, emoji2) { 63 | try { 64 | const { data: response } = await axios.get("https://goatbotserver.onrender.com/taoanhdep/emojimix", { 65 | params: { 66 | emoji1, 67 | emoji2 68 | }, 69 | responseType: "stream" 70 | }); 71 | response.path = `emojimix${Date.now()}.png`; 72 | return response; 73 | } 74 | catch (e) { 75 | return null; 76 | } 77 | } -------------------------------------------------------------------------------- /dashboard/views/register-resend-code.eta: -------------------------------------------------------------------------------- 1 | <%~ includeFile("partials/header.eta", { 2 | user: user 3 | }); %> 4 | <%~ includeFile("partials/message.eta"); %> 5 | <%~ includeFile("partials/title.eta", { 6 | icon: "fa-solid fa-envelope", 7 | title: "Resend Email Verification" 8 | }); %> 9 | 10 |
11 |
12 |
13 |
14 |
15 |
16 |

Resend Email Verification

17 |
18 |
19 |
20 | 21 | 22 |
23 | 24 |
25 |
26 |
27 |
28 |
29 |
30 | 31 | 59 | 60 | <%~ includeFile("partials/footer.eta") %> -------------------------------------------------------------------------------- /scripts/cmds/antiout.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "antiout", 4 | version: "1.0", 5 | author: "Elohime", 6 | countDown: 5, 7 | role: 1, 8 | shortDescription: "Enable😼 or disable🙁 antiout", 9 | longDescription: "", 10 | category: "boxchat", 11 | guide: "{pn} {{[on | off]}}", 12 | envConfig: { 13 | deltaNext: 5 14 | } 15 | }, 16 | onStart: async function({ message, event, threadsData, args }) { 17 | let antiout = await threadsData.get(event.threadID, "settings.antiout"); 18 | if (antiout === undefined) { 19 | await threadsData.set(event.threadID, true, "settings.antiout"); 20 | antiout = true; 21 | } 22 | if (!["on", "off"].includes(args[0])) { 23 | return message.reply("Please use 'on' or 'off' as an argument"); 24 | } 25 | await threadsData.set(event.threadID, args[0] === "on", "settings.antiout"); 26 | return message.reply(`Antiout has been ${args[0] === "on" ? "enabled😼" : "disabled🙁"}.`); 27 | }, 28 | onEvent: async function({ api, event, threadsData }) { 29 | const antiout = await threadsData.get(event.threadID, "settings.antiout"); 30 | if (antiout && event.logMessageData && event.logMessageData.leftParticipantFbId) { 31 | // A user has left the chat, get their user ID 32 | const userId = event.logMessageData.leftParticipantFbId; 33 | 34 | // Check if the user is still in the chat 35 | const threadInfo = await api.getThreadInfo(event.threadID); 36 | const userIndex = threadInfo.participantIDs.indexOf(userId); 37 | if (userIndex === -1) { 38 | // The user is not in the chat, add them back 39 | const addUser = await api.addUserToGroup(userId, event.threadID); 40 | if (addUser) { 41 | console.log(`User ${userId} was added back to the chat.`); 42 | } else { 43 | console.log(`Failed to add user ${userId} back to the chat.`); 44 | } 45 | } 46 | } 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /scripts/cmds/getfbstate.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs-extra"); 2 | 3 | module.exports = { 4 | config: { 5 | name: "getfbstate", 6 | aliases: ["getstate", "getcookie"], 7 | version: "1.2", 8 | author: "NTKhang", 9 | countDown: 5, 10 | role: 2, 11 | description: { 12 | vi: "Lấy fbstate hiện tại", 13 | en: "Get current fbstate" 14 | }, 15 | category: "owner", 16 | guide: { 17 | en: " {pn}: get fbstate (appState)\n" 18 | + " {pn} [cookies|cookie|c]: get fbstate with cookies format\n" 19 | + " {pn} [string|str|s]: get fbstate with string format\n", 20 | vi: " {pn}: get fbstate (appState)\n" 21 | + " {pn} [cookies|cookie|c]: get fbstate dạng cookies\n" 22 | + " {pn} [string|str|s]: get fbstate dạng string\n" 23 | } 24 | }, 25 | 26 | langs: { 27 | vi: { 28 | success: "Đã gửi fbstate đến bạn, vui lòng kiểm tra tin nhắn riêng của bot" 29 | }, 30 | en: { 31 | success: "Sent fbstate to you, please check bot's private message" 32 | } 33 | }, 34 | 35 | onStart: async function ({ message, api, event, args, getLang }) { 36 | let fbstate; 37 | let fileName; 38 | 39 | if (["cookie", "cookies", "c"].includes(args[0])) { 40 | fbstate = JSON.stringify(api.getAppState().map(e => ({ 41 | name: e.key, 42 | value: e.value 43 | })), null, 2); 44 | fileName = "cookies.json"; 45 | } 46 | else if (["string", "str", "s"].includes(args[0])) { 47 | fbstate = api.getAppState().map(e => `${e.key}=${e.value}`).join("; "); 48 | fileName = "cookiesString.txt"; 49 | } 50 | else { 51 | fbstate = JSON.stringify(api.getAppState(), null, 2); 52 | fileName = "appState.json"; 53 | } 54 | 55 | const pathSave = `${__dirname}/tmp/${fileName}`; 56 | fs.writeFileSync(pathSave, fbstate); 57 | 58 | if (event.senderID != event.threadID) 59 | message.reply(getLang("success")); 60 | 61 | api.sendMessage({ 62 | body: fbstate, 63 | attachment: fs.createReadStream(pathSave) 64 | }, event.senderID, () => fs.unlinkSync(pathSave)); 65 | } 66 | }; -------------------------------------------------------------------------------- /scripts/cmds/appstore.js: -------------------------------------------------------------------------------- 1 | const itunes = require("searchitunes"); 2 | const { getStreamFromURL } = global.utils; 3 | 4 | module.exports = { 5 | config: { 6 | name: "appstore", 7 | version: "1.2", 8 | author: "NTKhang", 9 | countDown: 5, 10 | role: 0, 11 | description: { 12 | vi: "Tìm app trên appstore", 13 | en: "Search app on appstore" 14 | }, 15 | category: "software", 16 | guide: " {pn}: " 17 | + "\n - Example:" 18 | + "\n {pn} PUBG", 19 | envConfig: { 20 | limitResult: 3 21 | } 22 | }, 23 | 24 | langs: { 25 | vi: { 26 | missingKeyword: "Bạn chưa nhập từ khóa", 27 | noResult: "Không tìm thấy kết quả nào cho từ khóa %1" 28 | }, 29 | en: { 30 | missingKeyword: "You haven't entered any keyword", 31 | noResult: "No result found for keyword %1" 32 | } 33 | }, 34 | 35 | onStart: async function ({ message, args, commandName, envCommands, getLang }) { 36 | if (!args[0]) 37 | return message.reply(getLang("missingKeyword")); 38 | let results = []; 39 | try { 40 | results = (await itunes({ 41 | entity: "software", 42 | country: "VN", 43 | term: args.join(" "), 44 | limit: envCommands[commandName].limitResult 45 | })).results; 46 | } 47 | catch (err) { 48 | return message.reply(getLang("noResult", args.join(" "))); 49 | } 50 | 51 | if (results.length > 0) { 52 | let msg = ""; 53 | const pedningImages = []; 54 | for (const result of results) { 55 | msg += `\n\n- ${result.trackCensoredName} by ${result.artistName}, ${result.formattedPrice} and rated ${"🌟".repeat(result.averageUserRating)} (${result.averageUserRating.toFixed(1)}/5)` 56 | + `\n- ${result.trackViewUrl}`; 57 | pedningImages.push(await getStreamFromURL(result.artworkUrl512 || result.artworkUrl100 || result.artworkUrl60)); 58 | } 59 | message.reply({ 60 | body: msg, 61 | attachment: await Promise.all(pedningImages) 62 | }); 63 | } 64 | else { 65 | message.reply(getLang("noResult", args.join(" "))); 66 | } 67 | } 68 | }; -------------------------------------------------------------------------------- /bot/handler/handlerCheckData.js: -------------------------------------------------------------------------------- 1 | const { db, utils, GoatBot } = global; 2 | const { config } = GoatBot; 3 | const { log, getText } = utils; 4 | const { creatingThreadData, creatingUserData } = global.client.database; 5 | 6 | module.exports = async function (usersData, threadsData, event) { 7 | const { threadID } = event; 8 | const senderID = event.senderID || event.author || event.userID; 9 | 10 | // ———————————— CHECK THREAD DATA ———————————— // 11 | if (threadID) { 12 | try { 13 | if (global.temp.createThreadDataError.includes(threadID)) 14 | return; 15 | 16 | const findInCreatingThreadData = creatingThreadData.find(t => t.threadID == threadID); 17 | if (!findInCreatingThreadData) { 18 | if (global.db.allThreadData.some(t => t.threadID == threadID)) 19 | return; 20 | 21 | const threadData = await threadsData.create(threadID); 22 | log.info("DATABASE", `New Thread: ${threadID} | ${threadData.threadName} | ${config.database.type}`); 23 | } 24 | else { 25 | await findInCreatingThreadData.promise; 26 | } 27 | } 28 | catch (err) { 29 | if (err.name != "DATA_ALREADY_EXISTS") { 30 | global.temp.createThreadDataError.push(threadID); 31 | log.err("DATABASE", getText("handlerCheckData", "cantCreateThread", threadID), err); 32 | } 33 | } 34 | } 35 | 36 | 37 | // ————————————— CHECK USER DATA ————————————— // 38 | if (senderID) { 39 | try { 40 | const findInCreatingUserData = creatingUserData.find(u => u.userID == senderID); 41 | if (!findInCreatingUserData) { 42 | if (db.allUserData.some(u => u.userID == senderID)) 43 | return; 44 | 45 | const userData = await usersData.create(senderID); 46 | log.info("DATABASE", `New User: ${senderID} | ${userData.name} | ${config.database.type}`); 47 | } 48 | else { 49 | await findInCreatingUserData.promise; 50 | } 51 | } 52 | catch (err) { 53 | if (err.name != "DATA_ALREADY_EXISTS") 54 | log.err("DATABASE", getText("handlerCheckData", "cantCreateUser", senderID), err); 55 | } 56 | } 57 | }; -------------------------------------------------------------------------------- /fb-chat-api/src/getUserInfo.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | function formatData(data) { 7 | const retObj = {}; 8 | 9 | for (const prop in data) { 10 | // eslint-disable-next-line no-prototype-builtins 11 | if (data.hasOwnProperty(prop)) { 12 | const innerObj = data[prop]; 13 | retObj[prop] = { 14 | name: innerObj.name, 15 | firstName: innerObj.firstName, 16 | vanity: innerObj.vanity, 17 | thumbSrc: innerObj.thumbSrc, 18 | profileUrl: innerObj.uri, 19 | gender: innerObj.gender, 20 | type: innerObj.type, 21 | isFriend: innerObj.is_friend, 22 | isBirthday: !!innerObj.is_birthday, 23 | searchTokens: innerObj.searchTokens, 24 | alternateName: innerObj.alternateName 25 | }; 26 | } 27 | } 28 | 29 | return retObj; 30 | } 31 | 32 | module.exports = function (defaultFuncs, api, ctx) { 33 | return function getUserInfo(id, callback) { 34 | let resolveFunc = function () { }; 35 | let rejectFunc = function () { }; 36 | const returnPromise = new Promise(function (resolve, reject) { 37 | resolveFunc = resolve; 38 | rejectFunc = reject; 39 | }); 40 | 41 | if (!callback) { 42 | callback = function (err, friendList) { 43 | if (err) { 44 | return rejectFunc(err); 45 | } 46 | resolveFunc(friendList); 47 | }; 48 | } 49 | 50 | if (utils.getType(id) !== "Array") { 51 | id = [id]; 52 | } 53 | 54 | const form = {}; 55 | id.map(function (v, i) { 56 | form["ids[" + i + "]"] = v; 57 | }); 58 | defaultFuncs 59 | .post("https://www.facebook.com/chat/user_info/", ctx.jar, form) 60 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 61 | .then(function (resData) { 62 | if (resData.error) { 63 | throw resData; 64 | } 65 | return callback(null, formatData(resData.payload.profiles)); 66 | }) 67 | .catch(function (err) { 68 | log.error("getUserInfo", err); 69 | return callback(err); 70 | }); 71 | 72 | return returnPromise; 73 | }; 74 | }; 75 | -------------------------------------------------------------------------------- /scripts/cmds/uid.js: -------------------------------------------------------------------------------- 1 | const { findUid } = global.utils; 2 | const regExCheckURL = /^(http|https):\/\/[^ "]+$/; 3 | 4 | module.exports = { 5 | config: { 6 | name: "uid", 7 | version: "1.3", 8 | author: "NTKhang", 9 | countDown: 5, 10 | role: 0, 11 | description: { 12 | vi: "Xem user id facebook của người dùng", 13 | en: "View facebook user id of user" 14 | }, 15 | category: "info", 16 | guide: { 17 | vi: " {pn}: dùng để xem id facebook của bạn" 18 | + "\n {pn} @tag: xem id facebook của những người được tag" 19 | + "\n {pn} : xem id facebook của link profile" 20 | + "\n Phản hồi tin nhắn của người khác kèm lệnh để xem id facebook của họ", 21 | en: " {pn}: use to view your facebook user id" 22 | + "\n {pn} @tag: view facebook user id of tagged people" 23 | + "\n {pn} : view facebook user id of profile link" 24 | + "\n Reply to someone's message with the command to view their facebook user id" 25 | } 26 | }, 27 | 28 | langs: { 29 | vi: { 30 | syntaxError: "Vui lòng tag người muốn xem uid hoặc để trống để xem uid của bản thân" 31 | }, 32 | en: { 33 | syntaxError: "Please tag the person you want to view uid or leave it blank to view your own uid" 34 | } 35 | }, 36 | 37 | onStart: async function ({ message, event, args, getLang }) { 38 | if (event.messageReply) 39 | return message.reply(event.messageReply.senderID); 40 | if (!args[0]) 41 | return message.reply(event.senderID); 42 | if (args[0].match(regExCheckURL)) { 43 | let msg = ''; 44 | for (const link of args) { 45 | try { 46 | const uid = await findUid(link); 47 | msg += `${link} => ${uid}\n`; 48 | } 49 | catch (e) { 50 | msg += `${link} (ERROR) => ${e.message}\n`; 51 | } 52 | } 53 | message.reply(msg); 54 | return; 55 | } 56 | 57 | let msg = ""; 58 | const { mentions } = event; 59 | for (const id in mentions) 60 | msg += `${mentions[id].replace("@", "")}: ${id}\n`; 61 | message.reply(msg || getLang("syntaxError")); 62 | } 63 | }; -------------------------------------------------------------------------------- /scripts/cmds/topuser.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | 3 | module.exports = { 4 | config: { 5 | name: "topuser", 6 | aliases: [], 7 | version: "1.0", 8 | author: "kshitiz", 9 | countDown: 5, 10 | role: 0, 11 | shortDescription: "Get the top 15 users by message count in the current chat", 12 | longDescription: "Get the top 15 users by message count in the current chat", 13 | category: "fun", 14 | guide: "{pn}", 15 | }, 16 | onStart: async function ({ api, event }) { 17 | const threadId = event.threadID; 18 | const senderId = event.senderID; 19 | 20 | try { 21 | 22 | const participants = await api.getThreadInfo(threadId, { participantIDs: true }); 23 | 24 | 25 | const messageCounts = {}; 26 | 27 | 28 | participants.participantIDs.forEach(participantId => { 29 | messageCounts[participantId] = 0; 30 | }); 31 | 32 | 33 | const messages = await api.getThreadHistory(threadId, 1000); // Adjust the limit as needed if you want if you wanna get all message 34 | 35 | 36 | messages.forEach(message => { 37 | const messageSender = message.senderID; 38 | if (messageCounts[messageSender] !== undefined) { 39 | messageCounts[messageSender]++; 40 | } 41 | }); 42 | 43 | 44 | const topUsers = Object.entries(messageCounts) 45 | .sort((a, b) => b[1] - a[1]) 46 | .slice(0, 15); 47 | 48 | 49 | const userList = []; 50 | for (const [userId, messageCount] of topUsers) { 51 | const userInfo = await api.getUserInfo(userId); 52 | const userName = userInfo[userId].name; 53 | userList.push(`╔═══════════╗\${userName}』 \ent ${messageCount} messages \═══════════╝`); 54 | } 55 | 56 | const messageText = `𝗧𝗼𝗽 𝘂𝘀𝗲𝗿𝘀 𝗼𝗳 𝘁𝗵𝗶𝘀 𝗰𝗵𝗮𝘁 💵:\{userList.join('\)}`; 57 | api.sendMessage({ body: messageText, mentions: [{ tag: senderId, id: senderId, type: "user" }] }, threadId); 58 | 59 | } catch (error) { 60 | console.error(error); 61 | } 62 | }, 63 | }; 64 | -------------------------------------------------------------------------------- /fb-chat-api/src/changeBio.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function changeBio(bio, publish, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | if (utils.getType(publish) == "Function" || utils.getType(publish) == "AsyncFunction") { 17 | callback = publish; 18 | } else { 19 | callback = function (err) { 20 | if (err) { 21 | return rejectFunc(err); 22 | } 23 | resolveFunc(); 24 | }; 25 | } 26 | } 27 | 28 | if (utils.getType(publish) != "Boolean") { 29 | publish = false; 30 | } 31 | 32 | if (utils.getType(bio) != "String") { 33 | bio = ""; 34 | publish = false; 35 | } 36 | 37 | const form = { 38 | fb_api_caller_class: "RelayModern", 39 | fb_api_req_friendly_name: "ProfileCometSetBioMutation", 40 | // This doc_is is valid as of May 23, 2020 41 | doc_id: "2725043627607610", 42 | variables: JSON.stringify({ 43 | input: { 44 | bio: bio, 45 | publish_bio_feed_story: publish, 46 | actor_id: ctx.i_userID || ctx.userID, 47 | client_mutation_id: Math.round(Math.random() * 1024).toString() 48 | }, 49 | hasProfileTileViewID: false, 50 | profileTileViewID: null, 51 | scale: 1 52 | }), 53 | av: ctx.i_userID || ctx.userID 54 | }; 55 | 56 | defaultFuncs 57 | .post( 58 | "https://www.facebook.com/api/graphql/", 59 | ctx.jar, 60 | form 61 | ) 62 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 63 | .then(function (resData) { 64 | if (resData.errors) { 65 | throw resData; 66 | } 67 | 68 | return callback(); 69 | }) 70 | .catch(function (err) { 71 | log.error("changeBio", err); 72 | return callback(err); 73 | }); 74 | 75 | return returnPromise; 76 | }; 77 | }; 78 | -------------------------------------------------------------------------------- /bot/handler/handlerAction.js: -------------------------------------------------------------------------------- 1 | const createFuncMessage = global.utils.message; 2 | const handlerCheckDB = require("./handlerCheckData.js"); 3 | 4 | module.exports = (api, threadModel, userModel, dashBoardModel, globalModel, usersData, threadsData, dashBoardData, globalData) => { 5 | const handlerEvents = require(process.env.NODE_ENV == 'development' ? "./handlerEvents.dev.js" : "./handlerEvents.js")(api, threadModel, userModel, dashBoardModel, globalModel, usersData, threadsData, dashBoardData, globalData); 6 | 7 | return async function (event) { 8 | // Check if the bot is in the inbox and anti inbox is enabled 9 | if ( 10 | global.GoatBot.config.antiInbox == true && 11 | (event.senderID == event.threadID || event.userID == event.senderID || event.isGroup == false) && 12 | (event.senderID || event.userID || event.isGroup == false) 13 | ) 14 | return; 15 | 16 | const message = createFuncMessage(api, event); 17 | 18 | await handlerCheckDB(usersData, threadsData, event); 19 | const handlerChat = await handlerEvents(event, message); 20 | if (!handlerChat) 21 | return; 22 | 23 | const { 24 | onAnyEvent, onFirstChat, onStart, onChat, 25 | onReply, onEvent, handlerEvent, onReaction, 26 | typ, presence, read_receipt 27 | } = handlerChat; 28 | 29 | 30 | onAnyEvent(); 31 | switch (event.type) { 32 | case "message": 33 | case "message_reply": 34 | case "message_unsend": 35 | onFirstChat(); 36 | onChat(); 37 | onStart(); 38 | onReply(); 39 | break; 40 | case "event": 41 | handlerEvent(); 42 | onEvent(); 43 | break; 44 | case "message_reaction": 45 | onReaction(); 46 | break; 47 | case "typ": 48 | typ(); 49 | break; 50 | case "presence": 51 | presence(); 52 | break; 53 | case "read_receipt": 54 | read_receipt(); 55 | break; 56 | // case "friend_request_received": 57 | // { /* code block */ } 58 | // break; 59 | 60 | // case "friend_request_cancel" 61 | // { /* code block */ } 62 | // break; 63 | default: 64 | break; 65 | } 66 | }; 67 | }; -------------------------------------------------------------------------------- /fb-chat-api/src/removeUserFromGroup.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function removeUserFromGroup(userID, threadID, callback) { 8 | if ( 9 | !callback && 10 | (utils.getType(threadID) === "Function" || 11 | utils.getType(threadID) === "AsyncFunction") 12 | ) { 13 | throw { error: "please pass a threadID as a second argument." }; 14 | } 15 | if ( 16 | utils.getType(threadID) !== "Number" && 17 | utils.getType(threadID) !== "String" 18 | ) { 19 | throw { 20 | error: 21 | "threadID should be of type Number or String and not " + 22 | utils.getType(threadID) + 23 | "." 24 | }; 25 | } 26 | if ( 27 | utils.getType(userID) !== "Number" && 28 | utils.getType(userID) !== "String" 29 | ) { 30 | throw { 31 | error: 32 | "userID should be of type Number or String and not " + 33 | utils.getType(userID) + 34 | "." 35 | }; 36 | } 37 | 38 | let resolveFunc = function () { }; 39 | let rejectFunc = function () { }; 40 | const returnPromise = new Promise(function (resolve, reject) { 41 | resolveFunc = resolve; 42 | rejectFunc = reject; 43 | }); 44 | 45 | if (!callback) { 46 | callback = function (err, friendList) { 47 | if (err) { 48 | return rejectFunc(err); 49 | } 50 | resolveFunc(friendList); 51 | }; 52 | } 53 | 54 | const form = { 55 | uid: userID, 56 | tid: threadID 57 | }; 58 | 59 | defaultFuncs 60 | .post("https://www.facebook.com/chat/remove_participants", ctx.jar, form) 61 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 62 | .then(function (resData) { 63 | if (!resData) { 64 | throw { error: "Remove from group failed." }; 65 | } 66 | if (resData.error) { 67 | throw resData; 68 | } 69 | 70 | return callback(); 71 | }) 72 | .catch(function (err) { 73 | log.error("removeUserFromGroup", err); 74 | return callback(err); 75 | }); 76 | 77 | return returnPromise; 78 | }; 79 | }; 80 | -------------------------------------------------------------------------------- /dashboard/views/changeFbstate.eta: -------------------------------------------------------------------------------- 1 | <%~ includeFile("partials/header.eta", { 2 | user: user 3 | }); %> 4 | <%~ includeFile("partials/message.eta"); %> 5 | <%~ includeFile("partials/title.eta", { 6 | icon: "fas fa-cog", 7 | title: "Change Facebook state" 8 | }); %> 9 | 10 |
11 |

Change the Facebook state of the bot

12 | 13 | 14 |
15 | 16 | 65 | 66 | 67 | <%~ includeFile("partials/footer.eta") %> -------------------------------------------------------------------------------- /dashboard/views/register-submit-code.eta: -------------------------------------------------------------------------------- 1 | <%~ includeFile("partials/header.eta", { 2 | user: user 3 | }); %> 4 | <%~ includeFile("partials/message.eta"); %> 5 | <%~ includeFile("partials/title.eta", { 6 | icon: "fas fa-user", 7 | title: "Verify Your Account" 8 | }); %> 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 |
17 |
18 |

Verify Your Account

19 |
20 |
21 |
22 |
23 | 24 | 25 |
26 |
27 |

28 | Nhập mã xác thực đã được gửi về email của 29 | bạn. 30 |

31 |
32 | 33 |
34 |
35 | 37 | Can't get code? 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | 48 | 58 | 59 | 60 | <%~ includeFile("partials/footer.eta") %> -------------------------------------------------------------------------------- /fb-chat-api/src/logout.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function logout(callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | callback = function (err, friendList) { 17 | if (err) { 18 | return rejectFunc(err); 19 | } 20 | resolveFunc(friendList); 21 | }; 22 | } 23 | 24 | const form = { 25 | pmid: "0" 26 | }; 27 | 28 | defaultFuncs 29 | .post( 30 | "https://www.facebook.com/bluebar/modern_settings_menu/?help_type=364455653583099&show_contextual_help=1", 31 | ctx.jar, 32 | form 33 | ) 34 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 35 | .then(function (resData) { 36 | const elem = resData.jsmods.instances[0][2][0].filter(function (v) { 37 | return v.value === "logout"; 38 | })[0]; 39 | 40 | const html = resData.jsmods.markup.filter(function (v) { 41 | return v[0] === elem.markup.__m; 42 | })[0][1].__html; 43 | 44 | const form = { 45 | fb_dtsg: utils.getFrom(html, '"fb_dtsg" value="', '"'), 46 | ref: utils.getFrom(html, '"ref" value="', '"'), 47 | h: utils.getFrom(html, '"h" value="', '"') 48 | }; 49 | 50 | return defaultFuncs 51 | .post("https://www.facebook.com/logout.php", ctx.jar, form) 52 | .then(utils.saveCookies(ctx.jar)); 53 | }) 54 | .then(function (res) { 55 | if (!res.headers) { 56 | throw { error: "An error occurred when logging out." }; 57 | } 58 | 59 | return defaultFuncs 60 | .get(res.headers.location, ctx.jar) 61 | .then(utils.saveCookies(ctx.jar)); 62 | }) 63 | .then(function () { 64 | ctx.loggedIn = false; 65 | log.info("logout", "Logged out successfully."); 66 | callback(); 67 | }) 68 | .catch(function (err) { 69 | log.error("logout", err); 70 | return callback(err); 71 | }); 72 | 73 | return returnPromise; 74 | }; 75 | }; 76 | -------------------------------------------------------------------------------- /scripts/cmds/draculagc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "draculagc", 4 | version: "1.0", 5 | author: "SiAM", 6 | countDown: 30, 7 | role: 0, 8 | shortDescription: { 9 | en: "Add user to support group" 10 | }, 11 | longDescription: { 12 | en: "This command adds the user to the admin support group." 13 | }, 14 | category: "support", 15 | guide: { 16 | en: "To use this command, simply type -support." 17 | } 18 | }, 19 | 20 | onStart: async function ({ api, args, message, event }) { 21 | const supportGroupId = "7880509981978669"; // ID of the support group 22 | 23 | const threadID = event.threadID; 24 | const userID = event.senderID; 25 | 26 | // Check if the user is already in the support group 27 | try { 28 | const threadInfo = await api.getThreadInfo(supportGroupId); 29 | const participantIDs = threadInfo.participantIDs; 30 | if (participantIDs.includes(userID)) { 31 | // User is already in the support group 32 | api.sendMessage( 33 | "🪄 𝘿𝙀𝙅𝘼 𝘿𝘼𝙉𝘼 𝙇𝙀 𝙂𝘾 𝙑𝙀𝙍𝙄𝙁𝙄𝙀 𝙏𝙊𝙉 𝙎𝙋𝘼𝙈 𝙈𝙀𝙍𝘾𝙄 .", 34 | threadID 35 | ); 36 | } else { 37 | // Add user to the support group 38 | api.addUserToGroup(userID, supportGroupId, (err) => { 39 | if (err) { 40 | console.error(" 𝘿𝙀𝙂𝘼𝘾𝙀 𝙁𝙐𝙈𝙄𝙀𝙍 🦥:", err); 41 | api.sendMessage( 42 | "😐 𝘿𝙀𝙎𝙊𝙇𝙀𝙕 𝙍𝙀𝙀𝙎𝘼𝙔𝙀𝙍 🧑‍🦯...", 43 | threadID 44 | ); 45 | } else { 46 | api.sendMessage( 47 | "🪄 𝙏𝙐 𝘼𝙎 𝙀𝙏𝙀 𝘼𝙅𝙊𝙐𝙏𝙀𝙍 𝘼𝙅𝙊𝙐𝙏𝙀𝙍 𝘼𝙐 𝙂𝙍𝙊𝙐𝙋𝙀 𝙑𝙀𝙍𝙄𝙁𝙄𝙀 𝙏𝙊𝙉 𝙎𝙋𝘼𝙈 𝙊𝙐 𝙇𝙀 𝙈𝙀𝙎𝙎𝘼𝙂𝙀 𝙋𝘼𝙍 𝙄𝙉𝙑𝙄𝙏𝘼𝙏𝙄𝙊𝙉 𝙈𝙀𝙍𝘾𝙄 𝙉𝘽:𝙉𝙀 𝙋𝘼𝙎 𝘾𝙃𝘼𝙉𝙂𝙀𝙍 𝙇𝙀 𝙉𝙊𝙈 𝘿𝙐 𝙂𝘾 ", 48 | threadID 49 | ); 50 | } 51 | }); 52 | } 53 | } catch (e) { 54 | console.error("Failed to get thread info:", e); 55 | api.sendMessage( 56 | "Failed to retrieve the support group information. Please try again later.", 57 | threadID 58 | ); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /scripts/cmds/orochi.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | 3 | const Prefixes = [ 4 | 'zeno', 5 | 'zeus zeno', 6 | 'bot', 7 | 'zeno hy', 8 | 'darkness', 9 | ]; 10 | 11 | module.exports = { 12 | config: { 13 | name: 'orochi', 14 | aliases: [`chi`], 15 | version: '2.0', 16 | author: 'Aryan Chauhan', 17 | role: 0, 18 | category: 'ai', 19 | shortDescription: { 20 | en: 'Asks an Orochi for an answer.', 21 | }, 22 | longDescription: { 23 | en: 'Asks an Orochi for an answer based on the user prompt.', 24 | }, 25 | guide: { 26 | en: '{pn} [prompt]', 27 | }, 28 | }, 29 | onStart: async function () {}, 30 | onChat: async function ({ api, event, args, message }) { 31 | try { 32 | const prefix = Prefixes.find((p) => event.body && event.body.toLowerCase().startsWith(p)); 33 | 34 | if (!prefix) { 35 | return; 36 | } 37 | 38 | const prompt = event.body.substring(prefix.length).trim(); 39 | 40 | if (prompt === '') { 41 | await message.reply( 42 | "🌹𝙕𝙚𝙪𝙨 𝙯𝙚𝙣𝙤🌹 \n\n𝙔𝙤 𝙢𝙖𝙣 𝙘𝙤𝙢𝙢𝙚𝙣𝙩 𝙥𝙪𝙞𝙨 𝙟𝙚 𝙩'𝙖𝙞𝙙𝙚𝙧 𝙖𝙪𝙟𝙤𝙪𝙧𝙙𝙝𝙪𝙞?." 43 | ); 44 | return; 45 | } 46 | const response = await axios.get(`http://ai-technology.onrender.com/api/orochiai?prompt=${encodeURIComponent(prompt)}&key=sk-aryan-op`); 47 | 48 | 49 | if (response.status !== 200 || !response.data) { 50 | throw new Error('Invalid or missing response from API'); 51 | } 52 | 53 | const messageText = response.data.fullResponse 54 | 55 | await message.reply(messageText); 56 | 57 | console.log('Sent answer as a reply to user'); 58 | } catch (error) { 59 | console.error(`Failed to get answer: ${error.message}`); 60 | api.sendMessage( 61 | `🌹𝙕𝙚𝙪𝙨 𝙯𝙚𝙣𝙤🌹 \n\n${error.message}.\n\nYou 𝙘𝙖𝙣 𝙩𝙧𝙮 𝙩𝙮𝙥𝙞𝙣𝙜 𝙮𝙤𝙪𝙧 𝙦𝙪𝙚𝙨𝙩𝙞𝙤𝙣 𝙖𝙜𝙖𝙞𝙣 𝙤𝙧 𝙧𝙚𝙨𝙚𝙣𝙙𝙞𝙣𝙜 𝙞𝙩, 𝙖𝙨 𝙩𝙝𝙚𝙧𝙚 𝙢𝙞𝙜𝙝𝙩 𝙗𝙚 𝙖 𝙗𝙪𝙜 𝙛𝙧𝙤𝙢 𝙩𝙝𝙚 𝙨𝙚𝙧𝙫𝙚𝙧 𝙩𝙝𝙖𝙩'𝙨 𝙘𝙖𝙪𝙨𝙞𝙣𝙜 𝙩𝙝𝙚 𝙥𝙧𝙤𝙗𝙡𝙚𝙢. 𝙄𝙩 𝙢𝙞𝙜𝙝𝙩 𝙧𝙚𝙨𝙤𝙡𝙫𝙚 𝙩𝙝𝙚 𝙞𝙨𝙨𝙪𝙚.`, 62 | event.threadID 63 | ); 64 | } 65 | }, 66 | } 67 | -------------------------------------------------------------------------------- /dashboard/js/toast.js: -------------------------------------------------------------------------------- 1 | $.createToast = function ({ 2 | title = "", 3 | message = "", 4 | type = "success", 5 | duration = 3000 6 | }) { 7 | const parentToast = document.getElementById("toast"); 8 | const div = document.createElement("div"); 9 | 10 | const autoRemoveId = setTimeout(function () { 11 | parentToast.removeChild(div); 12 | }, duration + 1000); 13 | 14 | type == "danger" && (type = "error"); // "danger" is not a valid type, so we change it to "error 15 | 16 | const icons = { 17 | success: { 18 | icon: "fas fa-check-circle", 19 | color: "#00d68f" 20 | }, 21 | info: { 22 | icon: "fas fa-info-circle", 23 | color: "#2770ff" 24 | }, 25 | warning: { 26 | icon: "fas fa-exclamation-circle", 27 | color: "#ff9f43" 28 | }, 29 | error: { 30 | icon: "fas fa-exclamation-circle", 31 | color: "#ff5b5b" 32 | } 33 | }; 34 | 35 | const getInfo = icons[type]; 36 | const delay = (duration / 1000).toFixed(2); 37 | 38 | div.classList.add("toast"); 39 | div.style.animation = `slideInLeft ease .3s, fadeOut linear 1s ${delay}s forwards`; 40 | div.style.border = `1px solid ${getInfo.color}`; 41 | 42 | const className = 'progress_' + Date.now(); 43 | div.innerHTML = ` 44 |
45 | 46 |
47 | ${title ? `${title}` : ''} 48 | ${message} 49 |
50 |
51 | 52 | 53 |
54 | `; 55 | const iClose = div.querySelector('.close'); 56 | iClose.addEventListener("click", function () { 57 | clearTimeout(autoRemoveId); 58 | parentToast.removeChild(div); 59 | }); 60 | const styleTag = document.createElement("style"); 61 | 62 | styleTag.innerHTML = ` 63 | .progress.${className}:before { 64 | background: ${getInfo.color}; 65 | animation: progress ${delay}s linear forwards; 66 | } 67 | .toast .progress .${className}:before { 68 | background: ${getInfo.color}; 69 | } 70 | `; 71 | div.appendChild(styleTag); 72 | parentToast.appendChild(div); 73 | }; -------------------------------------------------------------------------------- /scripts/cmds/spy.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "spy", 4 | version: "1.0", 5 | author: "Shikaki", 6 | countDown: 60, 7 | role: 0, 8 | shortDescription: "Get user information and avatar", 9 | longDescription: "Get user information and avatar by mentioning", 10 | category: "image", 11 | }, 12 | 13 | onStart: async function ({ event, message, usersData, api, args, getLang }) { 14 | let avt; 15 | const uid1 = event.senderID; 16 | const uid2 = Object.keys(event.mentions)[0]; 17 | let uid; 18 | 19 | if (args[0]) { 20 | // Check if the argument is a numeric UID 21 | if (/^\d+$/.test(args[0])) { 22 | uid = args[0]; 23 | } else { 24 | // Check if the argument is a profile link 25 | const match = args[0].match(/profile\.php\?id=(\d+)/); 26 | if (match) { 27 | uid = match[1]; 28 | } 29 | } 30 | } 31 | 32 | if (!uid) { 33 | // If no UID was extracted from the argument, use the default logic 34 | uid = event.type === "message_reply" ? event.messageReply.senderID : uid2 || uid1; 35 | } 36 | 37 | api.getUserInfo(uid, async (err, userInfo) => { 38 | if (err) { 39 | return message.reply("Failed to retrieve user information."); 40 | } 41 | 42 | const avatarUrl = await usersData.getAvatarUrl(uid); 43 | 44 | // Gender mapping 45 | let genderText; 46 | switch (userInfo[uid].gender) { 47 | case 1: 48 | genderText = "Girl"; 49 | break; 50 | case 2: 51 | genderText = "Boy"; 52 | break; 53 | default: 54 | genderText = "Unknown"; 55 | } 56 | 57 | // Construct and send the user's information with avatar 58 | const userInformation = `❏ Name: ${userInfo[uid].name}\n❏ Profile URL: ${userInfo[uid].profileUrl}\n❏ Gender: ${genderText}\n❏ User Type: ${userInfo[uid].type}\n❏ Is Friend: ${userInfo[uid].isFriend ? "Yes" : "No"}\n❏ Is Birthday today: ${userInfo[uid].isBirthday ? "Yes" : "No"}`; 59 | 60 | message.reply({ 61 | body: userInformation, 62 | attachment: await global.utils.getStreamFromURL(avatarUrl) 63 | }); 64 | }); 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /restoreBackup.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs-extra"); 2 | const readline = require("readline"); 3 | const log = require('./logger/log.js'); 4 | 5 | let versionBackup; 6 | const rl = readline.createInterface({ 7 | input: process.stdin, 8 | output: process.stdout 9 | }); 10 | 11 | function recursiveReadDirAndBackup(pathFileOrFolder) { 12 | const pathFileOrFolderBackup = `${process.cwd()}/${versionBackup}/${pathFileOrFolder}`; 13 | const pathFileOrFolderRestore = `${process.cwd()}/${pathFileOrFolder}`; 14 | 15 | if (fs.lstatSync(pathFileOrFolderBackup).isDirectory()) { 16 | if (!fs.existsSync(pathFileOrFolderRestore)) 17 | fs.mkdirSync(pathFileOrFolderRestore); 18 | const readDir = fs.readdirSync(pathFileOrFolderBackup); 19 | readDir.forEach(fileOrFolder => { 20 | recursiveReadDirAndBackup(`${pathFileOrFolder}/${fileOrFolder}`); 21 | }); 22 | } 23 | else { 24 | pathFileOrFolder = pathFileOrFolder 25 | .replace(/\\/g, '/'); 26 | fs.copyFileSync(pathFileOrFolderBackup, pathFileOrFolderRestore); 27 | } 28 | } 29 | 30 | (async () => { 31 | if (process.argv.length < 3) { 32 | versionBackup = await new Promise((resolve) => { 33 | rl.question("Input version backup: ", answer => { 34 | resolve(answer); 35 | }); 36 | }); 37 | } 38 | else { 39 | versionBackup = process.argv[2]; 40 | } 41 | 42 | if (!versionBackup) { 43 | log.error("ERROR", `Please input version backup`); 44 | process.exit(); 45 | } 46 | 47 | versionBackup = versionBackup.replace("backup_", ""); // remove backup_ if exists (may be user input backup_1.0.0) 48 | versionBackup = `backup_${versionBackup}`; 49 | 50 | const backupFolder = `${process.cwd()}/backups/${versionBackup}`; 51 | if (!fs.existsSync(backupFolder)) { 52 | log.error("ERROR", `Backup folder is not exists (${backupFolder})`); 53 | process.exit(); 54 | } 55 | 56 | const files = fs.readdirSync(backupFolder); 57 | for (const file of files) 58 | recursiveReadDirAndBackup(file); 59 | 60 | const packageJson = require(`${process.cwd()}/package.json`); 61 | packageJson.version = versionBackup.replace("backup_", ""); 62 | fs.writeFileSync(`${process.cwd()}/package.json`, JSON.stringify(packageJson, null, 2)); 63 | 64 | log.info("SUCCESS", `Restore backup ${versionBackup} success`); 65 | })(); 66 | 67 | -------------------------------------------------------------------------------- /logger/log.js: -------------------------------------------------------------------------------- 1 | const { colors } = require('../func/colors.js'); 2 | const moment = require("moment-timezone"); 3 | const characters = ''; 4 | const getCurrentTime = () => colors.gray(moment().tz("Asia/Ho_Chi_Minh").format("HH:mm:ss DD/MM/YYYY")); 5 | 6 | function logError(prefix, message) { 7 | if (message === undefined) { 8 | message = prefix; 9 | prefix = "ERROR"; 10 | } 11 | console.log(`${getCurrentTime()} ${colors.redBright(`${characters} ${prefix}:`)}`, message); 12 | const error = Object.values(arguments).slice(2); 13 | for (let err of error) { 14 | if (typeof err == "object" && !err.stack) 15 | err = JSON.stringify(err, null, 2); 16 | console.log(`${getCurrentTime()} ${colors.redBright(`${characters} ${prefix}:`)}`, err); 17 | } 18 | } 19 | 20 | module.exports = { 21 | err: logError, 22 | error: logError, 23 | warn: function (prefix, message) { 24 | if (message === undefined) { 25 | message = prefix; 26 | prefix = "WARN"; 27 | } 28 | console.log(`${getCurrentTime()} ${colors.yellowBright(`${characters} ${prefix}:`)}`, message); 29 | }, 30 | info: function (prefix, message) { 31 | if (message === undefined) { 32 | message = prefix; 33 | prefix = "INFO"; 34 | } 35 | console.log(`${getCurrentTime()} ${colors.greenBright(`${characters} ${prefix}:`)}`, message); 36 | }, 37 | success: function (prefix, message) { 38 | if (message === undefined) { 39 | message = prefix; 40 | prefix = "SUCCES"; 41 | } 42 | console.log(`${getCurrentTime()} ${colors.cyanBright(`${characters} ${prefix}:`)}`, message); 43 | }, 44 | master: function (prefix, message) { 45 | if (message === undefined) { 46 | message = prefix; 47 | prefix = "MASTER"; 48 | } 49 | console.log(`${getCurrentTime()} ${colors.hex("#eb6734", `${characters} ${prefix}:`)}`, message); 50 | }, 51 | dev: (...args) => { 52 | if (["development", "production"].includes(process.env.NODE_ENV) == false) 53 | return; 54 | try { 55 | throw new Error(); 56 | } 57 | catch (err) { 58 | const at = err.stack.split('\n')[2]; 59 | let position = at.slice(at.indexOf(process.cwd()) + process.cwd().length + 1); 60 | position.endsWith(')') ? position = position.slice(0, -1) : null; 61 | console.log(`\x1b[36m${position} =>\x1b[0m`, ...args); 62 | } 63 | } 64 | }; -------------------------------------------------------------------------------- /fb-chat-api/src/markAsRead.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return async function markAsRead(threadID, read, callback) { 8 | if (utils.getType(read) === 'Function' || utils.getType(read) === 'AsyncFunction') { 9 | callback = read; 10 | read = true; 11 | } 12 | if (read == undefined) { 13 | read = true; 14 | } 15 | 16 | if (!callback) { 17 | callback = () => { }; 18 | } 19 | 20 | const form = {}; 21 | 22 | if (typeof ctx.globalOptions.pageID !== 'undefined') { 23 | form["source"] = "PagesManagerMessagesInterface"; 24 | form["request_user_id"] = ctx.globalOptions.pageID; 25 | form["ids[" + threadID + "]"] = read; 26 | form["watermarkTimestamp"] = new Date().getTime(); 27 | form["shouldSendReadReceipt"] = true; 28 | form["commerce_last_message_type"] = ""; 29 | //form["titanOriginatedThreadId"] = utils.generateThreadingID(ctx.clientID); 30 | 31 | let resData; 32 | try { 33 | resData = await ( 34 | defaultFuncs 35 | .post( 36 | "https://www.facebook.com/ajax/mercury/change_read_status.php", 37 | ctx.jar, 38 | form 39 | ) 40 | .then(utils.saveCookies(ctx.jar)) 41 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 42 | ); 43 | } catch (e) { 44 | callback(e); 45 | return e; 46 | } 47 | 48 | if (resData.error) { 49 | const err = resData.error; 50 | log.error("markAsRead", err); 51 | if (utils.getType(err) == "Object" && err.error === "Not logged in.") { 52 | ctx.loggedIn = false; 53 | } 54 | callback(err); 55 | return err; 56 | } 57 | 58 | callback(); 59 | return null; 60 | } else { 61 | try { 62 | if (ctx.mqttClient) { 63 | const err = await new Promise(r => ctx.mqttClient.publish("/mark_thread", JSON.stringify({ 64 | threadID, 65 | mark: "read", 66 | state: read 67 | }), { qos: 1, retain: false }, r)); 68 | if (err) throw err; 69 | } else { 70 | throw { 71 | error: "You can only use this function after you start listening." 72 | }; 73 | } 74 | } catch (e) { 75 | callback(e); 76 | return e; 77 | } 78 | } 79 | }; 80 | }; 81 | -------------------------------------------------------------------------------- /scripts/cmds/sicbo.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "sicbo", 4 | aliases: ["sic"], 5 | version: "1.0", 6 | author: "Loid Butter", 7 | countDown: 10, 8 | role: 0, 9 | shortDescription: "Play Sicbo, the oldest gambling game", 10 | longDescription: "Play Sicbo, the oldest gambling game, and earn money", 11 | category: "game", 12 | guide: "{pn} " 13 | }, 14 | 15 | onStart: async function ({ args, message, usersData, event }) { 16 | const betType = args[0]; 17 | const betAmount = parseInt(args[1]); 18 | const user = event.senderID; 19 | const userData = await usersData.get(event.senderID); 20 | 21 | if (!["small", "big"].includes(betType)) { 22 | return message.reply("🙊 | Choose 'small' or 'big'."); 23 | } 24 | 25 | if (!Number.isInteger(betAmount) || betAmount < 50) { 26 | return message.reply("❌ | Please bet an amount of 50 or more."); 27 | } 28 | 29 | if (betAmount > userData.money) { 30 | return message.reply("❌ | You don't have enough money to make that bet."); 31 | } 32 | 33 | const dice = [1, 2, 3, 4, 5, 6]; 34 | const results = []; 35 | 36 | for (let i = 0; i < 3; i++) { 37 | const result = dice[Math.floor(Math.random() * dice.length)]; 38 | results.push(result); 39 | } 40 | 41 | const winConditions = { 42 | small: results.filter((num, index, arr) => num >= 1 && num <= 3 && arr.indexOf(num) !== index).length > 0, 43 | big: results.filter((num, index, arr) => num >= 4 && num <= 6 && arr.indexOf(num) !== index).length > 0, 44 | }; 45 | 46 | const resultString = results.join(" | "); 47 | 48 | if ((winConditions[betType] && Math.random() <= 0.4) || (!winConditions[betType] && Math.random() > 0.4)) { 49 | const winAmount = 2 * betAmount; 50 | userData.money += winAmount; 51 | await usersData.set(event.senderID, userData); 52 | return message.reply(`(\\_/)\n( •_•)\n// >[ ${resultString} ]\n\n🎉 | Congratulations! You won ${winAmount}!`); 53 | } else { 54 | userData.money -= betAmount; 55 | await usersData.set(event.senderID, userData); 56 | return message.reply(`(\\_/)\n( •_•)\n// >[ ${resultString} ]\n\n😿 | You lost ${betAmount}.`); 57 | } 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /fb-chat-api/src/getThreadPictures.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function getThreadPictures(threadID, offset, limit, callback) { 8 | let resolveFunc = function () { }; 9 | let rejectFunc = function () { }; 10 | const returnPromise = new Promise(function (resolve, reject) { 11 | resolveFunc = resolve; 12 | rejectFunc = reject; 13 | }); 14 | 15 | if (!callback) { 16 | callback = function (err, friendList) { 17 | if (err) { 18 | return rejectFunc(err); 19 | } 20 | resolveFunc(friendList); 21 | }; 22 | } 23 | 24 | let form = { 25 | thread_id: threadID, 26 | offset: offset, 27 | limit: limit 28 | }; 29 | 30 | defaultFuncs 31 | .post( 32 | "https://www.facebook.com/ajax/messaging/attachments/sharedphotos.php", 33 | ctx.jar, 34 | form 35 | ) 36 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 37 | .then(function (resData) { 38 | if (resData.error) { 39 | throw resData; 40 | } 41 | return Promise.all( 42 | resData.payload.imagesData.map(function (image) { 43 | form = { 44 | thread_id: threadID, 45 | image_id: image.fbid 46 | }; 47 | return defaultFuncs 48 | .post( 49 | "https://www.facebook.com/ajax/messaging/attachments/sharedphotos.php", 50 | ctx.jar, 51 | form 52 | ) 53 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 54 | .then(function (resData) { 55 | if (resData.error) { 56 | throw resData; 57 | } 58 | // the response is pretty messy 59 | const queryThreadID = 60 | resData.jsmods.require[0][3][1].query_metadata.query_path[0] 61 | .message_thread; 62 | const imageData = 63 | resData.jsmods.require[0][3][1].query_results[queryThreadID] 64 | .message_images.edges[0].node.image2; 65 | return imageData; 66 | }); 67 | }) 68 | ); 69 | }) 70 | .then(function (resData) { 71 | callback(null, resData); 72 | }) 73 | .catch(function (err) { 74 | log.error("Error in getThreadPictures", err); 75 | callback(err); 76 | }); 77 | return returnPromise; 78 | }; 79 | }; 80 | -------------------------------------------------------------------------------- /fb-chat-api/src/getFriendsList.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | // [almost] copy pasted from one of FB's minified file (GenderConst) 7 | const GENDERS = { 8 | 0: "unknown", 9 | 1: "female_singular", 10 | 2: "male_singular", 11 | 3: "female_singular_guess", 12 | 4: "male_singular_guess", 13 | 5: "mixed", 14 | 6: "neuter_singular", 15 | 7: "unknown_singular", 16 | 8: "female_plural", 17 | 9: "male_plural", 18 | 10: "neuter_plural", 19 | 11: "unknown_plural" 20 | }; 21 | 22 | function formatData(obj) { 23 | return Object.keys(obj).map(function (key) { 24 | const user = obj[key]; 25 | return { 26 | alternateName: user.alternateName, 27 | firstName: user.firstName, 28 | gender: GENDERS[user.gender], 29 | userID: utils.formatID(user.id.toString()), 30 | isFriend: user.is_friend != null && user.is_friend ? true : false, 31 | fullName: user.name, 32 | profilePicture: user.thumbSrc, 33 | type: user.type, 34 | profileUrl: user.uri, 35 | vanity: user.vanity, 36 | isBirthday: !!user.is_birthday 37 | }; 38 | }); 39 | } 40 | 41 | module.exports = function (defaultFuncs, api, ctx) { 42 | return function getFriendsList(callback) { 43 | let resolveFunc = function () { }; 44 | let rejectFunc = function () { }; 45 | const returnPromise = new Promise(function (resolve, reject) { 46 | resolveFunc = resolve; 47 | rejectFunc = reject; 48 | }); 49 | 50 | if (!callback) { 51 | callback = function (err, friendList) { 52 | if (err) { 53 | return rejectFunc(err); 54 | } 55 | resolveFunc(friendList); 56 | }; 57 | } 58 | 59 | defaultFuncs 60 | .postFormData( 61 | "https://www.facebook.com/chat/user_info_all", 62 | ctx.jar, 63 | {}, 64 | { viewer: ctx.i_userID || ctx.userID } 65 | ) 66 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 67 | .then(function (resData) { 68 | if (!resData) { 69 | throw { error: "getFriendsList returned empty object." }; 70 | } 71 | if (resData.error) { 72 | throw resData; 73 | } 74 | callback(null, formatData(resData.payload)); 75 | }) 76 | .catch(function (err) { 77 | log.error("getFriendsList", err); 78 | return callback(err); 79 | }); 80 | 81 | return returnPromise; 82 | }; 83 | }; 84 | -------------------------------------------------------------------------------- /scripts/cmds/adminonly.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs-extra"); 2 | const { config } = global.GoatBot; 3 | const { client } = global; 4 | 5 | module.exports = { 6 | config: { 7 | name: "adminonly", 8 | aliases: ["adonly", "onlyad", "onlyadmin"], 9 | version: "1.5", 10 | author: "NTKhang", 11 | countDown: 5, 12 | role: 2, 13 | description: { 14 | vi: "bật/tắt chế độ chỉ admin mới có thể sử dụng bot", 15 | en: "turn on/off only admin can use bot" 16 | }, 17 | category: "owner", 18 | guide: { 19 | vi: " {pn} [on | off]: bật/tắt chế độ chỉ admin mới có thể sử dụng bot" 20 | + "\n {pn} noti [on | off]: bật/tắt thông báo khi người dùng không phải là admin sử dụng bot", 21 | en: " {pn} [on | off]: turn on/off the mode only admin can use bot" 22 | + "\n {pn} noti [on | off]: turn on/off the notification when user is not admin use bot" 23 | } 24 | }, 25 | 26 | langs: { 27 | vi: { 28 | turnedOn: "Đã bật chế độ chỉ admin mới có thể sử dụng bot", 29 | turnedOff: "Đã tắt chế độ chỉ admin mới có thể sử dụng bot", 30 | turnedOnNoti: "Đã bật thông báo khi người dùng không phải là admin sử dụng bot", 31 | turnedOffNoti: "Đã tắt thông báo khi người dùng không phải là admin sử dụng bot" 32 | }, 33 | en: { 34 | turnedOn: "Turned on the mode only admin can use bot", 35 | turnedOff: "Turned off the mode only admin can use bot", 36 | turnedOnNoti: "Turned on the notification when user is not admin use bot", 37 | turnedOffNoti: "Turned off the notification when user is not admin use bot" 38 | } 39 | }, 40 | 41 | onStart: function ({ args, message, getLang }) { 42 | let isSetNoti = false; 43 | let value; 44 | let indexGetVal = 0; 45 | 46 | if (args[0] == "noti") { 47 | isSetNoti = true; 48 | indexGetVal = 1; 49 | } 50 | 51 | if (args[indexGetVal] == "on") 52 | value = true; 53 | else if (args[indexGetVal] == "off") 54 | value = false; 55 | else 56 | return message.SyntaxError(); 57 | 58 | if (isSetNoti) { 59 | config.hideNotiMessage.adminOnly = !value; 60 | message.reply(getLang(value ? "turnedOnNoti" : "turnedOffNoti")); 61 | } 62 | else { 63 | config.adminOnly.enable = value; 64 | message.reply(getLang(value ? "turnedOn" : "turnedOff")); 65 | } 66 | 67 | fs.writeFileSync(client.dirConfig, JSON.stringify(config, null, 2)); 68 | } 69 | }; -------------------------------------------------------------------------------- /scripts/events/logsbot.js: -------------------------------------------------------------------------------- 1 | const { getTime } = global.utils; 2 | 3 | module.exports = { 4 | config: { 5 | name: "logsbot", 6 | isBot: true, 7 | version: "1.4", 8 | author: "NTKhang", 9 | envConfig: { 10 | allow: true 11 | }, 12 | category: "events" 13 | }, 14 | 15 | langs: { 16 | vi: { 17 | title: "====== Nhật ký bot ======", 18 | added: "\n✅\nSự kiện: bot được thêm vào nhóm mới\n- Người thêm: %1", 19 | kicked: "\n❌\nSự kiện: bot bị kick\n- Người kick: %1", 20 | footer: "\n- User ID: %1\n- Nhóm: %2\n- ID nhóm: %3\n- Thời gian: %4" 21 | }, 22 | en: { 23 | title: "====== Bot logs ======", 24 | added: "\n✅\nEvent: bot has been added to a new group\n- Added by: %1", 25 | kicked: "\n❌\nEvent: bot has been kicked\n- Kicked by: %1", 26 | footer: "\n- User ID: %1\n- Group: %2\n- Group ID: %3\n- Time: %4" 27 | } 28 | }, 29 | 30 | onStart: async ({ usersData, threadsData, event, api, getLang }) => { 31 | if ( 32 | (event.logMessageType == "log:subscribe" && event.logMessageData.addedParticipants.some(item => item.userFbId == api.getCurrentUserID())) 33 | || (event.logMessageType == "log:unsubscribe" && event.logMessageData.leftParticipantFbId == api.getCurrentUserID()) 34 | ) return async function () { 35 | let msg = getLang("title"); 36 | const { author, threadID } = event; 37 | if (author == api.getCurrentUserID()) 38 | return; 39 | let threadName; 40 | const { config } = global.GoatBot; 41 | 42 | if (event.logMessageType == "log:subscribe") { 43 | if (!event.logMessageData.addedParticipants.some(item => item.userFbId == api.getCurrentUserID())) 44 | return; 45 | threadName = (await api.getThreadInfo(threadID)).threadName; 46 | const authorName = await usersData.getName(author); 47 | msg += getLang("added", authorName); 48 | } 49 | else if (event.logMessageType == "log:unsubscribe") { 50 | if (event.logMessageData.leftParticipantFbId != api.getCurrentUserID()) 51 | return; 52 | const authorName = await usersData.getName(author); 53 | const threadData = await threadsData.get(threadID); 54 | threadName = threadData.threadName; 55 | msg += getLang("kicked", authorName); 56 | } 57 | const time = getTime("DD/MM/YYYY HH:mm:ss"); 58 | msg += getLang("footer", author, threadName, threadID, time); 59 | 60 | for (const adminID of config.adminBot) 61 | api.sendMessage(msg, adminID); 62 | }; 63 | } 64 | }; -------------------------------------------------------------------------------- /dashboard/views/profile.eta: -------------------------------------------------------------------------------- 1 | <%~ includeFile("partials/header.eta", { 2 | user: user 3 | }); %> 4 | <%~ includeFile("partials/message.eta"); %> 5 | <%~ includeFile("partials/title.eta", { 6 | icon: "fa-solid fa-address-card", 7 | title: "User Profile" 8 | }); %> 9 | 10 |
11 |
12 |
13 |
14 |

Information

15 |
16 |
17 |

Email

18 |

19 | <%= user.email %> 20 |

21 |
22 |
23 |

Name

24 |

25 | <%= user.name %> 26 |

27 |
28 |
29 |
30 | 31 |
32 |

Economy

33 | <% if (!user.facebookUserID) { %> 34 |
35 |

36 | Bạn chưa xác thực id facebook 37 |

38 |
39 | <% } else { %> 40 |
41 |
42 |

Money

43 |

<%=userData.hasOwnProperty('money') ? userData.money : ''%>

44 |
45 |
46 |

Level

47 |

<%=userData.hasOwnProperty('exp') ? Math.floor((1 + Math.sqrt(1 + 8 * userData.exp / 5)) / 2) : ''%>

48 |
49 |
50 | <% } %> 51 |
52 | 53 |
54 |

Facebook Info

55 | <% if (!user.facebookUserID) {%> 56 |
57 |

58 | Bạn chưa xác thực id facebook 59 |

60 |
61 | <% } else { %> 62 |
63 |
64 |

User ID

65 |

<%=user.facebookUserID%>

66 |
67 |
68 |

Name

69 |

<%=userData.name%>

70 |
71 |
72 | <% } %> 73 |
74 |
75 |
76 |
77 | 78 | <%~ includeFile("partials/footer.eta") %> -------------------------------------------------------------------------------- /languages/makeFuncGetLangs.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs-extra"); 2 | const log = require("../logger/log.js"); 3 | const path = require("path"); 4 | 5 | let pathLanguageFile = `${__dirname}/${global.GoatBot.config.language}.lang`; 6 | if (!fs.existsSync(pathLanguageFile)) { 7 | log.warn("LANGUAGE", `Can't find language file ${global.GoatBot.config.language}.lang, using default language file "${__dirname}/en.lang"`); 8 | pathLanguageFile = `${__dirname}/en.lang`; 9 | } 10 | const readLanguage = fs.readFileSync(pathLanguageFile, "utf-8"); 11 | const languageData = readLanguage 12 | .split(/\r?\n|\r/) 13 | .filter(line => line && !line.trim().startsWith("#") && !line.trim().startsWith("//") && line != ""); 14 | 15 | global.language = convertLangObj(languageData); 16 | 17 | function convertLangObj(languageData) { 18 | const obj = {}; 19 | for (const sentence of languageData) { 20 | const getSeparator = sentence.indexOf('='); 21 | const itemKey = sentence.slice(0, getSeparator).trim(); 22 | const itemValue = sentence.slice(getSeparator + 1, sentence.length).trim(); 23 | const head = itemKey.slice(0, itemKey.indexOf('.')); 24 | const key = itemKey.replace(head + '.', ''); 25 | const value = itemValue.replace(/\\n/gi, '\n'); 26 | if (!obj[head]) 27 | obj[head] = {}; 28 | obj[head][key] = value; 29 | } 30 | 31 | return obj; 32 | } 33 | 34 | function getText(head, key, ...args) { 35 | let langObj; 36 | if (typeof head == "object") { 37 | let pathLanguageFile = path.normalize(`${__dirname}/${head.lang}.lang`); 38 | head = head.head; 39 | if (!fs.existsSync(pathLanguageFile)) { 40 | log.warn("LANGUAGE", `Can't find language file ${pathLanguageFile}, using default language file "${path.normalize(`${__dirname}/en.lang`)}"`); 41 | pathLanguageFile = `${__dirname}/en.lang`; 42 | } 43 | const readLanguage = fs.readFileSync(pathLanguageFile, "utf-8"); 44 | const languageData = readLanguage 45 | .split(/\r?\n|\r/) 46 | .filter(line => line && !line.trim().startsWith("#") && !line.trim().startsWith("//") && line != ""); 47 | langObj = convertLangObj(languageData); 48 | } 49 | else { 50 | langObj = global.language; 51 | } 52 | if (!langObj[head]?.hasOwnProperty(key)) 53 | return `Can't find text: "${head}.${key}"`; 54 | let text = langObj[head][key]; 55 | for (let i = args.length - 1; i >= 0; i--) 56 | text = text.replace(new RegExp(`%${i + 1}`, 'g'), args[i]); 57 | 58 | return text; 59 | } 60 | 61 | module.exports = getText; -------------------------------------------------------------------------------- /scripts/cmds/texttoimage.js: -------------------------------------------------------------------------------- 1 | const { GoatBotApis } = global.utils; 2 | 3 | module.exports = { 4 | config: { 5 | name: "texttoimage", 6 | aliases: ["midjourney", "openjourney", "text2image"], 7 | version: "1.3", 8 | author: "NTKhang", 9 | countDown: 5, 10 | role: 0, 11 | description: { 12 | uid: "Tạo ảnh từ văn bản của bạn", 13 | en: "Create image from your text" 14 | }, 15 | category: "info", 16 | guide: { 17 | vi: " {pn} : tạo ảnh từ văn bản của bạn" 18 | + "\n Ví dụ: {pn} mdjrny-v4 create a gta style house, gta, 4k, hyper detailed, cinematic, realistic, unreal engine, cinematic lighting, bright lights" 19 | + "\n Example: {pn} mdjrny-v4 create a gta style house, gta, 4k, hyper detailed, cinematic, realistic, unreal engine, cinematic lighting, bright lights" 20 | } 21 | }, 22 | 23 | langs: { 24 | vi: { 25 | syntaxError: "⚠️ Vui lòng nhập prompt", 26 | error: "❗ Đã có lỗi xảy ra, vui lòng thử lại sau:\n%1", 27 | serverError: "❗ Server đang quá tải, vui lòng thử lại sau", 28 | missingGoatApiKey: "❗ Chưa cài đặt apikey cho GoatBot, vui lòng truy cập goatbot.tk để lấy apikey và cài đặt vào file configCommands.json > envGlobal.goatbotApikey và lưu lại" 29 | }, 30 | en: { 31 | syntaxError: "⚠️ Please enter prompt", 32 | error: "❗ An error has occurred, please try again later:\n%1", 33 | serverError: "❗ Server is overloaded, please try again later", 34 | missingGoatApiKey: "❗ Not set apikey for GoatBot, please visit goatbot.tk to get apikey and set it to configCommands.json > envGlobal.goatbotApikey and save" 35 | } 36 | }, 37 | 38 | onStart: async function ({ message, args, getLang, envGlobal }) { 39 | const goatBotApi = new GoatBotApis(envGlobal.goatbotApikey); 40 | if (!goatBotApi.isSetApiKey()) 41 | return message.reply(getLang("missingGoatApiKey")); 42 | const prompt = args.join(" "); 43 | if (!prompt) 44 | return message.reply(getLang("syntaxError")); 45 | 46 | try { 47 | const { data: imageStream } = await goatBotApi.api({ 48 | url: "/image/mdjrny", 49 | method: "GET", 50 | params: { 51 | prompt, 52 | style_id: 28, 53 | aspect_ratio: "1:1" 54 | }, 55 | responseType: "stream" 56 | }); 57 | 58 | imageStream.path = "image.jpg"; 59 | 60 | return message.reply({ 61 | attachment: imageStream 62 | }); 63 | } 64 | catch (err) { 65 | return message.reply(getLang("error", err.data?.message || err.message)); 66 | } 67 | } 68 | }; -------------------------------------------------------------------------------- /fb-chat-api/src/createNewGroup.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function createNewGroup(participantIDs, groupTitle, callback) { 8 | if (utils.getType(groupTitle) == "Function") { 9 | callback = groupTitle; 10 | groupTitle = null; 11 | } 12 | 13 | if (utils.getType(participantIDs) !== "Array") { 14 | throw { error: "createNewGroup: participantIDs should be an array." }; 15 | } 16 | 17 | if (participantIDs.length < 2) { 18 | throw { error: "createNewGroup: participantIDs should have at least 2 IDs." }; 19 | } 20 | 21 | let resolveFunc = function () { }; 22 | let rejectFunc = function () { }; 23 | const returnPromise = new Promise(function (resolve, reject) { 24 | resolveFunc = resolve; 25 | rejectFunc = reject; 26 | }); 27 | 28 | if (!callback) { 29 | callback = function (err, threadID) { 30 | if (err) { 31 | return rejectFunc(err); 32 | } 33 | resolveFunc(threadID); 34 | }; 35 | } 36 | 37 | const pids = []; 38 | for (const n in participantIDs) { 39 | pids.push({ 40 | fbid: participantIDs[n] 41 | }); 42 | } 43 | pids.push({ fbid: ctx.i_userID || ctx.userID }); 44 | 45 | const form = { 46 | fb_api_caller_class: "RelayModern", 47 | fb_api_req_friendly_name: "MessengerGroupCreateMutation", 48 | av: ctx.i_userID || ctx.userID, 49 | //This doc_id is valid as of January 11th, 2020 50 | doc_id: "577041672419534", 51 | variables: JSON.stringify({ 52 | input: { 53 | entry_point: "jewel_new_group", 54 | actor_id: ctx.i_userID || ctx.userID, 55 | participants: pids, 56 | client_mutation_id: Math.round(Math.random() * 1024).toString(), 57 | thread_settings: { 58 | name: groupTitle, 59 | joinable_mode: "PRIVATE", 60 | thread_image_fbid: null 61 | } 62 | } 63 | }) 64 | }; 65 | 66 | defaultFuncs 67 | .post( 68 | "https://www.facebook.com/api/graphql/", 69 | ctx.jar, 70 | form 71 | ) 72 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 73 | .then(function (resData) { 74 | if (resData.errors) { 75 | throw resData; 76 | } 77 | return callback(null, resData.data.messenger_group_thread_create.thread.thread_key.thread_fbid); 78 | }) 79 | .catch(function (err) { 80 | log.error("createNewGroup", err); 81 | return callback(err); 82 | }); 83 | 84 | return returnPromise; 85 | }; 86 | }; 87 | -------------------------------------------------------------------------------- /scripts/cmds/rankup.js: -------------------------------------------------------------------------------- 1 | const deltaNext = global.GoatBot.configCommands.envCommands.rank.deltaNext; 2 | const expToLevel = exp => Math.floor((1 + Math.sqrt(1 + 8 * exp / deltaNext)) / 2); 3 | const { drive } = global.utils; 4 | 5 | module.exports = { 6 | config: { 7 | name: "rankup", 8 | version: "1.3", 9 | author: "NTKhang", 10 | countDown: 5, 11 | role: 0, 12 | description: { 13 | vi: "Bật/tắt thông báo level up", 14 | en: "Turn on/off level up notification" 15 | }, 16 | category: "rank", 17 | guide: { 18 | en: "{pn} [on | off]" 19 | }, 20 | envConfig: { 21 | deltaNext: 5 22 | } 23 | }, 24 | 25 | langs: { 26 | vi: { 27 | syntaxError: "Sai cú pháp, chỉ có thể dùng {pn} on hoặc {pn} off", 28 | turnedOn: "Đã bật thông báo level up", 29 | turnedOff: "Đã tắt thông báo level up", 30 | notiMessage: "🎉🎉 chúc mừng bạn đạt level %1" 31 | }, 32 | en: { 33 | syntaxError: "Syntax error, only use {pn} on or {pn} off", 34 | turnedOn: "Turned on level up notification", 35 | turnedOff: "Turned off level up notification", 36 | notiMessage: "🎉🎉 Congratulations on reaching level %1" 37 | } 38 | }, 39 | 40 | onStart: async function ({ message, event, threadsData, args, getLang }) { 41 | if (!["on", "off"].includes(args[0])) 42 | return message.reply(getLang("syntaxError")); 43 | await threadsData.set(event.threadID, args[0] == "on", "settings.sendRankupMessage"); 44 | return message.reply(args[0] == "on" ? getLang("turnedOn") : getLang("turnedOff")); 45 | }, 46 | 47 | onChat: async function ({ threadsData, usersData, event, message, getLang }) { 48 | const threadData = await threadsData.get(event.threadID); 49 | const sendRankupMessage = threadData.settings.sendRankupMessage; 50 | if (!sendRankupMessage) 51 | return; 52 | const { exp } = await usersData.get(event.senderID); 53 | const currentLevel = expToLevel(exp); 54 | if (currentLevel > expToLevel(exp - 1)) { 55 | const forMessage = { 56 | body: getLang("notiMessage", currentLevel) 57 | }; 58 | if (threadData.data.rankup?.attachments?.length > 0) { 59 | const files = threadData.data.rankup.attachments; 60 | const attachments = files.reduce((acc, file) => { 61 | acc.push(drive.getFile(file, "stream")); 62 | return acc; 63 | }, []); 64 | forMessage.attachment = (await Promise.allSettled(attachments)) 65 | .filter(({ status }) => status == "fulfilled") 66 | .map(({ value }) => value); 67 | } 68 | message.reply(forMessage); 69 | } 70 | } 71 | }; 72 | -------------------------------------------------------------------------------- /scripts/cmds/pinterest.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs-extra") 2 | const axios = require("axios") 3 | module.exports = { 4 | config: { 5 | name: "pinterest", 6 | aliases: ["pin","Pint"], 7 | version: "1", 8 | author: "Aesther", 9 | countDown: 5, 10 | role: 0, 11 | shortDescription: { 12 | vi: "Image Pinterest Search 📷", 13 | en: "Image pinterest Search 📸" 14 | }, 15 | longDescription: { 16 | uid: "Pinterest Search", 17 | en: "Pinterest 🔎 image 😼" 18 | }, 19 | category: "images search", 20 | guide: { 21 | vi: " {pn}: enter in the format, example: Pinterest JUJUK-AISEN - 10 (it depends on you how many images you want to appear in the result)", 22 | en: " {pn}: enter in the format, example: Pinterest SASUKE KUN - 10 (it depends on you how many images you want to appear in the result)" 23 | } 24 | }, 25 | 26 | langs: { 27 | vi: { 28 | syntaxError: "Server Busy" 29 | }, 30 | en: { 31 | syntaxError: "Server Busy" 32 | } 33 | }, 34 | 35 | onStart: async function ({ api, message, event, args, getLang }) 36 | { 37 | 38 | const keySearch = args.join(" "); 39 | if(keySearch.includes("-") == false) return api.sendMessage('ↈ༈ 𝘿𝘼𝙍𝙆𝙉𝙀𝙎𝙎 ༈ↈ\n_______________________________\n 𝙀𝙭𝙚𝙢𝙥𝙡𝙚 : 𝙋𝙞𝙣𝙩𝙚𝙧𝙚𝙨𝙩 𝙋𝘼𝙄𝙉 - 10\n (Ç𝐀 𝐃𝐄𝐏𝐀𝐍𝐃 𝐃𝐔 𝐍𝐎𝐌𝐁𝐑𝐄 𝐃.𝐈𝐌𝐀𝐆𝐄 𝐐𝐔𝐄 𝐕𝐎𝐔𝐒 𝐕𝐎𝐔𝐋𝐄𝐙 )🧑‍🦯💔🏴‍☠️', event.threadID, event.messageID) 40 | const keySearchs = keySearch.substr(0, keySearch.indexOf('-')) 41 | let numberSearch = keySearch.split("-").pop() || 6 42 | if(numberSearch>20){ 43 | numberSearch = 20 44 | } 45 | const res = await axios.get(`https://hazee-social-downloader-9080f854bdab.herokuapp.com/pinterest?search=${encodeURIComponent(keySearchs)}`); 46 | const data = res.data.data; 47 | var num = 0; 48 | var imgData = []; 49 | for (var i = 0; i < parseInt(numberSearch); i++) { 50 | let path = __dirname + `/tmp/${num+=1}.jpg`; 51 | let getDown = (await axios.get(`${data[i]}`, { responseType: 'arraybuffer' })).data; 52 | fs.writeFileSync(path, Buffer.from(getDown, 'utf-8')); 53 | imgData.push(fs.createReadStream(__dirname + `/tmp/${num}.jpg`)); 54 | } 55 | api.sendMessage({ 56 | attachment: imgData, 57 | body: numberSearch + '-- 𝙍𝙀𝙎𝙐𝙇𝙏 --🌹:\n '+ keySearchs 58 | }, event.threadID, event.messageID) 59 | for (let ii = 1; ii < parseInt(numberSearch); ii++) { 60 | fs.unlinkSync(__dirname + `/tmp/${ii}.jpg`) 61 | } 62 | } 63 | 64 | }; 65 | -------------------------------------------------------------------------------- /fb-chat-api/src/refreshFb_dtsg.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | /** 8 | * Refreshes the fb_dtsg and jazoest values. 9 | * @param {Function} callback 10 | * @returns {Promise} 11 | * @description if you don't update the value of fb_dtsg and jazoest for a long time an error "Please try closing and re-opening your browser window" will appear 12 | * @description you should refresh it every 48h or less 13 | */ 14 | return function refreshFb_dtsg(obj, callback) { 15 | let resolveFunc = function () { }; 16 | let rejectFunc = function () { }; 17 | const returnPromise = new Promise(function (resolve, reject) { 18 | resolveFunc = resolve; 19 | rejectFunc = reject; 20 | }); 21 | 22 | if (utils.getType(obj) === "Function" || utils.getType(obj) === "AsyncFunction") { 23 | callback = obj; 24 | obj = {}; 25 | } 26 | 27 | if (!obj) { 28 | obj = {}; 29 | } 30 | 31 | if (utils.getType(obj) !== "Object") { 32 | throw new utils.CustomError("the first parameter must be an object or a callback function"); 33 | } 34 | 35 | if (!callback) { 36 | callback = function (err, friendList) { 37 | if (err) { 38 | return rejectFunc(err); 39 | } 40 | resolveFunc(friendList); 41 | }; 42 | } 43 | 44 | if (Object.keys(obj).length == 0) { 45 | utils 46 | .get('https://m.facebook.com/', ctx.jar, null, ctx.globalOptions, { noRef: true }) 47 | .then(function (resData) { 48 | const html = resData.body; 49 | const fb_dtsg = utils.getFrom(html, 'name="fb_dtsg" value="', '"'); 50 | const jazoest = utils.getFrom(html, 'name="jazoest" value="', '"'); 51 | if (!fb_dtsg) { 52 | throw new utils.CustomError("Could not find fb_dtsg in HTML after requesting https://www.facebook.com/"); 53 | } 54 | ctx.fb_dtsg = fb_dtsg; 55 | ctx.jazoest = jazoest; 56 | callback(null, { 57 | data: { 58 | fb_dtsg: fb_dtsg, 59 | jazoest: jazoest 60 | }, 61 | message: "refreshed fb_dtsg and jazoest" 62 | }); 63 | }) 64 | .catch(function (err) { 65 | log.error("refreshFb_dtsg", err); 66 | return callback(err); 67 | }); 68 | } 69 | else { 70 | Object.keys(obj).forEach(function (key) { 71 | ctx[key] = obj[key]; 72 | }); 73 | callback(null, { 74 | data: obj, 75 | message: "refreshed " + Object.keys(obj).join(", ") 76 | }); 77 | } 78 | 79 | return returnPromise; 80 | }; 81 | }; 82 | -------------------------------------------------------------------------------- /dashboard/views/verifyfbid-submit-code.eta: -------------------------------------------------------------------------------- 1 | <%~ includeFile("partials/header.eta", { 2 | user: user 3 | }); %> 4 | <%~ includeFile("partials/message.eta"); %> 5 | <%~ includeFile("partials/title.eta", { 6 | icon: "fas fa-cog", 7 | title: "Verify Code" 8 | }); %> 9 | 10 |
11 |
12 |
13 |
14 |
15 |
16 |

17 | Verify Code 18 |

19 |
20 |
21 |
22 |
23 | 26 | 27 |
28 |
29 | 30 |
31 |
32 |

33 | Nhập mã xác minh đã được gửi đến facebook 34 | của bạn 35 |

36 | 37 |
38 |
39 |
40 |
41 |
42 |
43 | 44 | 73 | 74 | <%~ includeFile("partials/footer.eta") %> -------------------------------------------------------------------------------- /fb-chat-api/src/uploadAttachment.js: -------------------------------------------------------------------------------- 1 | const utils = require("../utils"); 2 | const log = require("npmlog"); 3 | 4 | module.exports = function (defaultFuncs, api, ctx) { 5 | function upload(attachments, callback) { 6 | callback = callback || function () { }; 7 | const uploads = []; 8 | 9 | // create an array of promises 10 | for (let i = 0; i < attachments.length; i++) { 11 | if (!utils.isReadableStream(attachments[i])) { 12 | throw { 13 | error: 14 | "Attachment should be a readable stream and not " + 15 | utils.getType(attachments[i]) + 16 | "." 17 | }; 18 | } 19 | 20 | const form = { 21 | upload_1024: attachments[i], 22 | voice_clip: "true" 23 | }; 24 | 25 | uploads.push( 26 | defaultFuncs 27 | .postFormData( 28 | "https://upload.facebook.com/ajax/mercury/upload.php", 29 | ctx.jar, 30 | form, 31 | {} 32 | ) 33 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 34 | .then(function (resData) { 35 | if (resData.error) { 36 | throw resData; 37 | } 38 | 39 | // We have to return the data unformatted unless we want to change it 40 | // back in sendMessage. 41 | return resData.payload.metadata[0]; 42 | }) 43 | ); 44 | } 45 | 46 | // resolve all promises 47 | Promise 48 | .all(uploads) 49 | .then(function (resData) { 50 | callback(null, resData); 51 | }) 52 | .catch(function (err) { 53 | log.error("uploadAttachment", err); 54 | return callback(err); 55 | }); 56 | } 57 | 58 | return function uploadAttachment(attachments, callback) { 59 | if ( 60 | !attachments && 61 | !utils.isReadableStream(attachments) && 62 | !utils.getType(attachments) === "Array" && 63 | (utils.getType(attachments) === "Array" && !attachments.length) 64 | ) 65 | throw { error: "Please pass an attachment or an array of attachments." }; 66 | 67 | let resolveFunc = function () { }; 68 | let rejectFunc = function () { }; 69 | const returnPromise = new Promise(function (resolve, reject) { 70 | resolveFunc = resolve; 71 | rejectFunc = reject; 72 | }); 73 | 74 | if (!callback) { 75 | callback = function (err, info) { 76 | if (err) { 77 | return rejectFunc(err); 78 | } 79 | resolveFunc(info); 80 | }; 81 | } 82 | 83 | if (utils.getType(attachments) !== "Array") 84 | attachments = [attachments]; 85 | 86 | upload(attachments, (err, info) => { 87 | if (err) { 88 | return callback(err); 89 | } 90 | callback(null, info); 91 | }); 92 | 93 | return returnPromise; 94 | }; 95 | }; -------------------------------------------------------------------------------- /fb-chat-api/src/changeAdminStatus.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function changeAdminStatus(threadID, adminIDs, adminStatus, callback) { 8 | if (utils.getType(threadID) !== "String") { 9 | throw new utils.CustomError({ error: "changeAdminStatus: threadID must be a string" }); 10 | } 11 | 12 | if (utils.getType(adminIDs) === "String") { 13 | adminIDs = [adminIDs]; 14 | } 15 | 16 | if (utils.getType(adminIDs) !== "Array") { 17 | throw new utils.CustomError({ error: "changeAdminStatus: adminIDs must be an array or string" }); 18 | } 19 | 20 | if (utils.getType(adminStatus) !== "Boolean") { 21 | throw new utils.CustomError({ error: "changeAdminStatus: adminStatus must be a string" }); 22 | } 23 | 24 | let resolveFunc = function () { }; 25 | let rejectFunc = function () { }; 26 | const returnPromise = new Promise(function (resolve, reject) { 27 | resolveFunc = resolve; 28 | rejectFunc = reject; 29 | }); 30 | 31 | if (!callback) { 32 | callback = function (err) { 33 | if (err) { 34 | return rejectFunc(err); 35 | } 36 | resolveFunc(); 37 | }; 38 | } 39 | 40 | if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") { 41 | throw new utils.CustomError({ error: "changeAdminStatus: callback is not a function" }); 42 | } 43 | 44 | const form = { 45 | "thread_fbid": threadID 46 | }; 47 | 48 | let i = 0; 49 | for (const u of adminIDs) { 50 | form[`admin_ids[${i++}]`] = u; 51 | } 52 | form["add"] = adminStatus; 53 | 54 | defaultFuncs 55 | .post("https://www.facebook.com/messaging/save_admins/?dpr=1", ctx.jar, form) 56 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 57 | .then(function (resData) { 58 | if (resData.error) { 59 | switch (resData.error) { 60 | case 1976004: 61 | throw new utils.CustomError({ error: "Cannot alter admin status: you are not an admin.", rawResponse: resData }); 62 | case 1357031: 63 | throw new utils.CustomError({ error: "Cannot alter admin status: this thread is not a group chat.", rawResponse: resData }); 64 | default: 65 | throw new utils.CustomError({ error: "Cannot alter admin status: unknown error.", rawResponse: resData }); 66 | } 67 | } 68 | 69 | callback(); 70 | }) 71 | .catch(function (err) { 72 | log.error("changeAdminStatus", err); 73 | return callback(err); 74 | }); 75 | 76 | return returnPromise; 77 | }; 78 | }; 79 | 80 | -------------------------------------------------------------------------------- /scripts/cmds/adboxonly.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "onlyadminbox", 4 | aliases: ["onlyadbox", "adboxonly", "adminboxonly"], 5 | version: "1.3", 6 | author: "NTKhang", 7 | countDown: 5, 8 | role: 1, 9 | description: { 10 | vi: "bật/tắt chế độ chỉ quản trị của viên nhóm mới có thể sử dụng bot", 11 | en: "turn on/off only admin box can use bot" 12 | }, 13 | category: "box chat", 14 | guide: { 15 | vi: " {pn} [on | off]: bật/tắt chế độ chỉ quản trị viên nhóm mới có thể sử dụng bot" 16 | + "\n {pn} noti [on | off]: bật/tắt thông báo khi người dùng không phải là quản trị viên nhóm sử dụng bot", 17 | en: " {pn} [on | off]: turn on/off the mode only admin of group can use bot" 18 | + "\n {pn} noti [on | off]: turn on/off the notification when user is not admin of group use bot" 19 | } 20 | }, 21 | 22 | langs: { 23 | vi: { 24 | turnedOn: "Đã bật chế độ chỉ quản trị viên nhóm mới có thể sử dụng bot", 25 | turnedOff: "Đã tắt chế độ chỉ quản trị viên nhóm mới có thể sử dụng bot", 26 | turnedOnNoti: "Đã bật thông báo khi người dùng không phải là quản trị viên nhóm sử dụng bot", 27 | turnedOffNoti: "Đã tắt thông báo khi người dùng không phải là quản trị viên nhóm sử dụng bot", 28 | syntaxError: "Sai cú pháp, chỉ có thể dùng {pn} on hoặc {pn} off" 29 | }, 30 | en: { 31 | turnedOn: "Turned on the mode only admin of group can use bot", 32 | turnedOff: "Turned off the mode only admin of group can use bot", 33 | turnedOnNoti: "Turned on the notification when user is not admin of group use bot", 34 | turnedOffNoti: "Turned off the notification when user is not admin of group use bot", 35 | syntaxError: "Syntax error, only use {pn} on or {pn} off" 36 | } 37 | }, 38 | 39 | onStart: async function ({ args, message, event, threadsData, getLang }) { 40 | let isSetNoti = false; 41 | let value; 42 | let keySetData = "data.onlyAdminBox"; 43 | let indexGetVal = 0; 44 | 45 | if (args[0] == "noti") { 46 | isSetNoti = true; 47 | indexGetVal = 1; 48 | keySetData = "data.hideNotiMessageOnlyAdminBox"; 49 | } 50 | 51 | if (args[indexGetVal] == "on") 52 | value = true; 53 | else if (args[indexGetVal] == "off") 54 | value = false; 55 | else 56 | return message.reply(getLang("syntaxError")); 57 | 58 | await threadsData.set(event.threadID, isSetNoti ? !value : value, keySetData); 59 | 60 | if (isSetNoti) 61 | return message.reply(value ? getLang("turnedOnNoti") : getLang("turnedOffNoti")); 62 | else 63 | return message.reply(value ? getLang("turnedOn") : getLang("turnedOff")); 64 | } 65 | }; -------------------------------------------------------------------------------- /fb-chat-api/src/setTitle.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const utils = require("../utils"); 4 | const log = require("npmlog"); 5 | 6 | module.exports = function (defaultFuncs, api, ctx) { 7 | return function setTitle(newTitle, threadID, callback) { 8 | if ( 9 | !callback && 10 | (utils.getType(threadID) === "Function" || 11 | utils.getType(threadID) === "AsyncFunction") 12 | ) { 13 | throw { error: "please pass a threadID as a second argument." }; 14 | } 15 | 16 | let resolveFunc = function () { }; 17 | let rejectFunc = function () { }; 18 | const returnPromise = new Promise(function (resolve, reject) { 19 | resolveFunc = resolve; 20 | rejectFunc = reject; 21 | }); 22 | 23 | if (!callback) { 24 | callback = function (err, friendList) { 25 | if (err) { 26 | return rejectFunc(err); 27 | } 28 | resolveFunc(friendList); 29 | }; 30 | } 31 | 32 | const messageAndOTID = utils.generateOfflineThreadingID(); 33 | const form = { 34 | client: "mercury", 35 | action_type: "ma-type:log-message", 36 | author: "fbid:" + (ctx.i_userID || ctx.userID), 37 | author_email: "", 38 | coordinates: "", 39 | timestamp: Date.now(), 40 | timestamp_absolute: "Today", 41 | timestamp_relative: utils.generateTimestampRelative(), 42 | timestamp_time_passed: "0", 43 | is_unread: false, 44 | is_cleared: false, 45 | is_forward: false, 46 | is_filtered_content: false, 47 | is_spoof_warning: false, 48 | source: "source:chat:web", 49 | "source_tags[0]": "source:chat", 50 | status: "0", 51 | offline_threading_id: messageAndOTID, 52 | message_id: messageAndOTID, 53 | threading_id: utils.generateThreadingID(ctx.clientID), 54 | manual_retry_cnt: "0", 55 | thread_fbid: threadID, 56 | thread_name: newTitle, 57 | thread_id: threadID, 58 | log_message_type: "log:thread-name" 59 | }; 60 | 61 | defaultFuncs 62 | .post("https://www.facebook.com/messaging/set_thread_name/", ctx.jar, form) 63 | .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) 64 | .then(function (resData) { 65 | if (resData.error && resData.error === 1545012) { 66 | throw { error: "Cannot change chat title: Not member of chat." }; 67 | } 68 | 69 | if (resData.error && resData.error === 1545003) { 70 | throw { error: "Cannot set title of single-user chat." }; 71 | } 72 | 73 | if (resData.error) { 74 | throw resData; 75 | } 76 | 77 | return callback(); 78 | }) 79 | .catch(function (err) { 80 | log.error("setTitle", err); 81 | return callback(err); 82 | }); 83 | 84 | return returnPromise; 85 | }; 86 | }; 87 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": false, 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "prettier.singleQuote": true, 5 | "prettier.trailingComma": "es5", 6 | "prettier.printWidth": 100, 7 | "prettier.bracketSpacing": true, 8 | "prettier.jsxBracketSameLine": false, 9 | "prettier.arrowParens": "avoid", 10 | "prettier.semi": true, 11 | "prettier.endOfLine": "lf", 12 | "javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": true, 13 | "javascript.format.wrapLogicalExpressions": true, 14 | "javascript.format.breakBeforeBinaryOperators": true, 15 | "javascript.format.breakBeforeTernaryOperators": true, 16 | "javascript.format.alignArgumentsInBraces": true, 17 | "javascript.format.indentBraces": true, 18 | "javascript.format.wrapFunctionParameters": true, 19 | "javascript.format.sortImports": true, 20 | "javascript.format.placeCursorAfterClosingCurlyBrace": true, 21 | "javascript.format.insertSpaceBeforeFunctionKeyword": true, 22 | "javascript.format.insertSpaceBetweenFunctionKeywordAndParenthesis": true, 23 | "javascript.format.insertSpaceAfterFunctionName": true, 24 | "javascript.format.insertSpaceAfterComma": true, 25 | "javascript.format.insertSpaceAfterSemicolon": true, 26 | "javascript.format.insertSpaceBeforeColon": true, 27 | "javascript.format.insertSpaceAfterColon": true, 28 | "javascript.format.insertSpaceAroundOperators": true, 29 | "javascript.format.insertSpaceBeforeBlockComments": true, 30 | "javascript.format.insertSpaceAfterBlockComments": true, 31 | "javascript.format.insertSpaceBeforeLineComments": true, 32 | "javascript.format.insertSpaceAfterLineComments": true, 33 | "javascript.format.insertSpaceBeforeKeywordsInControlFlowStatements": true, 34 | "javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": true, 35 | "javascript.format.insertSpaceBeforeFunctionKeyword": true, 36 | "javascript.format.insertSpaceBetweenFunctionKeywordAndParenthesis": true, 37 | "javascript.format.insertSpaceAfterFunctionName": true, 38 | "javascript.format.insertSpaceAfterComma": true, 39 | "javascript.format.insertSpaceAfterSemicolon": true, 40 | "javascript.format.insertSpaceBeforeColon": true, 41 | "javascript.format.insertSpaceAfterColon": true, 42 | "javascript.format.insertSpaceAroundOperators": true, 43 | "javascript.format.insertSpaceBeforeBlockComments": true, 44 | "javascript.format.insertSpaceAfterBlockComments": true, 45 | "javascript.format.insertSpaceBeforeLineComments": true, 46 | "javascript.format.insertSpaceAfterLineComments": true, 47 | "[javascript]": { 48 | "editor.defaultFormatter": "vscode.typescript-language-features" 49 | }, 50 | } -------------------------------------------------------------------------------- /STEP_INSTALL.md: -------------------------------------------------------------------------------- 1 | ## **STEP INSTALL GOAT BOT V2** 2 | > This is a guide to install Goat Bot V2 on mobile devices (Android, iOS) and PC (Windows, MacOS, Linux) with replit.com 3 | 4 | * Watch the detailed video tutorial to install Goat Bot V2 on mobile devices (Android, iOS) 5 |
6 | 7 |
8 | 9 | * If you want to install Goat Bot V2 on vps/computer, please follow the guide below: 10 |
11 | 12 |
13 | 14 | --- 15 |

STEP BY STEP GUIDE

16 | 17 | * Download kiwi browser from play store. Open kiwi browser and go to https://replit.com 18 | ``` 19 | https://replit.com 20 | ``` 21 | * Create a new team education, then create a new project with `bash` language, then open console and type: 22 | ```bash 23 | git clone https://github.com/ntkhang03/Goat-Bot-V2 && cp -r Goat-Bot-V2/. . && rm -rf Goat-Bot-V2 24 | ``` 25 | * Then type: 26 | ```bash 27 | npm install 28 | ``` 29 | * Download extension `Cookie Editor` from chrom web store, then go to https://facebook.com, open that extension and click `Export` -> `Export as JSON` 30 | * Then back to replit, open file `account.txt` and paste your cookie there 31 | --- 32 | * Go to https://console.cloud.google.com/ to create a new project (don't forget to **`public`** your project) and add Authorized redirect URIs: `https://developers.google.com/oauthplayground` (without backslash at the end), then go to https://developers.google.com/oauthplayground to create a new OAuth 2.0 Client ID with permission: `https://www.googleapis.com/auth/drive` and `https://mail.google.com` then copy your `Refresh token` `Client ID` and `Client Secret` to `config.json` in part `credentials` -> `google` 33 | ``` 34 | https://console.cloud.google.com/ 35 | ``` 36 | ``` 37 | https://developers.google.com/oauthplayground 38 | ``` 39 | * Go to https://www.google.com/recaptcha/admin/create to create a new reCAPTCHA v2 with `I'm not a robot checkbox` 40 | * Add domain **`repl.co`** (not repl.com) to your reCAPTCHA v2 41 | * Accept the reCAPTCHA v2 terms of service 42 | * Then copy your `Site key` and `Secret key` to `config.json` 43 | ``` 44 | https://www.google.com/recaptcha/admin/create 45 | ``` 46 | * Go to https://betterstack.com/better-uptime or https://uptimerobot.com/ to create a new monitor for your project 47 | ``` 48 | https://betterstack.com/better-uptime 49 | ``` 50 | 51 | -------------------------------------------------------------------------------- /scripts/cmds/dhbc.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | const { getStreamFromURL } = global.utils; 3 | 4 | module.exports = { 5 | config: { 6 | name: "dhbc", 7 | version: "1.3", 8 | author: "NTKhang", 9 | countDown: 5, 10 | role: 0, 11 | description: { 12 | vi: "chơi game đuổi hình bắt chữ", 13 | en: "play game catch the word" 14 | }, 15 | category: "game", 16 | guide: { 17 | en: "{pn}" 18 | }, 19 | envConfig: { 20 | reward: 1000 21 | } 22 | }, 23 | 24 | langs: { 25 | vi: { 26 | reply: "Hãy reply tin nhắn này với câu trả lời\n%1", 27 | isSong: "Đây là tên bài hát của ca sĩ %1", 28 | notPlayer: "⚠️ Bạn không phải là người chơi của câu hỏi này", 29 | correct: "🎉 Chúc mừng bạn đã trả lời đúng và nhận được %1$", 30 | wrong: "⚠️ Bạn đã trả lời sai" 31 | }, 32 | en: { 33 | reply: "Please reply this message with the answer\n%1", 34 | isSong: "This is the name of the song of the singer %1", 35 | notPlayer: "⚠️ You are not the player of this question", 36 | correct: "🎉 Congratulations you have answered correctly and received %1$", 37 | wrong: "⚠️ You have answered incorrectly" 38 | } 39 | }, 40 | 41 | onStart: async function ({ message, event, commandName, getLang }) { 42 | const datagame = (await axios.get("https://goatbotserver.onrender.com/api/duoihinhbatchu")).data; 43 | const { wordcomplete, casi, image1, image2 } = datagame.data; 44 | 45 | message.reply({ 46 | body: getLang("reply", wordcomplete.replace(/\S/g, "█ ")) + (casi ? getLang("isSong", casi) : ''), 47 | attachment: [ 48 | await getStreamFromURL(image1), 49 | await getStreamFromURL(image2) 50 | ] 51 | }, (err, info) => { 52 | global.GoatBot.onReply.set(info.messageID, { 53 | commandName, 54 | messageID: info.messageID, 55 | author: event.senderID, 56 | wordcomplete 57 | }); 58 | }); 59 | }, 60 | 61 | onReply: async ({ message, Reply, event, getLang, usersData, envCommands, commandName }) => { 62 | const { author, wordcomplete, messageID } = Reply; 63 | if (event.senderID != author) 64 | return message.reply(getLang("notPlayer")); 65 | 66 | if (formatText(event.body) == formatText(wordcomplete)) { 67 | global.GoatBot.onReply.delete(messageID); 68 | await usersData.addMoney(event.senderID, envCommands[commandName].reward); 69 | message.reply(getLang("correct", envCommands[commandName].reward)); 70 | } 71 | else 72 | message.reply(getLang("wrong")); 73 | } 74 | }; 75 | 76 | function formatText(text) { 77 | return text.normalize("NFD") 78 | .toLowerCase() 79 | .replace(/[\u0300-\u036f]/g, "") 80 | .replace(/[đ|Đ]/g, (x) => x == "đ" ? "d" : "D"); 81 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "goat-bot-v2", 3 | "version": "1.5.30", 4 | "description": "A simple Bot chat messenger using personal account. Made by NTKhang.", 5 | "main": "index.js", 6 | "engines": { 7 | "node": "16.x", 8 | "npm": ">=7.0.0" 9 | }, 10 | "dependencies": { 11 | "@distube/ytdl-core": "^4.13.3", 12 | "axios": "^1.4.0", 13 | "bcrypt": "^5.0.1", 14 | "canvas": "^2.9.1", 15 | "cheerio": "^1.0.0-rc.12", 16 | "child_process": "^1.0.2", 17 | "connect-flash": "^0.1.1", 18 | "cookie-parser": "^1.4.6", 19 | "eta": "^1.12.3", 20 | "express": "^4.18.1", 21 | "express-fileupload": "^1.4.0", 22 | "express-rate-limit": "^6.5.2", 23 | "express-session": "^1.17.3", 24 | "form-data": "^4.0.0", 25 | "fs-extra": "^11.1.0", 26 | "googleapis": "^100.0.0", 27 | "gradient-string": "^2.0.2", 28 | "graphql-query-to-json": "^2.0.1", 29 | "https": "^1.0.0", 30 | "jsonlint-mod": "^1.7.6", 31 | "moment-timezone": "^0.5.34", 32 | "mongoose": "^6.3.1", 33 | "mqtt": "^4.3.7", 34 | "node-cron": "^3.0.2", 35 | "nodemailer": "^6.7.5", 36 | "npmlog": "^7.0.1", 37 | "ora": "^5.4.1", 38 | "passport": "^0.6.0", 39 | "passport-local": "^1.0.0", 40 | "path": "^0.12.7", 41 | "qrcode-reader": "^1.0.4", 42 | "qs": "^6.11.0", 43 | "request": "^2.88.2", 44 | "searchitunes": "^2.5.4", 45 | "sequelize": "^6.19.0", 46 | "socket.io": "^4.5.1", 47 | "sqlite3": "^5.0.5", 48 | "tinyurl": "^1.1.7", 49 | "totp-generator": "^0.0.13", 50 | "websocket-stream": "^5.5.2" 51 | }, 52 | "scripts": { 53 | "start": "set NODE_ENV=&& node index.js", 54 | "dev": "set NODE_ENV=development&& node index.js", 55 | "prod": "set NODE_ENV=production&& node index.js" 56 | }, 57 | "author": "NTKhang", 58 | "license": "MIT", 59 | "repository": { 60 | "type": "git", 61 | "url": "git+https://github.com/ntkhang03/Goat-Bot-V2.git" 62 | }, 63 | "keywords": [], 64 | "bugs": { 65 | "url": "https://github.com/ntkhang03/Goat-Bot-V2/issues" 66 | }, 67 | "homepage": "https://github.com/ntkhang03/Goat-Bot-V2#readme", 68 | "devDependencies": { 69 | "eslint": "^8.2.0", 70 | "eslint-config-airbnb": "^19.0.4", 71 | "eslint-config-node": "^4.1.0", 72 | "eslint-config-prettier": "^8.5.0", 73 | "eslint-plugin-import": "^2.25.3", 74 | "eslint-plugin-jsx-a11y": "^6.5.1", 75 | "eslint-plugin-node": "^11.1.0", 76 | "eslint-plugin-prettier": "^4.0.0", 77 | "eslint-plugin-react": "^7.28.0", 78 | "eslint-plugin-react-hooks": "^4.3.0", 79 | "javascript-obfuscator": "^4.0.1", 80 | "npm-size": "^1.3.0", 81 | "os": "^0.1.2", 82 | "pm2": "^5.3.0", 83 | "prettier": "^2.7.1", 84 | "prompt-checkbox": "^2.2.0", 85 | "terser": "^5.15.0" 86 | } 87 | } -------------------------------------------------------------------------------- /scripts/cmds/setavt.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | 3 | module.exports = { 4 | config: { 5 | name: "setavt", 6 | aliases: ["changeavt", "setavatar"], 7 | version: "1.3", 8 | author: "NTKhang", 9 | countDown: 5, 10 | role: 2, 11 | description: { 12 | vi: "Đổi avatar bot", 13 | en: "Change bot avatar" 14 | }, 15 | category: "owner", 16 | guide: { 17 | vi: " {pn} [ | ] [ | để trống] [ | để trống]" 18 | + "\nPhản hồi 1 tin nhắn có chứa ảnh với nội dung: {pn}" 19 | + "\nGửi kèm 1 tin nhắn có chứa ảnh với nội dung: {pn}" 20 | + "\n\nGhi chú:" 21 | + "\n + caption: caption sẽ đăng kèm khi đổi avatar" 22 | + "\n + expirationAfter: đặt chế độ ảnh đại diện tạm thời (hết hạn sau expirationAfter(seconds))" 23 | + "\nVí dụ:" 24 | + "\n {pn} https://example.com/image.jpg: (đổi ảnh đại diện không caption, không hết hạn)" 25 | + "\n {pn} https://example.com/image.jpg Hello: (đổi ảnh đại diện với caption là \"Hello\", không hết hạn)" 26 | + "\n {pn} https://example.com/image.jpg Hello 3600: (đổi ảnh đại diện với caption là \"Hello\", đặt tạm thời 1h)" 27 | } 28 | }, 29 | 30 | langs: { 31 | vi: { 32 | cannotGetImage: "❌ | Đã xảy ra lỗi khi truy vấn đến url hình ảnh", 33 | invalidImageFormat: "❌ | Định dạng hình ảnh không hợp lệ", 34 | changedAvatar: "✅ | Đã thay đổi avatar của bot thành công" 35 | }, 36 | en: { 37 | cannotGetImage: "❌ | An error occurred while querying the image url", 38 | invalidImageFormat: "❌ | Invalid image format", 39 | changedAvatar: "✅ | Changed bot avatar successfully" 40 | } 41 | }, 42 | 43 | onStart: async function ({ message, event, api, args, getLang }) { 44 | const imageURL = (args[0] || "").startsWith("http") ? args.shift() : event.attachments[0]?.url || event.messageReply?.attachments[0]?.url; 45 | const expirationAfter = !isNaN(args[args.length - 1]) ? args.pop() : null; 46 | const caption = args.join(" "); 47 | if (!imageURL) 48 | return message.SyntaxError(); 49 | let response; 50 | try { 51 | response = (await axios.get(imageURL, { 52 | responseType: "stream" 53 | })); 54 | } 55 | catch (err) { 56 | return message.reply(getLang("cannotGetImage")); 57 | } 58 | if (!response.headers["content-type"].includes("image")) 59 | return message.reply(getLang("invalidImageFormat")); 60 | response.data.path = "avatar.jpg"; 61 | 62 | api.changeAvatar(response.data, caption, expirationAfter ? expirationAfter * 1000 : null, (err) => { 63 | if (err) 64 | return message.err(err); 65 | return message.reply(getLang("changedAvatar")); 66 | }); 67 | } 68 | }; -------------------------------------------------------------------------------- /dashboard/views/stats.eta: -------------------------------------------------------------------------------- 1 | <%~ includeFile("partials/header", { 2 | user: user 3 | }); %> 4 | <%~ includeFile("partials/message.eta"); %> 5 | <%~ includeFile("partials/title.eta", { 6 | icon: "fas fa-robot", 7 | title: "Bot stats" 8 | }); %> 9 | 10 |
11 |
12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 43 | 44 | 45 | 46 | 49 | 50 | 51 | 52 | 55 | 56 | 57 | 58 | 61 | 62 | 63 |
Users 17 | <%= totalUser %> 18 |
Threads 23 | <%= totalThread %> 24 |
Prefix 29 | <%= prefix %> 30 |
Uptime 35 | <%= uptime %> 36 |
Node.js Version 41 | <%= process.version %> 42 |
Memory 47 | <%= (process.memoryUsage().rss / 1024 / 1024).toFixed(2) %> MB 48 |
CPU 53 | <%= (process.cpuUsage().system / 1024 / 1024).toFixed(2) %>% 54 |
Node CPU 59 | <%= (process.cpuUsage().user / 1024 / 1024).toFixed(2) %>% 60 |
64 |
65 |
66 | 67 | 70 | 71 | <%~ includeFile("partials/footer") %> -------------------------------------------------------------------------------- /scripts/cmds/busy.js: -------------------------------------------------------------------------------- 1 | if (!global.client.busyList) 2 | global.client.busyList = {}; 3 | 4 | module.exports = { 5 | config: { 6 | name: "busy", 7 | version: "1.6", 8 | author: "NTKhang", 9 | countDown: 5, 10 | role: 0, 11 | description: { 12 | vi: "bật chế độ không làm phiền, khi bạn được tag bot sẽ thông báo", 13 | en: "turn on do not disturb mode, when you are tagged bot will notify" 14 | }, 15 | category: "box chat", 16 | guide: { 17 | vi: " {pn} [để trống | ]: bật chế độ không làm phiền" 18 | + "\n {pn} off: tắt chế độ không làm phiền", 19 | en: " {pn} [empty | ]: turn on do not disturb mode" 20 | + "\n {pn} off: turn off do not disturb mode" 21 | } 22 | }, 23 | 24 | langs: { 25 | vi: { 26 | turnedOff: "✅ | Đã tắt chế độ không làm phiền", 27 | turnedOn: "✅ | Đã bật chế độ không làm phiền", 28 | turnedOnWithReason: "✅ | Đã bật chế độ không làm phiền với lý do: %1", 29 | turnedOnWithoutReason: "✅ | Đã bật chế độ không làm phiền", 30 | alreadyOn: "Hiện tại người dùng %1 đang bận", 31 | alreadyOnWithReason: "Hiện tại người dùng %1 đang bận với lý do: %2" 32 | }, 33 | en: { 34 | turnedOff: "✅ | Do not disturb mode has been turned off", 35 | turnedOn: "✅ | Do not disturb mode has been turned on", 36 | turnedOnWithReason: "✅ | Do not disturb mode has been turned on with reason: %1", 37 | turnedOnWithoutReason: "✅ | Do not disturb mode has been turned on", 38 | alreadyOn: "User %1 is currently busy", 39 | alreadyOnWithReason: "User %1 is currently busy with reason: %2" 40 | } 41 | }, 42 | 43 | onStart: async function ({ args, message, event, getLang, usersData }) { 44 | const { senderID } = event; 45 | 46 | if (args[0] == "off") { 47 | const { data } = await usersData.get(senderID); 48 | delete data.busy; 49 | await usersData.set(senderID, data, "data"); 50 | return message.reply(getLang("turnedOff")); 51 | } 52 | 53 | const reason = args.join(" ") || ""; 54 | await usersData.set(senderID, reason, "data.busy"); 55 | return message.reply( 56 | reason ? 57 | getLang("turnedOnWithReason", reason) : 58 | getLang("turnedOnWithoutReason") 59 | ); 60 | }, 61 | 62 | onChat: async ({ event, message, getLang }) => { 63 | const { mentions } = event; 64 | 65 | if (!mentions || Object.keys(mentions).length == 0) 66 | return; 67 | const arrayMentions = Object.keys(mentions); 68 | 69 | for (const userID of arrayMentions) { 70 | const reasonBusy = global.db.allUserData.find(item => item.userID == userID)?.data.busy || false; 71 | if (reasonBusy !== false) { 72 | return message.reply( 73 | reasonBusy ? 74 | getLang("alreadyOnWithReason", mentions[userID].replace("@", ""), reasonBusy) : 75 | getLang("alreadyOn", mentions[userID].replace("@", ""))); 76 | } 77 | } 78 | } 79 | }; -------------------------------------------------------------------------------- /scripts/cmds/slot.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | name: "slot", 4 | version: "1.0", 5 | author: "Rishad", 6 | shortDescription: { 7 | en: "Game slot", 8 | }, 9 | longDescription: { 10 | en: "Game slot.", 11 | }, 12 | category: "game", 13 | }, 14 | langs: { 15 | en: { 16 | invalid_amount: "Put a big 🌝 number, you can win twice the risk of my son 🌝🙌", 17 | not_enough_money: "You have this amount, see your balance then 🌝🤣", 18 | spin_message: "continued Rotation 🌝", 19 | win_message:"You win %1$💗!", 20 | lose_message: "You lost %1$🥲.", 21 | jackpot_message: "This is the amount that Diem won! tripartite %1 $!", 22 | }, 23 | }, 24 | onStart: async function ({ args, message, event, envCommands, usersData, commandName, getLang }) { 25 | const { senderID } = event; 26 | const userData = await usersData.get(senderID); 27 | const amount = parseInt(args[0]); 28 | 29 | if (isNaN(amount) || amount <= 0) { 30 | return message.reply(getLang("invalid_amount")); 31 | } 32 | 33 | if (amount > userData.money) { 34 | return message.reply(getLang("not_enough_money")); 35 | } 36 | 37 | const slots = ["🍒", "🍇", "🍊", "🍉", "🍋", "🍎", "🍓", "🍑", "🥝"]; 38 | const slot1 = slots[Math.floor(Math.random() * slots.length)]; 39 | const slot2 = slots[Math.floor(Math.random() * slots.length)]; 40 | const slot3 = slots[Math.floor(Math.random() * slots.length)]; 41 | 42 | const winnings = calculateWinnings(slot1, slot2, slot3, amount); 43 | 44 | await usersData.set(senderID, { 45 | money: userData.money + winnings, 46 | data: userData.data, 47 | }); 48 | 49 | const messageText = getSpinResultMessage(slot1, slot2, slot3, winnings, getLang); 50 | 51 | return message.reply(messageText); 52 | }, 53 | }; 54 | 55 | function calculateWinnings(slot1, slot2, slot3, betAmount) { 56 | if (slot1 === "🍒" && slot2 === "🍒" && slot3 === "🍒") { 57 | return betAmount * 10; 58 | } else if (slot1 === "🍇" && slot2 === "🍇" && slot3 === "🍇") { 59 | return betAmount * 5; 60 | } else if (slot1 === slot2 && slot2 === slot3) { 61 | return betAmount * 3; 62 | } else if (slot1 === slot2 || slot1 === slot3 || slot2 === slot3) { 63 | return betAmount * 2; 64 | } else { 65 | return -betAmount; 66 | } 67 | } 68 | 69 | function getSpinResultMessage(slot1, slot2, slot3, winnings, getLang) { 70 | if (winnings > 0) { 71 | if (slot1 === "🍒" && slot2 === "🍒" && slot3 === "🍒") { 72 | return getLang("jackpot_message", winnings); 73 | } else { 74 | return getLang("win_message", winnings) + `\n[ ${slot1} | ${slot2} | ${slot3} ]`; 75 | } 76 | } else { 77 | return getLang("lose_message", -winnings) + `\n[ ${slot1} | ${slot2} | ${slot3} ]`; 78 | } 79 | } 80 | --------------------------------------------------------------------------------