GamerC0der commited on
Commit
02a5061
·
verified ·
1 Parent(s): d632f3e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +15 -706
app.py CHANGED
@@ -1,4 +1,4 @@
1
- from flask import Flask, render_template_string, request, redirect, url_for, jsonify
2
  from flask_sqlalchemy import SQLAlchemy
3
  import uuid
4
  from datetime import datetime
@@ -16,7 +16,6 @@ app.config['SECRET_KEY'] = 'your-secret-key-here'
16
  db = SQLAlchemy(app)
17
 
18
  def get_encryption_key():
19
- """Get or generate encryption key"""
20
  key_file = 'encryption.key'
21
  if os.path.exists(key_file):
22
  with open(key_file, 'rb') as f:
@@ -31,16 +30,14 @@ ENCRYPTION_KEY = get_encryption_key()
31
  cipher_suite = Fernet(ENCRYPTION_KEY)
32
 
33
  def encrypt_value(value):
34
- """Encrypt a string value"""
35
  if isinstance(value, str):
36
  value = value.encode()
37
  return cipher_suite.encrypt(value).decode()
38
 
39
  def decrypt_value(encrypted_value):
40
- """Decrypt an encrypted string value"""
41
  return cipher_suite.decrypt(encrypted_value.encode()).decode()
42
 
43
- ENCRYPTED_CONNECT_SID = encrypt_value('s%3AeAVq_RB9TcaxBH_VSqYlYPiaYMlm1PbS.kFS%2BOEI4zH5ZS8VLv1dExjTe7dMiCXvNYeT4YG%2FoV04')
44
  ENCRYPTED_API_URL = encrypt_value('https://astra-bank-moh1812.replit.app/api/transactions')
45
  ENCRYPTED_REFERER = encrypt_value('https://astra-bank-moh1812.replit.app/')
46
  ENCRYPTED_ETAG = encrypt_value('W/"6e3-L0zHI4rHMa4nHmyewyA/4y+lL6c"')
@@ -49,6 +46,7 @@ class PaymentLink(db.Model):
49
  id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
50
  amount = db.Column(db.Integer, nullable=False)
51
  description = db.Column(db.String(500), nullable=False)
 
52
  created_at = db.Column(db.DateTime, default=datetime.utcnow)
53
  paid = db.Column(db.Boolean, default=False)
54
 
@@ -89,7 +87,6 @@ def get_transactions():
89
  return []
90
 
91
  def check_for_payment(amount, existing_transaction_ids):
92
- """Check for new transactions matching the payment amount"""
93
  try:
94
  transactions = get_transactions()
95
 
@@ -108,702 +105,9 @@ def check_for_payment(amount, existing_transaction_ids):
108
  with app.app_context():
109
  db.create_all()
110
 
