| import { |
| makeWASocket, |
| useMultiFileAuthState, |
| DisconnectReason, |
| fetchLatestBaileysVersion, |
| Browsers |
| } from '@whiskeysockets/baileys'; |
| import { TelegramClient } from "telegram"; |
| import { StringSession } from "telegram/sessions/index.js"; |
| import { NewMessage } from "telegram/events/index.js"; |
| import { Boom } from '@hapi/boom'; |
| import pino from 'pino'; |
| import express from 'express'; |
| import bodyParser from 'body-parser'; |
| import fs from 'fs-extra'; |
| import QRCode from 'qrcode'; |
| import admin from "firebase-admin"; |
|
|
| const app = express(); |
| app.use(bodyParser.urlencoded({ extended: true })); |
|
|
| |
| const firebaseKeyPath = "./firebase-key.json"; |
| if (!fs.existsSync(firebaseKeyPath)) { |
| console.error("❌ ERROR: file firebase-key.json tidak ditemukan!"); |
| process.exit(1); |
| } |
|
|
| const serviceAccount = JSON.parse(fs.readFileSync(firebaseKeyPath, "utf-8")); |
| admin.initializeApp({ |
| credential: admin.credential.cert(serviceAccount), |
| databaseURL: "https://kevcodex-db-default-rtdb.asia-southeast1.firebasedatabase.app" |
| }); |
| const db = admin.database(); |
|
|
| const cloudDB = { |
| set: async (path, data) => await db.ref(path).set(data), |
| get: async (path) => { |
| const snap = await db.ref(path).once("value"); |
| return snap.exists() ? snap.val() : null; |
| } |
| }; |
|
|
| |
| const config = { |
| botNumber: "4915511371360", |
| waGroupTarget: "120363407491179391@g.us", |
| waNewsTarget: "120363426506078314@newsletter", |
| apiId: 32686082, |
| apiHash: "309ed88802eb09b85d9a82af87f59bf5", |
| tgNumber: "6285600235109", |
| imageUrl: "https://c.termai.cc/i171/eKwk.jpg", |
| stickersIndo: [ |
| "https://c.termai.cc/i107/b7T.webp", |
| "https://c.termai.cc/i122/4TSR9E.webp", |
| "https://c.termai.cc/i183/fZqSNN.webp" |
| ] |
| }; |
|
|
| |
| const countryMap = { "🇦🇫": "Afghanistan", "🇦🇽": "Åland Islands", "🇦🇱": "Albania", "🇩🇿": "Algeria", "🇦🇸": "American Samoa", "🇦🇩": "Andorra", "🇦🇴": "Angola", "🇦🇮": "Anguilla", "🇦🇶": "Antarctica", "🇦🇬": "Antigua and Barbuda", "🇦🇷": "Argentina", "🇦🇲": "Armenia", "🇦🇼": "Aruba", "🇦🇺": "Australia", "🇦🇹": "Austria", "🇦🇿": "Azerbaijan", "🇧🇸": "Bahamas", "🇧🇭": "Bahrain", "🇧🇩": "Bangladesh", "🇧🇧": "Barbados", "🇧🇾": "Belarus", "🇧🇪": "Belgium", "🇧🇿": "Belize", "🇧🇯": "Benin", "🇧🇲": "Bermuda", "🇧🇹": "Bhutan", "🇧🇴": "Bolivia", "🇧🇶": "Bonaire, Sint Eustatius and Saba", "🇧🇦": "Bosnia and Herzegovina", "🇧🇼": "Botswana", "🇧🇻": "Bouvet Island", "🇧🇷": "Brazil", "🇮🇴": "British Indian Ocean Territory", "🇧🇳": "Brunei", "🇧🇬": "Bulgaria", "🇧🇫": "Burkina Faso", "🇧🇮": "Burundi", "🇨🇻": "Cabo Verde", "🇰🇭": "Cambodia", "🇨🇲": "Cameroon", "🇨🇦": "Canada", "🇰🇾": "Cayman Islands", "🇨🇫": "Central African Republic", "🇹🇩": "Chad", "🇨🇱": "Chile", "🇨🇳": "China", "🇨🇽": "Christmas Island", "🇨🇨": "Cocos (Keeling) Islands", "🇨🇴": "Colombia", "🇰🇲": "Comoros", "🇨🇩": "DR Congo", "🇨🇬": "Congo", "🇨🇰": "Cook Islands", "🇨🇷": "Costa Rica", "🇨🇮": "Côte d'Ivoire", "🇭🇷": "Croatia", "🇨🇺": "Cuba", "🇨🇼": "Curaçao", "🇨🇾": "Cyprus", "🇨🇿": "Czechia", "🇩🇰": "Denmark", "🇩🇯": "Djibouti", "🇩🇲": "Dominica", "🇩🇴": "Dominican Republic", "🇪🇨": "Ecuador", "🇪🇬": "Egypt", "🇸🇻": "El Salvador", "🇬🇶": "Equatorial Guinea", "🇪🇷": "Eritrea", "🇪🇪": "Estonia", "🇸🇿": "Eswatini", "🇪🇹": "Ethiopia", "🇫🇰": "Falkland Islands", "🇫🇴": "Faroe Islands", "🇫🇯": "Fiji", "🇫🇮": "Finland", "🇫🇷": "France", "🇬🇫": "French Guiana", "🇵🇫": "French Polynesia", "🇹🇫": "French Southern Territories", "🇬🇦": "Gabon", "🇬🇲": "Gambia", "🇬🇪": "Georgia", "🇩🇪": "Germany", "🇬🇭": "Ghana", "🇬🇮": "Gibraltar", "🇬🇷": "Greece", "🇬🇱": "Greenland", "🇬🇩": "Grenada", "🇬🇵": "Guadeloupe", "🇬🇺": "Guam", "🇬🇹": "Guatemala", "🇬🇬": "Guernsey", "🇬🇳": "Guinea", "🇬🇼": "Guinea-Bissau", "🇬🇾": "Guyana", "🇭🇹": "Haiti", "🇭🇲": "Heard Island and McDonald Islands", "🇻🇦": "Vatican City", "🇭🇳": "Honduras", "🇭🇰": "Hong Kong", "🇭🇺": "Hungary", "🇮🇸": "Iceland", "🇮🇳": "India", "🇮🇩": "Indonesia", "🇮🇷": "Iran", "🇮🇶": "Iraq", "🇮🇪": "Ireland", "🇮🇲": "Isle of Man", "🇮🇱": "Israel", "🇮🇹": "Italy", "🇯🇲": "Jamaica", "🇯🇵": "Japan", "🇯🇪": "Jersey", "🇯🇴": "Jordan", "🇰🇿": "Kazakhstan", "🇰🇪": "Kenya", "🇰🇮": "Kiribati", "🇰🇵": "North Korea", "🇰🇷": "South Korea", "🇰🇼": "Kuwait", "🇰🇬": "Kyrgyzstan", "🇱🇦": "Laos", "🇱🇻": "Latvia", "🇱🇧": "Lebanon", "🇱🇸": "Lesotho", "🇱🇷": "Liberia", "🇱🇾": "Libya", "🇱🇮": "Liechtenstein", "🇱🇹": "Lithuania", "🇱🇺": "Luxembourg", "🇲🇴": "Macao", "🇲🇬": "Madagascar", "🇲🇼": "Malawi", "🇲🇾": "Malaysia", "🇲🇻": "Maldives", "🇲🇱": "Mali", "🇲🇹": "Malta", "🇲🇭": "Marshall Islands", "🇲🇶": "Martinique", "🇲🇷": "Mauritania", "🇲🇺": "Mauritius", "🇾🇹": "Mayotte", "🇲🇽": "Mexico", "🇫🇲": "Micronesia", "🇲🇩": "Moldova", "🇲🇨": "Monaco", "🇲🇳": "Mongolia", "🇲🇪": "Montenegro", "🇲🇸": "Montserrat", "🇲🇦": "Morocco", "🇲🇿": "Mozambique", "🇲🇲": "Myanmar", "🇳🇦": "Namibia", "🇳🇷": "Nauru", "🇳🇵": "Nepal", "🇳🇱": "Netherlands", "🇳🇨": "New Caledonia", "🇳🇿": "New Zealand", "🇳🇮": "Nicaragua", "🇳🇪": "Niger", "🇳🇬": "Nigeria", "🇳🇺": "Niue", "🇳🇫": "Norfolk Island", "🇲🇰": "North Macedonia", "🇲🇵": "Northern Mariana Islands", "🇳🇴": "Norway", "🇴🇲": "Oman", "🇵🇰": "Pakistan", "🇵🇼": "Palau", "🇵🇸": "Palestine", "🇵🇦": "Panama", "🇵🇬": "Papua New Guinea", "🇵🇾": "Paraguay", "🇵🇪": "Peru", "🇵🇭": "Philippines", "🇵🇳": "Pitcairn", "🇵🇱": "Poland", "🇵🇹": "Portugal", "🇵🇷": "Puerto Rico", "🇶🇦": "Qatar", "🇷🇪": "Réunion", "🇷🇴": "Romania", "🇷🇺": "Russia", "🇷🇼": "Rwanda", "🇧🇱": "Saint Barthélemy", "🇸🇭": "Saint Helena", "🇰🇳": "Saint Kitts and Nevis", "🇱🇨": "Saint Lucia", "🇲🇫": "Saint Martin", "🇵🇲": "Saint Pierre and Miquelon", "🇻🇨": "Saint Vincent and the Grenadines", "🇼🇸": "Samoa", "🇸🇲": "San Marino", "🇸🇹": "Sao Tome and Principe", "🇸🇦": "Saudi Arabia", "🇸🇳": "Senegal", "🇷🇸": "Serbia", "🇸🇨": "Seychelles", "🇸🇱": "Sierra Leone", "🇸🇬": "Singapore", "🇸🇽": "Sint Maarten", "🇸🇰": "Slovakia", "🇸🇮": "Slovenia", "🇸🇧": "Solomon Islands", "🇸🇴": "Somalia", "🇿🇦": "South Africa", "🇬🇸": "South Georgia", "🇸🇸": "South Sudan", "🇪🇸": "Spain", "🇱🇰": "Sri Lanka", "🇸🇩": "Sudan", "🇸🇷": "Suriname", "🇸🇯": "Svalbard and Jan Mayen", "🇸🇪": "Sweden", "🇨🇭": "Switzerland", "🇸🇾": "Syria", "🇹🇼": "Taiwan", "🇹🇯": "Tajikistan", "🇹🇿": "Tanzania", "🇹🇭": "Thailand", "🇹🇱": "Timor-Leste", "🇹🇬": "Togo", "🇹🇰": "Tokelau", "🇹🇴": "Tonga", "🇹🇹": "Trinidad and Tobago", "🇹🇳": "Tunisia", "🇹🇷": "Türkiye", "🇹🇲": "Turkmenistan", "🇹🇨": "Turks and Caicos Islands", "🇹🇻": "Tuvalu", "🇺🇬": "Uganda", "🇺🇦": "Ukraine", "🇦🇪": "United Arab Emirates", "🇬🇧": "United Kingdom", "🇺🇸": "United States", "🇺🇲": "United States Minor Outlying Islands", "🇺🇾": "Uruguay", "🇺🇿": "Uzbekistan", "🇻🇺": "Vanuatu", "🇻🇪": "Venezuela", "🇻🇳": "Vietnam", "🇻🇬": "British Virgin Islands", "🇻🇮": "U.S. Virgin Islands", "🇼🇫": "Wallis and Futuna", "🇪🇭": "Western Sahara", "🇾🇪": "Yemen", "🇿🇲": "Zambia", "🇿🇼": "Zimbabwe" }; |
|
|
| let tgStatus = "Menunggu Login..."; |
| let waQrBase64 = ""; |
| let waConnected = false; |
| let resolveTgCode = null; |
| let sock = null; |
|
|
| |
| app.get('/', (req, res) => { |
| res.send(`<!DOCTYPE html><html><head><title>KEV-SMS Ultra Pro</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body { font-family: sans-serif; background: #0b0e11; color: #e9edef; text-align: center; padding: 20px; }.card { background: #111b21; padding: 20px; border-radius: 12px; margin: 10px auto; max-width: 400px; border: 1px solid #222e35; }.status { color: #00ff00; font-weight: bold; }.qr-box { background: white; padding: 10px; border-radius: 8px; display: inline-block; margin: 15px 0; }input { padding: 12px; border-radius: 8px; border: 1px solid #2a3942; background: #2a3942; color: white; width: 80%; outline: none; }button { padding: 12px 20px; background: #00a884; color: white; border: none; border-radius: 8px; margin-top: 10px; cursor: pointer; font-weight: bold; }</style></head><body><h2>🚀 KEV-SMS Multi-Forwarder</h2><div class="card"><h3>WhatsApp Status</h3>${waConnected ? '<p class="status">CONNECTED ✅</p>' : (waQrBase64 ? `<div class="qr-box"><img src="${waQrBase64}" width="200"></div><p>Scan QR untuk Login</p>` : '<p>Memproses QR...</p>')}</div><div class="card"><h3>Telegram Status</h3><p>Status: <span class="status" id="tg-stat">${tgStatus}</span></p><form action="/submit-tg" method="POST"><input type="text" name="otp" placeholder="Masukkan Kode Telegram" required><button type="submit">Hubungkan Telegram</button></form></div><script>setTimeout(() => { if(!document.querySelector('input:focus')) location.reload(); }, 10000);</script></body></html>`); |
| }); |
|
|
| app.post('/submit-tg', (req, res) => { |
| if (resolveTgCode) { |
| resolveTgCode(req.body.otp); |
| tgStatus = "Memproses OTP..."; |
| res.send("<script>alert('OTP terkirim ke sistem!'); window.location.href='/';</script>"); |
| } else { |
| res.send("<script>alert('Sistem belum siap menerima OTP. Tunggu status: INPUT KODE OTP!'); window.location.href='/';</script>"); |
| } |
| }); |
|
|
| |
| async function startWhatsApp() { |
| const waAuthFolder = './session_wa'; |
| if (!fs.existsSync(waAuthFolder)) fs.mkdirSync(waAuthFolder); |
|
|
| if (!fs.existsSync(`${waAuthFolder}/creds.json`)) { |
| const savedWaSession = await cloudDB.get("sessions/whatsapp"); |
| if (savedWaSession) { |
| fs.writeFileSync(`${waAuthFolder}/creds.json`, JSON.stringify(savedWaSession)); |
| } |
| } |
|
|
| const { state, saveCreds } = await useMultiFileAuthState(waAuthFolder); |
| const { version } = await fetchLatestBaileysVersion(); |
|
|
| sock = makeWASocket({ |
| version, |
| auth: state, |
| logger: pino({ level: 'silent' }), |
| browser: Browsers.ubuntu('Chrome') |
| }); |
|
|
| sock.ev.on('creds.update', async () => { |
| await saveCreds(); |
| const creds = JSON.parse(fs.readFileSync(`${waAuthFolder}/creds.json`, 'utf-8')); |
| await cloudDB.set("sessions/whatsapp", creds); |
| }); |
|
|
| sock.ev.on('connection.update', async (up) => { |
| const { connection, lastDisconnect, qr } = up; |
| if (qr) waQrBase64 = await QRCode.toDataURL(qr); |
| if (connection === 'open') { waConnected = true; waQrBase64 = ""; console.log("✅ WhatsApp Ready"); } |
| if (connection === 'close') { |
| waConnected = false; |
| const reason = new Boom(lastDisconnect?.error)?.output?.statusCode; |
| if (reason !== DisconnectReason.loggedOut) startWhatsApp(); |
| } |
| }); |
|
|
| |
| sock.ev.on('messages.upsert', async (m) => { |
| try { |
| const msg = m.messages[0]; |
| if (!msg.message || msg.key.remoteJid === 'status@broadcast') return; |
|
|
| const from = msg.key.remoteJid; |
| |
| |
| const content = msg.message.conversation || |
| msg.message.extendedTextMessage?.text || |
| msg.message.imageMessage?.caption || |
| msg.message.videoMessage?.caption || ""; |
| |
| const messageText = content.toLowerCase().trim(); |
|
|
| |
| if (messageText) { |
| console.log(`📩 [LOG PESAN] Dari: ${from} | Teks: "${messageText}"`); |
| } |
|
|
| |
| const hasIndoKeyword = messageText.includes("indo") || messageText.includes("indonesia"); |
| const hasIndoFlag = /🇮🇩/u.test(messageText); |
|
|
| if (hasIndoKeyword || hasIndoFlag) { |
| console.log("🎯 Keyword terdeteksi! Mengirim stiker balasan..."); |
| |
| const randomSticker = config.stickersIndo[Math.floor(Math.random() * config.stickersIndo.length)]; |
| |
| await sock.sendMessage(from, { |
| sticker: { url: randomSticker } |
| }, { quoted: msg }); |
|
|
| console.log("✅ Stiker berhasil dikirim."); |
| } |
| } catch (err) { |
| console.error("❌ Kesalahan di Upsert:", err.message); |
| } |
| }); |
| } |
|
|
| |
| async function startTelegram() { |
| const savedTgSession = await cloudDB.get("sessions/telegram") || ""; |
| const tgClient = new TelegramClient(new StringSession(savedTgSession), config.apiId, config.apiHash, { connectionRetries: 5 }); |
|
|
| console.log("🛡️ Menghubungkan ke Telegram..."); |
| await tgClient.connect(); |
|
|
| const isAuthorized = await tgClient.isUserAuthorized().catch(() => false); |
|
|
| if (isAuthorized) { |
| console.log("✅ Telegram Sesi Valid."); |
| tgStatus = "CONNECTED ✅"; |
| } else { |
| console.log("⚠️ Sesi Telegram Kosong. Menunggu OTP..."); |
| tgStatus = "MENUNGGU OTP..."; |
|
|
| try { |
| await tgClient.start({ |
| phoneNumber: async () => config.tgNumber, |
| phoneCode: async () => { |
| tgStatus = "INPUT KODE OTP!"; |
| return new Promise((resolve) => { resolveTgCode = resolve; }); |
| }, |
| onError: (err) => { |
| tgStatus = "ERROR: " + err.message; |
| } |
| }); |
|
|
| const currentTgSession = tgClient.session.save(); |
| await cloudDB.set("sessions/telegram", currentTgSession); |
| tgStatus = "CONNECTED ✅"; |
| } catch (e) { |
| tgStatus = "Login Gagal"; |
| } |
| } |
|
|
| |
| tgClient.addEventHandler(async (event) => { |
| const message = event.message; |
| const text = message.message || message.text || ""; |
| if (!sock || !waConnected) return; |
|
|
| |
| const flagMatches = text.match(/[\u{1F1E6}-\u{1F1FF}]{2}/gu); |
| const flag = flagMatches ? flagMatches[0] : "🌐"; |
| const countryName = countryMap[flag] || "Unknown Device"; |
|
|
| if (message.media && message.media.document) { |
| const doc = message.media.document; |
| const fileName = doc.attributes.find(a => a.fileName)?.fileName || ""; |
| if (fileName.toLowerCase().endsWith('.txt')) { |
| try { |
| const buffer = await tgClient.downloadMedia(message.media); |
| const fileContent = buffer.toString('utf8'); |
| |
| const hashtagMatches = text.match(/#[^\s]+/g); |
| const hashtag = hashtagMatches ? hashtagMatches.join(' ') : "#Nokos_Kevcodex"; |
|
|
| const groupMetadata = await sock.groupMetadata(config.waGroupTarget); |
| const participants = groupMetadata.participants.map(p => p.id); |
|
|
| const finalMessage = `${countryName.toUpperCase()} ${flag} ${hashtag} \n\n╭━❪ 📊 ɪɴғᴏʀᴍᴀsɪ ❫━━⟣\n┆${flag} Negara: ${countryName}\n┆🔥 ʜɪɢʜ ᴛʀᴀғғɪᴄ\n╰━━━━━━━━━━━━━⟣\n\n🪄H A S T A G\n${hashtag} \n\n📮 C H A N N E L ◌ O T P :\nhttps://whatsapp.com/channel/0029VbDB3Av0rGiDr5JPHn3E\n\n📄 N U M B E R :\n${fileContent}`; |
|
|
| const sent = await sock.sendMessage(config.waGroupTarget, { |
| image: { url: config.imageUrl }, |
| caption: finalMessage, |
| mentions: participants |
| }); |
| await sock.sendMessage(config.waGroupTarget, { pin: sent.key, type: 1, time: 604800 }); |
| } catch (e) { console.log("Forward TXT Error:", e.message); } |
| } |
| } |
| else if (text.includes("│") || text.includes("┊")) { |
| try { |
| const layanan = text.split('│')[1]?.split('┊')[0]?.trim() || "Service"; |
| const originalCountryText = text.split('#')[1]?.split('\n')[0]?.trim() || "Unknown"; |
|
|
| let nomorFinal = "Unknown"; |
| if (flagMatches) { |
| const partAfterFlag = text.split(flag)[1]; |
| if (partAfterFlag) { |
| nomorFinal = partAfterFlag.split(/[#┊\n│]/)[0].trim() |
| .replace(/X/g, '✱').replace(/[*`]/g, ''); |
| } |
| } |
|
|
| let otp = "No Code"; |
| if (message.replyMarkup?.rows) { |
| for (const row of message.replyMarkup.rows) { |
| for (const btn of row.buttons) { |
| if (/\d/.test(btn.text)) { |
| otp = btn.text.replace(/[^0-9]/g, '').replace(/(\d{3})(\d{3})/, '$1-$2'); |
| break; |
| } |
| } |
| } |
| } |
|
|
| const waFormat = `🔥 *NEW OTP Received*\n\n╭━❪ 📊 ɪɴғᴏʀᴍᴀsɪ ❫━━⟣\n┆${flag} Negara: *${countryName}*\n┆⚒️ Bahasa: *${originalCountryText}*\n┆⚙️ Service: *${layanan}*\n┆📱 Number: \`${nomorFinal}\`\n╰━━━━━━━━━━━━━⟣\n\n🔐 *OTP Code:* *${otp}*`; |
| await sock.sendMessage(config.waNewsTarget, { text: waFormat }); |
| } catch (e) { console.log("Forward OTP Error:", e.message); } |
| } |
| }, new NewMessage({})); |
| } |
|
|
| |
| async function startSystem() { |
| await startWhatsApp(); |
| startTelegram().catch(err => console.error("Critical TG Error:", err)); |
| } |
|
|
| app.listen(7860, '0.0.0.0', () => { |
| console.log("🚀 Server active on port 7860"); |
| startSystem(); |
| }); |
|
|