krsyer-server-monitor-pro 1.0.10 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,8 +17,8 @@ const mysql = require('mysql2/promise');
17
17
  // --- Database (MySQL) ---
18
18
  const dbConfig = {
19
19
  host: process.env.DB_HOST || 'localhost',
20
- user: process.env.DB_USER || 'root',
21
- password: process.env.DB_PASSWORD || '',
20
+ user: process.env.DB_USER || 'mulaorg',
21
+ password: process.env.DB_PASSWORD || 'Krishika@9959',
22
22
  waitForConnections: true,
23
23
  connectionLimit: 10,
24
24
  queueLimit: 0
@@ -65,7 +65,13 @@ let pool;
65
65
  console.log('MySQL Database initialized');
66
66
  conn.release();
67
67
  } catch (err) {
68
- console.error('MySQL Init Error:', err);
68
+ console.error('MySQL Init Error:', err.message);
69
+ if (err.code === 'ECONNREFUSED') {
70
+ console.error('❌ Could not connect to MySQL Server. Is it installed and running?');
71
+ console.error('👉 Try: sudo systemctl start mysql');
72
+ } else if (err.code === 'ER_ACCESS_DENIED_ERROR') {
73
+ console.error('❌ Access Denied. Check DB_USER and DB_PASSWORD.');
74
+ }
69
75
  }
70
76
  })();
71
77
 
