0vergeared commited on
Commit
5f00f06
·
verified ·
1 Parent(s): bc70712

Update server.py

Browse files
Files changed (1) hide show
  1. server.py +112 -165
server.py CHANGED
@@ -1,179 +1,155 @@
1
  import os
2
- import random
3
  import sqlite3
4
  import csv
5
  import json
 
 
6
  from datetime import datetime, timedelta
7
- from flask import Flask, request, jsonify, redirect, session, render_template_string, send_file
8
-
9
  from flask_limiter import Limiter
10
  from flask_limiter.util import get_remote_address
11
- import pathlib
 
 
 
 
 
 
 
 
12
 
13
- # Paths and setup
14
- DATABASE = "/tmp/database.db"
15
- EXPORT_CSV = "/data/otp_logs.csv"
16
- EXPORT_JSON = "/data/otp_logs.json"
17
- pathlib.Path("/data").mkdir(parents=True, exist_ok=True)
18
 
19
- # App setup
20
  app = Flask(__name__)
21
- app.secret_key = os.getenv("FLASK_SECRET_KEY", "IDONTKNOWWHATISTHIS")
22
 
23
- # Rate limiter setup
24
  limiter = Limiter(key_func=get_remote_address)
25
  limiter.init_app(app)
26
 
27
- # Auth
28
- ADMIN_USER = os.getenv("ADMIN_USER", "admin")
29
- ADMIN_PASS = os.getenv("ADMIN_PASS", "Welcome123")
30
- OTP_API_KEY = os.getenv("OTP_API_KEY", "IDONTKNOWWHATIMDOING")
31
-
32
- # Templates
33
- LOGIN_TEMPLATE = """
34
- <!DOCTYPE html><html><head><title>Login</title></head><body>
35
- <h2>Admin Login</h2>
36
- <form method="post">
37
- Username: <input name="username"><br>
38
- Password: <input name="password" type="password"><br>
39
- <input type="submit" value="Login">
40
- </form>
41
- </body></html>
42
- """
43
-
44
- GEN_TEMPLATE = """
45
- <!DOCTYPE html><html><head><title>OTP Admin</title></head><body>
46
- <h2>Generate OTP</h2>
47
- <form method="post">
48
- <button type="submit">Generate OTP</button>
49
- </form>
50
- {% if otp %}
51
- <p><b>OTP:</b> {{ otp }}<br><b>Expires:</b> {{ expires }}</p>
52
- {% endif %}
53
-
54
- <hr>
55
- <h3>Recent OTPs</h3>
56
- <table border="1" cellpadding="5">
57
- <tr><th>OTP</th><th>Generated At</th><th>Expires</th><th>Used At</th><th>Status</th><th>IP</th></tr>
58
- {% for row in otps %}
59
- <tr>
60
- <td>{{ row[0] }}</td>
61
- <td>{{ row[1] }}</td>
62
- <td>{{ row[2] }}</td>
63
- <td>{{ row[3] or "-" }}</td>
64
- <td>{{ row[5] }}</td>
65
- <td>{{ row[4] }}</td>
66
- </tr>
67
- {% endfor %}
68
- </table>
69
- <p><a href="/download-csv" target="_blank">📥 Download CSV</a> | <a href="/download-json" target="_blank">📥 Download JSON</a></p>
70
- <a href="/logout">Logout</a>
71
- </body></html>
72
- """
73
-
74
- # DB init
75
  def init_db():
76
  with sqlite3.connect(DATABASE) as conn:
77
  c = conn.cursor()
78
- c.execute("""CREATE TABLE IF NOT EXISTS otps (
79
- id INTEGER PRIMARY KEY AUTOINCREMENT,
80
- otp TEXT,
81
- generated_at TEXT,
82
- expires_at TEXT,
83
- used_at TEXT,
84
- ip_address TEXT,
85
- status TEXT
86
- )""")
 
 
87
  conn.commit()
88
 
