0vergeared commited on
Commit
eb796ce
·
verified ·
1 Parent(s): 836d418

Update server.py

Browse files
Files changed (1) hide show
  1. server.py +130 -152
server.py CHANGED
@@ -1,190 +1,168 @@
1
- from flask import Flask, request, jsonify, render_template_string, redirect, session
 
 
2
  from flask_limiter import Limiter
3
  from flask_limiter.util import get_remote_address
4
  from datetime import datetime, timedelta
5
- import secrets
6
- import sqlite3
7
- import os
8
  import threading
9
 
10
- app = Flask(__name__)
11
- app.secret_key = os.environ.get("FLASK_SECRET_KEY", "supersecret")
12
-
13
- # --- Rate limiting ---
14
- limiter = Limiter(get_remote_address, app=app, default_limits=["10 per minute"])
15
-
16
- # --- Configurable credentials ---
17
- API_KEY = os.environ.get("OTP_API_KEY", "secretapikey123")
18
  ADMIN_USER = os.environ.get("ADMIN_USER", "admin")
19
- ADMIN_PASS = os.environ.get("ADMIN_PASS", "admin123")
 
 
20
 
21
- # --- DB init ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  def init_db():
23
- conn = sqlite3.connect("database.db")
24
- c = conn.cursor()
25
- c.execute('''CREATE TABLE IF NOT EXISTS otp (
26
- id INTEGER PRIMARY KEY AUTOINCREMENT,
27
- code TEXT UNIQUE,
28
- created_at TEXT,
29
- expires_at TEXT,
30
- used INTEGER DEFAULT 0,
31
- used_at TEXT,
32
- result TEXT,
33
- ip TEXT
34
- )''')
35
- conn.commit()
36
- conn.close()
37
 
38
  init_db()
39
 
40
- def generate_otp():
41
- return str(secrets.randbelow(900000) + 100000)
 
42
 
43
- def insert_otp(code, created_at, expires_at, result="generated", ip=""):
44
- conn = sqlite3.connect("database.db")
45
- c = conn.cursor()
46
- c.execute("INSERT INTO otp (code, created_at, expires_at, result, ip) VALUES (?, ?, ?, ?, ?)",
47
- (code, created_at, expires_at, result, ip))
48
- conn.commit()
49
- conn.close()
50
-
51
- def mark_otp_used(code, result, ip):
52
- now = datetime.utcnow().isoformat()
53
- conn = sqlite3.connect("database.db")
54
- c = conn.cursor()
55
- c.execute("UPDATE otp SET used = 1, used_at = ?, result = ?, ip = ? WHERE code = ?",
56
- (now, result, ip, code))
57
- conn.commit()
58
- conn.close()
59
-
60
- # --- Routes ---
61
 
62
- @app.route("/")
63
- def home():
64
- return "✅ OTP API is running."
 
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  @app.route("/generate-otp", methods=["POST"])
67
- @limiter.limit("3 per minute")
68
- def generate_api():
69
- api_key = request.headers.get("X-API-Key")
70
- if api_key != API_KEY:
71
  return jsonify({"error": "Unauthorized"}), 401
72
-
73
  otp = generate_otp()
74
  now = datetime.utcnow()
75
  expires = now + timedelta(minutes=5)
76
- insert_otp(otp, now.isoformat(), expires.isoformat(), ip=request.remote_addr)
77
-
 
 
 
 
78
  return jsonify({"otp": otp, "expires_at": expires.isoformat()})
79
 
 
80
  @app.route("/verify-otp", methods=["POST"])
81
  @limiter.limit("10 per minute")
82
- def verify():
83
- data = request.json
84
- otp = data.get("otp")
85
- if not otp:
86
- return jsonify({"success": False, "message": "No OTP provided"}), 400
87
-
88
  now = datetime.utcnow()
89
- conn = sqlite3.connect("database.db")
90
  c = conn.cursor()
91
- c.execute("SELECT used, expires_at FROM otp WHERE code = ?", (otp,))
92
  row = c.fetchone()
93
-
94
  if not row:
95
- insert_otp(otp, now.isoformat(), now.isoformat(), result="invalid", ip=request.remote_addr)
96
- return jsonify({"success": False, "message": "Invalid OTP"}), 401
97
-
98
- used, expires_at = row
99
- expires_at = datetime.fromisoformat(expires_at)
100
-
101
- if used:
102
- return jsonify({"success": False, "message": "OTP already used"}), 403
103
- if now > expires_at:
104
- mark_otp_used(otp, result="expired", ip=request.remote_addr)
105
- return jsonify({"success": False, "message": "OTP expired"}), 403
106
-
107
- mark_otp_used(otp, result="success", ip=request.remote_addr)
108
- return jsonify({"success": True})
109
 
 
110
  @app.route("/export-log")
111
  def export_log():
112
- api_key = request.headers.get("X-API-Key")
113
- if api_key != API_KEY:
114
- return jsonify({"error": "Unauthorized"}), 401
115
-
116
- conn = sqlite3.connect("database.db")
117
  c = conn.cursor()
