Spaces:
Paused
Paused
| const express = require('express'); | |
| const admin = require('firebase-admin'); | |
| const app = express(); | |
| app.use(express.json()); | |
| // ========================================== | |
| // ১. ফায়ারবেজ সেটআপ (Environment Variable থেকে) | |
| // ========================================== | |
| // Hugging Face-এর Secrets এ FIREBASE_ADMIN JSON স্ট্রিং হিসেবে সেভ করা থাকতে হবে | |
| // এবং FIREBASE_DB_URL নামে ডাটাবেজ লিংকটি রাখতে হবে। | |
| const serviceAccount = JSON.parse(process.env.FIREBASE_ADMIN); | |
| admin.initializeApp({ | |
| credential: admin.credential.cert(serviceAccount), | |
| databaseURL: process.env.FIREBASE_DB_URL // উদাহরণ: "https://your-project.firebaseio.com" | |
| }); | |
| const db = admin.database(); | |
| // ========================================== | |
| // ২. হেলথ চেক রাউটস (যেকোনো রিকোয়েস্ট) | |
| // ========================================== | |
| const healthHandler = (req, res) => { | |
| res.send('Ok yes done'); | |
| }; | |
| app.all('/health', healthHandler); | |
| app.all('/check', healthHandler); | |
| app.all('/unps', healthHandler); | |
| // ========================================== | |
| // ৩. মূল কাজের পাথগুলো | |
| // ========================================== | |
| const pathGroup1 = ['/link-visit']; | |
| const pathGroup2 = ['/adsgram-1', '/adsgram-2', '/gigapub-1', '/gigapub-2', '/monetag-1', '/monetag-2', '/add-account']; | |
| const allActionPaths = [...pathGroup1, ...pathGroup2]; | |
| // শুধুমাত্র POST রিকোয়েস্ট পারমিট করার মিডলওয়্যার | |
| app.use(allActionPaths, (req, res, next) => { | |
| if (req.method !== 'POST') { | |
| return res.status(405).json({ error: 'Method Not Allowed. Only POST is accepted.' }); | |
| } | |
| next(); | |
| }); | |
| // ========================================== | |
| // ৪. Cloudflare Turnstile ভ্যালিডেশন মিডলওয়্যার | |
| // ========================================== | |
| const verifyCloudflare = async (req, res, next) => { | |
| // ক্লায়েন্ট থেকে আসা টোকেন (ধরে নিচ্ছি বডিতে 'cf_token' নামে আসবে) | |
| const token = req.body.cf_token; | |
| if (!token) return res.status(403).json({ error: 'Cloudflare token is missing' }); | |
| try { | |
| const response = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, | |
| body: `secret=${process.env.CLOUDFLIRE_CHECK}&response=${token}` | |
| }); | |
| const data = await response.json(); | |
| if (data.success) { | |
| next(); // ভ্যালিডেশন সফল, পরের ধাপে যাও | |
| } else { | |
| return res.status(403).json({ error: 'Cloudflare verification failed' }); | |
| } | |
| } catch (error) { | |
| return res.status(500).json({ error: 'Server error during Cloudflare verification' }); | |
| } | |
| }; | |
| // ========================================== | |
| // ৫. ডাটা প্রসেসিং এবং ফায়ারবেজে সেভ করা | |
| // ========================================== | |
| app.post(allActionPaths, verifyCloudflare, async (req, res) => { | |
| const { user_id, action, 'action_type-1': balance, 'action_type-2': stock } = req.body; | |
| // ভ্যালিডেশন: ইউজার আইডি এবং অ্যাকশন চেক | |
| if (!user_id || !action) { | |
| return res.status(400).json({ error: 'Missing user_id or action' }); | |
| } | |
| // ভ্যালিডেশন: ডাটা ডিলিট করার রিকোয়েস্ট বাতিল | |
| if (action.toLowerCase().includes('delete') || action.toLowerCase() !== 'add') { | |
| return res.status(400).json({ error: 'Invalid action. Only "add" is allowed.' }); | |
| } | |
| const currentPath = req.path; // যেমন: '/link-visit' | |
| // ভ্যালিডেশন: ফিক্সড ব্যালেন্স এবং স্টক চেক | |
| if (pathGroup1.includes(currentPath)) { | |
| if (Number(balance) !== 0.05 || stock !== '+1') { | |
| return res.status(400).json({ error: 'Invalid balance or stock for this path. Expected 0.05 and +1.' }); | |
| } | |
| } else if (pathGroup2.includes(currentPath)) { | |
| if (Number(balance) !== 0.06 || stock !== '+1') { | |
| return res.status(400).json({ error: 'Invalid balance or stock for this path. Expected 0.06 and +1.' }); | |
| } | |
| } | |
| // ফায়ারবেজে ডাটা সেভ করা | |
| try { | |
| // ফায়ারবেজে রিকোয়েস্টের পাথের নামেই ডাটা সেভ হবে (যেমন: /link-visit/user_id/...) | |
| const dbRef = db.ref(currentPath).child(user_id); | |
| const newData = { | |
| action: action, | |
| balance: Number(balance), | |
| stock: stock, | |
| timestamp: admin.database.ServerValue.TIMESTAMP | |
| }; | |
| // ইউজারের নোডের আন্ডারে নতুন ডাটা পুশ করা হলো | |
| await dbRef.push(newData); | |
| res.status(200).json({ message: 'Success! Data saved to Firebase.', path: currentPath }); | |
| } catch (error) { | |
| console.error('Firebase Error:', error); | |
| res.status(500).json({ error: 'Failed to save data to Firebase' }); | |
| } | |
| }); | |
| // সার্ভার স্টার্ট | |
| const PORT = process.env.PORT || 7860; // Hugging Face Space ডিফল্টভাবে 7860 পোর্ট ব্যবহার করে | |
| app.listen(PORT, () => { | |
| console.log(`Server is running on port ${PORT}`); | |
| }); | |