89
- init_db()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
- # Routes
92
  @app.route("/login", methods=["GET", "POST"])
93
  def login():
94
  if request.method == "POST":
95
  if request.form["username"] == ADMIN_USER and request.form["password"] == ADMIN_PASS:
96
  session["admin"] = True
97
- return redirect("/generate")
98
- else:
99
- return "Invalid credentials", 403
100
- return LOGIN_TEMPLATE
101
-
102
- @app.route("/logout")
103
- def logout():
104
- session.clear()
105
- return redirect("/login")
 
106
 
107
  @app.route("/generate", methods=["GET", "POST"])
108
- def generate_page():
109
- if not session.get("admin"):
110
- return redirect("/login")
111
-
112
- otp = None
113
- expires = None
114
 
115
  if request.method == "POST":
116
  otp = generate_otp()
117
  now = datetime.utcnow()
118
  expires_at = now + timedelta(minutes=10)
 
119
  with sqlite3.connect(DATABASE) as conn:
120
  c = conn.cursor()
121
  c.execute("INSERT INTO otps (otp, generated_at, expires_at, ip_address, status) VALUES (?, ?, ?, ?, ?)",
122
  (otp, now.isoformat(), expires_at.isoformat(), request.remote_addr, "generated"))
123
  conn.commit()
124
- expires = expires_at.isoformat()
125
- export_logs()
126
 
127
- with sqlite3.connect(DATABASE) as conn:
128
- c = conn.cursor()
129
- c.execute("SELECT otp, generated_at, expires_at, used_at, ip_address, status FROM otps ORDER BY id DESC LIMIT 10")
130
- otps = c.fetchall()
131
-
132
- return render_template_string(GEN_TEMPLATE, otp=otp, expires=expires, otps=otps)
133
-
134
- @app.route("/generate-otp", methods=["POST"])
135
- @limiter.limit("10 per minute")
136
- def api_generate_otp():
137
- api_key = request.headers.get("X-API-Key")
138
- if api_key != OTP_API_KEY:
139
- return jsonify({"error": "Invalid API key"}), 403
140
-
141
- otp = generate_otp()
142
- now = datetime.utcnow()
143
- expires_at = now + timedelta(minutes=10)
144
- with sqlite3.connect(DATABASE) as conn:
145
- c = conn.cursor()
146
- c.execute("INSERT INTO otps (otp, generated_at, expires_at, ip_address, status) VALUES (?, ?, ?, ?, ?)",
147
- (otp, now.isoformat(), expires_at.isoformat(), request.remote_addr, "generated"))
148
- conn.commit()
149
- export_logs()
150
- return jsonify({"otp": otp, "expires": expires_at.isoformat()})
151
-
152
- @app.route("/verify-otp", methods=["POST"])
153
- @limiter.limit("30 per minute")
154
- def verify_otp():
155
- data = request.get_json()
156
- otp = data.get("otp")
157
 
158
- with sqlite3.connect(DATABASE) as conn:
159
- c = conn.cursor()
160
- c.execute("SELECT id, expires_at, used_at, status FROM otps WHERE otp = ?", (otp,))
161
- row = c.fetchone()
162
- if not row:
163
- return jsonify({"valid": False, "reason": "Invalid OTP"})
164
- otp_id, expires_at, used_at, status = row
165
 
166
- if status == "used":
167
- return jsonify({"valid": False, "reason": "OTP already used"})
168
 
169
- if datetime.fromisoformat(expires_at) < datetime.utcnow():
170
- return jsonify({"valid": False, "reason": "OTP expired"})
 
 
 
 
 
 
 
171
 
172
- now = datetime.utcnow().isoformat()
173
- c.execute("UPDATE otps SET used_at = ?, status = ? WHERE id = ?", (now, "used", otp_id))
174
- conn.commit()
175
- export_logs()
176
- return jsonify({"valid": True})
177
 
178
  @app.route("/download-csv")
179
  def download_csv():