118
- c.execute("SELECT * FROM otp")
119
  rows = c.fetchall()
120
  conn.close()
 
121
 
122
- return jsonify({
123
- "columns": ["id", "code", "created_at", "expires_at", "used", "used_at", "result", "ip"],
124
- "data": rows
125
- })
126
-
127
- # --- UI with login ---
128
-
129
- @app.route("/login", methods=["GET", "POST"])
130
- def login():
131
- error = ""
132
- if request.method == "POST":
133
- username = request.form.get("username")
134
- password = request.form.get("password")
135
- if username == ADMIN_USER and password == ADMIN_PASS:
136
- session["logged_in"] = True
137
- return redirect("/generate")
138
- else:
139
- error = "❌ Invalid login"
140
- return render_template_string('''
141
- <h2>🔐 Admin Login</h2>
142
- <form method="post">
143
- <input name="username" placeholder="Username" required><br><br>
144
- <input name="password" type="password" placeholder="Password" required><br><br>
145
- <input type="submit" value="Login">
146
- </form>
147
- <p>{{ error }}</p>
148
- ''', error=error)
149
-
150
- @app.route("/generate", methods=["GET", "POST"])
151
- def generate_page():
152
- if not session.get("logged_in"):
153
- return redirect("/login")
154
-
155
- message = ""
156
- otp_data = None
157
- if request.method == "POST":
158
- otp = generate_otp()
159
- now = datetime.utcnow()
160
- expires = now + timedelta(minutes=5)
161
- insert_otp(otp, now.isoformat(), expires.isoformat(), ip=request.remote_addr)
162
- message = "✅ OTP generated!"
163
- otp_data = {"otp": otp, "expires_at": expires.isoformat()}
164
-
165
- return render_template_string("""
166
- <h2>🎯 Generate OTP</h2>
167
- <form method="post">
168
- <input type="submit" value="Generate New OTP">
169
- </form>
170
- {% if message %}
171
- <p><strong>{{ message }}</strong></p>
172
- {% endif %}
173
- {% if otp_data %}
174
- <div>
175
- <p><strong>OTP:</strong> {{ otp_data['otp'] }}</p>
176
- <p><strong>Expires At:</strong> {{ otp_data['expires_at'] }}</p>
177
- </div>
178
- {% endif %}
179
- <p><a href="/logout">Logout</a></p>
180
- """, message=message, otp_data=otp_data)
181
-
182
- @app.route("/logout")
183
- def logout():
184
- session.pop("logged_in", None)
185
- return redirect("/login")
186
 
187
- # --- Required Flask startup for Hugging Face Spaces ---
188
  def run():
189
  app.run(host="0.0.0.0", port=7860)
190
 
 
1
+ import os
2
+ import sqlite3
3
+ from flask import Flask, request, jsonify, render_template_string, redirect, url_for, session
4
  from flask_limiter import Limiter
5
  from flask_limiter.util import get_remote_address
6
  from datetime import datetime, timedelta
7
+ import random
8
+ import string
 
9
  import threading
10
 
11
+ # Configs from secrets
 
 
 
 
 
 
 
12
  ADMIN_USER = os.environ.get("ADMIN_USER", "admin")
13
+ ADMIN_PASS = os.environ.get("ADMIN_PASS", "Welcome123")
14
+ API_KEY = os.environ.get("OTP_API_KEY", "IDONTKNOWWHATIMDOING")
15
+ FLASK_SECRET_KEY = os.environ.get("FLASK_SECRET_KEY", "IDONTKNOWWHATISTHIS")
16
 
17
+ app = Flask(__name__)
18
+ app.secret_key = FLASK_SECRET_KEY
19
+
20
+ limiter = Limiter(get_remote_address, app=app)
21
+
22
+ DATABASE = "database.db"
23
+
24
+ # HTML template
25
+ template = """
26
+ <!DOCTYPE html>
27
+ <html>
28
+ <head>
29
+ <title>OTP Generator</title>
30
+ </head>
31
+ <body>
32
+ {% if not session.get("logged_in") %}
33
+ <h2>Login</h2>
34
+ <form method="POST">
35
+ <input name="username" placeholder="Username"><br>
36
+ <input name="password" placeholder="Password" type="password"><br>
37
+ <button type="submit">Login</button>
38
+ </form>
39
+ {% else %}
40
+ <h2>Generate OTP</h2>
41
+ <form method="POST">
42
+ <button type="submit">Generate OTP</button>
43
+ </form>
44
+ {% if otp %}
45
+ <p><strong>OTP:</strong> {{ otp }}</p>
46
+ <p>Expires At: {{ expires_at }}</p>
47
+ {% endif %}
48
+ <p><a href="{{ url_for('logout') }}">Logout</a></p>
49
+ {% endif %}
50
+ </body>
51
+ </html>
52
+ """
53
+
54
+ # Initialize DB
55
  def init_db():