111
- HOME_TEMPLATE = """
112
- <!DOCTYPE html>
113
- <html lang="en">
114
- <head>
115
- <meta charset="UTF-8">
116
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
117
- <title>AstraPay</title>
118
- <style>
119
- body {
120
- margin: 0;
121
- padding: 0;
122
- height: 100vh;
123
- background-color: #000000;
124
- display: flex;
125
- justify-content: center;
126
- align-items: center;
127
- font-family: Arial, sans-serif;
128
- }
129
- .container {
130
- text-align: center;
131
- }
132
- .title {
133
- color: #ffffff;
134
- font-size: 4rem;
135
- font-weight: bold;
136
- text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.3);
137
- margin-bottom: 2rem;
138
- }
139
- .button {
140
- background-color: #ffffff;
141
- color: #000000;
142
- border: none;
143
- padding: 1rem 2rem;
144
- font-size: 1.2rem;
145
- font-weight: bold;
146
- border-radius: 8px;
147
- cursor: pointer;
148
- transition: all 0.3s ease;
149
- text-decoration: none;
150
- display: inline-block;
151
- }
152
- .button:hover {
153
- background-color: #f0f0f0;
154
- transform: translateY(-2px);
155
- box-shadow: 0 4px 8px rgba(255, 255, 255, 0.2);
156
- }
157
- .modal {
158
- display: none;
159
- position: fixed;
160
- z-index: 1;
161
- left: 0;
162
- top: 0;
163
- width: 100%;
164
- height: 100%;
165
- background-color: rgba(0, 0, 0, 0.8);
166
- }
167
- .modal-content {
168
- background-color: #1a1a1a;
169
- margin: 15% auto;
170
- padding: 2rem;
171
- border-radius: 8px;
172
- width: 90%;
173
- max-width: 500px;
174
- border: 1px solid #333;
175
- }
176
- .modal-header {
177
- color: #ffffff;
178
- margin-bottom: 1.5rem;
179
- font-size: 1.5rem;
180
- font-weight: bold;
181
- }
182
- .form-group {
183
- margin-bottom: 1.5rem;
184
- }
185
- .form-label {
186
- display: block;
187
- color: #ffffff;
188
- margin-bottom: 0.5rem;
189
- font-weight: bold;
190
- }
191
- .form-input {
192
- width: 100%;
193
- padding: 0.75rem;
194
- border: 1px solid #555;
195
- border-radius: 4px;
196
- background-color: #2a2a2a;
197
- color: #ffffff;
198
- font-size: 1rem;
199
- }
200
- .form-input:focus {
201
- outline: none;
202
- border-color: #ffffff;
203
- }
204
- .form-textarea {
205
- width: 100%;
206
- padding: 0.75rem;
207
- border: 1px solid #555;
208
- border-radius: 4px;
209
- background-color: #2a2a2a;
210
- color: #ffffff;
211
- font-size: 1rem;
212
- min-height: 100px;
213
- resize: vertical;
214
- }
215
- .form-textarea:focus {
216
- outline: none;
217
- border-color: #ffffff;
218
- }
219
- .modal-buttons {
220
- display: flex;
221
- gap: 1rem;
222
- justify-content: flex-end;
223
- margin-top: 2rem;
224
- }
225
- .btn-secondary {
226
- background-color: #555;
227
- color: #ffffff;
228
- border: none;
229
- padding: 0.75rem 1.5rem;
230
- border-radius: 4px;
231
- cursor: pointer;
232
- font-size: 1rem;
233
- }
234
- .btn-secondary:hover {
235
- background-color: #666;
236
- }
237
- .banner {
238
- background: rgba(255, 193, 7, 0.15);
239
- border: 1px solid rgba(255, 193, 7, 0.3);
240
- border-radius: 8px;
241
- padding: 0.75rem 1.5rem;
242
- margin-bottom: 2rem;
243
- color: #ffc107;
244
- font-size: 0.9rem;
245
- font-weight: 500;
246
- text-align: center;
247
- max-width: 500px;
248
- margin-left: auto;
249
- margin-right: auto;
250
- }
251
- </style>
252
- </head>
253
- <body>
254
- <div class="container">
255
- <h1 class="title">AstraPay</h1>
256
- <div class="banner">
257
- Payments May Reset Daily. Ensure your link works.
258
- </div>
259
- <button class="button" onclick="openModal()">Create Payment Link</button>
260
- </div>
261
-
262
- <!-- Modal -->
263
- <div id="paymentModal" class="modal">
264
- <div class="modal-content">
265
- <div class="modal-header">Create Payment Link</div>
266
-
267
- <div class="form-group">
268
- <label class="form-label" for="astras">Number of Astras</label>
269
- <input type="number" id="astras" class="form-input" min="1" placeholder="Enter number of astras" required>
270
- </div>
271
-
272
- <div class="form-group">
273
- <label class="form-label" for="description">Description</label>
274
- <textarea id="description" class="form-textarea" placeholder="Enter payment description" required></textarea>
275
- </div>
276
-
277
- <div class="modal-buttons">
278
- <button class="btn-secondary" onclick="closeModal()">Cancel</button>
279
- <button class="button" onclick="createPaymentLink()">Create Link</button>
280
- </div>
281
- </div>
282
- </div>
283
-
284
- <script>
285
- function openModal() {
286
- document.getElementById('paymentModal').style.display = 'block';
287
- }
288
-
289
- function closeModal() {
290
- document.getElementById('paymentModal').style.display = 'none';
291
- // Clear form
292
- document.getElementById('astras').value = '';
293
- document.getElementById('description').value = '';
294
- }
295
-
296
- async function createPaymentLink() {
297
- const astras = document.getElementById('astras').value;
298
- const description = document.getElementById('description').value;
299
-
300
- if (!astras || !description.trim()) {
301
- alert('Please fill in all fields');
302
- return;
303
- }
304
-
305
- try {
306
- const response = await fetch('/create-payment-link', {
307
- method: 'POST',
308
- headers: {
309
- 'Content-Type': 'application/json',
310
- },
311
- body: JSON.stringify({
312
- amount: parseInt(astras),
313
- description: description.trim()
314
- })
315
- });
316
-
317
- const data = await response.json();
318
-
319
- if (response.ok) {
320
- // Redirect to the payment link
321
- window.location.href = data.payment_url;
322
- } else {
323
- alert('Error creating payment link: ' + data.error);
324
- }
325
- } catch (error) {
326
- alert('Error creating payment link: ' + error.message);
327
- }
328
- }
329
-
330
- // Close modal when clicking outside
331
- window.onclick = function(event) {
332
- const modal = document.getElementById('paymentModal');
333
- if (event.target == modal) {
334
- closeModal();
335
- }
336
- }
337
- </script>
338
- </body>
339
- </html>
340
- """
341
-
342
- PAYMENT_TEMPLATE = """
343
- <!DOCTYPE html>
344
- <html lang="en">
345
- <head>
346
- <meta charset="UTF-8">
347
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
348
- <title>Payment Link - AstraPay</title>
349
- <style>
350
- body {
351
- margin: 0;
352
- padding: 0;
353
- min-height: 100vh;
354
- background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%);
355
- display: flex;
356
- justify-content: center;
357
- align-items: center;
358
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
359
- color: #ffffff;
360
- line-height: 1.6;
361
- }
362
- .container {
363
- text-align: center;
364
- max-width: 500px;
365
- padding: 2rem;
366
- }
367
- .title {
368
- font-size: 2.2rem;
369
- font-weight: 600;
370
- margin-bottom: 1.5rem;
371
- letter-spacing: -0.02em;
372
- }
373
- .payment-card {
374
- background: rgba(255, 255, 255, 0.02);
375
- backdrop-filter: blur(20px);
376
- border: 1px solid rgba(255, 255, 255, 0.1);
377
- border-radius: 16px;
378
- padding: 2.5rem;
379
- margin-bottom: 2rem;
380
- position: relative;
381
- overflow: hidden;
382
- }
383
- .payment-card::before {
384
- content: '';
385
- position: absolute;
386
- top: 0;
387
- left: 0;
388
- right: 0;
389
- height: 1px;
390
- background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
391
- }
392
- .amount {
393
- font-size: 3.2rem;
394
- font-weight: 700;
395
- background: linear-gradient(135deg, #ffffff 0%, #e0e0e0 100%);
396
- -webkit-background-clip: text;
397
- -webkit-text-fill-color: transparent;
398
- background-clip: text;
399
- margin-bottom: 0.5rem;
400
- letter-spacing: -0.02em;
401
- }
402
- .description {
403
- font-size: 1.1rem;
404
- color: rgba(255, 255, 255, 0.7);
405
- margin-bottom: 2rem;
406
- font-weight: 400;
407
- }
408
- .status {
409
- font-size: 0.95rem;
410
- padding: 0.5rem 1.2rem;
411
- border-radius: 20px;
412
- display: inline-block;
413
- margin-bottom: 2rem;
414
- font-weight: 500;
415
- letter-spacing: 0.01em;
416
- }
417
- .status.pending {
418
- background: rgba(255, 255, 255, 0.1);
419
- color: rgba(255, 255, 255, 0.8);
420
- border: 1px solid rgba(255, 255, 255, 0.2);
421
- }
422
- .status.paid {
423
- background: rgba(0, 255, 136, 0.1);
424
- color: #00ff88;
425
- border: 1px solid rgba(0, 255, 136, 0.3);
426
- }
427
- .pay-button {
428
- background: linear-gradient(135deg, #ffffff 0%, #f8f8f8 100%);
429
- color: #000000;
430
- border: none;
431
- padding: 1rem 2.5rem;
432
- font-size: 1rem;
433
- font-weight: 600;
434
- border-radius: 12px;
435
- cursor: pointer;
436
- transition: all 0.3s ease;
437
- letter-spacing: 0.01em;
438
- box-shadow: 0 4px 20px rgba(255, 255, 255, 0.1);
439
- }
440
- .pay-button:hover:not(:disabled) {
441
- transform: translateY(-2px);
442
- box-shadow: 0 8px 30px rgba(255, 255, 255, 0.2);
443
- }
444
- .pay-button:disabled {
445
- background: rgba(255, 255, 255, 0.3);
446
- color: rgba(255, 255, 255, 0.5);
447
- cursor: not-allowed;
448
- transform: none;
449
- box-shadow: none;
450
- }
451
- .confirmation-text {
452
- font-size: 1.2rem;
453
- color: #00ff88;
454
- font-weight: 500;
455
- margin-top: 1rem;
456
- }
457
- .sender-email {
458
- font-size: 0.9rem;
459
- color: rgba(255, 255, 255, 0.6);
460
- margin-top: 0.5rem;
461
- font-family: 'Monaco', 'Consolas', monospace;
462
- }
463
- .timer {
464
- font-size: 0.8rem;
465
- color: rgba(255, 255, 255, 0.5);
466
- margin-top: 1rem;
467
- font-family: 'Monaco', 'Consolas', monospace;
468
- }
469
- .expired {
470
- color: #ff6b6b;
471
- }
472
- .back-link {
473
- color: rgba(255, 255, 255, 0.6);
474
- text-decoration: none;
475
- font-size: 0.9rem;
476
- margin-top: 2rem;
477
- display: inline-block;
478
- font-weight: 500;
479
- transition: color 0.3s ease;
480
- }
481
- .back-link:hover {
482
- color: rgba(255, 255, 255, 0.9);
483
- }
484
- .banner {
485
- background: rgba(255, 193, 7, 0.15);
486
- border: 1px solid rgba(255, 193, 7, 0.3);
487
- border-radius: 8px;
488
- padding: 0.75rem 1.5rem;
489
- margin-bottom: 2rem;
490
- color: #ffc107;
491
- font-size: 0.9rem;
492
- font-weight: 500;
493
- text-align: center;
494
- }
495
- .payment-modal {
496
- display: none;
497
- position: fixed;
498
- z-index: 1;
499
- left: 0;
500
- top: 0;
501
- width: 100%;
502
- height: 100%;
503
- background-color: rgba(0, 0, 0, 0.9);
504
- }
505
- .payment-modal-content {
506
- background-color: #1a1a1a;
507
- margin: 15% auto;
508
- padding: 2rem;
509
- border-radius: 8px;
510
- width: 90%;
511
- max-width: 500px;
512
- border: 1px solid #333;
513
- text-align: center;
514
- }
515
- .payment-modal-title {
516
- color: #ffffff;
517
- font-size: 1.5rem;
518
- font-weight: bold;
519
- margin-bottom: 1.5rem;
520
- }
521
- .payment-instruction {
522
- color: #cccccc;
523
- font-size: 1.1rem;
524
- margin-bottom: 2rem;
525
- line-height: 1.6;
526
- }
527
- .email-address {
528
- background-color: #2a2a2a;
529
- border: 1px solid #555;
530
- border-radius: 4px;
531
- padding: 1rem;
532
- margin: 1rem 0;
533
- color: #00ff88;
534
- font-family: monospace;
535
- font-size: 1.1rem;
536
- word-break: break-all;
537
- display: inline-block;
538
- }
539
- .payment-modal-buttons {
540
- display: flex;
541
- gap: 1rem;
542
- justify-content: center;
543
- margin-top: 2rem;
544
- }
545
- </style>
546
- </head>
547
- <body>
548
- <div class="container">
549
- <h1 class="title">AstraPay</h1>
550
-
551
- <div class="banner">
552
- Payments May Reset Daily. Ensure your link works.
553
- </div>
554
-
555
- <div class="payment-card">
556
- <div class="amount">{{ amount }} Astra{{ 's' if amount > 1 else '' }}</div>
557
- <div class="description">{{ description }}</div>
558
- <div class="status {{ 'paid' if paid else 'pending' }}">
559
- {{ 'Paid' if paid else 'Pending Payment' }}
560
- </div>
561
-
562
- {% if not paid %}
563
- <button class="pay-button" onclick="processPayment()">
564
- Pay {{ amount }} Astra{{ 's' if amount > 1 else '' }}
565
- </button>
566
- {% else %}
567
- <div style="font-size: 1.2rem; color: #00ff88;">✓ Payment Completed</div>
568
- {% endif %}
569
- </div>
570
-
571
- <a href="/" class="back-link">← Back to AstraPay</a>
572
- </div>
573
-
574
- <!-- Payment Modal -->
575
- <div id="paymentModal" class="payment-modal">
576
- <div class="payment-modal-content">
577
- <div class="payment-modal-title">Complete Payment</div>
578
- <div class="payment-instruction">
579
- Please send {{ amount }} Astra{{ 's' if amount > 1 else '' }} to the following address:
580
- </div>
581
- <div class="email-address">matthew@astranova.org</div>
582
-
583
- <div id="payment-status" class="payment-instruction">
584
- <div id="waiting-message">
585
- Waiting for payment confirmation...
586
- <div id="timer" class="timer">5:00</div>
587
- </div>
588
- <div id="payment-received" style="display: none;">
589
- ✓ Payment of {{ amount }} Astra{{ 's' if amount > 1 else '' }} received!
590
- <br><br>
591
- Please enter your email to confirm:
592
- <br>
593
- <input type="email" id="user-email" class="form-input" placeholder="Enter your email" style="margin-top: 1rem; width: 100%; max-width: 300px;">
594
- </div>
595
- <div id="payment-expired" style="display: none;">
596
- Payment window expired.
597
- <br><br>
598
- Please create a new payment link.
599
- </div>
600
- <div id="confirmation-complete" style="display: none;">
601
- <div class="confirmation-text">Payment Confirmed ✓</div>
602
- <div class="sender-email" id="sender-email-display"></div>
603
- </div>
604
- </div>
605
-
606
- <div class="payment-modal-buttons">
607
- <button class="btn-secondary" onclick="closePaymentModal()">Cancel</button>
608
- <button id="confirm-btn" class="pay-button" onclick="confirmPayment()" style="display: none;">Confirm Payment</button>
609
- <button id="verify-btn" class="pay-button" onclick="verifyEmail()" style="display: none;">Verify Email</button>
610
- </div>
611
- </div>
612
- </div>
613
-
614
- <script>
615
- let paymentCheckInterval;
616
- let timerInterval;
617
- let existingTransactionIds = [];
618
- let timeLeft = 300; // 5 minutes in seconds
619
- let paymentTransaction = null;
620
-
621
- function processPayment() {
622
- document.getElementById('paymentModal').style.display = 'block';
623
- timeLeft = 300; // Reset timer
624
- paymentTransaction = null; // Reset payment data
625
- // Initialize payment checking
626
- initPaymentCheck();
627
- startTimer();
628
- }
629
-
630
- function closePaymentModal() {
631
- document.getElementById('paymentModal').style.display = 'none';
632
- stopPaymentCheck();
633
- stopTimer();
634
- document.getElementById('waiting-message').style.display = 'block';
635
- document.getElementById('payment-received').style.display = 'none';
636
- document.getElementById('payment-expired').style.display = 'none';
637
- document.getElementById('confirmation-complete').style.display = 'none';
638
- document.getElementById('confirm-btn').style.display = 'none';
639
- document.getElementById('verify-btn').style.display = 'none';
640
- document.getElementById('user-email').value = '';
641
- document.getElementById('timer').classList.remove('expired');
642
- existingTransactionIds = [];
643
- }
644
-
645
- async function initPaymentCheck() {
646
- try {
647
- const response = await fetch('/init-payment-check/{{ payment_id }}');
648
- const data = await response.json();
649
-
650
- if (data.existing_transaction_ids) {
651
- existingTransactionIds = data.existing_transaction_ids;
652
- startPaymentCheck();
653
- } else {
654
- console.error('Failed to initialize payment check');
655
- }
656
- } catch (error) {
657
- console.error('Error initializing payment check:', error);
658
- }
659
- }
660
-
661
- function startPaymentCheck() {
662
- paymentCheckInterval = setInterval(async () => {
663
- if (timeLeft <= 0) return; // Don't check if expired
664
-
665
- try {
666
- const existingIdsParam = existingTransactionIds.join(',');
667
- const response = await fetch(`/check-payment/{{ payment_id }}?existing_ids=${existingIdsParam}`);
668
- const data = await response.json();
669
-
670
- if (data.payment_received) {
671
- paymentTransaction = data.transaction;
672
- document.getElementById('waiting-message').style.display = 'none';
673
- document.getElementById('payment-received').style.display = 'block';
674
- document.getElementById('verify-btn').style.display = 'inline-block';
675
- stopPaymentCheck();
676
- }
677
- } catch (error) {
678
- console.log('Error checking payment status:', error);
679
- }
680
- }, 2000); // Check every 2 seconds
681
- }
682
-
683
- function stopPaymentCheck() {
684
- if (paymentCheckInterval) {
685
- clearInterval(paymentCheckInterval);
686
- paymentCheckInterval = null;
687
- }
688
- }
689
-
690
- function startTimer() {
691
- timerInterval = setInterval(() => {
692
- timeLeft--;
693
- updateTimerDisplay();
694
-
695
- if (timeLeft <= 0) {
696
- stopTimer();
697
- stopPaymentCheck();
698
- document.getElementById('waiting-message').style.display = 'none';
699
- document.getElementById('payment-expired').style.display = 'block';
700
- document.getElementById('confirm-btn').style.display = 'none';
701
- document.getElementById('verify-btn').style.display = 'none';
702
- }
703
- }, 1000);
704
- }
705
-
706
- function stopTimer() {
707
- if (timerInterval) {
708
- clearInterval(timerInterval);
709
- timerInterval = null;
710
- }
711
- }
712
-
713
- function updateTimerDisplay() {
714
- const minutes = Math.floor(timeLeft / 60);
715
- const seconds = timeLeft % 60;
716
- const timerElement = document.getElementById('timer');
717
-
718
- timerElement.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
719
-
720
- if (timeLeft <= 60) {
721
- timerElement.classList.add('expired');
722
- }
723
- }
724
-
725
- function verifyEmail() {
726
- const userEmail = document.getElementById('user-email').value.trim();
727
- const senderEmail = paymentTransaction ? paymentTransaction.from_email : '';
728
-
729
- if (!userEmail) {
730
- alert('Please enter your email address');
731
- return;
732
- }
733
-
734
- if (userEmail.toLowerCase() === senderEmail.toLowerCase()) {
735
- document.getElementById('verify-btn').style.display = 'none';
736
- document.getElementById('confirm-btn').style.display = 'inline-block';
737
- } else {
738
- alert('Email address does not match the payment sender. Please use the email you sent the payment from.');
739
- document.getElementById('user-email').focus();
740
- }
741
- }
742
-
743
- async function confirmPayment() {
744
- const confirmButton = document.getElementById('confirm-btn');
745
- confirmButton.disabled = true;
746
- confirmButton.textContent = 'Confirming...';
747
-
748
- try {
749
- const response = await fetch('/pay/{{ payment_id }}', {
750
- method: 'POST',
751
- headers: {
752
- 'Content-Type': 'application/json',
753
- }
754
- });
755
-
756
- const data = await response.json();
757
-
758
- if (response.ok) {
759
- // Hide all other elements and show confirmation
760
- document.getElementById('payment-received').style.display = 'none';
761
- document.getElementById('confirm-btn').style.display = 'none';
762
- document.getElementById('confirmation-complete').style.display = 'block';
763
-
764
- // Show sender email if available
765
- if (paymentTransaction && paymentTransaction.from_email) {
766
- document.getElementById('sender-email-display').textContent = `From: ${paymentTransaction.from_email}`;
767
- }
768
-
769
- stopTimer();
770
- // Redirect after a delay
771
- setTimeout(() => {
772
- location.reload();
773
- }, 3000);
774
- } else {
775
- alert('Payment confirmation failed: ' + data.error);
776
- confirmButton.disabled = false;
777
- confirmButton.textContent = 'Confirm Payment';
778
- }
779
- } catch (error) {
780
- alert('Payment confirmation failed: ' + error.message);
781
- confirmButton.disabled = false;
782
- confirmButton.textContent = 'Confirm Payment';
783
- }
784
- }
785
-
786
- // Close modal when clicking outside
787
- window.onclick = function(event) {
788
- const modal = document.getElementById('paymentModal');
789
- if (event.target == modal) {
790
- closePaymentModal();
791
- }
792
- }
793
-
794
- // Stop checking when page unloads
795
- window.onbeforeunload = function() {
796
- stopPaymentCheck();
797
- stopTimer();
798
- };
799
- </script>
800
- </body>
801
- </html>
802
- """
803
-
804
  @app.route('/')
