Channel Deals Secure Chat - Backend Code Success ✅

// ========================================== // CONFIGURATION // ========================================== const SHEET_ID = '1gw1Zu5fvyJNRJO0ObdSDeO9OrHg-Vgg18uEyJT0jA-o'; // JSON Response helper function jsonResponse(data) { return ContentService.createTextOutput(JSON.stringify(data)).setMimeType(ContentService.MimeType.JSON); } // Get Admin Number function getAdminNumber(sheet) { let settingsSheet = sheet.getSheetByName('Settings'); let data = settingsSheet.getDataRange().getValues(); for (let i = 1; i < data.length; i++) { if (data[i][0] === 'AdminNumber') { return String(data[i][1]).trim(); } } return ""; } // ========================================== // SECURITY FILTER // ========================================== function isMessageSafeBackend(text) { if (!text || String(text).trim() === "") return false; let lowerText = String(text).toLowerCase(); let strippedText = lowerText.replace(/[\s\.\-]/g, ''); if(/\d{10}/.test(strippedText)) return false; let socialRegex = /(instagram|facebook|twitter|fb|insta|ig|t\.me|\.com|\.in)/; if(socialRegex.test(lowerText) || /@\w+/.test(lowerText)) return false; // UPDATED BLOCKED WORDS LIST let blockedWords = [ "mera", "mera mobile", "mera userid", "my insta id", "my number", "contact me", "whatsapp", "wahtsapp", "watsapp", "call me", "call kar", "telegram", "gpay", "google pay", "phonepe", "paytm", "upi", "qr code", "qr bhej", "send money", "paise bhejo", "payment bhej", "account number", "ifsc" ]; for(let i = 0; i < blockedWords.length; i++) { if(new RegExp("\\b" + blockedWords[i] + "\\b", "i").test(lowerText)) { return false; } } return true; } // ========================================== // 1. GET REQUESTS // ========================================== function doGet(e) { let sheet = SpreadsheetApp.openById(SHEET_ID); let action = e.parameter.action; if (action === 'getMessages') { let groupId = e.parameter.groupId; let groupSheet = sheet.getSheetByName('Groups'); let groupData = groupSheet.getDataRange().getValues(); let isFrozen = false; for (let i = 1; i < groupData.length; i++) { if (groupData[i][0] === groupId) { isFrozen = (groupData[i][5] === true || String(groupData[i][5]).toLowerCase() === "true"); break; } } let usersSheet = sheet.getSheetByName('Users'); let usersData = usersSheet.getDataRange().getValues(); let userMap = {}; let adminNum = getAdminNumber(sheet); for (let i = 1; i < usersData.length; i++) { let isThisAdmin = (String(usersData[i][2]).trim() === adminNum); userMap[usersData[i][0]] = isThisAdmin ? "Admin" : usersData[i][1]; } let msgSheet = sheet.getSheetByName('Messages'); let msgData = msgSheet.getDataRange().getValues(); let groupMessages = []; for (let i = 1; i < msgData.length; i++) { if (msgData[i][1] === groupId) { let timeValue = msgData[i][4]; let timeStr = ""; if(timeValue) { timeStr = new Date(timeValue).toLocaleTimeString('en-IN', { timeZone: 'Asia/Kolkata', hour: '2-digit', minute:'2-digit' }); } groupMessages.push({ msgId: msgData[i][0], senderId: msgData[i][2], senderName: userMap[msgData[i][2]] || "Member", message: String(msgData[i][3]), timeStr: timeStr, seen: msgData[i][5] || 0 }); } } return jsonResponse({ messages: groupMessages, isFrozen: isFrozen }); } if (action === 'getAdminGroups') { let adminPhone = e.parameter.phone ? String(e.parameter.phone).trim() : ""; if (adminPhone !== getAdminNumber(sheet)) { return jsonResponse({status: 'error', error_msg: 'Aap Admin nahi hain!'}); } let groupSheet = sheet.getSheetByName('Groups'); let groupData = groupSheet.getDataRange().getValues(); let activeGroups = []; for (let i = 1; i < groupData.length; i++) { if(groupData[i][0] !== "") { activeGroups.push({ groupId: groupData[i][0], groupName: groupData[i][1] || "Unnamed Deal", isFrozen: groupData[i][5], groupType: groupData[i][6] || "Standard Deal" }); } } return jsonResponse({status: 'success', groups: activeGroups}); } } // ========================================== // 2. POST REQUESTS // ========================================== function doPost(e) { let sheet = SpreadsheetApp.openById(SHEET_ID); let action = e.parameter.action; let requesterPhone = e.parameter.phone ? String(e.parameter.phone).trim() : ""; let ADMIN_NUMBER = getAdminNumber(sheet); if (action === 'createGroup') { if (requesterPhone !== ADMIN_NUMBER) return jsonResponse({status: 'error', error_msg: 'Access Denied!'}); let groupSheet = sheet.getSheetByName('Groups'); let groupId = Utilities.getUuid(); let groupName = e.parameter.groupName || "CHANNEL DEALS"; let groupType = e.parameter.groupType || "Standard Deal"; groupSheet.appendRow([groupId, groupName, "", "", "", false, groupType]); return jsonResponse({status: 'success', groupId: groupId}); } if (action === 'login') { // BUG FIX: Added LockService to prevent slot collision if 2 users join at the exact same millisecond let lock = LockService.getScriptLock(); try { lock.waitLock(5000); let usersSheet = sheet.getSheetByName('Users'); let groupsSheet = sheet.getSheetByName('Groups'); let phone = requesterPhone; let groupId = e.parameter.groupId; let role = e.parameter.role || "Member"; let isAdmin = (phone === ADMIN_NUMBER); let usersData = usersSheet.getDataRange().getValues(); let userId = ""; let userName = ""; let userExists = false; for(let i = 1; i < usersData.length; i++) { if(String(usersData[i][2]).trim() === phone) { userExists = true; userId = usersData[i][0]; userName = isAdmin ? "Admin" : usersData[i][1]; break; } } if(!userExists) { userId = Utilities.getUuid(); let random4Digit = Math.floor(1000 + Math.random() * 9000); userName = isAdmin ? "Admin" : role + "_" + random4Digit; usersSheet.appendRow([userId, userName, phone, "1234"]); } let groupData = groupsSheet.getDataRange().getValues(); let groupRowIndex = -1; let members = []; for(let i = 1; i < groupData.length; i++) { if(groupData[i][0] === groupId) { groupRowIndex = i + 1; members = [groupData[i][2], groupData[i][3], groupData[i][4]]; break; } } if (groupRowIndex !== -1) { if (!members.includes(userId)) { if (members[0] === "") groupsSheet.getRange(groupRowIndex, 3).setValue(userId); else if (members[1] === "") groupsSheet.getRange(groupRowIndex, 4).setValue(userId); else if (members[2] === "") groupsSheet.getRange(groupRowIndex, 5).setValue(userId); else return jsonResponse({status: 'error', error_msg: 'Yeh deal group full ho chuka hai (Limit: 3 Members).'}); } } else { return jsonResponse({status: 'error', error_msg: 'Invalid Link. Yeh deal exist nahi karti.'}); } return jsonResponse({status: 'success', userId: userId, userName: userName, isAdmin: isAdmin}); } catch (e) { return jsonResponse({status: 'error', error_msg: 'Server busy, retry in 2 seconds.'}); } finally { lock.releaseLock(); } } if (action === 'sendMessage') { let rawMessage = e.parameter.message ? String(e.parameter.message).trim() : ""; // Yahan Frontend se bheja gaya msgId receive karenge let msgId = e.parameter.msgId || Utilities.getUuid(); if (!isMessageSafeBackend(rawMessage)) { return jsonResponse({ status: 'error', error_msg: 'System Alert: Restricted words, Links ya Number allow nahi hai!' }); } let msgSheet = sheet.getSheetByName('Messages'); msgSheet.appendRow([ msgId, // Ab yahan backend apna ID nahi banayega, balki frontend ka ID use karega e.parameter.groupId, e.parameter.senderId, rawMessage, new Date(), 0 ]); return jsonResponse({status: 'success'}); } if (action === 'markSeen') { let msgSheet = sheet.getSheetByName('Messages'); let data = msgSheet.getDataRange().getValues(); let unseenIds = JSON.parse(e.parameter.unseenIds || "[]"); let foundCount = 0; // BUG FIX: Bottom-to-Top loop for extreme speed (prevents Timeout limits on large sheets) for (let i = data.length - 1; i > 0; i--) { if (unseenIds.includes(data[i][0])) { msgSheet.getRange(i + 1, 6).setValue(1); foundCount++; if (foundCount === unseenIds.length) break; // Optimization: Stop looping when found } } return jsonResponse({status: 'success'}); } if (action === 'freezeChat' || action === 'unfreezeChat') { if (requesterPhone !== ADMIN_NUMBER) return jsonResponse({status: 'error'}); let groupSheet = sheet.getSheetByName('Groups'); let data = groupSheet.getDataRange().getValues(); let groupId = e.parameter.groupId; let freezeStatus = (action === 'freezeChat'); for (let i = 1; i < data.length; i++) { if (data[i][0] === groupId) { groupSheet.getRange(i + 1, 6).setValue(freezeStatus); break; } } return jsonResponse({status: 'success'}); } if (action === 'clearHistory') { if (requesterPhone !== ADMIN_NUMBER) return jsonResponse({status: 'error'}); let msgSheet = sheet.getSheetByName('Messages'); let data = msgSheet.getDataRange().getValues(); let groupId = e.parameter.groupId; // Bottom-to-top loop mandatory for deleting rows for (let i = data.length - 1; i > 0; i--) { if (data[i][1] === groupId) msgSheet.deleteRow(i + 1); } return jsonResponse({status: 'success'}); } if (action === 'deleteGroup') { if (requesterPhone !== ADMIN_NUMBER) return jsonResponse({status: 'error'}); let groupId = e.parameter.groupId; let groupSheet = sheet.getSheetByName('Groups'); let msgSheet = sheet.getSheetByName('Messages'); let groupData = groupSheet.getDataRange().getValues(); for (let i = groupData.length - 1; i > 0; i--) { if (groupData[i][0] === groupId) groupSheet.deleteRow(i + 1); } let msgData = msgSheet.getDataRange().getValues(); for (let i = msgData.length - 1; i > 0; i--) { if (msgData[i][1] === groupId) msgSheet.deleteRow(i + 1); } return jsonResponse({status: 'success'}); } }