HerzaJ commited on
Commit
4b8862e
·
verified ·
1 Parent(s): c729c1f

Upload 5 files

Browse files
Files changed (5) hide show
  1. Dockerfile +18 -0
  2. generated-icon.png +0 -0
  3. index.js +2109 -0
  4. package-lock.json +0 -0
  5. package.json +29 -0
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Gunakan Node.js versi LTS
2
+ FROM node:18
3
+
4
+ # Set working directory di container
5
+ WORKDIR /app
6
+
7
+ # Copy package.json dan install dependencies dulu
8
+ COPY package*.json ./
9
+ RUN npm install
10
+
11
+ # Copy semua file project
12
+ COPY . .
13
+
14
+ # Expose port default Hugging Face (7860)
15
+ EXPOSE 7860
16
+
17
+ # Jalankan server Express
18
+ CMD ["npm", "start"]
generated-icon.png ADDED
index.js ADDED
@@ -0,0 +1,2109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require('express');
2
+ const mongoose = require('mongoose');
3
+ const bcrypt = require('bcryptjs');
4
+ const jwt = require('jsonwebtoken');
5
+ const nodemailer = require('nodemailer');
6
+ const rateLimit = require('express-rate-limit');
7
+ const path = require('path');
8
+ const fs = require('fs');
9
+ const crypto = require('crypto');
10
+ const syntaxError = require('syntax-error');
11
+
12
+ const app = express();
13
+ app.use(express.json());
14
+
15
+ app.set('trust proxy', true);
16
+
17
+ const getRealIP = (req, res, next) => {
18
+ let ip;
19
+
20
+ if (req.headers['cf-connecting-ip']) {
21
+ ip = req.headers['cf-connecting-ip'];
22
+ } else if (req.headers['x-real-ip']) {
23
+ ip = req.headers['x-real-ip'];
24
+ } else if (req.headers['x-forwarded-for']) {
25
+ ip = req.headers['x-forwarded-for'].split(',')[0].trim();
26
+ } else {
27
+ ip = req.socket.remoteAddress || req.connection.remoteAddress || '0.0.0.0';
28
+ }
29
+
30
+ if (ip.startsWith('::ffff:')) {
31
+ ip = ip.substring(7);
32
+ }
33
+
34
+ req.realIP = ip;
35
+ next();
36
+ };
37
+
38
+ app.use(getRealIP);
39
+ app.use(express.static('public'));
40
+
41
+ const JWT_SECRET = process.env.JWT;
42
+ const MONGODB_URI = process.env.MONGODB;
43
+
44
+ mongoose.connect(MONGODB_URI)
45
+ .then(() => console.log('Connected to MongoDB'))
46
+ .catch(err => console.error('MongoDB connection error:', err));
47
+
48
+ const activitySchema = new mongoose.Schema({
49
+ userId: { type: String, required: true },
50
+ username: String,
51
+ type: {
52
+ type: String,
53
+ enum: ['api_key_generated', 'limit_updated', 'profile_updated', 'redeem_code_used', 'premium_activated', 'api_request', 'temp_banned', 'ban_removed', 'limit_reset', 'role_expired', 'role_assigned', 'api_key_updated'],
54
+ required: true
55
+ },
56
+ description: String,
57
+ metadata: Object,
58
+ timestamp: { type: Date, default: Date.now }
59
+ });
60
+
61
+ const userSchema = new mongoose.Schema({
62
+ username: { type: String, required: true, unique: true },
63
+ email: { type: String, required: true, unique: true },
64
+ password: { type: String, required: true },
65
+ apikey: { type: String, required: true, unique: true },
66
+ profileUrl: { type: String, default: 'https://files.catbox.moe/8l6hhm' },
67
+ verified: { type: Boolean, default: true },
68
+ role: { type: String, enum: ['user', 'admin'], default: 'user' },
69
+ userRole: { type: String, enum: ['cheap', 'premium', 'vip', 'supreme'], default: null },
70
+ userRoleExpiresAt: { type: Date, default: null },
71
+ premium: { type: Boolean, default: false },
72
+ premiumExpiredAt: { type: Date, default: null },
73
+ limit: { type: Number, default: 30 },
74
+ requests: { type: Number, default: 0 },
75
+ requestsToday: { type: Number, default: 0 },
76
+ lastReset: { type: Date, default: Date.now },
77
+ banned: { type: Boolean, default: false },
78
+ tempBanned: { type: Boolean, default: false },
79
+ tempBanUntil: { type: Date, default: null },
80
+ tempBanReason: { type: String, default: null },
81
+ ipAddress: String,
82
+ createdAt: { type: Date, default: Date.now }
83
+ });
84
+
85
+ const pendingVerificationSchema = new mongoose.Schema({
86
+ email: { type: String, required: true, unique: true },
87
+ username: { type: String, required: true },
88
+ password: { type: String, required: true },
89
+ verificationCode: { type: String, required: true },
90
+ ipAddress: String,
91
+ ispInfo: Object,
92
+ expiresAt: { type: Date, default: () => new Date(Date.now() + 15 * 60 * 1000) },
93
+ createdAt: { type: Date, default: Date.now }
94
+ });
95
+
96
+ pendingVerificationSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
97
+
98
+ const redeemCodeSchema = new mongoose.Schema({
99
+ code: { type: String, required: true, unique: true },
100
+ type: { type: String, enum: ['limit', 'premium', 'both'], required: true },
101
+ limitValue: { type: Number, default: 0 },
102
+ codeExpired: { type: Date, required: true },
103
+ premiumExpired: { type: Date, default: null },
104
+ used: { type: Boolean, default: false },
105
+ usedBy: String,
106
+ createdBy: { type: String, required: true },
107
+ createdAt: { type: Date, default: Date.now }
108
+ });
109
+
110
+ redeemCodeSchema.index({ codeExpired: 1 }, { expireAfterSeconds: 0 });
111
+
112
+ const requestLogSchema = new mongoose.Schema({
113
+ userId: String,
114
+ username: String,
115
+ apikey: String,
116
+ endpoint: String,
117
+ ipAddress: String,
118
+ userAgent: String,
119
+ timestamp: { type: Date, default: Date.now },
120
+ success: Boolean,
121
+ responseTime: Number,
122
+ limitDeducted: { type: Number, default: 1 }
123
+ });
124
+
125
+ const banListSchema = new mongoose.Schema({
126
+ ipAddress: String,
127
+ bannedUntil: Date,
128
+ reason: String,
129
+ createdAt: { type: Date, default: Date.now }
130
+ });
131
+
132
+ banListSchema.index({ bannedUntil: 1 }, { expireAfterSeconds: 0 });
133
+
134
+ const roleSchema = new mongoose.Schema({
135
+ userId: { type: String, required: true },
136
+ roleName: { type: String, enum: ['cheap', 'premium', 'vip', 'supreme'], required: true },
137
+ customApiKey: { type: String, unique: true, sparse: true },
138
+ expiresAt: { type: Date, required: true },
139
+ createdAt: { type: Date, default: Date.now },
140
+ createdBy: String
141
+ });
142
+
143
+ const UserRole = mongoose.model('UserRole', roleSchema);
144
+ const Activity = mongoose.model('Activity', activitySchema);
145
+ const User = mongoose.model('User', userSchema);
146
+ const PendingVerification = mongoose.model('PendingVerification', pendingVerificationSchema);
147
+ const RedeemCode = mongoose.model('RedeemCode', redeemCodeSchema);
148
+ const RequestLog = mongoose.model('RequestLog', requestLogSchema);
149
+ const BanList = mongoose.model('BanList', banListSchema);
150
+
151
+ const transporter = nodemailer.createTransport({
152
+ service: 'gmail',
153
+ auth: {
154
+ user: 'dashxapi@gmail.com',
155
+ pass: 'hlje fkqz usbm ycvq'
156
+ }
157
+ });
158
+
159
+ const generateApiKey = () => {
160
+ return 'DHX-' + crypto.randomBytes(3).toString('hex').toUpperCase();
161
+ };
162
+
163
+ const generateVerificationCode = () => {
164
+ return Math.random().toString(36).substring(2, 8).toUpperCase();
165
+ };
166
+
167
+ const logActivity = async (userId, username, type, description, metadata = {}) => {
168
+ try {
169
+ await Activity.create({
170
+ userId,
171
+ username,
172
+ type,
173
+ description,
174
+ metadata,
175
+ timestamp: new Date()
176
+ });
177
+ } catch (error) {
178
+ console.error('Activity logging error:', error);
179
+ }
180
+ };
181
+
182
+ const getTimeAgo = (date) => {
183
+ const now = new Date();
184
+ const diff = now - new Date(date);
185
+ const minutes = Math.floor(diff / 60000);
186
+ const hours = Math.floor(diff / 3600000);
187
+ const days = Math.floor(diff / 86400000);
188
+
189
+ if (minutes < 1) return 'Just now';
190
+ if (minutes < 60) return `${minutes} minutes ago`;
191
+ if (hours < 24) return `${hours} hours ago`;
192
+ return `${days} days ago`;
193
+ };
194
+
195
+ const getNextMidnight = () => {
196
+ const now = new Date();
197
+ const midnight = new Date(now);
198
+ midnight.setHours(24, 0, 0, 0);
199
+ return midnight;
200
+ };
201
+
202
+ const getTimeUntilMidnight = () => {
203
+ const now = new Date();
204
+ const midnight = getNextMidnight();
205
+ const diff = midnight - now;
206
+
207
+ const hours = Math.floor(diff / (1000 * 60 * 60));
208
+ const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
209
+ const seconds = Math.floor((diff % (1000 * 60)) / 1000);
210
+
211
+ return { hours, minutes, seconds, totalMs: diff };
212
+ };
213
+
214
+ const apiRateLimit = rateLimit({
215
+ windowMs: 10 * 1000,
216
+ max: 3,
217
+ message: { success: false, error: 'Too many requests, please try again later' },
218
+ standardHeaders: true,
219
+ legacyHeaders: false,
220
+ keyGenerator: (req) => req.realIP,
221
+ handler: async (req, res) => {
222
+ const ip = req.realIP;
223
+ const bannedUntil = new Date(Date.now() + 10 * 60 * 1000);
224
+ try {
225
+ await BanList.create({ ipAddress: ip, bannedUntil, reason: 'Rate limit exceeded' });
226
+ } catch (error) {
227
+ console.error('Ban list creation error:', error);
228
+ }
229
+
230
+ const randomStatus = Math.random() > 0.5 ? 429 : 403;
231
+ res.status(randomStatus).json({
232
+ success: false,
233
+ error: randomStatus === 429 ? 'Too many requests' : 'Forbidden - IP temporarily banned'
234
+ });
235
+ }
236
+ });
237
+
238
+ const authRateLimit = rateLimit({
239
+ windowMs: 5 * 60 * 1000,
240
+ max: 10,
241
+ message: { success: false, error: '429 Forbidden Request flood detected' },
242
+ standardHeaders: true,
243
+ legacyHeaders: false,
244
+ keyGenerator: (req) => req.realIP,
245
+ handler: async (req, res) => {
246
+ const ip = req.realIP;
247
+ const bannedUntil = new Date(Date.now() + 30 * 60 * 1000);
248
+
249
+ try {
250
+ const existingBan = await BanList.findOne({ ipAddress: ip });
251
+
252
+ if (!existingBan) {
253
+ await BanList.create({
254
+ ipAddress: ip,
255
+ bannedUntil,
256
+ reason: 'Authentication flood detected'
257
+ });
258
+ console.log(`IP ${ip} banned for 30 minutes due to auth flood`);
259
+ }
260
+ } catch (error) {
261
+ console.error('Auth ban list creation error:', error);
262
+ }
263
+
264
+ res.status(429).json({
265
+ success: false,
266
+ error: '429 Forbidden Request flood detected',
267
+ bannedUntil: bannedUntil.toISOString(),
268
+ message: 'Your IP has been temporarily blocked for 30 minutes'
269
+ });
270
+ }
271
+ });
272
+
273
+ const checkBanned = async (req, res, next) => {
274
+ const ip = req.realIP;
275
+ try {
276
+ const banned = await BanList.findOne({
277
+ ipAddress: ip,
278
+ bannedUntil: { $gt: new Date() }
279
+ });
280
+
281
+ if (banned) {
282
+ return res.status(403).json({
283
+ success: false,
284
+ error: 'IP is temporarily banned',
285
+ bannedUntil: banned.bannedUntil,
286
+ reason: banned.reason
287
+ });
288
+ }
289
+ } catch (error) {
290
+ console.error('Check banned error:', error);
291
+ }
292
+ next();
293
+ };
294
+
295
+ const checkTempBan = async (user) => {
296
+ if (user.tempBanned && user.tempBanUntil) {
297
+ if (new Date() > user.tempBanUntil) {
298
+ user.tempBanned = false;
299
+ user.tempBanUntil = null;
300
+ user.tempBanReason = null;
301
+ await user.save();
302
+
303
+ await logActivity(user._id, user.username, 'ban_removed', 'Temporary ban expired automatically');
304
+ return false;
305
+ }
306
+ return true;
307
+ }
308
+ return false;
309
+ };
310
+
311
+ const checkPremiumExpiry = async (user) => {
312
+ if (user.premium && user.premiumExpiredAt) {
313
+ if (new Date() > user.premiumExpiredAt) {
314
+ user.premium = false;
315
+ user.premiumExpiredAt = null;
316
+ await user.save();
317
+ return true;
318
+ }
319
+ }
320
+ return false;
321
+ };
322
+
323
+ const checkRoleExpiry = async (user) => {
324
+ if (user.userRoleExpiresAt && new Date() > user.userRoleExpiresAt) {
325
+ const oldRole = user.userRole;
326
+ const oldLimit = user.limit;
327
+
328
+ user.userRole = null;
329
+ user.userRoleExpiresAt = null;
330
+ user.premium = false;
331
+ user.premiumExpiredAt = null;
332
+
333
+ if (user.limit <= 30) {
334
+ user.limit = 30;
335
+ }
336
+
337
+ await user.save();
338
+ await UserRole.deleteOne({ userId: user._id });
339
+
340
+ await logActivity(user._id, user.username, 'role_expired', `Role ${oldRole} expired, limit ${oldLimit} → ${user.limit}`);
341
+ return true;
342
+ }
343
+ return false;
344
+ };
345
+
346
+ const resetUserLimitIfNeeded = async (user) => {
347
+ const now = new Date();
348
+ const lastReset = new Date(user.lastReset);
349
+
350
+ now.setHours(0, 0, 0, 0);
351
+ lastReset.setHours(0, 0, 0, 0);
352
+
353
+ const needsReset = now.getTime() !== lastReset.getTime();
354
+
355
+ if (needsReset) {
356
+ if (user.userRole) {
357
+ const roleConfig = {
358
+ cheap: 500,
359
+ premium: 1500,
360
+ vip: 2500,
361
+ supreme: 3000
362
+ };
363
+
364
+ const oldLimit = user.limit;
365
+ user.limit = roleConfig[user.userRole] || 30;
366
+ user.requestsToday = 0;
367
+ user.lastReset = new Date();
368
+
369
+ await user.save();
370
+
371
+ await logActivity(user._id, user.username, 'limit_reset', `Daily limit reset from ${oldLimit} to ${user.limit} (Role: ${user.userRole})`);
372
+
373
+ return true;
374
+ } else {
375
+ if (user.limit <= 30) {
376
+ user.limit = 30;
377
+ user.requestsToday = 0;
378
+ user.lastReset = new Date();
379
+
380
+ await user.save();
381
+
382
+ await logActivity(user._id, user.username, 'limit_reset', 'Daily limit reset to 30 (No role)');
383
+
384
+ return true;
385
+ } else {
386
+ user.requestsToday = 0;
387
+ user.lastReset = new Date();
388
+
389
+ await user.save();
390
+
391
+ await logActivity(user._id, user.username, 'limit_reset', `Requests reset, limit remains ${user.limit} (waiting to reach 30)`);
392
+
393
+ return true;
394
+ }
395
+ }
396
+ }
397
+
398
+ return false;
399
+ };
400
+
401
+ const authenticate = async (req, res, next) => {
402
+ const token = req.headers.authorization?.replace('Bearer ', '');
403
+ if (!token) {
404
+ return res.status(401).json({ success: false, error: 'No token provided' });
405
+ }
406
+
407
+ try {
408
+ const decoded = jwt.verify(token, JWT_SECRET);
409
+ req.user = await User.findById(decoded.userId);
410
+ if (!req.user) {
411
+ return res.status(401).json({ success: false, error: 'User not found' });
412
+ }
413
+
414
+ await checkPremiumExpiry(req.user);
415
+ await checkRoleExpiry(req.user);
416
+ await resetUserLimitIfNeeded(req.user);
417
+
418
+ next();
419
+ } catch (error) {
420
+ return res.status(401).json({ success: false, error: 'Invalid token' });
421
+ }
422
+ };
423
+
424
+ const validateApiKey = async (req, res, next) => {
425
+ const { key } = req.query;
426
+ if (!key) {
427
+ return res.status(400).json({ success: false, error: 'API key required' });
428
+ }
429
+
430
+ try {
431
+ const user = await User.findOne({ apikey: key });
432
+ if (!user || user.banned) {
433
+ return res.status(401).json({ success: false, error: 'Invalid or banned API key' });
434
+ }
435
+
436
+ await checkPremiumExpiry(user);
437
+ await checkRoleExpiry(user);
438
+ await resetUserLimitIfNeeded(user);
439
+
440
+ const isTempBanned = await checkTempBan(user);
441
+ if (isTempBanned) {
442
+ const banUntil = new Date(user.tempBanUntil);
443
+ return res.status(403).json({
444
+ success: false,
445
+ error: `Account temporarily banned until ${banUntil.toLocaleString()}. Reason: ${user.tempBanReason || 'No reason provided'}`
446
+ });
447
+ }
448
+
449
+ const limitDeduction = req.limitDeduction || 1;
450
+
451
+ if (user.role !== 'admin' && user.requestsToday >= user.limit) {
452
+ return res.status(429).json({ success: false, error: 'Daily limit exceeded' });
453
+ }
454
+
455
+ user.requests++;
456
+ user.requestsToday += limitDeduction;
457
+ await user.save();
458
+
459
+ await logActivity(user._id, user.username, 'api_request', 'API request made', {
460
+ endpoint: req.path,
461
+ method: req.method,
462
+ ip: req.realIP,
463
+ limitDeducted: limitDeduction
464
+ });
465
+
466
+ req.apiUser = user;
467
+ req.limitDeducted = limitDeduction;
468
+ next();
469
+ } catch (error) {
470
+ console.error('API key validation error:', error);
471
+ return res.status(500).json({ success: false, error: 'Internal server error' });
472
+ }
473
+ };
474
+
475
+ const BLOCKED_ISP_KEYWORDS = [
476
+ 'digitalocean', 'linode', 'vultr', 'ovh', 'hetzner',
477
+ 'contabo', 'amazon', 'aws', 'google cloud', 'microsoft azure',
478
+ 'scaleway', 'ramnode', 'buyvm', 'hostinger', 'namecheap',
479
+ 'godaddy', 'hostgator', 'bluehost', 'siteground',
480
+ 'cloudflare', 'fastly', 'maxcdn', 'keycdn', 'bunnycdn',
481
+ 'rackspace', 'packet', 'equinix', 'servermania',
482
+ 'quadranet', 'psychz', 'choopa', 'fdcservers', 'nobistech',
483
+ 'colocrossing', 'hostus', 'reliablesite', 'serverpronto',
484
+ 'wholesaleinternet', 'online.net', 'nforce', 'leaseweb',
485
+ 'expressvpn', 'nordvpn', 'surfshark', 'cyberghost', 'purevpn',
486
+ 'ipvanish', 'tunnelbear', 'protonvpn', 'mullvad',
487
+ 'tor exit', 'proxy', 'vpn', 'anonymous'
488
+ ];
489
+
490
+ const detectSuspiciousISP = async (ip) => {
491
+ try {
492
+ const response = await fetch(`https://ipinfo.io/${ip}?token=790c300f1388ce`);
493
+ const data = await response.json();
494
+
495
+ const isp = (data.org || '').toLowerCase();
496
+ const company = (data.company?.name || '').toLowerCase();
497
+ const asn = (data.asn?.name || '').toLowerCase();
498
+
499
+ const suspiciousKeywords = BLOCKED_ISP_KEYWORDS.some(keyword =>
500
+ isp.includes(keyword) || company.includes(keyword) || asn.includes(keyword)
501
+ );
502
+
503
+ return {
504
+ isSuspicious: suspiciousKeywords,
505
+ isp: data.org,
506
+ country: data.country,
507
+ region: data.region,
508
+ city: data.city
509
+ };
510
+ } catch (error) {
511
+ console.error('ISP detection error:', error);
512
+ return { isSuspicious: false };
513
+ }
514
+ };
515
+
516
+ const initializeAdmin = async () => {
517
+ try {
518
+ let admin = await User.findOne({ username: 'HERXA' });
519
+ if (!admin) {
520
+ admin = new User({
521
+ username: 'HERXA',
522
+ email: 'admin@dashx.com',
523
+ password: await bcrypt.hash('BTXHZ', 12),
524
+ apikey: 'DHX-M3SA',
525
+ profileUrl: 'https://files.catbox.moe/8l6hhm',
526
+ verified: true,
527
+ role: 'admin',
528
+ premium: true,
529
+ limit: 9999,
530
+ ipAddress: '127.0.0.1'
531
+ });
532
+ await admin.save();
533
+ } else {
534
+ admin.apikey = 'DHX-M3SA';
535
+ admin.limit = 9999;
536
+ admin.role = 'admin';
537
+ admin.premium = true;
538
+ await admin.save();
539
+ }
540
+ } catch (error) {
541
+ console.error('Admin initialization error:', error);
542
+ }
543
+ };
544
+
545
+ app.get('/', (req, res) => {
546
+ res.sendFile(path.join(__dirname, 'public', 'index.html'));
547
+ });
548
+
549
+ app.get('/auth', (req, res) => {
550
+ res.sendFile(path.join(__dirname, 'public', 'auth.html'));
551
+ });
552
+
553
+ app.get('/denied', (req, res) => {
554
+ res.sendFile(path.join(__dirname, 'public', 'denied.html'));
555
+ });
556
+
557
+ app.get('/dashboard', (req, res) => {
558
+ res.sendFile(path.join(__dirname, 'public', 'dashboard.html'));
559
+ });
560
+
561
+ app.get('/profile', (req, res) => {
562
+ res.sendFile(path.join(__dirname, 'public', 'profile.html'));
563
+ });
564
+
565
+ app.get('/check-ip', (req, res) => {
566
+ res.json({
567
+ realIP: req.realIP,
568
+ headers: {
569
+ 'x-forwarded-for': req.headers['x-forwarded-for'],
570
+ 'x-real-ip': req.headers['x-real-ip'],
571
+ 'cf-connecting-ip': req.headers['cf-connecting-ip']
572
+ },
573
+ socket: req.socket.remoteAddress
574
+ });
575
+ });
576
+
577
+ app.get('/api/stats', async (req, res) => {
578
+ try {
579
+ const totalUsers = await User.countDocuments();
580
+ const totalRequests = await RequestLog.countDocuments();
581
+
582
+ const todayStart = new Date();
583
+ todayStart.setHours(0, 0, 0, 0);
584
+
585
+ const todayRequests = await RequestLog.countDocuments({
586
+ timestamp: { $gte: todayStart }
587
+ });
588
+
589
+ res.json({
590
+ success: true,
591
+ stats: {
592
+ totalUsers,
593
+ totalRequests,
594
+ todayRequests
595
+ }
596
+ });
597
+ } catch (error) {
598
+ console.error('Stats error:', error);
599
+ res.status(500).json({
600
+ success: false,
601
+ error: 'Failed to load statistics'
602
+ });
603
+ }
604
+ });
605
+
606
+ app.get('/api/plugins', (req, res) => {
607
+ const plugins = [];
608
+
609
+ try {
610
+ Object.keys(global.plugins).forEach(file => {
611
+ try {
612
+ const plugin = global.plugins[file];
613
+ if (plugin && plugin.enabled) {
614
+ plugins.push({
615
+ name: plugin.name || 'Unknown Plugin',
616
+ description: plugin.description || 'No description',
617
+ type: plugin.type || 'GET',
618
+ routes: plugin.routes || [],
619
+ main: plugin.main || [],
620
+ tags: plugin.tags || [],
621
+ parameters: plugin.parameters || {},
622
+ limit: plugin.limit || 1
623
+ });
624
+ }
625
+ } catch (error) {
626
+ console.error(`Error loading plugin info ${file}:`, error.message);
627
+ }
628
+ });
629
+ } catch (error) {
630
+ console.error('Error reading plugins:', error);
631
+ }
632
+
633
+ res.json({ success: true, plugins });
634
+ });
635
+
636
+ app.get('/DB/delete', validateApiKey, async (req, res) => {
637
+ try {
638
+ if (req.apiUser.role !== 'admin') {
639
+ return res.status(403).json({ success: false, error: 'Admin access required' });
640
+ }
641
+
642
+ const deleteResults = {};
643
+
644
+ const userResult = await User.deleteMany({
645
+ _id: { $ne: req.apiUser._id }
646
+ });
647
+ deleteResults.users = userResult.deletedCount;
648
+
649
+ const pendingResult = await PendingVerification.deleteMany({});
650
+ deleteResults.pendingVerifications = pendingResult.deletedCount;
651
+
652
+ const redeemResult = await RedeemCode.deleteMany({});
653
+ deleteResults.redeemCodes = redeemResult.deletedCount;
654
+
655
+ const logResult = await RequestLog.deleteMany({});
656
+ deleteResults.requestLogs = logResult.deletedCount;
657
+
658
+ const banResult = await BanList.deleteMany({});
659
+ deleteResults.banList = banResult.deletedCount;
660
+
661
+ const activityResult = await Activity.deleteMany({});
662
+ deleteResults.activities = activityResult.deletedCount;
663
+
664
+ res.json({
665
+ success: true,
666
+ message: 'Database cleared successfully',
667
+ deletedCounts: deleteResults,
668
+ timestamp: new Date().toISOString()
669
+ });
670
+
671
+ } catch (error) {
672
+ console.error('Database deletion error:', error);
673
+ res.status(500).json({
674
+ success: false,
675
+ error: 'Failed to delete database data',
676
+ details: error.message
677
+ });
678
+ }
679
+ });
680
+
681
+ app.post('/api/auth/register', checkBanned, authRateLimit, async (req, res) => {
682
+ try {
683
+ const { username, email, password } = req.body;
684
+ const ipAddress = req.realIP;
685
+
686
+ if (!username || !email || !password) {
687
+ return res.status(400).json({
688
+ success: false,
689
+ error: 'Username, email, and password are required'
690
+ });
691
+ }
692
+
693
+ if (password.length < 6) {
694
+ return res.status(400).json({
695
+ success: false,
696
+ error: 'Password must be at least 6 characters long'
697
+ });
698
+ }
699
+
700
+ const ispCheck = await detectSuspiciousISP(ipAddress);
701
+ if (ispCheck.isSuspicious) {
702
+ return res.status(403).json({
703
+ success: false,
704
+ error: 'Registration not allowed from this network. Please use a different connection.',
705
+ blocked_reason: 'suspicious_isp'
706
+ });
707
+ }
708
+
709
+ const existingUser = await User.findOne({
710
+ $or: [{ email }, { username }, { ipAddress }]
711
+ });
712
+
713
+ if (existingUser) {
714
+ return res.status(400).json({
715
+ success: false,
716
+ error: 'User already exists with this email, username, or IP address'
717
+ });
718
+ }
719
+
720
+ const existingPending = await PendingVerification.findOne({ email });
721
+ if (existingPending) {
722
+ await PendingVerification.deleteOne({ _id: existingPending._id });
723
+ }
724
+
725
+ const verificationCode = generateVerificationCode();
726
+ const hashedPassword = await bcrypt.hash(password, 12);
727
+
728
+ const pendingVerification = new PendingVerification({
729
+ email,
730
+ username,
731
+ password: hashedPassword,
732
+ verificationCode,
733
+ ipAddress,
734
+ ispInfo: {
735
+ isp: ispCheck.isp,
736
+ country: ispCheck.country,
737
+ region: ispCheck.region,
738
+ city: ispCheck.city,
739
+ registeredAt: new Date()
740
+ }
741
+ });
742
+
743
+ await pendingVerification.save();
744
+
745
+ const emailTemplate = `
746
+ <!DOCTYPE html>
747
+ <html lang="en">
748
+ <head>
749
+ <meta charset="UTF-8">
750
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
751
+ <title>DashX Verification</title>
752
+ </head>
753
+ <body style="margin: 0; padding: 0; font-family: 'Arial', sans-serif; background: linear-gradient(135deg, #853030 0%, #292727 100%); min-height: 100vh;">
754
+ <div style="max-width: 600px; margin: 0 auto; padding: 20px;">
755
+ <div style="background: #ffffff; border-radius: 20px; box-shadow: 0 20px 40px rgba(0,0,0,0.1); overflow: hidden;">
756
+ <div style="background: linear-gradient(135deg, #853030 0%, #292727 100%); padding: 40px 30px; text-align: center;">
757
+ <h1 style="color: #ffffff; margin: 0; font-size: 32px; font-weight: 700; text-shadow: 0 2px 4px rgba(0,0,0,0.1);">
758
+ 🚀 DashX
759
+ </h1>
760
+ <p style="color: #e8eaf6; margin: 10px 0 0 0; font-size: 16px; opacity: 0.9;">
761
+ API Dashboard Platform
762
+ </p>
763
+ </div>
764
+ <div style="padding: 40px 30px;">
765
+ <div style="text-align: center; margin-bottom: 30px;">
766
+ <h2 style="color: #2c3e50; margin: 0 0 15px 0; font-size: 28px; font-weight: 600;">
767
+ Welcome to DashX!
768
+ </h2>
769
+ <p style="color: #7f8c8d; margin: 0; font-size: 16px; line-height: 1.6;">
770
+ Please verify your email address to complete registration.
771
+ </p>
772
+ </div>
773
+ <div style="background: linear-gradient(135deg, #f8f9ff 0%, #e8eaf6 100%); border-radius: 15px; padding: 30px; text-align: center; margin: 30px 0; border: 2px solid #e3f2fd;">
774
+ <p style="color: #853030; margin: 0 0 15px 0; font-size: 18px; font-weight: 600;">
775
+ Your Verification Code
776
+ </p>
777
+ <div style="background: #ffffff; border-radius: 10px; padding: 20px; margin: 15px 0; box-shadow: 0 4px 12px rgba(0,0,0,0.1);">
778
+ <span style="font-size: 36px; font-weight: 700; color: #853030; letter-spacing: 8px; font-family: 'Courier New', monospace;">
779
+ ${verificationCode}
780
+ </span>
781
+ </div>
782
+ <p style="color: #7986cb; margin: 15px 0 0 0; font-size: 14px;">
783
+ This code will expire in 15 minutes
784
+ </p>
785
+ </div>
786
+ </div>
787
+ <div style="background: #f8f9fa; padding: 25px 30px; text-align: center; border-top: 1px solid #e9ecef;">
788
+ <p style="color: #6c757d;
789
+ margin: 0 0 10px 0; font-size: 14px;">
790
+ Need help? Contact our support team
791
+ </p>
792
+ <p style="color: #adb5bd; margin: 0; font-size: 12px;">
793
+ © 2025 DashX. All rights reserved.
794
+ </p>
795
+ </div>
796
+ </div>
797
+ </div>
798
+ </body>
799
+ </html>
800
+ `;
801
+
802
+ await transporter.sendMail({
803
+ from: 'dashxapi@gmail.com',
804
+ to: email,
805
+ subject: 'DashX - Email Verification',
806
+ html: emailTemplate
807
+ });
808
+
809
+ res.json({
810
+ success: true,
811
+ message: 'Verification code sent to your email. Please verify within 15 minutes.',
812
+ expiresIn: '15 minutes'
813
+ });
814
+
815
+ } catch (error) {
816
+ console.error('Registration error:', error);
817
+ res.status(500).json({ success: false, error: 'Internal server error' });
818
+ }
819
+ });
820
+
821
+ app.post('/api/auth/verify', checkBanned, authRateLimit, async (req, res) => {
822
+ try {
823
+ const { email, code } = req.body;
824
+
825
+ if (!email || !code) {
826
+ return res.status(400).json({
827
+ success: false,
828
+ error: 'Email and verification code are required'
829
+ });
830
+ }
831
+
832
+ const pendingVerification = await PendingVerification.findOne({
833
+ email,
834
+ verificationCode: code
835
+ });
836
+
837
+ if (!pendingVerification) {
838
+ return res.status(400).json({
839
+ success: false,
840
+ error: 'Invalid verification code or code has expired'
841
+ });
842
+ }
843
+
844
+ const existingUser = await User.findOne({
845
+ $or: [{ email: pendingVerification.email }, { username: pendingVerification.username }]
846
+ });
847
+
848
+ if (existingUser) {
849
+ await PendingVerification.deleteOne({ _id: pendingVerification._id });
850
+ return res.status(400).json({
851
+ success: false,
852
+ error: 'User already exists in database'
853
+ });
854
+ }
855
+
856
+ const apikey = generateApiKey();
857
+
858
+ const user = new User({
859
+ username: pendingVerification.username,
860
+ email: pendingVerification.email,
861
+ password: pendingVerification.password,
862
+ apikey: apikey,
863
+ profileUrl: 'https://files.catbox.moe/8l6hhm',
864
+ verified: true,
865
+ ipAddress: pendingVerification.ipAddress,
866
+ role: 'user',
867
+ premium: false,
868
+ limit: 30,
869
+ requests: 0,
870
+ requestsToday: 0,
871
+ lastReset: new Date(),
872
+ banned: false
873
+ });
874
+
875
+ await user.save();
876
+ await PendingVerification.deleteOne({ _id: pendingVerification._id });
877
+
878
+ await logActivity(user._id, user.username, 'api_key_generated', 'Account created and verified successfully', {
879
+ apikey: user.apikey,
880
+ registrationIP: pendingVerification.ipAddress
881
+ });
882
+
883
+ const token = jwt.sign({ userId: user._id }, JWT_SECRET, { expiresIn: '30d' });
884
+
885
+ res.json({
886
+ success: true,
887
+ token,
888
+ user: {
889
+ id: user._id,
890
+ username: user.username,
891
+ email: user.email,
892
+ apikey: user.apikey,
893
+ profileUrl: user.profileUrl,
894
+ premium: user.premium,
895
+ limit: user.limit
896
+ },
897
+ message: 'Account created and verified successfully!'
898
+ });
899
+
900
+ } catch (error) {
901
+ console.error('Verification error:', error);
902
+ res.status(500).json({ success: false, error: 'Internal server error' });
903
+ }
904
+ });
905
+
906
+ app.get('/api/admin/search-users', authenticate, async (req, res) => {
907
+ try {
908
+ if (req.user.role !== 'admin') {
909
+ return res.status(403).json({ success: false, error: 'Admin access required' });
910
+ }
911
+
912
+ const { query } = req.query;
913
+ if (!query) {
914
+ return res.json({ success: true, users: [] });
915
+ }
916
+
917
+ const users = await User.find({
918
+ $or: [
919
+ { username: { $regex: query, $options: 'i' } },
920
+ { email: { $regex: query, $options: 'i' } }
921
+ ],
922
+ role: { $ne: 'admin' }
923
+ }).limit(10).select('username email limit premium role');
924
+
925
+ res.json({ success: true, users });
926
+ } catch (error) {
927
+ console.error('Search users error:', error);
928
+ res.status(500).json({ success: false, error: 'Internal server error' });
929
+ }
930
+ });
931
+
932
+ app.get('/api/admin/user-role/:userId', authenticate, async (req, res) => {
933
+ try {
934
+ if (req.user.role !== 'admin') {
935
+ return res.status(403).json({ success: false, error: 'Admin access required' });
936
+ }
937
+
938
+ const userRole = await UserRole.findOne({ userId: req.params.userId });
939
+ res.json({ success: true, role: userRole });
940
+ } catch (error) {
941
+ res.status(500).json({ success: false, error: 'Internal server error' });
942
+ }
943
+ });
944
+
945
+ app.post('/api/auth/login', checkBanned, authRateLimit, async (req, res) => {
946
+ try {
947
+ const { email, password } = req.body;
948
+
949
+ if (!email || !password) {
950
+ return res.status(400).json({
951
+ success: false,
952
+ error: 'Email and password are required'
953
+ });
954
+ }
955
+
956
+ const user = await User.findOne({ email });
957
+ if (!user) {
958
+ return res.status(400).json({ success: false, error: 'Invalid credentials' });
959
+ }
960
+
961
+ const isValidPassword = await bcrypt.compare(password, user.password);
962
+ if (!isValidPassword) {
963
+ return res.status(400).json({ success: false, error: 'Invalid credentials' });
964
+ }
965
+
966
+ if (user.banned) {
967
+ return res.status(403).json({ success: false, error: 'Account is permanently banned' });
968
+ }
969
+
970
+ await checkPremiumExpiry(user);
971
+ await checkRoleExpiry(user);
972
+ await resetUserLimitIfNeeded(user);
973
+
974
+ const isTempBanned = await checkTempBan(user);
975
+ if (isTempBanned) {
976
+ const banUntil = new Date(user.tempBanUntil);
977
+ return res.status(403).json({
978
+ success: false,
979
+ error: `Account temporarily banned until ${banUntil.toLocaleString()}. Reason: ${user.tempBanReason || 'No reason provided'}`
980
+ });
981
+ }
982
+
983
+ const token = jwt.sign({ userId: user._id }, JWT_SECRET, { expiresIn: '30d' });
984
+
985
+ res.json({
986
+ success: true,
987
+ token,
988
+ user: {
989
+ id: user._id,
990
+ username: user.username,
991
+ email: user.email,
992
+ apikey: user.apikey,
993
+ profileUrl: user.profileUrl,
994
+ premium: user.premium,
995
+ premiumExpiredAt: user.premiumExpiredAt,
996
+ limit: user.limit,
997
+ role: user.role
998
+ }
999
+ });
1000
+ } catch (error) {
1001
+ console.error('Login error:', error);
1002
+ res.status(500).json({ success: false, error: 'Internal server error' });
1003
+ }
1004
+ });
1005
+
1006
+ app.post('/api/auth/admin-login', checkBanned, authRateLimit, async (req, res) => {
1007
+ try {
1008
+ const { username, password } = req.body;
1009
+
1010
+ if (username === 'HERXA' && password === 'BTXHZ') {
1011
+ let admin = await User.findOne({ username: 'HERXA' });
1012
+ if (!admin) {
1013
+ admin = new User({
1014
+ username: 'HERXA',
1015
+ email: 'admin@dashx.com',
1016
+ password: await bcrypt.hash('BTXHZ', 12),
1017
+ apikey: 'DHX-M3SA',
1018
+ profileUrl: 'https://files.catbox.moe/8l6hhm',
1019
+ verified: true,
1020
+ role: 'admin',
1021
+ premium: true,
1022
+ limit: 9999,
1023
+ ipAddress: req.realIP
1024
+ });
1025
+ await admin.save();
1026
+ } else {
1027
+ admin.apikey = 'DHX-M3SA';
1028
+ admin.limit = 9999;
1029
+ admin.role = 'admin';
1030
+ admin.premium = true;
1031
+ await admin.save();
1032
+ }
1033
+
1034
+ const token = jwt.sign({ userId: admin._id }, JWT_SECRET, { expiresIn: '30d' });
1035
+ return res.json({
1036
+ success: true,
1037
+ token,
1038
+ user: {
1039
+ id: admin._id,
1040
+ username: admin.username,
1041
+ role: admin.role,
1042
+ apikey: admin.apikey,
1043
+ profileUrl: admin.profileUrl,
1044
+ limit: admin.limit
1045
+ }
1046
+ });
1047
+ }
1048
+
1049
+ const admin = await User.findOne({ username, role: 'admin' });
1050
+ if (!admin || !await bcrypt.compare(password, admin.password)) {
1051
+ return res.status(400).json({ success: false, error: 'Invalid admin credentials' });
1052
+ }
1053
+
1054
+ const token = jwt.sign({ userId: admin._id }, JWT_SECRET, { expiresIn: '30d' });
1055
+ res.json({
1056
+ success: true,
1057
+ token,
1058
+ user: {
1059
+ id: admin._id,
1060
+ username: admin.username,
1061
+ role: admin.role,
1062
+ apikey: admin.apikey,
1063
+ profileUrl: admin.profileUrl,
1064
+ limit: admin.limit
1065
+ }
1066
+ });
1067
+ } catch (error) {
1068
+ console.error('Admin login error:', error);
1069
+ res.status(500).json({ success: false, error: 'Internal server error' });
1070
+ }
1071
+ });
1072
+
1073
+ app.get('/api/user/profile', authenticate, async (req, res) => {
1074
+ try {
1075
+ const personalTodayStart = new Date();
1076
+ personalTodayStart.setHours(0, 0, 0, 0);
1077
+
1078
+ const userTodayRequestCount = await RequestLog.countDocuments({
1079
+ $or: [
1080
+ { userId: req.user._id.toString() },
1081
+ { userId: req.user._id }
1082
+ ],
1083
+ timestamp: { $gte: personalTodayStart }
1084
+ });
1085
+
1086
+ const userTotalRequestCount = await RequestLog.countDocuments({
1087
+ $or: [
1088
+ { userId: req.user._id.toString() },
1089
+ { userId: req.user._id }
1090
+ ]
1091
+ });
1092
+
1093
+ const timeUntilReset = getTimeUntilMidnight();
1094
+
1095
+ res.json({
1096
+ success: true,
1097
+ user: {
1098
+ id: req.user._id,
1099
+ username: req.user.username,
1100
+ email: req.user.email,
1101
+ apikey: req.user.apikey,
1102
+ profileUrl: req.user.profileUrl,
1103
+ premium: req.user.premium,
1104
+ premiumExpiredAt: req.user.premiumExpiredAt,
1105
+ limit: req.user.limit,
1106
+ requests: userTotalRequestCount,
1107
+ requestsToday: userTodayRequestCount,
1108
+ lastReset: req.user.lastReset,
1109
+ nextResetTime: getNextMidnight(),
1110
+ hoursUntilReset: timeUntilReset.hours,
1111
+ minutesUntilReset: timeUntilReset.minutes,
1112
+ secondsUntilReset: timeUntilReset.seconds,
1113
+ role: req.user.role,
1114
+ userRole: req.user.userRole,
1115
+ roleExpiresAt: req.user.userRoleExpiresAt,
1116
+ createdAt: req.user.createdAt,
1117
+ tempBanned: req.user.tempBanned,
1118
+ tempBanUntil: req.user.tempBanUntil,
1119
+ tempBanReason: req.user.tempBanReason
1120
+ }
1121
+ });
1122
+ } catch (error) {
1123
+ console.error('Profile fetch error:', error);
1124
+ res.status(500).json({
1125
+ success: false,
1126
+ error: 'Failed to load profile'
1127
+ });
1128
+ }
1129
+ });
1130
+
1131
+ app.get('/api/user/activities', authenticate, async (req, res) => {
1132
+ try {
1133
+ const activities = await Activity.find({ userId: req.user._id })
1134
+ .sort({ timestamp: -1 })
1135
+ .limit(50);
1136
+
1137
+ const requestLogs = await RequestLog.find({ userId: req.user._id })
1138
+ .sort({ timestamp: -1 })
1139
+ .limit(20);
1140
+
1141
+ res.json({
1142
+ success: true,
1143
+ activities: activities.map(activity => ({
1144
+ type: activity.type,
1145
+ description: activity.description,
1146
+ timestamp: activity.timestamp,
1147
+ timeAgo: getTimeAgo(activity.timestamp),
1148
+ metadata: activity.metadata
1149
+ })),
1150
+ requestLogs: requestLogs.map(log => ({
1151
+ endpoint: log.endpoint,
1152
+ timestamp: log.timestamp,
1153
+ timeAgo: getTimeAgo(log.timestamp),
1154
+ success: log.success,
1155
+ ipAddress: log.ipAddress,
1156
+ limitDeducted: log.limitDeducted
1157
+ }))
1158
+ });
1159
+ } catch (error) {
1160
+ console.error('Activities fetch error:', error);
1161
+ res.status(500).json({ success: false, error: 'Internal server error' });
1162
+ }
1163
+ });
1164
+
1165
+ app.get('/api/user/usage-stats', authenticate, async (req, res) => {
1166
+ try {
1167
+ const userId = req.user._id.toString();
1168
+
1169
+ // Hitung request hari ini untuk user ini
1170
+ const todayStart = new Date();
1171
+ todayStart.setHours(0, 0, 0, 0);
1172
+
1173
+ const userTodayRequests = await RequestLog.countDocuments({
1174
+ userId,
1175
+ timestamp: { $gte: todayStart }
1176
+ });
1177
+
1178
+ // Hitung total request untuk user ini
1179
+ const userTotalRequests = await RequestLog.countDocuments({
1180
+ userId
1181
+ });
1182
+
1183
+ const topEndpoints = await RequestLog.aggregate([
1184
+ { $match: { userId } },
1185
+ { $group: { _id: '$endpoint', count: { $sum: 1 } } },
1186
+ { $sort: { count: -1 } },
1187
+ { $limit: 10 }
1188
+ ]);
1189
+
1190
+ const recentIPs = await RequestLog.aggregate([
1191
+ { $match: { userId } },
1192
+ { $group: {
1193
+ _id: '$ipAddress',
1194
+ count: { $sum: 1 },
1195
+ lastUsed: { $max: '$timestamp' }
1196
+ }},
1197
+ { $sort: { lastUsed: -1 } },
1198
+ { $limit: 10 }
1199
+ ]);
1200
+
1201
+ const dailyUsage = await RequestLog.aggregate([
1202
+ { $match: {
1203
+ userId,
1204
+ timestamp: { $gte: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) }
1205
+ }},
1206
+ { $group: {
1207
+ _id: { $dateToString: { format: '%Y-%m-%d', date: '$timestamp' } },
1208
+ requests: { $sum: 1 },
1209
+ limitUsed: { $sum: '$limitDeducted' }
1210
+ }},
1211
+ { $sort: { _id: 1 } }
1212
+ ]);
1213
+
1214
+ res.json({
1215
+ success: true,
1216
+ stats: {
1217
+ totalRequests: userTotalRequests,
1218
+ todayRequests: userTodayRequests,
1219
+ topEndpoints: topEndpoints.map(ep => ({
1220
+ endpoint: ep._id,
1221
+ count: ep.count
1222
+ })),
1223
+ recentIPs: recentIPs.map(ip => ({
1224
+ address: ip._id,
1225
+ count: ip.count,
1226
+ lastUsed: ip.lastUsed,
1227
+ timeAgo: getTimeAgo(ip.lastUsed)
1228
+ })),
1229
+ dailyUsage: dailyUsage.map(day => ({
1230
+ date: day._id,
1231
+ requests: day.requests,
1232
+ limitUsed: day.limitUsed
1233
+ }))
1234
+ }
1235
+ });
1236
+ } catch (error) {
1237
+ console.error('Usage stats error:', error);
1238
+ res.status(500).json({ success: false, error: 'Internal server error' });
1239
+ }
1240
+ });
1241
+
1242
+ app.put('/api/user/profile', authenticate, async (req, res) => {
1243
+ try {
1244
+ const { username, profileUrl, customApiKey } = req.body;
1245
+ let updated = false;
1246
+
1247
+ if (username && username !== req.user.username) {
1248
+ const existing = await User.findOne({ username });
1249
+ if (existing) {
1250
+ return res.status(400).json({ success: false, error: 'Username already taken' });
1251
+ }
1252
+
1253
+ const oldUsername = req.user.username;
1254
+ req.user.username = username;
1255
+ updated = true;
1256
+
1257
+ await logActivity(req.user._id, req.user.username, 'profile_updated', `Username changed from ${oldUsername} to ${username}`, {
1258
+ oldUsername,
1259
+ newUsername: username
1260
+ });
1261
+ }
1262
+
1263
+ if (profileUrl !== undefined && profileUrl !== req.user.profileUrl) {
1264
+ req.user.profileUrl = profileUrl;
1265
+ updated = true;
1266
+
1267
+ await logActivity(req.user._id, req.user.username, 'profile_updated', 'Profile URL updated', {
1268
+ newProfileUrl: profileUrl
1269
+ });
1270
+ }
1271
+
1272
+ if (customApiKey && (req.user.premium || req.user.role === 'admin')) {
1273
+ const existing = await User.findOne({ apikey: customApiKey });
1274
+ if (existing && existing._id.toString() !== req.user._id.toString()) {
1275
+ return res.status(400).json({ success: false, error: 'API key already in use' });
1276
+ }
1277
+
1278
+ const oldApiKey = req.user.apikey;
1279
+ req.user.apikey = customApiKey;
1280
+ updated = true;
1281
+
1282
+ await logActivity(req.user._id, req.user.username, 'api_key_updated', 'Custom API key set', {
1283
+ oldApiKey,
1284
+ newApiKey: customApiKey
1285
+ });
1286
+ }
1287
+
1288
+ if (updated) {
1289
+ await req.user.save();
1290
+ }
1291
+
1292
+ res.json({ success: true, message: 'Profile updated successfully' });
1293
+ } catch (error) {
1294
+ console.error('Profile update error:', error);
1295
+ res.status(500).json({ success: false, error: 'Internal server error' });
1296
+ }
1297
+ });
1298
+
1299
+ app.delete('/api/user/account', authenticate, async (req, res) => {
1300
+ try {
1301
+ if (req.user.role === 'admin') {
1302
+ return res.status(403).json({ success: false, error: 'Cannot delete admin account' });
1303
+ }
1304
+
1305
+ await User.deleteOne({ _id: req.user._id });
1306
+ await Activity.deleteMany({ userId: req.user._id });
1307
+ res.json({ success: true, message: 'Account deleted successfully' });
1308
+ } catch (error) {
1309
+ console.error('Account deletion error:', error);
1310
+ res.status(500).json({ success: false, error: 'Internal server error' });
1311
+ }
1312
+ });
1313
+
1314
+ app.get('/api/stats/all', async (req, res) => {
1315
+ try {
1316
+ const totalUsers = await User.countDocuments();
1317
+ const totalRequests = await RequestLog.countDocuments();
1318
+
1319
+ const todayStart = new Date();
1320
+ todayStart.setHours(0, 0, 0, 0);
1321
+
1322
+ const todayRequests = await RequestLog.countDocuments({
1323
+ timestamp: { $gte: todayStart }
1324
+ });
1325
+
1326
+ const topEndpoints = await RequestLog.aggregate([
1327
+ { $group: {
1328
+ _id: '$endpoint',
1329
+ count: { $sum: 1 },
1330
+ successCount: {
1331
+ $sum: { $cond: ['$success', 1, 0] }
1332
+ },
1333
+ failCount: {
1334
+ $sum: { $cond: ['$success', 0, 1] }
1335
+ }
1336
+ }},
1337
+ { $sort: { count: -1 } },
1338
+ { $limit: 10 }
1339
+ ]);
1340
+
1341
+ const successCount = await RequestLog.countDocuments({ success: true });
1342
+ const failCount = await RequestLog.countDocuments({ success: false });
1343
+ const successRate = totalRequests > 0 ? ((successCount / totalRequests) * 100).toFixed(2) : 0;
1344
+ const failRate = totalRequests > 0 ? ((failCount / totalRequests) * 100).toFixed(2) : 0;
1345
+
1346
+ const sevenDaysAgo = new Date();
1347
+ sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
1348
+
1349
+ const dailyRequests = await RequestLog.aggregate([
1350
+ {
1351
+ $match: {
1352
+ timestamp: { $gte: sevenDaysAgo }
1353
+ }
1354
+ },
1355
+ {
1356
+ $group: {
1357
+ _id: { $dateToString: { format: '%Y-%m-%d', date: '$timestamp' } },
1358
+ count: { $sum: 1 },
1359
+ success: { $sum: { $cond: ['$success', 1, 0] } },
1360
+ fail: { $sum: { $cond: ['$success', 0, 1] } }
1361
+ }
1362
+ },
1363
+ { $sort: { _id: 1 } }
1364
+ ]);
1365
+
1366
+ const yesterday = new Date();
1367
+ yesterday.setHours(yesterday.getHours() - 24);
1368
+
1369
+ const hourlyRequests = await RequestLog.aggregate([
1370
+ {
1371
+ $match: {
1372
+ timestamp: { $gte: yesterday }
1373
+ }
1374
+ },
1375
+ {
1376
+ $group: {
1377
+ _id: { $dateToString: { format: '%Y-%m-%d %H:00', date: '$timestamp' } },
1378
+ count: { $sum: 1 }
1379
+ }
1380
+ },
1381
+ { $sort: { _id: 1 } }
1382
+ ]);
1383
+
1384
+ res.json({
1385
+ success: true,
1386
+ stats: {
1387
+ totalUsers,
1388
+ totalRequests,
1389
+ todayRequests,
1390
+ topEndpoints: topEndpoints.map(ep => ({
1391
+ endpoint: ep._id,
1392
+ count: ep.count,
1393
+ successCount: ep.successCount,
1394
+ failCount: ep.failCount
1395
+ })),
1396
+ successRate: parseFloat(successRate),
1397
+ failRate: parseFloat(failRate),
1398
+ successCount,
1399
+ failCount,
1400
+ dailyRequests: dailyRequests.map(day => ({
1401
+ date: day._id,
1402
+ count: day.count,
1403
+ success: day.success,
1404
+ fail: day.fail
1405
+ })),
1406
+ hourlyRequests: hourlyRequests.map(hour => ({
1407
+ hour: hour._id,
1408
+ count: hour.count
1409
+ }))
1410
+ }
1411
+ });
1412
+ } catch (error) {
1413
+ console.error('All stats error:', error);
1414
+ res.status(500).json({
1415
+ success: false,
1416
+ error: 'Failed to load statistics'
1417
+ });
1418
+ }
1419
+ });
1420
+
1421
+ app.post('/api/user/regenerate-key', authenticate, async (req, res) => {
1422
+ try {
1423
+ if (!req.user.premium && req.user.role !== 'admin') {
1424
+ return res.status(403).json({ success: false, error: 'Premium feature only' });
1425
+ }
1426
+
1427
+ const oldApikey = req.user.apikey;
1428
+
1429
+ if (req.user.role === 'admin') {
1430
+ req.user.apikey = 'DHX-M3SA';
1431
+ } else {
1432
+ req.user.apikey = generateApiKey();
1433
+ }
1434
+
1435
+ await req.user.save();
1436
+
1437
+ await logActivity(req.user._id, req.user.username, 'api_key_generated', 'API key regenerated', {
1438
+ oldApikey,
1439
+ newApikey: req.user.apikey
1440
+ });
1441
+
1442
+ res.json({ success: true, apikey: req.user.apikey });
1443
+ } catch (error) {
1444
+ console.error('API key regeneration error:', error);
1445
+ res.status(500).json({ success: false, error: 'Internal server error' });
1446
+ }
1447
+ });
1448
+
1449
+ app.post('/api/user/redeem', authenticate, async (req, res) => {
1450
+ try {
1451
+ const { code } = req.body;
1452
+
1453
+ if (!code) {
1454
+ return res.status(400).json({
1455
+ success: false,
1456
+ error: 'Redeem code is required'
1457
+ });
1458
+ }
1459
+
1460
+ const redeemCode = await RedeemCode.findOne({ code });
1461
+
1462
+ if (!redeemCode) {
1463
+ return res.status(400).json({
1464
+ success: false,
1465
+ error: 'This redeem code is not available anymore or never exist'
1466
+ });
1467
+ }
1468
+
1469
+ if (redeemCode.used) {
1470
+ return res.status(400).json({
1471
+ success: false,
1472
+ error: 'This redeem code has already been used'
1473
+ });
1474
+ }
1475
+
1476
+ if (new Date() > redeemCode.codeExpired) {
1477
+ return res.status(400).json({
1478
+ success: false,
1479
+ error: 'This redeem code is not available anymore or never exist'
1480
+ });
1481
+ }
1482
+
1483
+ let benefits = [];
1484
+
1485
+ if (redeemCode.type === 'limit' || redeemCode.type === 'both') {
1486
+ req.user.limit += redeemCode.limitValue;
1487
+ benefits.push(`+${redeemCode.limitValue} API requests`);
1488
+ }
1489
+
1490
+ if (redeemCode.type === 'premium' || redeemCode.type === 'both') {
1491
+ req.user.premium = true;
1492
+ req.user.premiumExpiredAt = redeemCode.premiumExpired;
1493
+ benefits.push(`Premium activated until ${redeemCode.premiumExpired.toLocaleString()}`);
1494
+ }
1495
+
1496
+ if (redeemCode.type === 'premium' && redeemCode.limitValue > 0) {
1497
+ req.user.limit += redeemCode.limitValue;
1498
+ benefits.push(`+${redeemCode.limitValue} API requests (bonus)`);
1499
+ }
1500
+
1501
+ redeemCode.used = true;
1502
+ redeemCode.usedBy = req.user.username;
1503
+
1504
+ await req.user.save();
1505
+ await redeemCode.save();
1506
+
1507
+ await logActivity(req.user._id, req.user.username, 'redeem_code_used', `Redeem code used: ${benefits.join(', ')}`, {
1508
+ code: code,
1509
+ type: redeemCode.type,
1510
+ benefits
1511
+ });
1512
+
1513
+ res.json({
1514
+ success: true,
1515
+ message: 'Redeem code used successfully',
1516
+ benefits
1517
+ });
1518
+ } catch (error) {
1519
+ console.error('Redeem code error:', error);
1520
+ res.status(500).json({ success: false, error: 'Internal server error' });
1521
+ }
1522
+ });
1523
+
1524
+ app.get('/api/admin/stats', authenticate, async (req, res) => {
1525
+ try {
1526
+ if (req.user.role !== 'admin') {
1527
+ return res.status(403).json({ success: false, error: 'Admin access required' });
1528
+ }
1529
+
1530
+ const totalUsers = await User.countDocuments();
1531
+ const pendingUsers = await PendingVerification.countDocuments();
1532
+ const totalRequests = await RequestLog.countDocuments();
1533
+
1534
+ const todayStart = new Date();
1535
+ todayStart.setHours(0, 0, 0, 0);
1536
+
1537
+ const todayRequests = await RequestLog.countDocuments({
1538
+ timestamp: { $gte: todayStart }
1539
+ });
1540
+
1541
+ res.json({
1542
+ success: true,
1543
+ stats: {
1544
+ totalUsers,
1545
+ pendingUsers,
1546
+ totalRequests,
1547
+ todayRequests
1548
+ }
1549
+ });
1550
+ } catch (error) {
1551
+ console.error('Admin stats error:', error);
1552
+ res.status(500).json({ success: false, error: 'Internal server error' });
1553
+ }
1554
+ });
1555
+
1556
+ app.get('/api/server-stats', async (req, res) => {
1557
+ try {
1558
+
1559
+ const totalUsers = await User.countDocuments();
1560
+ const regularUsers = await User.countDocuments({
1561
+ $and: [
1562
+ { premium: false },
1563
+ { $or: [{ userRole: null }, { userRole: { $exists: false } }] }
1564
+ ]
1565
+ });
1566
+ const premiumUsers = await User.countDocuments({ premium: true });
1567
+
1568
+ const cheapCount = await User.countDocuments({ userRole: 'cheap' });
1569
+ const premiumRoleCount = await User.countDocuments({ userRole: 'premium' });
1570
+ const vipCount = await User.countDocuments({ userRole: 'vip' });
1571
+ const supremeCount = await User.countDocuments({ userRole: 'supreme' });
1572
+
1573
+ let dbSize = '0 MB';
1574
+ let storageSize = '0 GB';
1575
+
1576
+ try {
1577
+ const dbStats = await mongoose.connection.db.stats();
1578
+ dbSize = (dbStats.dataSize / 1024 / 1024).toFixed(2) + ' MB';
1579
+ storageSize = (dbStats.storageSize / 1024 / 1024 / 1024).toFixed(2) + ' GB';
1580
+ } catch (dbError) {
1581
+ console.log('DB stats not available:', dbError.message);
1582
+ }
1583
+
1584
+ const memUsage = process.memoryUsage();
1585
+ const ramUsage = (memUsage.heapUsed / 1024 / 1024).toFixed(2) + ' MB';
1586
+
1587
+ const cpuUsage = process.cpuUsage();
1588
+ const cpuPercent = ((cpuUsage.user + cpuUsage.system) / 1000000).toFixed(2);
1589
+
1590
+ res.json({
1591
+ success: true,
1592
+ stats: {
1593
+ totalUsers,
1594
+ regularUsers,
1595
+ premiumUsers,
1596
+ roleDistribution: {
1597
+ regular: regularUsers,
1598
+ cheap: cheapCount,
1599
+ premium: premiumRoleCount,
1600
+ vip: vipCount,
1601
+ supreme: supremeCount
1602
+ },
1603
+ database: {
1604
+ size: dbSize
1605
+ },
1606
+ system: {
1607
+ ramUsage: ramUsage,
1608
+ cpuUsage: cpuPercent,
1609
+ storageUsed: storageSize
1610
+ }
1611
+ }
1612
+ });
1613
+ } catch (error) {
1614
+ console.error('Server stats error:', error);
1615
+ res.status(500).json({
1616
+ success: false,
1617
+ error: 'Internal server error',
1618
+ details: error.message
1619
+ });
1620
+ }
1621
+ });
1622
+
1623
+ app.post('/api/admin/set-role', authenticate, async (req, res) => {
1624
+ try {
1625
+ if (req.user.role !== 'admin') {
1626
+ return res.status(403).json({ success: false, error: 'Admin access required' });
1627
+ }
1628
+
1629
+ const { userId, roleName, customApiKey } = req.body;
1630
+
1631
+ if (!userId || !roleName) {
1632
+ return res.status(400).json({ success: false, error: 'User ID and role name required' });
1633
+ }
1634
+
1635
+ const user = await User.findById(userId);
1636
+ if (!user) {
1637
+ return res.status(404).json({ success: false, error: 'User not found' });
1638
+ }
1639
+
1640
+ if (user.role === 'admin') {
1641
+ return res.status(403).json({ success: false, error: 'Cannot modify admin users' });
1642
+ }
1643
+
1644
+ const roleConfig = {
1645
+ cheap: { limit: 500, premium: true },
1646
+ premium: { limit: 1500, premium: true },
1647
+ vip: { limit: 2500, premium: true },
1648
+ supreme: { limit: 3000, premium: true }
1649
+ };
1650
+
1651
+ if (!roleConfig[roleName]) {
1652
+ return res.status(400).json({ success: false, error: 'Invalid role name' });
1653
+ }
1654
+
1655
+ const expiresAt = new Date();
1656
+ expiresAt.setMonth(expiresAt.getMonth() + 1);
1657
+
1658
+ let finalApiKey = user.apikey;
1659
+ if (customApiKey && customApiKey.trim()) {
1660
+ const existing = await User.findOne({ apikey: customApiKey });
1661
+ if (existing && existing._id.toString() !== userId) {
1662
+ return res.status(400).json({ success: false, error: 'API key already in use' });
1663
+ }
1664
+ user.apikey = customApiKey;
1665
+ finalApiKey = customApiKey;
1666
+ }
1667
+
1668
+ user.userRole = roleName;
1669
+ user.userRoleExpiresAt = expiresAt;
1670
+ user.limit = roleConfig[roleName].limit;
1671
+ user.premium = roleConfig[roleName].premium;
1672
+ user.premiumExpiredAt = expiresAt;
1673
+
1674
+ await user.save();
1675
+
1676
+ const userRole = await UserRole.findOne({ userId: user._id });
1677
+ if (userRole) {
1678
+ userRole.roleName = roleName;
1679
+ userRole.customApiKey = customApiKey || null;
1680
+ userRole.expiresAt = expiresAt;
1681
+ userRole.createdBy = req.user.username;
1682
+ await userRole.save();
1683
+ } else {
1684
+ await UserRole.create({
1685
+ userId: user._id,
1686
+ roleName,
1687
+ customApiKey: customApiKey || null,
1688
+ expiresAt,
1689
+ createdBy: req.user.username
1690
+ });
1691
+ }
1692
+
1693
+ await logActivity(user._id, user.username, 'role_assigned', `Role ${roleName} assigned by admin`, {
1694
+ roleName,
1695
+ limit: user.limit,
1696
+ expiresAt,
1697
+ customApiKey: customApiKey || 'none',
1698
+ assignedBy: req.user.username
1699
+ });
1700
+
1701
+ res.json({
1702
+ success: true,
1703
+ message: `Role ${roleName} assigned successfully`,
1704
+ expiresAt,
1705
+ newLimit: user.limit,
1706
+ apiKey: user.apikey
1707
+ });
1708
+ } catch (error) {
1709
+ console.error('Set role error:', error);
1710
+ res.status(500).json({ success: false, error: 'Internal server error' });
1711
+ }
1712
+ });
1713
+
1714
+ app.get('/api/admin/users', authenticate, async (req, res) => {
1715
+ try {
1716
+ if (req.user.role !== 'admin') {
1717
+ return res.status(403).json({ success: false, error: 'Admin access required' });
1718
+ }
1719
+
1720
+ const users = await User.find({}, {
1721
+ password: 0
1722
+ }).sort({ createdAt: -1 });
1723
+
1724
+ res.json({
1725
+ success: true,
1726
+ users: users.map(user => ({
1727
+ id: user._id,
1728
+ username: user.username,
1729
+ email: user.email,
1730
+ role: user.role,
1731
+ userRole: user.userRole,
1732
+ userRoleExpiresAt: user.userRoleExpiresAt,
1733
+ premium: user.premium,
1734
+ premiumExpiredAt: user.premiumExpiredAt,
1735
+ banned: user.banned,
1736
+ tempBanned: user.tempBanned,
1737
+ tempBanUntil: user.tempBanUntil,
1738
+ tempBanReason: user.tempBanReason,
1739
+ limit: user.limit,
1740
+ requests: user.requests,
1741
+ requestsToday: user.requestsToday,
1742
+ createdAt: user.createdAt,
1743
+ ipAddress: user.ipAddress
1744
+ }))
1745
+ });
1746
+ } catch (error) {
1747
+ console.error('Admin users fetch error:', error);
1748
+ res.status(500).json({ success: false, error: 'Internal server error' });
1749
+ }
1750
+ });
1751
+
1752
+ app.post('/api/admin/temp-ban', authenticate, async (req, res) => {
1753
+ try {
1754
+ if (req.user.role !== 'admin') {
1755
+ return res.status(403).json({
1756
+ success: false, error: 'Admin access required' });
1757
+ }
1758
+
1759
+ const { userId, banUntil, reason } = req.body;
1760
+
1761
+ if (!userId || !banUntil) {
1762
+ return res.status(400).json({
1763
+ success: false,
1764
+ error: 'User ID and ban until date are required'
1765
+ });
1766
+ }
1767
+
1768
+ const user = await User.findById(userId);
1769
+ if (!user) {
1770
+ return res.status(404).json({ success: false, error: 'User not found' });
1771
+ }
1772
+
1773
+ if (user.role === 'admin') {
1774
+ return res.status(403).json({ success: false, error: 'Cannot ban admin users' });
1775
+ }
1776
+
1777
+ const banUntilDate = new Date(banUntil);
1778
+ if (banUntilDate <= new Date()) {
1779
+ return res.status(400).json({
1780
+ success: false,
1781
+ error: 'Ban until date must be in the future'
1782
+ });
1783
+ }
1784
+
1785
+ user.tempBanned = true;
1786
+ user.tempBanUntil = banUntilDate;
1787
+ user.tempBanReason = reason || 'No reason provided';
1788
+
1789
+ await user.save();
1790
+
1791
+ await logActivity(user._id, user.username, 'temp_banned', `User temporarily banned until ${banUntilDate.toLocaleString()}`, {
1792
+ bannedBy: req.user.username,
1793
+ banUntil: banUntilDate,
1794
+ reason: user.tempBanReason
1795
+ });
1796
+
1797
+ res.json({
1798
+ success: true,
1799
+ message: `User ${user.username} temporarily banned until ${banUntilDate.toLocaleString()}`
1800
+ });
1801
+ } catch (error) {
1802
+ console.error('Temp ban error:', error);
1803
+ res.status(500).json({ success: false, error: 'Internal server error' });
1804
+ }
1805
+ });
1806
+
1807
+ app.post('/api/admin/remove-temp-ban', authenticate, async (req, res) => {
1808
+ try {
1809
+ if (req.user.role !== 'admin') {
1810
+ return res.status(403).json({ success: false, error: 'Admin access required' });
1811
+ }
1812
+
1813
+ const { userId } = req.body;
1814
+
1815
+ if (!userId) {
1816
+ return res.status(400).json({
1817
+ success: false,
1818
+ error: 'User ID is required'
1819
+ });
1820
+ }
1821
+
1822
+ const user = await User.findById(userId);
1823
+ if (!user) {
1824
+ return res.status(404).json({ success: false, error: 'User not found' });
1825
+ }
1826
+
1827
+ user.tempBanned = false;
1828
+ user.tempBanUntil = null;
1829
+ user.tempBanReason = null;
1830
+
1831
+ await user.save();
1832
+
1833
+ await logActivity(user._id, user.username, 'ban_removed', 'Temporary ban removed by admin', {
1834
+ removedBy: req.user.username
1835
+ });
1836
+
1837
+ res.json({
1838
+ success: true,
1839
+ message: `Temporary ban removed for user ${user.username}`
1840
+ });
1841
+ } catch (error) {
1842
+ console.error('Remove temp ban error:', error);
1843
+ res.status(500).json({ success: false, error: 'Internal server error' });
1844
+ }
1845
+ });
1846
+
1847
+ app.post('/api/admin/redeem-code', authenticate, async (req, res) => {
1848
+ try {
1849
+ if (req.user.role !== 'admin') {
1850
+ return res.status(403).json({ success: false, error: 'Admin access required' });
1851
+ }
1852
+
1853
+ const { type, limitValue, codeExpired, premiumExpired } = req.body;
1854
+
1855
+ if (!type || !codeExpired) {
1856
+ return res.status(400).json({
1857
+ success: false,
1858
+ error: 'Type and code expiration date are required'
1859
+ });
1860
+ }
1861
+
1862
+ const codeExpiredDate = new Date(codeExpired);
1863
+ if (codeExpiredDate <= new Date()) {
1864
+ return res.status(400).json({
1865
+ success: false,
1866
+ error: 'Code expiration date must be in the future'
1867
+ });
1868
+ }
1869
+
1870
+ if (type === 'limit' && (!limitValue || limitValue <= 0)) {
1871
+ return res.status(400).json({
1872
+ success: false,
1873
+ error: 'Limit value must be greater than 0 for Limit Only type'
1874
+ });
1875
+ }
1876
+
1877
+ if (type === 'premium' && !premiumExpired) {
1878
+ return res.status(400).json({
1879
+ success: false,
1880
+ error: 'Premium expiration date is required for Premium Only type'
1881
+ });
1882
+ }
1883
+
1884
+ if (type === 'both') {
1885
+ if (!limitValue || limitValue <= 0) {
1886
+ return res.status(400).json({
1887
+ success: false,
1888
+ error: 'Limit value must be greater than 0 for Both type'
1889
+ });
1890
+ }
1891
+ if (!premiumExpired) {
1892
+ return res.status(400).json({
1893
+ success: false,
1894
+ error: 'Premium expiration date is required for Both type'
1895
+ });
1896
+ }
1897
+ }
1898
+
1899
+ let premiumExpiredDate = null;
1900
+ if (premiumExpired) {
1901
+ premiumExpiredDate = new Date(premiumExpired);
1902
+ if (premiumExpiredDate <= new Date()) {
1903
+ return res.status(400).json({
1904
+ success: false,
1905
+ error: 'Premium expiration date must be in the future'
1906
+ });
1907
+ }
1908
+ }
1909
+
1910
+ const code = crypto.randomBytes(4).toString('hex').toUpperCase();
1911
+
1912
+ const redeemCode = new RedeemCode({
1913
+ code,
1914
+ type,
1915
+ limitValue: parseInt(limitValue) || 0,
1916
+ codeExpired: codeExpiredDate,
1917
+ premiumExpired: premiumExpiredDate,
1918
+ createdBy: req.user.username
1919
+ });
1920
+
1921
+ await redeemCode.save();
1922
+
1923
+ await logActivity(req.user._id, req.user.username, 'redeem_code_created', `Created redeem code: ${code}`, {
1924
+ code,
1925
+ type,
1926
+ limitValue,
1927
+ codeExpired: codeExpiredDate,
1928
+ premiumExpired: premiumExpiredDate
1929
+ });
1930
+
1931
+ res.json({ success: true, code });
1932
+ } catch (error) {
1933
+ console.error('Redeem code creation error:', error);
1934
+ res.status(500).json({ success: false, error: 'Internal server error' });
1935
+ }
1936
+ });
1937
+
1938
+ app.use('/api', checkBanned);
1939
+ app.use('/api', apiRateLimit);
1940
+
1941
+ let pluginsDir = path.join(__dirname, "plugins");
1942
+ let isJavaScriptFile = (fileName) => /\.js$/.test(fileName);
1943
+ global.plugins = {};
1944
+
1945
+ const loadPlugins = () => {
1946
+ if (!fs.existsSync(pluginsDir)) {
1947
+ console.log('Plugins directory not found, creating...');
1948
+ try {
1949
+ fs.mkdirSync(pluginsDir, { recursive: true });
1950
+ } catch (error) {
1951
+ console.error('Error creating plugins directory:', error);
1952
+ }
1953
+ return;
1954
+ }
1955
+
1956
+ for (let pluginFile of fs.readdirSync(pluginsDir).filter(isJavaScriptFile)) {
1957
+ try {
1958
+ delete require.cache[require.resolve(path.join(pluginsDir, pluginFile))];
1959
+ global.plugins[pluginFile] = require(path.join(pluginsDir, pluginFile));
1960
+ } catch (error) {
1961
+ console.error(`Error loading plugin ${pluginFile}:`, error.message);
1962
+ delete global.plugins[pluginFile];
1963
+ }
1964
+ }
1965
+
1966
+ console.log('Loaded plugins:', Object.keys(global.plugins));
1967
+ };
1968
+
1969
+ global.reload = (event, filename) => {
1970
+ if (/\.js$/.test(filename)) {
1971
+ let fullFilePath = path.join(pluginsDir, filename);
1972
+ if (fullFilePath in require.cache) {
1973
+ delete require.cache[fullFilePath];
1974
+ if (fs.existsSync(fullFilePath)) {
1975
+ console.log(`♻️ Re-requiring plugin '${filename}'`);
1976
+ } else {
1977
+ console.log(`🗑️ Deleted plugin '${filename}'`);
1978
+ return delete global.plugins[filename];
1979
+ }
1980
+ } else {
1981
+ console.log(`🔁 Requiring new plugin '${filename}'`);
1982
+ }
1983
+
1984
+ let errorCheck = syntaxError(fs.readFileSync(fullFilePath), filename);
1985
+ if (errorCheck) {
1986
+ console.error(`❌ Syntax error while loading '${filename}':\n${errorCheck}`);
1987
+ } else {
1988
+ try {
1989
+ global.plugins[filename] = require(fullFilePath);
1990
+ reloadHandler();
1991
+ } catch (error) {
1992
+ console.error(`Error loading plugin ${filename}:`, error);
1993
+ } finally {
1994
+ global.plugins = Object.fromEntries(Object.entries(global.plugins).sort(([a], [b]) => a.localeCompare(b)));
1995
+ }
1996
+ }
1997
+ }
1998
+ };
1999
+
2000
+ const reloadHandler = () => {
2001
+ const routes = [];
2002
+
2003
+ Object.keys(global.plugins).forEach(file => {
2004
+ const plugin = global.plugins[file];
2005
+ if (plugin && plugin.enabled && plugin.routes && plugin.handler) {
2006
+ plugin.routes.forEach(route => {
2007
+ routes.push({ route, plugin, file });
2008
+ });
2009
+ }
2010
+ });
2011
+
2012
+ routes.forEach(({ route, plugin, file }) => {
2013
+ const method = (plugin.type || 'get').toLowerCase();
2014
+ if (app[method] && typeof app[method] === 'function') {
2015
+ app[method](`/${route}`, (req, res, next) => {
2016
+ req.limitDeduction = plugin.limit || 1;
2017
+ next();
2018
+ }, validateApiKey, async (req, res) => {
2019
+ const startTime = Date.now();
2020
+ try {
2021
+ await plugin.handler(req, res);
2022
+
2023
+ await RequestLog.create({
2024
+ userId: req.apiUser._id,
2025
+ username: req.apiUser.username,
2026
+ apikey: req.apiUser.apikey,
2027
+ endpoint: route,
2028
+ ipAddress: req.realIP,
2029
+ userAgent: req.get('User-Agent'),
2030
+ success: true,
2031
+ responseTime: Date.now() - startTime,
2032
+ limitDeducted: req.limitDeducted || 1
2033
+ });
2034
+ } catch (error) {
2035
+ console.error(`Plugin ${plugin.name} error:`, error);
2036
+
2037
+ await RequestLog.create({
2038
+ userId: req.apiUser._id,
2039
+ username: req.apiUser.username,
2040
+ apikey: req.apiUser.apikey,
2041
+ endpoint: route,
2042
+ ipAddress: req.realIP,
2043
+ userAgent: req.get('User-Agent'),
2044
+ success: false,
2045
+ responseTime: Date.now() - startTime,
2046
+ limitDeducted: req.limitDeducted || 1
2047
+ });
2048
+
2049
+ if (!res.headersSent) {
2050
+ res.status(500).json({
2051
+ success: false,
2052
+ error: 'Plugin execution failed'
2053
+ });
2054
+ }
2055
+ }
2056
+ });
2057
+ console.log(`✅ Registered route: ${method.toUpperCase()} /${route} from ${file}`);
2058
+ }
2059
+ });
2060
+ };
2061
+
2062
+ Object.freeze(global.reload);
2063
+ fs.watch(pluginsDir, global.reload);
2064
+
2065
+ setInterval(async () => {
2066
+ const now = new Date();
2067
+
2068
+ if (now.getHours() === 0 && now.getMinutes() === 0) {
2069
+ console.log('Running daily limit reset at midnight...');
2070
+
2071
+ try {
2072
+ const users = await User.find({});
2073
+
2074
+ for (const user of users) {
2075
+ await resetUserLimitIfNeeded(user);
2076
+ }
2077
+
2078
+ console.log('Daily limit reset completed for all users');
2079
+ } catch (error) {
2080
+ console.error('Daily reset error:', error);
2081
+ }
2082
+ }
2083
+ }, 60000);
2084
+
2085
+ initializeAdmin();
2086
+ loadPlugins();
2087
+ reloadHandler();
2088
+
2089
+ app.use((err, req, res, next) => {
2090
+ console.error('Unhandled error:', err);
2091
+ res.status(500).json({
2092
+ success: false,
2093
+ error: 'Internal server error'
2094
+ });
2095
+ });
2096
+
2097
+ const PORT = process.env.PORT || 7860;
2098
+ app.listen(PORT, () => {
2099
+ console.log(`DashX API Server running on port ${PORT}`);
2100
+ console.log('=== ADMIN ACCOUNT INFO ===');
2101
+ console.log('Username: HERXA');
2102
+ console.log('Password: BTXHZ');
2103
+ console.log('API Key: DHX-M3SA');
2104
+ console.log('Limit: 9999');
2105
+ console.log('=========================');
2106
+ console.log('Database connected successfully');
2107
+ console.log('Plugin auto-reload enabled');
2108
+ console.log('Daily reset cron job started');
2109
+ });
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
package.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "nodejs",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC",
12
+ "dependencies": {
13
+ "@types/node": "^22.13.11",
14
+ "axios": "^1.12.2",
15
+ "bcryptjs": "^3.0.2",
16
+ "bycf": "^1.0.1",
17
+ "express": "^5.1.0",
18
+ "express-rate-limit": "^8.1.0",
19
+ "groq-sdk": "^0.33.0",
20
+ "jimp": "^1.6.0",
21
+ "jsonwebtoken": "^9.0.2",
22
+ "jsqr": "^1.4.0",
23
+ "mongoose": "^8.18.1",
24
+ "multer": "^2.0.2",
25
+ "nodemailer": "^7.0.6",
26
+ "notmebotz-tools": "^2.0.29",
27
+ "syntax-error": "^1.4.0"
28
+ }
29
+ }