805
  def home():
806
- return render_template_string(HOME_TEMPLATE)
807
 
808
  @app.route('/create-payment-link', methods=['POST'])
809
  def create_payment_link():
@@ -815,6 +119,7 @@ def create_payment_link():
815
 
816
  amount = data['amount']
817
  description = data['description']
 
818
 
819
  if not isinstance(amount, int) or amount <= 0:
820
  return jsonify({'error': 'Invalid amount'}), 400
@@ -824,7 +129,8 @@ def create_payment_link():
824
 
825
  payment_link = PaymentLink(
826
  amount=amount,
827
- description=description.strip()
 
828
  )
829
 
830
  db.session.add(payment_link)
@@ -844,7 +150,6 @@ def create_payment_link():
844
 
845
  @app.route('/init-payment-check/<payment_id>')
846
  def init_payment_check(payment_id):
847
- """Initialize payment checking by storing current transaction state"""
848
  try:
849
  payment_link = PaymentLink.query.get_or_404(payment_id)
850
 
@@ -861,7 +166,6 @@ def init_payment_check(payment_id):
861
 
862
  @app.route('/check-payment/<payment_id>')
863
  def check_payment_status(payment_id):
864
- """Check if payment has been received"""
865
  try:
866
  payment_link = PaymentLink.query.get_or_404(payment_id)
