0vergeared commited on
Commit
d9fbe52
·
verified ·
1 Parent(s): 15850fa

Update server.py

Browse files
Files changed (1) hide show
  1. server.py +101 -104
server.py CHANGED
@@ -1,104 +1,67 @@
1
  import os
2
- import sqlite3
3
- import secrets
 
 
4
  from datetime import datetime, timedelta
5
- from flask import Flask, request, redirect, url_for, render_template, session, flash
6
  from flask_limiter import Limiter
7
  from flask_limiter.util import get_remote_address
8
- from huggingface_hub import HfApi
 
9
  import pandas as pd
10
 
11
- # ENV
 
 
 
 
 
 
12
  ADMIN_USER = os.getenv("ADMIN_USER", "admin")
13
  ADMIN_PASS = os.getenv("ADMIN_PASS", "Welcome123")
14
- FLASK_SECRET = os.getenv("FLASK_SECRET", "supersecret")
15
  HF_TOKEN = os.getenv("HF_TOKEN")
16
- HF_REPO_ID = "0vergeared/otp-logs"
17
-
18
- # Writeable database path
19
- DATABASE = "/tmp/otp.db"
20
- EXPORT_CSV = "/tmp/otp_all.csv"
21
-
22
- # Flask app
23
- app = Flask(__name__, template_folder="templates")
24
- app.secret_key = FLASK_SECRET
25
- limiter = Limiter(get_remote_address, app=app)
26
-
27
- # Initialize DB
28
- def init_db():
29
- with sqlite3.connect(DATABASE) as conn:
30
- c = conn.cursor()
31
- c.execute('''CREATE TABLE IF NOT EXISTS otps (
32
- id INTEGER PRIMARY KEY AUTOINCREMENT,
33
- otp TEXT UNIQUE,
34
- generated_at TEXT,
35
- expires_at TEXT,
36
- used_at TEXT,
37
- ip_address TEXT,
38
- status TEXT
39
- )''')
40
- conn.commit()
41
-
42
- # Generate OTP
43
- def generate_otp():
44
- return ''.join(secrets.choice("0123456789") for _ in range(6))
45
-
46
- # Upload CSV to HF dataset
47
- def upload_to_hf(otp_row):
48
- file_exists = os.path.exists(EXPORT_CSV)
49
- df_new = pd.DataFrame([otp_row], columns=["otp", "generated_at", "expires_at", "used_at", "ip", "status"])
50
-
51
- if file_exists:
52
- df_old = pd.read_csv(EXPORT_CSV)
53
- df = pd.concat([df_old, df_new], ignore_index=True)
54
- else:
55
- df = df_new
56
-
57
- df.to_csv(EXPORT_CSV, index=False)
58
 
59
  try:
 
60
  api = HfApi()
61
- api.upload_file(
62
- path_or_fileobj=EXPORT_CSV,
63
- path_in_repo="otp_all.csv",
64
- repo_id=HF_REPO_ID,
65
- token=HF_TOKEN,
66
- create_pr=False
67
- )
68
- print("✅ OTP log uploaded to HF.")
 
 
 
 
 
 
69
  except Exception as e:
70
- print("⚠️ Hugging Face upload failed:", e)
71
 
72
- # Routes
73
- @app.route("/", methods=["GET", "POST"])
74
  def index():
75
- if request.method == "POST":
76
- otp_input = request.form.get("otp")
77
- now = datetime.utcnow()
78
-
79
- with sqlite3.connect(DATABASE) as conn:
80
- c = conn.cursor()
81
- c.execute("SELECT * FROM otps WHERE otp = ?", (otp_input,))
82
- row = c.fetchone()
83
-
84
- if row:
85
- otp, gen_at, exp_at, used_at, ip, status = row[1:7]
86
- exp_time = datetime.fromisoformat(exp_at)
87
- if used_at:
88
- flash("OTP already used!", "danger")
89
- elif now > exp_time:
90
- flash("OTP expired!", "danger")
91
- else:
92
- used_time = now.isoformat()
93
- c.execute("UPDATE otps SET used_at = ?, status = ? WHERE otp = ?", (used_time, "used", otp_input))
94
- conn.commit()
95
- otp_row = [otp_input, gen_at, exp_at, used_time, request.remote_addr, "used"]
96
- upload_to_hf(otp_row)
97
- flash("✅ OTP accepted. Installation can proceed!", "success")
98
- return redirect(url_for("index"))
99
- else:
100
- flash("❌ Invalid OTP!", "danger")
101
-
102
  return render_template("index.html")
