diff --git a/fusion_plating/fusion_plating_shopfloor/controllers/_tablet_session_audit.py b/fusion_plating/fusion_plating_shopfloor/controllers/_tablet_session_audit.py new file mode 100644 index 00000000..4f66820f --- /dev/null +++ b/fusion_plating/fusion_plating_shopfloor/controllers/_tablet_session_audit.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +"""Helper for writing fp.tablet.session.event rows from the new +unlock_session / lock_session endpoints and the force-lock cron. + +Single source of truth for hashing the session sid, trimming the +user-agent, and capturing forensic ip / acting_uid. +""" +import hashlib + +from odoo import fields +from odoo.http import request + + +def _sha256_session_sid(sid): + """Return sha256 hex digest of the session sid. Stored in the audit + log so DB leaks can't be replayed.""" + if not sid: + return '' + return hashlib.sha256(sid.encode('utf-8')).hexdigest() + + +def _trim_ua(ua): + """Trim user-agent to 256 chars (Odoo's standard Char width).""" + if not ua: + return '' + return ua[:256] + + +def write_event(env, *, event_type, user_id=None, attempted_user_id=None, + session_id_hash=None, session_started_at=None, + session_ended_at=None, duration_seconds=None, + failure_reason=None, notes=None): + """Append an fp.tablet.session.event row. All writes sudo'd. + + The acting_uid + ip + ua are pulled from the current request + automatically so callers never forget them. + """ + vals = { + 'event_type': event_type, + 'user_id': user_id, + 'attempted_user_id': attempted_user_id, + 'session_id_hash': session_id_hash, + 'session_started_at': session_started_at, + 'session_ended_at': session_ended_at, + 'duration_seconds': duration_seconds, + 'failure_reason': failure_reason, + 'notes': notes, + 'acting_uid': env.uid, + } + if request: + vals['ip_address'] = request.httprequest.remote_addr or '' + vals['user_agent'] = _trim_ua( + request.httprequest.headers.get('User-Agent', '') + ) + return env['fp.tablet.session.event'].sudo().create(vals)