@@ -193,36 +169,7 @@ def debug():
193
  "json_exists": os.path.exists(EXPORT_JSON),
194
  })
195
 
196
- # Helpers
197
- def generate_otp():
198
- return str(random.randint(100000, 999999))
199
-
200
- def export_logs():
201
- with sqlite3.connect(DATABASE) as conn:
202
- c = conn.cursor()
203
- c.execute("SELECT otp, generated_at, expires_at, used_at, ip_address, status FROM otps ORDER BY id DESC")
204
- rows = c.fetchall()
205
-
206
- # Save CSV
207
- with open(EXPORT_CSV, "w", newline="") as f:
208
- writer = csv.writer(f)
209
- writer.writerow(["otp", "generated_at", "expires_at", "used_at", "ip_address", "status"])
210
- writer.writerows(rows)
211
-
212
- # Save JSON
213
- json_data = [
214
- {
215
- "otp": row[0],
216
- "generated_at": row[1],
217
- "expires_at": row[2],
218
- "used_at": row[3],
219
- "ip_address": row[4],
220
- "status": row[5]
221
- }
222
- for row in rows
223
- ]
224
- with open(EXPORT_JSON, "w") as f:
225
- json.dump(json_data, f, indent=2)
226
-
227
  if __name__ == "__main__":
 
228
  app.run(host="0.0.0.0", port=7860)
 
1
  import os
 
2
  import sqlite3
3
  import csv
4
  import json
5
+ import pathlib
6
+ import random
7
  from datetime import datetime, timedelta
8
+ from flask import Flask, request, render_template_string, redirect, url_for, session, send_file, jsonify
 
9
  from flask_limiter import Limiter
10
  from flask_limiter.util import get_remote_address
11
+ from datasets import Dataset
12
+ from huggingface_hub import HfApi
13
+
14
+ # === Config ===
15
+ ADMIN_USER = os.getenv("ADMIN_USER", "admin")
16
+ ADMIN_PASS = os.getenv("ADMIN_PASS", "Welcome123")
17
+ FLASK_SECRET = os.getenv("FLASK_SECRET", "IDONTKNOWWHATISTHIS")
18
+ HF_TOKEN = os.getenv("HF_TOKEN", "")
19
+ HF_DATASET_REPO = "0vergeared/otp-logs"
20
 
21
+ DATABASE = "/tmp/otp.db"
22
+ EXPORT_CSV = "/tmp/otp_logs.csv"
23
+ EXPORT_JSON = "/tmp/otp_logs.json"
24
+ pathlib.Path("/tmp").mkdir(parents=True, exist_ok=True)
 
25
 
26
+ # === App Setup ===
27
  app = Flask(__name__)
28
+ app.secret_key = FLASK_SECRET
29
 
 
30
  limiter = Limiter(key_func=get_remote_address)
31
  limiter.init_app(app)
32
 
33
+ # === Helpers ===
34
+ def generate_otp():
35
+ return str(random.randint(100000, 999999))
36
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  def init_db():
38
  with sqlite3.connect(DATABASE) as conn:
39
  c = conn.cursor()
40
+ c.execute("""
41
+ CREATE TABLE IF NOT EXISTS otps (
42
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
43
+ otp TEXT,
44
+ generated_at TEXT,
45
+ expires_at TEXT,
46
+ used_at TEXT,
47
+ ip_address TEXT,
48
+ status TEXT
49
+ )
50
+ """)
51
  conn.commit()
52
 