103
 
104
  @app.route("/admin", methods=["GET", "POST"])
@@ -109,38 +72,72 @@ def admin():
109
  if username == ADMIN_USER and password == ADMIN_PASS:
110
  session["admin"] = True
111
  return redirect(url_for("dashboard"))
112
- else:
113
- flash("❌ Login failed", "danger")
114
  return render_template("admin_login.html")
115
 
116
- @app.route("/dashboard", methods=["GET", "POST"])
117
  def dashboard():
 
 
 
 
 
 
 
 
 
 
 
118
  if not session.get("admin"):
119
  return redirect(url_for("admin"))
120
 
121
- if request.method == "POST":
122
- otp = generate_otp()
123
- now = datetime.utcnow()
124
- expires = now + timedelta(minutes=10)
125
- ip = request.remote_addr
 
 
 
 
 
 
 
 
 
 
 
126
 
127
- with sqlite3.connect(DATABASE) as conn:
128
- c = conn.cursor()
129
- c.execute("INSERT INTO otps (otp, generated_at, expires_at, ip_address, status) VALUES (?, ?, ?, ?, ?)",
130
- (otp, now.isoformat(), expires.isoformat(), ip, "generated"))
131
- conn.commit()
132
 
133
- otp_row = [otp, now.isoformat(), expires.isoformat(), None, ip, "generated"]
134
- upload_to_hf(otp_row)
135
- flash(f"✅ OTP Generated: {otp}", "success")
136
 
137
- return render_template("dashboard.html")
 
 
 
 
 
 
 
 
 
138
 
139
  @app.route("/logout")
140
  def logout():
141
  session.clear()
142
  return redirect(url_for("index"))
143
 
 
 
 
 
 
 
 
144
  if __name__ == "__main__":
145
- init_db()
146
  app.run(host="0.0.0.0", port=7860)
 
1
  import os
2
+ import csv
3
+ import random
4
+ import string
5
+ import pathlib
6
  from datetime import datetime, timedelta
7
+ from flask import Flask, request, redirect, url_for, session, render_template, flash, jsonify
8
  from flask_limiter import Limiter
9
  from flask_limiter.util import get_remote_address
10
+ from huggingface_hub import HfApi, HfFolder
11
+ from datasets import Dataset as HFDataset
12
  import pandas as pd
13
 
14
+ # --- Setup ---
15
+ app = Flask(__name__)
16
+ app.secret_key = os.getenv("FLASK_SECRET", "supersecret")
17
+ limiter = Limiter(get_remote_address)
18
+ limiter.init_app(app)
19
+
20
+ # --- Admin credentials ---
21
  ADMIN_USER = os.getenv("ADMIN_USER", "admin")
22
  ADMIN_PASS = os.getenv("ADMIN_PASS", "Welcome123")
 
23
  HF_TOKEN = os.getenv("HF_TOKEN")
24
+
25
+ # --- Dataset info ---
26
+ REPO_ID = "0vergeared/otp-logs"
27
+ LOCAL_CSV = "otp_temp.csv"
28
+
29
+ # --- Ensure templates folder exists ---
30
+ pathlib.Path("templates").mkdir(parents=True, exist_ok=True)
31
+
32
+ # --- OTP Generator ---
33
+ def generate_otp(length=6):
34
+ return ''.join(random.choices(string.digits, k=length))
35
+
36
+ # --- Save OTP to Hugging Face Dataset ---
37
+ def save_otp_to_dataset(otp: str, expiry: str):
38
+ if not HF_TOKEN:
39
+ print("❌ HF_TOKEN missing. Skipping dataset upload.")
40
+ return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  try:
43
+ HfFolder.save_token(HF_TOKEN)
44
  api = HfApi()
