jebin2 commited on
Commit
ae46515
·
1 Parent(s): 7f05702
Files changed (1) hide show
  1. main.py +43 -17
main.py CHANGED
@@ -4,16 +4,27 @@ import glob
4
  import re
5
  import base64
6
  import time
 
 
 
 
 
 
 
 
 
7
 
8
  app = Flask(__name__)
9
 
10
- # --- CONFIGURATION ---
11
- # Store data in a dedicated directory
12
- DATA_DIR = os.path.join('/tmp')
13
- MAX_TOTAL_SIZE_MB = 100 # Max total size of all notes in MB
14
- PURGE_TO_SIZE_MB = 80 # When purging, reduce total size to this
15
- AGE_LIMIT_DAYS = 2
16
- MAX_CONTENT_SIZE_MB = 10 # Max size for a single note in MB
 
 
17
 
18
  # Limit request payload size (prevents large uploads from consuming memory)
19
  app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16 MB
@@ -85,7 +96,7 @@ def cleanup_files():
85
  if not files_to_delete:
86
  return
87
 
88
- print(f"Cleanup: Deleting {len(files_to_delete)} old/oversized file(s).")
89
  for f_info in files_to_delete:
90
  try:
91
  content_path = f_info['path']
@@ -95,20 +106,26 @@ def cleanup_files():
95
  if os.path.exists(salt_path):
96
  os.remove(salt_path)
97
  except OSError as e:
98
- print(f"Cleanup: Error removing file {f_info['path']}: {e}")
99
 
100
  except Exception as e:
101
- # Log this error in a real application
102
- print(f"Error during file cleanup: {e}")
103
 
104
  # --- FLASK ROUTES ---
105
  @app.route('/')
106
  def index():
107
- return send_from_directory('.', 'index.html')
 
 
 
 
 
108
 
109
  @app.route('/api/load', methods=['POST'])
110
  def load_content():
111
  data = request.json
 
 
112
  file_hash = data.get('hash', '')
113
 
114
  # CRITICAL: Sanitize input to prevent path traversal
@@ -127,9 +144,16 @@ def load_content():
127
  # New note: generate a new, cryptographically secure salt
128
  salt_bytes = os.urandom(16)
129
  salt_b64 = base64.b64encode(salt_bytes).decode('utf-8')
130
- # Save the new salt immediately
131
- with open(salt_path, 'w', encoding='utf-8') as f:
132
- f.write(salt_b64)
 
 
 
 
 
 
 
133
 
134
  # Now, handle the content. It might not exist yet for a new note.
135
  if os.path.exists(content_path):
@@ -140,12 +164,14 @@ def load_content():
140
 
141
  return jsonify({'content': encrypted_content, 'salt': salt_b64})
142
  except Exception as e:
143
- print(f"Error during load: {e}") # For debugging
144
  return jsonify({'error': 'Failed to load content from server'}), 500
145
 
146
  @app.route('/api/save', methods=['POST'])
147
  def save_content():
148
  data = request.json
 
 
149
  file_hash = data.get('hash', '')
150
  encrypted_content = data.get('content', '')
151
 
@@ -174,7 +200,7 @@ def save_content():
174
 
175
  return jsonify({'status': 'saved'})
176
  except Exception as e:
177
- print(f"Error during save: {e}") # For debugging
178
  return jsonify({'error': 'Save failed on server'}), 500
179
 
180
  if __name__ == '__main__':
 
4
  import re
5
  import base64
6
  import time
7
+ import tempfile
8
+ import logging
9
+
10
+ # --- LOGGING SETUP ---
11
+ logging.basicConfig(
12
+ level=logging.INFO,
13
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
14
+ )
15
+ logger = logging.getLogger(__name__)
16
 
17
  app = Flask(__name__)
18
 
19
+ # --- CONFIGURATION (Environment Variables with Defaults) ---
20
+ DATA_DIR = os.environ.get('DATA_DIR', '/tmp')
21
+ MAX_TOTAL_SIZE_MB = int(os.environ.get('MAX_TOTAL_SIZE_MB', 100))
22
+ PURGE_TO_SIZE_MB = int(os.environ.get('PURGE_TO_SIZE_MB', 80))
23
+ AGE_LIMIT_DAYS = int(os.environ.get('AGE_LIMIT_DAYS', 2))
24
+ MAX_CONTENT_SIZE_MB = int(os.environ.get('MAX_CONTENT_SIZE_MB', 10))
25
+
26
+ # Directory for static files (index.html, etc.)
27
+ STATIC_DIR = os.environ.get('STATIC_DIR', os.path.dirname(os.path.abspath(__file__)))
28
 
29
  # Limit request payload size (prevents large uploads from consuming memory)
30
  app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16 MB
 
96
  if not files_to_delete:
97
  return
98
 
99
+ logger.info(f"Cleanup: Deleting {len(files_to_delete)} old/oversized file(s).")
100
  for f_info in files_to_delete:
101
  try:
102
  content_path = f_info['path']
 
106
  if os.path.exists(salt_path):
107
  os.remove(salt_path)
108
  except OSError as e:
109
+ logger.error(f"Cleanup: Error removing file {f_info['path']}: {e}")
110
 
111
  except Exception as e:
112
+ logger.error(f"Error during file cleanup: {e}")
 
113
 
114
  # --- FLASK ROUTES ---
115
  @app.route('/')
116
  def index():
117
+ return send_from_directory(STATIC_DIR, 'index.html')
118
+
119
+ @app.route('/health')
120
+ def health():
121
+ """Health check endpoint for monitoring."""
122
+ return jsonify({'status': 'ok'})
123
 
124
  @app.route('/api/load', methods=['POST'])
125
  def load_content():
126
  data = request.json
127
+ if not data:
128
+ return jsonify({'error': 'Invalid JSON payload'}), 400
129
  file_hash = data.get('hash', '')
130
 
131
  # CRITICAL: Sanitize input to prevent path traversal
 
144
  # New note: generate a new, cryptographically secure salt
145
  salt_bytes = os.urandom(16)
146
  salt_b64 = base64.b64encode(salt_bytes).decode('utf-8')
147
+ # Save the new salt atomically to prevent race conditions
148
+ try:
149
+ fd, tmp_path = tempfile.mkstemp(dir=DATA_DIR, suffix='.tmp')
150
+ os.write(fd, salt_b64.encode('utf-8'))
151
+ os.close(fd)
152
+ os.rename(tmp_path, salt_path) # Atomic on POSIX
153
+ except OSError:
154
+ # If atomic write fails, fall back to direct write
155
+ with open(salt_path, 'w', encoding='utf-8') as f:
156
+ f.write(salt_b64)
157
 
158
  # Now, handle the content. It might not exist yet for a new note.
159
  if os.path.exists(content_path):
 
164
 
165
  return jsonify({'content': encrypted_content, 'salt': salt_b64})
166
  except Exception as e:
167
+ logger.error(f"Error during load: {e}")
168
  return jsonify({'error': 'Failed to load content from server'}), 500
169
 
170
  @app.route('/api/save', methods=['POST'])
171
  def save_content():
172
  data = request.json
173
+ if not data:
174
+ return jsonify({'error': 'Invalid JSON payload'}), 400
175
  file_hash = data.get('hash', '')
176
  encrypted_content = data.get('content', '')
177
 
 
200
 
201
  return jsonify({'status': 'saved'})
202
  except Exception as e:
203
+ logger.error(f"Error during save: {e}")
204
  return jsonify({'error': 'Save failed on server'}), 500
205
 
206
  if __name__ == '__main__':