53
+ def export_logs():
54
+ with sqlite3.connect(DATABASE) as conn:
55
+ c = conn.cursor()
56
+ c.execute("SELECT otp, generated_at, expires_at, used_at, ip_address, status FROM otps ORDER BY id DESC")
57
+ rows = c.fetchall()
58
+
59
+ # Save CSV
60
+ with open(EXPORT_CSV, "w", newline="") as f:
61
+ writer = csv.writer(f)
62
+ writer.writerow(["otp", "generated_at", "expires_at", "used_at", "ip_address", "status"])
63
+ writer.writerows(rows)
64
+
65
+ # Save JSON
66
+ json_data = [
67
+ {
68
+ "otp": row[0],
69
+ "generated_at": row[1],
70
+ "expires_at": row[2],
71
+ "used_at": row[3],
72
+ "ip_address": row[4],
73
+ "status": row[5]
74
+ }
75
+ for row in rows
76
+ ]
77
+ with open(EXPORT_JSON, "w") as f:
78
+ json.dump(json_data, f, indent=2)
79
+
80
+ def upload_to_hf(otp_row):
81
+ try:
82
+ import pandas as pd
83
+ df = pd.DataFrame([otp_row], columns=["otp", "generated_at", "expires_at", "used_at", "ip_address", "status"])
84
+ dataset = Dataset.from_pandas(df)
85
+ dataset.push_to_hub(repo_id=HF_DATASET_REPO, token=HF_TOKEN)
86
+ print("✅ OTP log pushed to Hugging Face")
87
+ except Exception as e:
88
+ print("⚠️ Failed to upload OTP log:", e)
89
+
90
+ # === Routes ===
91
+
92
+ @app.route("/")
93
+ def home():
94
+ if "admin" not in session:
95
+ return redirect(url_for("login"))
96
+ return redirect(url_for("generate"))
97
 
 
98
  @app.route("/login", methods=["GET", "POST"])
99
  def login():
100
  if request.method == "POST":
101
  if request.form["username"] == ADMIN_USER and request.form["password"] == ADMIN_PASS:
102
  session["admin"] = True
103
+ return redirect(url_for("generate"))
104
+ return "Login failed"
105
+ return render_template_string("""
106
+ <h2>Admin Login</h2>
107
+ <form method="post">
108
+ Username: <input name="username"><br>
109
+ Password: <input type="password" name="password"><br>
110
+ <input type="submit" value="Login">
111
+ </form>
112
+ """)
113
 
114
  @app.route("/generate", methods=["GET", "POST"])
115
+ def generate():
116
+ if "admin" not in session:
117
+ return redirect(url_for("login"))
 
 
 
118
 
119
  if request.method == "POST":
120
  otp = generate_otp()
121
  now = datetime.utcnow()
122
  expires_at = now + timedelta(minutes=10)
123
+
124
  with sqlite3.connect(DATABASE) as conn:
125
  c = conn.cursor()
126
  c.execute("INSERT INTO otps (otp, generated_at, expires_at, ip_address, status) VALUES (?, ?, ?, ?, ?)",
127
  (otp, now.isoformat(), expires_at.isoformat(), request.remote_addr, "generated"))
128
  conn.commit()
 
 
129
 
130
+ # Export logs
131
+ export_logs()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
+ # Push to Hugging Face Dataset
134
+ otp_row = [otp, now.isoformat(), expires_at.isoformat(), None, request.remote_addr, "generated"]
135
+ upload_to_hf(otp_row)
 
 
 
 
136
 
137
+ return f"Generated OTP: <b>{otp}</b> (expires in 10 mins)<br><a href='/generate'>Back</a>"
 
138
 
139
+ return render_template_string("""
140
+ <h2>Generate OTP</h2>
141
+ <form method="post">
142
+ <input type="submit" value="Generate OTP">
143
+ </form>
144
+ <a href='/download-csv'>Download CSV</a> |
145
+ <a href='/download-json'>Download JSON</a> |
146
+ <a href='/logout'>Logout</a>
147
+ """)
148
 
149
+ @app.route("/logout")
150
+ def logout():
151
+ session.pop("admin", None)
152
+ return redirect(url_for("login"))
 
153
 
154
  @app.route("/download-csv")
155
  def download_csv():
 
169
  "json_exists": os.path.exists(EXPORT_JSON),
170
  })
171
 
172
+ # === Run App ===
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  if __name__ == "__main__":
174
+ init_db()
175
  app.run(host="0.0.0.0", port=7860)