867
 
@@ -910,11 +214,16 @@ def process_payment(payment_id):
910
  @app.route('/pay/<payment_id>')
911
  def view_payment(payment_id):
912
  payment_link = PaymentLink.query.get_or_404(payment_id)
913
- return render_template_string(PAYMENT_TEMPLATE,
914
  amount=payment_link.amount,
915
  description=payment_link.description,
916
  paid=payment_link.paid,
917
- payment_id=payment_link.id)
 
 
 
 
 
918
 
919
  if __name__ == '__main__':
920
- app.run(debug=True, host='0.0.0.0', port=7860)
 
1
+ from flask import Flask, render_template, request, redirect, url_for, jsonify
2
  from flask_sqlalchemy import SQLAlchemy
3
  import uuid
4
  from datetime import datetime
 
16
  db = SQLAlchemy(app)
17
 
18
  def get_encryption_key():
 
19
  key_file = 'encryption.key'
20
  if os.path.exists(key_file):
21
  with open(key_file, 'rb') as f:
 
30
  cipher_suite = Fernet(ENCRYPTION_KEY)
31
 
32
  def encrypt_value(value):
 
33
  if isinstance(value, str):
34
  value = value.encode()
35
  return cipher_suite.encrypt(value).decode()
36
 
37
  def decrypt_value(encrypted_value):
 
