Software: Apache/2.4.41 (Ubuntu). PHP/8.0.30 uname -a: Linux apirnd 5.4.0-204-generic #224-Ubuntu SMP Thu Dec 5 13:38:28 UTC 2024 x86_64 uid=33(www-data) gid=33(www-data) groups=33(www-data) Safe-mode: OFF (not secure) /var/www/html/instagram/ drwxr-xr-x | |
| Viewing file: Select action/file-type: const express = require("express");
const app = express();
const bodyParser = require("body-parser");
app.use(bodyParser.json());
const redis = require('./config/redisClient');
const {InstaProfile} = require('./src/models/InstaProfile');
const mongoose = require("mongoose");
const crypto = require("crypto");
require('dotenv').config({ path: './config.env' });
const login=require("./src_old/login/index.js");
const dispatcher = require("./src/dispatcher");
const {postComment} = require("./src/handlers/postComment");
const {liveComment} = require("./src/handlers/liveComment");
const instagram = require("./src/routes/instagram/profile");
app.use("/instagram", instagram);
app.use("/", login);
function verifySignature(req, res, buf) {
const signature = req.headers["x-hub-signature-256"];
if (!signature) return;
const hash = crypto
.createHmac("sha256", process.env.FB_APP_SECRET)
.update(buf)
.digest("hex");
const expected = `sha256=${hash}`;
if (signature !== expected) {
throw new Error("Invalid signature");
}
}
const port = process.env.PORT || 80;
// app.use(bodyParser.json({ verify: verifySignature }));
// Your Verify Token (set same in Meta Webhooks setup)
const VERIFY_TOKEN = "jiff_InStaGraM_TOkeN";
async function initializeAccountCache() {
try {
console.log('🔄 Priming Instagram Account Cache...');
// 1. Fetch only the ID field to keep it memory-efficient
// For MongoDB: .find({}, 'instagramId')
// For MySQL/Sequelize: .findAll({ attributes: ['instagramId'] })
const accounts = await InstaProfile.find({active: 1}, 'user_id');
if (accounts.length === 0) {
console.log('⚠️ No accounts found in DB to cache.');
return;
}
const accountIds = accounts.map(acc => acc.user_id);
// 2. Clear the old set to ensure a clean state (optional)
await redis.del('connected_instagram_accounts');
// 3. Add all IDs to the Redis Set
// SADD can take an array of values
await redis.sadd('connected_instagram_accounts', ...accountIds);
console.log(`✅ Cache primed with ${accountIds.length} accounts.`);
} catch (error) {
console.error('❌ Failed to initialize account cache:', error);
}
}
async function isOurAccount(id) {
return await redis.sismember('connected_instagram_accounts', id);
}
// ------------------------------
// 1. WEBHOOK VERIFICATION (GET)
// ------------------------------
app.get("/webhook", (req, res) => {
const mode = req.query["hub.mode"];
const token = req.query["hub.verify_token"];
const challenge = req.query["hub.challenge"];
if (mode && token === VERIFY_TOKEN) {
console.log("Webhook verified!");
return res.status(200).send(challenge);
}
return res.sendStatus(403);
});
// ------------------------------
// 2. RECEIVE WEBHOOK EVENTS (POST)
// ------------------------------
app.post("/webhook",async (req, res) => {
try {
const { body } = req;
if (body.object === 'instagram') {
body.entry.forEach(entry => {
// console.log(entry);
const currentEntryId = entry.id; // The ID this specific webhook is addressed to
// console.log(entry); // For comments, this contains the comment data
if (entry.messaging) {
entry.messaging.map(async (event) => {
const senderId = event.sender?.id;
const recipientId = event.recipient?.id;
// ✅ RULE 1: Standard Echo check
if (event.message?.is_echo) {
return;
}
// ✅ RULE 2: If the SENDER is any of your business accounts, IGNORE.
// This stops manual replies and bot replies from being processed.
const isSenderInternal = await isOurAccount(recipientId);
if (!isSenderInternal) {
// console.log(`Receiver is not in account list`);
// console.log(`Skipping: Sender ${senderId} is a known business account.`);
return;
}
// ✅ RULE 3: Ensure the RECIPIENT is the actual account owner for this entry.
// This stops the "mirrored" messages you see in your logs.
if (recipientId !== currentEntryId) {
console.log(`Skipping: Recipient ${recipientId} does not match Entry ${currentEntryId}.`);
return;
}
// Now it is safe to process
// console.log(`Processing real customer message: ${event.message?.text}`);
dispatcher(event);
});
}
// 2. Handling Comments (Changes)
if (entry.changes) {
entry.changes.forEach(async (change) => {
// console.log(change);
if (change.field === 'comments') {
const commentData = change.value;
const commenterId = commentData.from.id;
const isSenderInternal = await isOurAccount(commenterId);
// Ignore if the commenter is the Page itself
if (isSenderInternal) {
// console.log('Ignored: Self-comment');
return;
}
// page_id, comment_id, sender_psid, post_id, message
// if (commentData.media.media_product_type=='FEED') {
postComment(currentEntryId,commentData.id,commenterId,commentData.media.id,commentData.text);
// }
// handleComment(commenterId, commentData);
}else if (change.field === 'live_comments') {
const commentData = change.value;
const commenterId = commentData.from.id;
const isSenderInternal = await isOurAccount(commenterId);
// Ignore if the commenter is the Page itself
if (isSenderInternal) {
// console.log('Ignored: Self-comment');
return;
}
liveComment(currentEntryId,commenterId,commentData);
}
});
}
});
}
res.status(200).send('EVENT_RECEIVED');
// console.log(JSON.stringify(req.body));
// req.body.entry.forEach(entry => {
// const businessAccountId = entry.id; // The ID of YOUR account
// if (entry.messaging) {
// entry.messaging.forEach(event => {
// const senderId = event.sender?.id;
// // 1. Check is_echo (for App-sent messages)
// if (event.message?.is_echo) {
// return;
// }
// // 2. Check if sender is the Business Account itself (for Manual/Native app replies)
// if (senderId === businessAccountId) {
// return;
// }
// const entry = req.body.entry?.[0];
// const messaging = entry?.messaging?.[0];
// dispatcher(messaging);
// // Proceed with user logic...
// });
// }
// if (entry.changes) {
// entry.changes.forEach(change => {
// // For Comments
// if (change.value.from?.id === businessAccountId) {
// return;
// }
// // Proceed with comment logic...
// });
// }
// });
// // dispatcher(messaging);
// res.sendStatus(200);
} catch (err) {
console.error("Webhook Error:", err);
res.sendStatus(200);
}
});
// facebook user data deletion
app.post('auth/instagram/delete', (req, res) => {
console.log(req.body);
// const userId = req.body.user_id ?? "8542532005775617"; // Facebook sends the user ID in the body
// console.log(req.body);
// if (userId) {
// // Add logic to delete the user's data from your database
// // Example: deleteUserDataFromDatabase(userId);
// console.log(`Deleting data for user: ${userId}`);
// Respond with confirmation
return res.json({
status: 'success',
message: `Data deleted for user ${userId}`
});
// } else {
// return res.status(400).json({
// status: 'error',
// message: 'User ID not provided'
// });
// }
});
app.post('auth/instagram/deauthorize', (req, res) => {
try {
const signed = req.body.signed_request;
const data = parseSigned(signed);
const user_id = data.user_id;
console.log("User removed app:", user_id);
res.json({
success: true,
});
} catch (error) {
res.json({
success: false,
});
}
});
function parseSigned(signed) {
const parts = signed.split(".");
const payload = Buffer.from(parts[1], "base64");
return JSON.parse(payload.toString());
}
app.get("/", (req, res) => {
res.send("Hello, this is the Instagram Webhook server!");
});
// Sets server port and logs message on success
const start = async () => {
try {
await mongoose.connect(
process.env.MONGO_URI
);
await initializeAccountCache(); // Prime the cache on startup
app.listen(process.env.PORT || 90, () => console.log('webhook is listening on port : ' + process.env.PORT));
} catch (error) {
console.error(error);
process.exit(1);
}
};
start(); |
:: Command execute :: | |
--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0045 ]-- |