06/01 Optimize codes

This commit is contained in:
2026-06-01 17:07:00 -04:00
parent 25b15d8432
commit 4406d9734c
7 changed files with 231 additions and 10 deletions
+34 -2
View File
@@ -322,12 +322,36 @@ def import_confirm():
ALLOWED_RECEIPT_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'pdf'}
# Magic bytes → (canonical_extension, mime_type)
_MAGIC = [
(b'\xff\xd8\xff', 'jpg', 'image/jpeg'),
(b'\x89PNG\r\n\x1a\n', 'png', 'image/png'),
(b'GIF87a', 'gif', 'image/gif'),
(b'GIF89a', 'gif', 'image/gif'),
(b'%PDF-', 'pdf', 'application/pdf'),
# WEBP: RIFF????WEBP (bytes 0-3 = RIFF, bytes 8-11 = WEBP)
]
def _allowed_receipt(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_RECEIPT_EXTENSIONS
def _check_magic(header_bytes):
"""
Inspect the first 12 bytes of a file and return (ext, mime) if recognised,
or (None, None) if the bytes don't match any allowed type.
"""
for magic, ext, mime in _MAGIC:
if header_bytes[:len(magic)] == magic:
return ext, mime
# WEBP special case: RIFF at 0, WEBP at 8
if header_bytes[:4] == b'RIFF' and header_bytes[8:12] == b'WEBP':
return 'webp', 'image/webp'
return None, None
@settings_bp.route('/receipt/upload/<int:txn_id>', methods=['POST'])
@login_required
def upload_receipt(txn_id):
@@ -350,7 +374,15 @@ def upload_receipt(txn_id):
flash('File too large. Maximum 10MB.', 'warning')
return redirect(request.referrer or url_for('transactions.index'))
ext = f.filename.rsplit('.', 1)[1].lower()
# Validate actual file content via magic bytes (prevents renamed-file attacks)
header = f.read(12)
f.seek(0)
magic_ext, magic_mime = _check_magic(header)
if magic_ext is None:
flash('File content does not match an allowed type (PNG, JPG, GIF, PDF, WEBP).', 'warning')
return redirect(request.referrer or url_for('transactions.index'))
ext = magic_ext # use the extension we detected, not what the user claimed
unique_name = f'{uuid.uuid4().hex}.{ext}'
upload_dir = current_app.config.get('UPLOAD_FOLDER', '/home/pfm/app/uploads')
os.makedirs(upload_dir, exist_ok=True)
@@ -367,7 +399,7 @@ def upload_receipt(txn_id):
filename=unique_name,
original_filename=secure_filename(f.filename),
file_size=file_size,
mime_type=f.content_type,
mime_type=magic_mime, # use validated type, not the browser-supplied header
)
db.session.add(receipt)
db.session.flush()