38
  return cipher_suite.decrypt(encrypted_value.encode()).decode()
39
 
40
+ ENCRYPTED_CONNECT_SID = encrypt_value('s%3A7Bwbww_JK7pW55D-B57-3b7bi-FzrzEZ.ezXPafCUs8%2B9L632zAZaBD51TQfSnUXUwbga8Z9kyAo')
41
  ENCRYPTED_API_URL = encrypt_value('https://astra-bank-moh1812.replit.app/api/transactions')
42
  ENCRYPTED_REFERER = encrypt_value('https://astra-bank-moh1812.replit.app/')
43
  ENCRYPTED_ETAG = encrypt_value('W/"6e3-L0zHI4rHMa4nHmyewyA/4y+lL6c"')
 
46
  id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
47
  amount = db.Column(db.Integer, nullable=False)
48
  description = db.Column(db.String(500), nullable=False)
49
+ recipient_email = db.Column(db.String(255), nullable=True)
50
  created_at = db.Column(db.DateTime, default=datetime.utcnow)
51
  paid = db.Column(db.Boolean, default=False)
52
 
 
87
  return []
88
 
89
  def check_for_payment(amount, existing_transaction_ids):
 
90
  try:
91
  transactions = get_transactions()
92
 
 
105
  with app.app_context():
