Raybilhelp commited on
Commit
4a463ef
·
verified ·
1 Parent(s): 760f1c4

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +93 -85
app.js CHANGED
@@ -1,37 +1,74 @@
1
- Const express = require('express');
2
  const admin = require('firebase-admin');
3
  const crypto = require('crypto');
4
  const cluster = require('cluster');
5
  const os = require('os');
6
 
7
- // সার্ভারের মোট সিপিইউ কোর সংখ্যা স্বয়ংক্রিয়ভাবে ডিটেক্ট করা (১২ কোর হলে ১২টি প্রসেস তৈরি হবে)
8
  const numCPUs = os.cpus().length;
9
 
10
  if (cluster.isMaster) {
11
- console.log(`Master Server Process ${process.pid} is running. Detecting ${numCPUs} CPU cores...`);
12
-
13
- // প্রতিটি কোরের জন্য একটি করে ওয়ার্কার সার্ভার তৈরি করা হচ্ছে
14
- for (let i = 0; i < numCPUs; i++) {
15
- cluster.fork();
16
- }
17
-
18
- // কোনো ওয়ার্কার কোনো কারণে ক্র্যাশ করলে স্বয়ংক্রিয়ভাবে নতুন ওয়ার্কার চালু হবে
19
- cluster.on('exit', (worker, code, signal) => {
20
- cluster.fork();
21
- });
22
-
23
  } else {
24
- // এটি হলো ওয়ার্কার প্রসেস - যা আসল ট্রাফিক হ্যান্ডেল করবে
25
  const app = express();
26
  app.use(express.json());
 
27
 
28
  // ==========================================
29
- // ১. য়রবেজ্টি্যাডমিন সেটআপ
30
  // ==========================================
31
- const initFirebase = (envAdmin, envUrl, appName) => {
32
- if (!process.env[envAdmin] || !process.env[envUrl]) {
33
- return null;
 
 
 
 
 
 
 
 
 
 
 
 
34
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  return admin.initializeApp({
36
  credential: admin.credential.cert(JSON.parse(process.env[envAdmin])),
37
  databaseURL: process.env[envUrl]
@@ -47,17 +84,15 @@ if (cluster.isMaster) {
47
  const db4 = app4 ? app4.database() : null;
48
 
49
  // ==========================================
50
- // . হেলথ চেক রাউস (যেকোনো রিকোযেস্)
51
  // ==========================================
52
- const healthHandler = (req, res) => {
53
- res.send('Ok, yes, done');
54
- };
55
  app.all('/health', healthHandler);
56
  app.all('/ch', healthHandler);
57
  app.all('/unps', healthHandler);
58
 
59
  // ==========================================
60
- // . মিডলওয়্যার: শুধুমাত্র POST রিকোয়েস্ট পারমিট করা
61
  // ==========================================
62
  const checkPostMethod = (req, res, next) => {
63
  if (req.method !== 'POST') {
@@ -67,11 +102,10 @@ if (cluster.isMaster) {
67
  };
68
 
69
  // ==========================================
70
- // . Telegram Security ভ্যালিডেশন মিডলওয়্যার
71
  // ==========================================
72
  const verifyTelegramAuth = (req, res, next) => {
73
  const { init_data, user_id, name } = req.body;
74
-
75
  if (!init_data) return res.status(401).json({ error: 'Unauthorized: init_data is missing' });
76
 
77
  try {
@@ -82,29 +116,19 @@ if (cluster.isMaster) {
82
  const hash = urlParams.get('hash');
83
  urlParams.delete('hash');
84
 
85
- const dataToCheck = [...urlParams.entries()]
86
- .map(([key, value]) => `${key}=${value}`)
87
- .sort()
88
- .join('\n');
89
-
90
  const secretKey = crypto.createHmac('sha256', 'WebAppData').update(botToken).digest();
91
  const calculatedHash = crypto.createHmac('sha256', secretKey).update(dataToCheck).digest('hex');
92
 
93
- if (calculatedHash !== hash) {
94
- return res.status(403).json({ error: 'Forbidden: Invalid Telegram signature' });
95
- }
96
 
97
  const tgUser = JSON.parse(urlParams.get('user'));
98
-
99
- if (String(tgUser.id) !== String(user_id)) {
100
- return res.status(403).json({ error: 'Forbidden: User ID mismatch' });
101
- }
102
 
103
  const tgFullName = tgUser.last_name ? `${tgUser.first_name} ${tgUser.last_name}`.trim() : tgUser.first_name;
104
  if (String(tgFullName) !== String(name) && String(tgUser.first_name) !== String(name)) {
105
  return res.status(403).json({ error: 'Forbidden: Name mismatch' });
106
  }
107
-
108
  next();
109
  } catch (error) {
110
  return res.status(500).json({ error: 'Internal server error during validation' });
@@ -112,56 +136,52 @@ if (cluster.isMaster) {
112
  };
113
 
114
  // ==========================================
115
- // . API: ক্রিয়েট অ্যাকাউন্ট (/creataccoumt)
116
  // ==========================================
117
  app.post('/creataccoumt', checkPostMethod, verifyTelegramAuth, async (req, res) => {
118
  const { user_id, refer_id, name, username, profile_pic_url } = req.body;
119
-
120
  try {
121
  const userRef = db1.ref('user').child(user_id);
122
  const snapshot = await userRef.once('value');
123
 
124
  if (snapshot.exists()) {
125
- return res.status(200).json({ message: 'Account already exists. No action taken.' });
 
 
126
  }
127
 
128
  const newUserData = {
129
- user_id,
130
- refer_id: refer_id || null,
131
- name: name || null,
132
- username: username || null,
133
- profile_pic_url: profile_pic_url || null,
134
- balance: 0,
135
- total_withdraw: 0,
136
- total_withdraw_amount: 0,
137
- join_date: admin.database.ServerValue.TIMESTAMP,
138
- total_refer: 0
139
  };
140
 
141
  await userRef.set(newUserData);
 
142
 
143
  if (refer_id) {
144
  const referUserRef = db1.ref('user').child(refer_id);
145
  const referUserSnap = await referUserRef.once('value');
146
 
147
  if (referUserSnap.exists()) {
148
- await referUserRef.child('total_refer').transaction((currentValue) => {
149
- return (currentValue || 0) + 1;
150
- });
151
-
152
  const referListRef = db3.ref('refer').child(refer_id);
153
  await referListRef.push(user_id);
 
154
  }
155
  }
156
 
157
- res.status(201).json({ message: 'Account created successfully!' });
 
 
158
  } catch (error) {
 
159
  res.status(500).json({ error: 'Internal Server Error' });
160
  }
161
  });
162
 
163
  // ==========================================
164
- // . API: উইথড্র মেইন ব্যালেন্স (/withdraw-main)
165
  // ==========================================
166
  app.post('/withdraw-main', checkPostMethod, verifyTelegramAuth, async (req, res) => {
167
  const { user_id, method, address, time, amount } = req.body;
@@ -173,50 +193,40 @@ if (cluster.isMaster) {
173
  try {
174
  const userRef = db1.ref('user').child(user_id);
175
  const snapshot = await userRef.once('value');
176
-
177
  if (!snapshot.exists()) return res.status(404).json({ error: 'User not found' });
178
 
179
  const userData = snapshot.val();
180
  const currentBalance = Number(userData.balance || 0);
181
  const requestAmount = Number(amount);
182
 
183
- if (currentBalance < requestAmount) {
184
- return res.status(400).json({ error: 'Insufficient balance' });
185
- }
186
 
187
  await userRef.child('balance').set(currentBalance - requestAmount);
188
 
189
  const pendingRef = db3.ref('withdrow/painding').child(user_id);
190
  await pendingRef.push({
191
- method,
192
- address,
193
- time: time || admin.database.ServerValue.TIMESTAMP,
194
- amount: requestAmount,
195
- status: 'pending'
196
  });
197
 
198
- res.status(200).json({ message: 'Withdrawal request successful' });
 
 
199
  } catch (error) {
 
200
  res.status(500).json({ error: 'Internal Server Error' });
201
  }
202
  });
203
 
204
  // ==========================================
205
- // . API: অ্যাড ব্যালেন্স উইথড্র (Admin 4 -> Admin 1)
206
  // ==========================================
207
  const adWithdrawPaths = [
208
- '/withdraw-link-visit',
209
- '/withdraw-adsgram-1',
210
- '/withdraw-adsgram-2',
211
- '/withdraw-gigapub-1',
212
- '/withdraw-gigapub-2',
213
- '/withdraw-monetag-1',
214
- '/withdraw-monetag-2'
215
  ];
216
 
217
  app.post(adWithdrawPaths, checkPostMethod, async (req, res) => {
218
  const { user_id, amount, method } = req.body;
219
-
220
  if (!user_id || !amount || method !== 'wallet') {
221
  return res.status(400).json({ error: 'Invalid request. Method must be wallet and amount is required.' });
222
  }
@@ -227,14 +237,10 @@ if (cluster.isMaster) {
227
  try {
228
  const adRef = db4.ref(adNetworkName).child(user_id);
229
  const adSnapshot = await adRef.once('value');
230
-
231
  if (!adSnapshot.exists()) return res.status(404).json({ error: 'No ad earnings found for this user' });
232
 
233
  let adCurrentBalance = Number(adSnapshot.val().balance || 0);
234
-
235
- if (adCurrentBalance < requestAmount) {
236
- return res.status(400).json({ error: 'Insufficient ad balance' });
237
- }
238
 
239
  await adRef.child('balance').set(adCurrentBalance - requestAmount);
240
 
@@ -243,13 +249,15 @@ if (cluster.isMaster) {
243
  return (currentMainBalance || 0) + requestAmount;
244
  });
245
 
246
- res.status(200).json({ message: `Success! ${requestAmount} transferred to main balance from ${adNetworkName}` });
 
 
247
  } catch (error) {
 
248
  res.status(500).json({ error: 'Internal Server Error' });
249
  }
250
  });
251
 
252
- // সার্ভার স্টার্ট (প্রতিটি ওয়ার্কার এই পোর্টে রিকোয়েস্ট শেয়ার করবে)
253
  const PORT = process.env.PORT || 7860;
254
  app.listen(PORT);
255
- }
 
1
+ const express = require('express');
2
  const admin = require('firebase-admin');
3
  const crypto = require('crypto');
4
  const cluster = require('cluster');
5
  const os = require('os');
6
 
 
7
  const numCPUs = os.cpus().length;
8
 
9
  if (cluster.isMaster) {
10
+ console.log(`[Master Process ${process.pid}] Server Active. Detecting ${numCPUs} CPU cores...`);
11
+ for (let i = 0; i < numCPUs; i++) { cluster.fork(); }
12
+ cluster.on('exit', (worker) => { cluster.fork(); });
 
 
 
 
 
 
 
 
 
13
  } else {
 
14
  const app = express();
15
  app.use(express.json());
16
+ const workerId = process.pid;
17
 
18
  // ==========================================
19
+ // ১. ইনমিক CORS (ডোেন ক) মিওয়্যা
20
  // ==========================================
21
+ const allowedDomains = [
22
+ 'earnglow.raybil.tech',
23
+ 'earnglow-es.raybil.tech',
24
+ 'earnglow-rk.raybil.tech',
25
+ 'ffyef.raybil.tech'
26
+ ];
27
+
28
+ app.use((req, res, next) => {
29
+ // হেলথ চেক রাউটগুলোর জন্য ডোমেন লক সম্পূর্ণ ওপেন (CORS Bypass)
30
+ const publicPaths = ['/health', '/ch', '/unps'];
31
+ if (publicPaths.includes(req.path)) {
32
+ res.setHeader('Access-Control-Allow-Origin', '*');
33
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
34
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
35
+ return next();
36
  }
37
+
38
+ // মেইন রিকোয়েস্টগুলোর জন্য কঠোর ডোমেন ভ্যালিডেশন
39
+ const origin = req.headers.origin;
40
+ let originDomain = '';
41
+
42
+ if (origin) {
43
+ try {
44
+ originDomain = new URL(origin).hostname;
45
+ } catch (e) {
46
+ originDomain = '';
47
+ }
48
+ }
49
+
50
+ if (allowedDomains.includes(originDomain)) {
51
+ res.setHeader('Access-Control-Allow-Origin', origin);
52
+ res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
53
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
54
+
55
+ // প্রি-ফ্লাইট (OPTIONS) রিকোয়েস্টের জন্য হ্যান্ডেল
56
+ if (req.method === 'OPTIONS') {
57
+ return res.sendStatus(200);
58
+ }
59
+ next();
60
+ } else {
61
+ // যদি কেউ অননুমোদিত ডোমেন বা পোস্টম্যান দিয়ে ডিরেক্ট হিট করার চেষ্টা করে
62
+ console.log(`[Worker ${workerId}] Blocked Request from Unauthorized Origin: ${originDomain || 'No Origin'}`);
63
+ return res.status(403).json({ error: 'CORS Policy: Access Denied for this Origin.' });
64
+ }
65
+ });
66
+
67
+ // ==========================================
68
+ // ২. ফায়ারবেজ মাল্টিপল অ্যাডমিন সেটআপ
69
+ // ==========================================
70
+ const initFirebase = (envAdmin, envUrl, appName) => {
71
+ if (!process.env[envAdmin] || !process.env[envUrl]) return null;
72
  return admin.initializeApp({
73
  credential: admin.credential.cert(JSON.parse(process.env[envAdmin])),
74
  databaseURL: process.env[envUrl]
 
84
  const db4 = app4 ? app4.database() : null;
85
 
86
  // ==========================================
87
+ // . হেলথ চেক রাউ���স (যেকোনো মেন থেকে অ্াক্সেসযোগ)
88
  // ==========================================
89
+ const healthHandler = (req, res) => { res.send('Ok, yes, done'); };
 
 
90
  app.all('/health', healthHandler);
91
  app.all('/ch', healthHandler);
92
  app.all('/unps', healthHandler);
93
 
94
  // ==========================================
95
+ // . মিডলওয়্যার: শুধুমাত্র POST রিকোয়েস্ট পারমিট করা
96
  // ==========================================
97
  const checkPostMethod = (req, res, next) => {
98
  if (req.method !== 'POST') {
 
102
  };
103
 
104
  // ==========================================
105
+ // . Telegram Security ভ্যালিডেশন মিডলওয়্যার
106
  // ==========================================
107
  const verifyTelegramAuth = (req, res, next) => {
108
  const { init_data, user_id, name } = req.body;
 
109
  if (!init_data) return res.status(401).json({ error: 'Unauthorized: init_data is missing' });
110
 
111
  try {
 
116
  const hash = urlParams.get('hash');
117
  urlParams.delete('hash');
118
 
119
+ const dataToCheck = [...urlParams.entries()].map(([key, value]) => `${key}=${value}`).sort().join('\n');
 
 
 
 
120
  const secretKey = crypto.createHmac('sha256', 'WebAppData').update(botToken).digest();
121
  const calculatedHash = crypto.createHmac('sha256', secretKey).update(dataToCheck).digest('hex');
122
 
123
+ if (calculatedHash !== hash) return res.status(403).json({ error: 'Forbidden: Invalid Telegram signature' });
 
 
124
 
125
  const tgUser = JSON.parse(urlParams.get('user'));
126
+ if (String(tgUser.id) !== String(user_id)) return res.status(403).json({ error: 'Forbidden: User ID mismatch' });
 
 
 
127
 
128
  const tgFullName = tgUser.last_name ? `${tgUser.first_name} ${tgUser.last_name}`.trim() : tgUser.first_name;
129
  if (String(tgFullName) !== String(name) && String(tgUser.first_name) !== String(name)) {
130
  return res.status(403).json({ error: 'Forbidden: Name mismatch' });
131
  }
 
132
  next();
133
  } catch (error) {
134
  return res.status(500).json({ error: 'Internal server error during validation' });
 
136
  };
137
 
138
  // ==========================================
139
+ // . API: ক্রিয়েট অ্যাকাউন্ট (/creataccoumt)
140
  // ==========================================
141
  app.post('/creataccoumt', checkPostMethod, verifyTelegramAuth, async (req, res) => {
142
  const { user_id, refer_id, name, username, profile_pic_url } = req.body;
 
143
  try {
144
  const userRef = db1.ref('user').child(user_id);
145
  const snapshot = await userRef.once('value');
146
 
147
  if (snapshot.exists()) {
148
+ const reply = { message: 'Account already exists. No action taken.' };
149
+ console.log(`[Worker ${workerId}] User ID: ${user_id} | Status: Existing User | Reply: ${reply.message}`);
150
+ return res.status(200).json(reply);
151
  }
152
 
153
  const newUserData = {
154
+ user_id, refer_id: refer_id || null, name: name || null, username: username || null,
155
+ profile_pic_url: profile_pic_url || null, balance: 0, total_withdraw: 0,
156
+ total_withdraw_amount: 0, join_date: admin.database.ServerValue.TIMESTAMP, total_refer: 0
 
 
 
 
 
 
 
157
  };
158
 
159
  await userRef.set(newUserData);
160
+ let logMsg = `[Worker ${workerId}] User ID: ${user_id} | DB1: Updated`;
161
 
162
  if (refer_id) {
163
  const referUserRef = db1.ref('user').child(refer_id);
164
  const referUserSnap = await referUserRef.once('value');
165
 
166
  if (referUserSnap.exists()) {
167
+ await referUserRef.child('total_refer').transaction((currentValue) => { return (currentValue || 0) + 1; });
 
 
 
168
  const referListRef = db3.ref('refer').child(refer_id);
169
  await referListRef.push(user_id);
170
+ logMsg += ` & DB3: Refer Updated`;
171
  }
172
  }
173
 
174
+ const reply = { message: 'Account created successfully!' };
175
+ console.log(`${logMsg} | Reply: ${reply.message}`);
176
+ res.status(201).json(reply);
177
  } catch (error) {
178
+ console.error(`[Worker ${workerId}] User ID: ${user_id || 'Unknown'} | Error in /creataccoumt`);
179
  res.status(500).json({ error: 'Internal Server Error' });
180
  }
181
  });
182
 
183
  // ==========================================
184
+ // . API: উইথড্র মেইন ব্যালেন্স (/withdraw-main)
185
  // ==========================================
186
  app.post('/withdraw-main', checkPostMethod, verifyTelegramAuth, async (req, res) => {
187
  const { user_id, method, address, time, amount } = req.body;
 
193
  try {
194
  const userRef = db1.ref('user').child(user_id);
195
  const snapshot = await userRef.once('value');
 
196
  if (!snapshot.exists()) return res.status(404).json({ error: 'User not found' });
197
 
198
  const userData = snapshot.val();
199
  const currentBalance = Number(userData.balance || 0);
200
  const requestAmount = Number(amount);
201
 
202
+ if (currentBalance < requestAmount) return res.status(400).json({ error: 'Insufficient balance' });
 
 
203
 
204
  await userRef.child('balance').set(currentBalance - requestAmount);
205
 
206
  const pendingRef = db3.ref('withdrow/painding').child(user_id);
207
  await pendingRef.push({
208
+ method, address, time: time || admin.database.ServerValue.TIMESTAMP, amount: requestAmount, status: 'pending'
 
 
 
 
209
  });
210
 
211
+ const reply = { message: 'Withdrawal request successful' };
212
+ console.log(`[Worker ${workerId}] User ID: ${user_id} | DB1: Balance Cut | DB3: Request Saved | Reply: ${reply.message}`);
213
+ res.status(200).json(reply);
214
  } catch (error) {
215
+ console.error(`[Worker ${workerId}] User ID: ${user_id} | Error in /withdraw-main`);
216
  res.status(500).json({ error: 'Internal Server Error' });
217
  }
218
  });
219
 
220
  // ==========================================
221
+ // . API: অ্যাড ব্যালেন্স উইথড্র (Admin 4 -> Admin 1)
222
  // ==========================================
223
  const adWithdrawPaths = [
224
+ '/withdraw-link-visit', '/withdraw-adsgram-1', '/withdraw-adsgram-2',
225
+ '/withdraw-gigapub-1', '/withdraw-gigapub-2', '/withdraw-monetag-1', '/withdraw-monetag-2'
 
 
 
 
 
226
  ];
227
 
228
  app.post(adWithdrawPaths, checkPostMethod, async (req, res) => {
229
  const { user_id, amount, method } = req.body;
 
230
  if (!user_id || !amount || method !== 'wallet') {
231
  return res.status(400).json({ error: 'Invalid request. Method must be wallet and amount is required.' });
232
  }
 
237
  try {
238
  const adRef = db4.ref(adNetworkName).child(user_id);
239
  const adSnapshot = await adRef.once('value');
 
240
  if (!adSnapshot.exists()) return res.status(404).json({ error: 'No ad earnings found for this user' });
241
 
242
  let adCurrentBalance = Number(adSnapshot.val().balance || 0);
243
+ if (adCurrentBalance < requestAmount) return res.status(400).json({ error: 'Insufficient ad balance' });
 
 
 
244
 
245
  await adRef.child('balance').set(adCurrentBalance - requestAmount);
246
 
 
249
  return (currentMainBalance || 0) + requestAmount;
250
  });
251
 
252
+ const reply = { message: `Success! ${requestAmount} transferred to main balance from ${adNetworkName}` };
253
+ console.log(`[Worker ${workerId}] User ID: ${user_id} | DB4: Ad Balance Cut | DB1: Main Balance Added | Reply: ${reply.message}`);
254
+ res.status(200).json(reply);
255
  } catch (error) {
256
+ console.error(`[Worker ${workerId}] User ID: ${user_id} | Error in Ad Withdraw paths`);
257
  res.status(500).json({ error: 'Internal Server Error' });
258
  }
259
  });
260
 
 
261
  const PORT = process.env.PORT || 7860;
262
  app.listen(PORT);
263
+ }