const express = require('express'); const cors = require('cors'); const admin = require('firebase-admin'); const app = express(); const PORT = process.env.PORT || 7860; const allowedOrigins = [ 'https://raybil.me', 'https://story.raybil.me' ]; const corsOptions = { origin: function (origin, callback) { if (!origin) return callback(null, true); if (allowedOrigins.indexOf(origin) !== -1) { callback(null, true); } else { callback(null, false); } }, methods: ['POST', 'GET', 'OPTIONS'], credentials: true }; app.use(cors(corsOptions)); app.use(express.json()); try { const secretKeyString = process.env.FIREBASE_SERVICE_ACCOUNT; if (!secretKeyString) { throw new Error("FIREBASE_SERVICE_ACCOUNT secret is missing!"); } const serviceAccount = JSON.parse(secretKeyString); admin.initializeApp({ credential: admin.credential.cert(serviceAccount) }); console.log("Firebase Admin SDK initialized successfully!"); } catch (error) { console.error("Firebase Initialization Failed:", error.message); process.exit(1); } const healthCheckHandler = (req, res) => { res.status(200).send('ok'); }; app.all('/health', healthCheckHandler); app.all('/check', healthCheckHandler); const enforcePostOnly = (req, res, next) => { if (req.method !== 'POST') { return res.status(405).json({ success: false, message: `Method ${req.method} Not Allowed. Only POST requests are accepted.` }); } next(); }; function getSafeTopicName(category) { const mapping = { "নবীদের কাহিনী": "nobider_kahini", "সাহাবিদের জীবনী": "sahabider_jiboni", "আল-কুরআন ও হাদিসের গল্প": "quran_hadis", "পূর্বসূরি ও বুজুর্গদের কাহিনী": "scholars_stories", "শিশুদের ইসলামিক গল্প": "kids_stories" }; if (mapping[category]) { return mapping[category]; } return "general_stories"; } app.post('/subscribe', enforcePostOnly, async (req, res) => { const { fcm_token, selected_category, action } = req.body; if (!fcm_token || !selected_category || action !== 'subscribe') { return res.status(400).json({ success: false, message: "Invalid payload or wrong action." }); } try { const safeTopic = getSafeTopicName(selected_category); await admin.messaging().subscribeToTopic(fcm_token, safeTopic); res.status(200).json({ success: true, message: `Successfully registered to ${selected_category} category.` }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); app.post('/unsubscribe', enforcePostOnly, async (req, res) => { const { fcm_token, selected_category, action } = req.body; if (!fcm_token || !selected_category || action !== 'unsubscribe') { return res.status(400).json({ success: false, message: "Invalid payload or wrong action." }); } try { const safeTopic = getSafeTopicName(selected_category); await admin.messaging().unsubscribeFromTopic(fcm_token, safeTopic); res.status(200).json({ success: true, message: `Successfully removed from ${selected_category} category.` }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); app.use((req, res) => { res.status(404).json({ success: false, message: "Endpoint not found." }); }); app.listen(PORT, '0.0.0.0', () => { console.log(`Server is running securely on port ${PORT}`); });