106
  db.create_all()
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  @app.route('/')
109
  def home():
110
+ return render_template('home.html')
111
 
112
  @app.route('/create-payment-link', methods=['POST'])
113
  def create_payment_link():
 
119
 
120
  amount = data['amount']
121
  description = data['description']
122
+ recipient_email = data.get('recipient_email', '').strip() if data.get('recipient_email') else None
123
 
124
  if not isinstance(amount, int) or amount <= 0:
125
  return jsonify({'error': 'Invalid amount'}), 400
 
129
 
130
  payment_link = PaymentLink(
131
  amount=amount,
132
+ description=description.strip(),
133
+ recipient_email=recipient_email if recipient_email else None
134
  )
135
 
136
  db.session.add(payment_link)
 
150
 
151
  @app.route('/init-payment-check/<payment_id>')
152
  def init_payment_check(payment_id):
 
153
  try:
154
  payment_link = PaymentLink.query.get_or_404(payment_id)
155
 
 
166
 
167
  @app.route('/check-payment/<payment_id>')
168
  def check_payment_status(payment_id):
 
169
  try:
170
  payment_link = PaymentLink.query.get_or_404(payment_id)
171
 
 
214
  @app.route('/pay/<payment_id>')
215
  def view_payment(payment_id):
216
  payment_link = PaymentLink.query.get_or_404(payment_id)
217
+ return render_template('payment.html',
218
  amount=payment_link.amount,
219
  description=payment_link.description,
220
  paid=payment_link.paid,
221
+ payment_id=payment_link.id,
222
+ recipient_email=payment_link.recipient_email)
223
+
224
+ @app.route('/bank')
225
+ def bank():
226
+ return render_template('bank.html')
227
 
228
  if __name__ == '__main__':
229
+ app.run(debug=True, host='0.0.0.0', port=5000)