45
+
46
+ # Load existing data or create new
47
+ df = pd.read_csv(LOCAL_CSV) if os.path.exists(LOCAL_CSV) else pd.DataFrame(columns=["otp", "expiry", "used"])
48
+
49
+ # Append new OTP
50
+ df = pd.concat([df, pd.DataFrame([{"otp": otp, "expiry": expiry, "used": False}])], ignore_index=True)
51
+
52
+ # Save to local file
53
+ df.to_csv(LOCAL_CSV, index=False)
54
+
55
+ # Push to HF Hub
56
+ dataset = HFDataset.from_pandas(df)
57
+ dataset.push_to_hub(REPO_ID, token=HF_TOKEN)
58
+ print("✅ OTP pushed to Hugging Face dataset.")
59
  except Exception as e:
60
+ print(" Failed to save OTP to dataset:", e)
61
 
62
+ # --- Routes ---
63
+ @app.route("/")
64
  def index():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  return render_template("index.html")
66
 
67
  @app.route("/admin", methods=["GET", "POST"])
 
72
  if username == ADMIN_USER and password == ADMIN_PASS:
73
  session["admin"] = True
74
  return redirect(url_for("dashboard"))
75
+ flash("❌ Login failed", "danger")
 
76
  return render_template("admin_login.html")
77
 
78
+ @app.route("/dashboard")
79
  def dashboard():
80
+ if not session.get("admin"):
81
+ return redirect(url_for("admin"))
82
+ otps = []
83
+ if os.path.exists(LOCAL_CSV):
84
+ with open(LOCAL_CSV, newline='') as f:
85
+ reader = csv.DictReader(f)
86
+ otps = list(reader)
87
+ return render_template("dashboard.html", otps=otps)
88
+
89
+ @app.route("/generate_otp", methods=["POST"])
90
+ def generate_otp_route():
91
  if not session.get("admin"):
92
  return redirect(url_for("admin"))
93
 
94
+ otp = generate_otp()
95
+ expiry = (datetime.utcnow() + timedelta(minutes=5)).isoformat()
96
+ save_otp_to_dataset(otp, expiry)
97
+ flash(f"✅ OTP generated: {otp}", "success")
98
+ return redirect(url_for("dashboard"))
99
+
100
+ @app.route("/validate", methods=["POST"])
101
+ @limiter.limit("10 per minute")
102
+ def validate():
103
+ data = request.get_json()
104
+ input_otp = data.get("otp")
105
+
106
+ if not input_otp or not os.path.exists(LOCAL_CSV):
107
+ return jsonify({"status": "error", "message": "Invalid request"}), 400
108
+
109
+ df = pd.read_csv(LOCAL_CSV)
110
 
111
+ match = df[(df["otp"] == input_otp) & (df["used"] == False)]
112
+ if match.empty:
113
+ return jsonify({"status": "error", "message": "Invalid or used OTP"}), 403
 
 
114
 
115
+ expiry_time = datetime.fromisoformat(match.iloc[0]["expiry"])
116
+ if datetime.utcnow() > expiry_time:
117
+ return jsonify({"status": "error", "message": "OTP expired"}), 403
118
 
119
+ df.loc[df["otp"] == input_otp, "used"] = True
120
+ df.to_csv(LOCAL_CSV, index=False)
121
+
122
+ try:
123
+ dataset = HFDataset.from_pandas(df)
124
+ dataset.push_to_hub(REPO_ID, token=HF_TOKEN)
125
+ except Exception as e:
126
+ print("⚠️ Could not update dataset:", e)
127
+
128
+ return jsonify({"status": "success", "message": "OTP verified"})
129
 
130
  @app.route("/logout")
131
  def logout():
132
  session.clear()
133
  return redirect(url_for("index"))
134
 
135
+ # --- Prevent iframe login issues ---
136
+ @app.after_request
137
+ def add_header(response):
138
+ response.headers["X-Frame-Options"] = "SAMEORIGIN"
139
+ return response
140
+
141
+ # --- Start ---
142
  if __name__ == "__main__":
 
143
  app.run(host="0.0.0.0", port=7860)