From 96e33834bd3f103a867087ed42f84a4957e166d1 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Sun, 24 May 2026 12:53:03 -0400 Subject: [PATCH] feat(shopfloor): _tablet_session_audit helper for audit-log writes Single source for sha256(session sid), ua trim, ip/acting_uid capture from request. Used by unlock_session, lock_session, and force-lock cron. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../controllers/_tablet_session_audit.py | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 fusion_plating/fusion_plating_shopfloor/controllers/_tablet_session_audit.py 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)