Security hardening: IDOR fixes, rate limiting, secret key, session cookies

- IDOR: ownership checks on WO approve/reject/done, charter update/complete/
  send-contracts/request-insurance, captain-contract PDF, insurance-rider PDF,
  delete accounting entry, delete fuel entry, update vessel
- auth.py: rate limiting (10 req/15min), explicit is_active check
- owner.py: role guard on /owner/dashboard
- __init__.py: random SECRET_KEY if unset, absolute SQLite path, parameterized
  SQL (no f-strings), session cookie HTTPONLY+SameSite, 8h session lifetime,
  db.session.get() replacing deprecated query.get()
- api.py: P&L double-count bug fixed (wo_cost was summed twice), Content-
  Disposition filename quoted, APP_BASE_URL env var replaces hardcoded
  localhost:5010, create_management_company validates password length and
  email uniqueness, dead code removed from sync_all_accounting
- create_admin.py: removed password from console output

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-05 03:01:49 -04:00
parent 5b7b41aa50
commit 7fe7304392
5 changed files with 159 additions and 54 deletions
+3 -1
View File
@@ -1,4 +1,4 @@
from flask import Blueprint, render_template
from flask import Blueprint, render_template, abort
from flask_login import login_required, current_user
bp = Blueprint('owner', __name__, url_prefix='/owner')
@@ -6,4 +6,6 @@ bp = Blueprint('owner', __name__, url_prefix='/owner')
@bp.route('/dashboard')
@login_required
def dashboard():
if current_user.role not in ('owner', 'captain', 'admin'):
abort(403)
return render_template('owner/dashboard.html', user=current_user)