@@ -121,20 +127,22 @@ app.post('/api/buy', async (req, res) => {
121
127
 
122
128
  // 3. Verify Route (Return URL)
123
129
  app.get('/verify', async (req, res) => {
124
- const { order_id } = req.query;
130
+ const { order_id, email, phone } = req.query;
131
+
132
+ if (!order_id) {
133
+ return res.redirect('/');
134
+ }
135
+
125
136
  try {
126
137
  const cf = getCashfree();
138
+ // Check Payment Status
127
139
  const response = await cf.PGOrderFetchPayments(order_id);
128
140
  const payments = response.data;
141
+
142
+ // Find successful payment
129
143
  const isPaid = payments.some(p => p.payment_status === 'SUCCESS');
130
144
 
131
145
  if (isPaid) {
132
- // Get Customer Details from Order Fetch?
133
- // To simplify, we get email from stored order or just query Cashfree Order details again
134
- const orderDetails = await cf.PGOrderFetch(order_id);
135
- const email = orderDetails.data.customer_details.customer_email;
136
- const phone = orderDetails.data.customer_details.customer_phone;
137
-
138
146
  // Generate License
139
147
  const licenseKey = 'PRO-' + Math.random().toString(36).substring(2, 10).toUpperCase() + '-' + Date.now().toString(36).toUpperCase();
140
148
 
@@ -142,40 +150,29 @@ app.get('/verify', async (req, res) => {
142
150
  const expiryDate = new Date();
143
151
  expiryDate.setFullYear(expiryDate.getFullYear() + 1);
144
152
 
145
- // Save to MySQL
146
- await pool.query(
147
- 'INSERT INTO licenses (license_key, order_id, customer_email, customer_phone, expiry_date, active) VALUES (?, ?, ?, ?, ?, ?)',
148
- [licenseKey, order_id, email, phone, expiryDate, true]
149
- );
153
+ // Check if license already exists for this order (Idempotency)
154
+ if (pool) {
155
+ const [existing] = await pool.query('SELECT license_key FROM licenses WHERE order_id = ?', [order_id]);
156
+ if (existing.length > 0) {
157
+ return res.send(getSuccessHtml(existing[0].license_key, order_id, true));
158
+ }
159
+
160
+ await pool.query(
161
+ 'INSERT INTO licenses (license_key, order_id, customer_email, customer_phone, expiry_date, active) VALUES (?, ?, ?, ?, ?, ?)',
162
+ [licenseKey, order_id, email || 'Unknown', phone || 'Unknown', expiryDate, true]
163
+ );
164
+ } else {
165
+ console.error("Critical: DB Pool missing during verify. License generated but not saved:", licenseKey);
166
+ }
150
167
 
151
168
  // Show Success Page
152
- res.send(`
153
- <html>
154
- <body style="font-family: sans-serif; text-align: center; padding: 50px; background: #0f172a; color: white;">
155
- <div style="max-width: 600px; margin: auto; background: #1e293b; padding: 40px; border-radius: 12px; border: 1px solid #334155;">
156
- <h1 style="color: #4ade80;">Payment Successful!</h1>
157
- <p style="color: #94a3b8; font-size: 18px;">Thank you for your yearly subscription.</p>
158
-
159
- <div style="background: #0f172a; padding: 20px; margin: 30px 0; border-radius: 8px; border: 1px dashed #4ade80;">
160
- <p style="margin: 0; color: #94a3b8; font-size: 14px;">YOUR LICENSE KEY (Valid until ${expiryDate.toDateString()})</p>
161
- <h2 style="margin: 10px 0; letter-spacing: 2px; font-family: monospace;">${licenseKey}</h2>
162
- </div>
163
-
164
- <p style="color: #cbd5e1;">Copy this key and paste it into your server <code>.env</code> file:</p>
165
- <code style="background: black; padding: 10px; display: block; text-align: left; color: #fbbf24;">LICENSE_KEY=${licenseKey}</code>
166
-
167
- <br>
168
- <a href="/" style="color: white; text-decoration: none; border-bottom: 1px solid white;">Back Home</a>
169
- </div>
170
- </body>
171
- </html>
172
- `);
169
+ res.send(getSuccessHtml(licenseKey, order_id, false));
173
170
  } else {
174
171
  res.send(`<h1>Payment Failed or Pending</h1><a href="/">Try Again</a>`);
175
172
  }
176
173
  } catch (e) {
177
- console.error("Cashfree Verification Error:", e.response?.data || e.message);
178
- res.status(500).send("Verification Error");
174
+ console.error("Cashfree Verification Error:", e);
175
+ res.status(500).send(`<h1>Verification Error</h1><p>${e.message}</p><pre>${JSON.stringify(e.response?.data || {}, null, 2)}</pre>`);
179
176
  }
180
177
  });
181
178
 
@@ -191,6 +188,11 @@ app.get('/api/validate', async (req, res) => {
191
188
  return res.json({ valid: true, plan: 'Pro (Demo)' });
192
189
  }
193
190
 
191
+ if (!pool) {
192
+ console.error("DB Pool not ready");
193
+ return res.json({ valid: false, message: 'Server Starting...' });
194
+ }
195
+
194
196
  try {
195
197
  const [rows] = await pool.query('SELECT * FROM licenses WHERE license_key = ?', [key]);
196
198
  const license = rows[0];
@@ -217,5 +219,60 @@ app.get('/api/validate', async (req, res) => {
217
219
  return res.json({ valid: false, message: 'Invalid Key' });
218
220
  });
219
221
 
222
+ const getSuccessHtml = (licenseKey, orderId, isExisting) => {
223
+ return `
224
+ <!DOCTYPE html>
225
+ <html lang="en">
226
+ <head>
227
+ <meta charset="UTF-8">
228
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
229
+ <title>License Activated</title>
230
+ <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap" rel="stylesheet">
231
+ <style>
232
+ body { font-family: 'Space Grotesk', sans-serif; background: #0f172a; color: white; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; }
233
+ .card { background: #1e293b; padding: 2.5rem; border-radius: 16px; box-shadow: 0 10px 25px rgba(0,0,0,0.5); text-align: center; max-width: 500px; width: 90%; border: 1px solid #334155; }
234
+ h1 { color: ${isExisting ? '#fbbf24' : '#4ade80'}; margin-bottom: 0.5rem; font-size: 2rem; }
235
+ .key-box { background: rgba(0,0,0,0.3); padding: 15px; border-radius: 8px; margin: 20px 0; border: 1px dashed #475569; position: relative; }
236
+ .label { color: #94a3b8; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 5px; display: block; }
237
+ .value { font-family: monospace; font-size: 1.25rem; color: #fbbf24; word-break: break-all; font-weight: bold; }
238
+ .credentials { background: #334155; padding: 15px; border-radius: 8px; margin-top: 20px; text-align: left; }
239
+ .cred-row { display: flex; justify-content: space-between; margin-bottom: 8px; font-size: 0.95rem; }
240
+ .cred-label { color: #cbd5e1; }
241
+ .cred-val { color: #fff; font-weight: 600; font-family: monospace; }
242
+ .warning { color: #f87171; font-size: 0.85rem; margin-top: 10px; font-style: italic; text-align: center;}
243
+ .btn { display: inline-block; margin-top: 25px; padding: 12px 24px; background: #3b82f6; color: white; text-decoration: none; border-radius: 8px; font-weight: 600; transition: all 0.2s; }
244
+ .btn:hover { background: #2563eb; transform: translateY(-1px); }
245
+ </style>
246
+ </head>
247
+ <body>
248
+ <div class="card">
249
+ <h1>${isExisting ? 'License Retrieved' : 'Payment Successful!'}</h1>
250
+ <p style="color: #cbd5e1;">Your License is active.</p>
251
+
252
+ <div class="key-box">
253
+ <span class="label">License Key</span>
254
+ <div class="value">${licenseKey}</div>
255
+ </div>
256
+
257
+ <div class="credentials">
258
+ <div style="margin-bottom:12px; color:#60a5fa; font-weight:bold; font-size:0.95rem; text-align:center; text-transform:uppercase; letter-spacing:1px;">Monitor Credentials</div>
259
+ <div class="cred-row">
260
+ <span class="cred-label">Username:</span>
261
+ <span class="cred-val">admin@monitor.com</span>
262
+ </div>
263
+ <div class="cred-row">
264
+ <span class="cred-label">Password:</span>
265
+ <span class="cred-val">AdminPass123!</span>
266
+ </div>
267
+ <div class="warning">⚠️ Please change your password after initial login</div>
268
+ </div>
269
+
270
+ <a href="/" class="btn">Back Home</a>
271
+ </div>
272
+ </body>
273
+ </html>
274
+ `;
275
+ };
276
+
220
277
  const PORT = process.env.PORT || 3011;
221
278
  app.listen(PORT, () => console.log(`License Portal running on port ${PORT}`));
@@ -214,7 +214,7 @@
214
214
  </div>
215
215
 
216
216
  <p style="text-align: center; color: var(--text-muted); margin-top: 20px;">
217
- Once installed, visit your server IP on port 3000 to activate.
217
+ Once installed, visit your server IP on port 3014 to activate.
218
218
  </p>
219
219
  </div>
220
220
 
@@ -240,6 +240,30 @@
240
240
  </div>
241
241
  </div>
242
242
 
243
+ <style>
244
+ .loader-spinner {
245
+ border: 2px solid rgba(255, 255, 255, 0.3);
246
+ border-top: 2px solid #fff;
247
+ border-radius: 50%;
248
+ width: 16px;
249
+ height: 16px;
250
+ animation: spin 1s linear infinite;
251
+ display: inline-block;
252
+ vertical-align: middle;
253
+ margin-right: 8px;
254
+ }
255
+
256
+ @keyframes spin {
257
+ 0% {
258
+ transform: rotate(0deg);
259
+ }
260
+
261
+ 100% {
262
+ transform: rotate(360deg);
263
+ }
264
+ }
265
+ </style>
266
+
243
267
  <script>
244
268
  const cashfree = Cashfree({
245
269
  mode: "production"
@@ -255,7 +279,7 @@
255
279
  return;
256
280
  }
257
281
 
258
- btn.innerText = 'Processing...';
282
+ btn.innerHTML = '<span class="loader-spinner"></span> Processing...';
259
283
  btn.disabled = true;
260
284
 
261
285
  try {
@@ -269,10 +293,22 @@
269
293
 
270
294
  if (data.payment_session_id) {
271
295
  // Redirect to Payment
296
+ const email = document.getElementById('email').value;
297
+ const phone = document.getElementById('phone').value;
298
+
272
299
  cashfree.checkout({
273
- paymentSessionId: data.payment_session_id,
274
- redirectTarget: "_self"
275
- // returnUrl: `${window.location.origin}/verify?order_id=${data.order_id}` // Handled by Cashfree self redirect if desired, but better to use returnUrl
300
+ paymentSessionId: data.payment_session_id
301
+ }).then(() => {
302
+ console.log("Checkout initiated");
303
+ });
304
+
305
+ cashfree.on("payment.success", (data) => {
306
+ // Pass email/phone to verify route
307
+ window.location.href = `/verify?order_id=${data.orderId}&email=${encodeURIComponent(email)}&phone=${encodeURIComponent(phone)}`;
308
+ });
309
+
310
+ cashfree.on("payment.failed", (data) => {
311
+ alert("Payment Failed: " + data.message);
276
312
  });
277
313
  } else {
278
314
  alert('Error creating order');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "krsyer-server-monitor-pro",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "API to get server details like IP address, health, applications running, etc.",
5
5
  "main": "lib/server.js",
6
6
  "bin": {