Update app.py
Browse files
app.py
CHANGED
@@ -1,63 +1,73 @@
|
|
1 |
-
from flask import Flask, request, jsonify
|
2 |
from flask_cors import CORS
|
3 |
-
from
|
|
|
4 |
import uuid
|
5 |
-
import
|
|
|
|
|
|
|
6 |
import time
|
7 |
|
8 |
app = Flask(__name__)
|
9 |
CORS(app)
|
10 |
|
11 |
-
# In-memory
|
12 |
-
|
|
|
13 |
|
14 |
-
@app.route("/")
|
15 |
-
def index():
|
16 |
-
return "✅ Sharelock-style secret backend is running."
|
17 |
-
|
18 |
-
@app.route('/api/store', methods=['POST'])
|
19 |
def store():
|
20 |
-
|
21 |
-
data =
|
22 |
-
ttl = int(
|
23 |
-
view_once =
|
24 |
-
|
25 |
-
secret_id = str(uuid.uuid4())[:8]
|
26 |
-
expire_at = datetime.utcnow() + timedelta(seconds=ttl)
|
27 |
-
|
28 |
-
storage[secret_id] = {
|
29 |
-
'data': data,
|
30 |
-
'expire_at': expire_at,
|
31 |
-
'view_once': view_once,
|
32 |
-
}
|
33 |
|
34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
-
@app.route(
|
37 |
-
def fetch(
|
38 |
-
secret =
|
39 |
if not secret:
|
40 |
-
return jsonify({
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
time.sleep(60) # Run every minute
|
58 |
-
|
59 |
-
# Start cleanup thread
|
60 |
-
threading.Thread(target=cleanup, daemon=True).start()
|
61 |
|
62 |
if __name__ == "__main__":
|
63 |
app.run(host="0.0.0.0", port=7860)
|
|
|
1 |
+
from flask import Flask, request, jsonify, send_file
|
2 |
from flask_cors import CORS
|
3 |
+
from werkzeug.utils import secure_filename
|
4 |
+
import tempfile
|
5 |
import uuid
|
6 |
+
import os
|
7 |
+
import io
|
8 |
+
import base64
|
9 |
+
from PIL import Image
|
10 |
import time
|
11 |
|
12 |
app = Flask(__name__)
|
13 |
CORS(app)
|
14 |
|
15 |
+
# In-memory store: { id: { data, image (optional), expire_at, view_once } }
|
16 |
+
SECRETS = {}
|
17 |
+
MAX_IMAGE_SIZE = 300 * 1024 # 300 KB
|
18 |
|
19 |
+
@app.route("/api/store", methods=["POST"])
|
|
|
|
|
|
|
|
|
20 |
def store():
|
21 |
+
form = request.form
|
22 |
+
data = form.get("data")
|
23 |
+
ttl = int(form.get("ttl", 300))
|
24 |
+
view_once = form.get("view_once") == "true"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
|
26 |
+
# Handle image if present
|
27 |
+
image_file = request.files.get("image")
|
28 |
+
image_data = None
|
29 |
+
|
30 |
+
if image_file:
|
31 |
+
img_bytes = image_file.read()
|
32 |
+
if len(img_bytes) > MAX_IMAGE_SIZE:
|
33 |
+
image = Image.open(io.BytesIO(img_bytes))
|
34 |
+
image.thumbnail((1024, 1024)) # Resize for safety
|
35 |
+
output = io.BytesIO()
|
36 |
+
image.save(output, format="JPEG", optimize=True, quality=70)
|
37 |
+
image_data = base64.b64encode(output.getvalue()).decode("utf-8")
|
38 |
+
else:
|
39 |
+
image_data = base64.b64encode(img_bytes).decode("utf-8")
|
40 |
+
|
41 |
+
sid = str(uuid.uuid4())
|
42 |
+
SECRETS[sid] = {
|
43 |
+
"data": data,
|
44 |
+
"image": image_data,
|
45 |
+
"expire_at": time.time() + ttl,
|
46 |
+
"view_once": view_once
|
47 |
+
}
|
48 |
+
return jsonify({"id": sid})
|
49 |
|
50 |
+
@app.route("/api/fetch/<sid>")
|
51 |
+
def fetch(sid):
|
52 |
+
secret = SECRETS.get(sid)
|
53 |
if not secret:
|
54 |
+
return jsonify({"error": "Not found"}), 404
|
55 |
+
if time.time() > secret["expire_at"]:
|
56 |
+
del SECRETS[sid]
|
57 |
+
return jsonify({"error": "Expired"}), 410
|
58 |
+
|
59 |
+
response = {"data": secret["data"]}
|
60 |
+
if secret.get("image"):
|
61 |
+
response["image"] = secret["image"]
|
62 |
+
|
63 |
+
if secret["view_once"]:
|
64 |
+
del SECRETS[sid]
|
65 |
+
|
66 |
+
return jsonify(response)
|
67 |
+
|
68 |
+
@app.route("/")
|
69 |
+
def index():
|
70 |
+
return "Sharelock Flask backend is running."
|
|
|
|
|
|
|
|
|
71 |
|
72 |
if __name__ == "__main__":
|
73 |
app.run(host="0.0.0.0", port=7860)
|