HerzaJ commited on
Commit
80ea27a
·
verified ·
1 Parent(s): 945ada4

Upload 8 files

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