require("dotenv").config(); const express = require("express");
const bodyParser = require("body-parser");
const Pusher = require("pusher"); const crypto = require("crypto");
const app = express();
const port = process.env.BACKEND_PORT || 3000;
const pusher = new Pusher({
appId: process.env.PUSHER_APP_ID,
key: process.env.PUSHER_APP_KEY,
secret: process.env.PUSHER_APP_SECRET,
cluster: "mt1", host: process.env.PUSHER_HOST,
port: process.env.PUSHER_PORT,
useTLS: process.env.PUSHER_USE_TLS === "true",
});
console.log("Pusher Server SDK configured for:", {
appId: process.env.PUSHER_APP_ID,
key: process.env.PUSHER_APP_KEY ? "***" : "Not Set", secret: process.env.PUSHER_APP_SECRET ? "***" : "Not Set", host: process.env.PUSHER_HOST,
port: process.env.PUSHER_PORT,
useTLS: process.env.PUSHER_USE_TLS === "true",
});
let receivedWebhooks = [];
app.use(express.static("public"));
app.use(
bodyParser.json({
verify: (req, res, buf) => {
req.rawBody = buf;
},
}),
);
app.use(bodyParser.urlencoded({ extended: false }));
app.get("/config", (req, res) => {
res.json({
pusherKey: process.env.PUSHER_APP_KEY,
pusherHost: process.env.PUSHER_HOST,
pusherPort: process.env.PUSHER_PORT,
pusherUseTLS: process.env.PUSHER_USE_TLS === "true",
authEndpoint: `${process.env.BACKEND_BASE_URL}/pusher/auth`,
pusherCluster: "mt1", });
});
app.post("/pusher/auth", (req, res) => {
const socketId = req.body.socket_id;
const channel = req.body.channel_name;
console.log(`Auth attempt for socket_id: ${socketId}, channel: ${channel}`);
const MOCK_USER_ID = `user_${Date.now()}`; const MOCK_USER_INFO = {
name: `Test User ${MOCK_USER_ID}`,
id: MOCK_USER_ID,
};
try {
if (channel.startsWith("private-")) {
const authResponse = pusher.authorizeChannel(socketId, channel);
console.log("Auth success (private):", authResponse);
res.send(authResponse);
} else if (channel.startsWith("presence-")) {
const presenceData = {
user_id: MOCK_USER_ID,
user_info: MOCK_USER_INFO,
};
const authResponse = pusher.authorizeChannel(
socketId,
channel,
presenceData,
);
console.log("Auth success (presence):", authResponse);
res.send(authResponse);
} else {
console.error(
`Auth failed: Channel ${channel} is not private or presence.`,
);
res.status(403).send("Forbidden: Channel is not private or presence");
}
} catch (error) {
console.error("Auth error:", error);
res.status(500).send(`Authentication error: ${error.message}`);
}
});
app.post("/pusher/webhooks", (req, res) => {
console.log("\n--- Webhook Received ---");
const receivedSignature = req.headers["x-pusher-signature"];
const expectedSignature = crypto
.createHmac("sha256", process.env.PUSHER_APP_SECRET)
.update(req.rawBody) .digest("hex");
if (!receivedSignature) {
console.warn(
"Webhook received without signature. Skipping verification (Configure your server to send signatures!).",
);
} else if (receivedSignature !== expectedSignature) {
console.error("Webhook signature invalid!");
console.error(`Received: ${receivedSignature}`);
console.error(`Expected: ${expectedSignature}`);
return res.status(403).send("Webhook signature invalid");
} else {
console.log("Webhook signature verified successfully.");
}
const webhookBody = req.body; console.log("Webhook Body:", JSON.stringify(webhookBody, null, 2));
const webhookData = {
timestamp: new Date().toISOString(),
headers: req.headers,
body: webhookBody,
};
receivedWebhooks.unshift(webhookData); if (receivedWebhooks.length > 50) {
receivedWebhooks.pop();
}
res.status(200).json({ message: "Webhook received" });
});
app.get("/webhooks-log", (req, res) => {
res.json(receivedWebhooks);
});
app.listen(port, () => {
console.log(`\n--- Pusher Test Backend Server ---`);
console.log(
`Authentication & Webhook server running at ${process.env.BACKEND_BASE_URL}`,
);
console.log(` - Serving frontend from: ./public`);
console.log(
` - Auth Endpoint: POST ${process.env.BACKEND_BASE_URL}/pusher/auth`,
);
console.log(
` - Webhook Endpoint: POST ${process.env.BACKEND_BASE_URL}/pusher/webhooks`,
);
console.log(` - Config Endpoint: GET ${process.env.BACKEND_BASE_URL}/config`);
console.log(
` - Webhook Log: GET ${process.env.BACKEND_BASE_URL}/webhooks-log`,
);
console.log(`----------------------------------\n`);
});