56
+ with sqlite3.connect(DATABASE) as conn:
57
+ c = conn.cursor()
58
+ c.execute('''CREATE TABLE IF NOT EXISTS otps (
59
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
60
+ otp TEXT,
61
+ generated_at TEXT,
62
+ expires_at TEXT,
63
+ used_at TEXT,
64
+ ip_address TEXT,
65
+ status TEXT
66
+ )''')
67
+ conn.commit()
 
 
68
 
69
  init_db()
70
 
71
+ # Helper
72
+ def generate_otp(length=6):
73
+ return ''.join(random.choices(string.digits, k=length))
74
 
75
+ # Web login
76
+ @app.route("/login", methods=["GET", "POST"])
77
+ def login():
78
+ if request.method == "POST":
79
+ if request.form["username"] == ADMIN_USER and request.form["password"] == ADMIN_PASS:
80
+ session["logged_in"] = True
81
+ return redirect(url_for("generate_page"))
82
+ return render_template_string(template)
 
 
 
 
 
 
 
 
 
 
83
 
84
+ @app.route("/logout")
85
+ def logout():
86
+ session.pop("logged_in", None)
87
+ return redirect(url_for("login"))
88
 
89
+ # Web generate UI
90
+ @app.route("/generate", methods=["GET", "POST"])
91
+ def generate_page():
92
+ if not session.get("logged_in"):
93
+ return redirect(url_for("login"))
94
+ otp = None
95
+ expires_at = None
96
+ if request.method == "POST":
97
+ otp = generate_otp()
98
+ now = datetime.utcnow()
99
+ expires = now + timedelta(minutes=5)
100
+ expires_at = expires.isoformat()
101
+ conn = sqlite3.connect(DATABASE)
102
+ c = conn.cursor()
103
+ c.execute("INSERT INTO otps (otp, generated_at, expires_at, ip_address, status) VALUES (?, ?, ?, ?, ?)",
104
+ (otp, now.isoformat(), expires_at, request.remote_addr, "generated"))
105
+ conn.commit()
106
+ conn.close()
107
+ return render_template_string(template, otp=otp, expires_at=expires_at)
108
+
109
+ # API generate OTP
110
  @app.route("/generate-otp", methods=["POST"])
111
+ @limiter.limit("5 per minute")
112
+ def api_generate_otp():
113
+ if request.headers.get("X-API-Key") != API_KEY:
 
114
  return jsonify({"error": "Unauthorized"}), 401
 
115
  otp = generate_otp()
116
  now = datetime.utcnow()
117
  expires = now + timedelta(minutes=5)
118
+ conn = sqlite3.connect(DATABASE)
119
+ c = conn.cursor()
120
+ c.execute("INSERT INTO otps (otp, generated_at, expires_at, ip_address, status) VALUES (?, ?, ?, ?, ?)",
121
+ (otp, now.isoformat(), expires.isoformat(), request.remote_addr, "generated"))
122
+ conn.commit()
123
+ conn.close()
124
  return jsonify({"otp": otp, "expires_at": expires.isoformat()})
125
 
126
+ # API verify OTP
127
  @app.route("/verify-otp", methods=["POST"])
128
  @limiter.limit("10 per minute")
129
+ def verify_otp():
130
+ data = request.get_json()
131
+ otp_input = data.get("otp", "")
 
 
 
132
  now = datetime.utcnow()
133
+ conn = sqlite3.connect(DATABASE)
134
  c = conn.cursor()
135
+ c.execute("SELECT id, expires_at, used_at FROM otps WHERE otp=? AND status='generated'", (otp_input,))
136
  row = c.fetchone()
 
137
  if not row:
138
+ return jsonify({"success": False, "message": "Invalid or already used OTP"}), 400
139
+ otp_id, expires_at, used_at = row
140
+ if datetime.fromisoformat(expires_at) < now:
141
+ c.execute("UPDATE otps SET status='expired' WHERE id=?", (otp_id,))
142
+ conn.commit()
143
+ conn.close()
144
+ return jsonify({"success": False, "message": "OTP expired"}), 400
145
+ c.execute("UPDATE otps SET used_at=?, status='used' WHERE id=?", (now.isoformat(), otp_id))
146
+ conn.commit()
147
+ conn.close()
148
+ return jsonify({"success": True, "message": "OTP valid"})
 
 
 
149
 
150
+ # Audit log
151
  @app.route("/export-log")
152
  def export_log():
153
+ conn = sqlite3.connect(DATABASE)
 
 
 
 
154
  c = conn.cursor()
155
+ c.execute("SELECT * FROM otps ORDER BY id DESC")
156
  rows = c.fetchall()
157
  conn.close()
158
+ return jsonify(rows)
159
 
160
+ # Root
161
+ @app.route("/")
162
+ def home():
163
+ return "OTP API is running"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
+ # Run in HF Space
166
  def run():
167
  app.run(host="0.0.0.0", port=7860)
168