Files view: change details with before/after images (v2.4.0)
- the timeline's Δ glyph became a **Details** button, and it now appears on Update rows too (not just card-side changes); EN "Changed (card)" -> "Changed on card", RU "Изменено (картой)" -> "Изменено картой" - the details modal shows the affected unit — the whole file, or the single record that changed — **before and after** the change as hex views (16 bytes per row, ASCII column, never-observed bytes as `--`), with the bytes that changed and the bytes the operation *first observed* highlighted in two different colours, plus the changed/new byte counts and the APDU reference; the old before/after byte table is gone - `GET /api/sessions/<id>/files/image?key=…&change=…` returns those two views (segments with offsets) plus the change's metadata; the images are reconstructed from the current image by undoing the later changes (`FileTracker.change_images`), so nothing is duplicated per event — every value change is an event, hence the values are exact (a byte only first observed later can appear as known in both views) - tracker: change events carry `observed_ranges` (bytes that were unknown before the operation) next to `ranges`; an update that only observes new bytes now records an event (so it can be inspected); record-file ranges are in-record byte offsets (the record number stays in its own field), which the previous "record number as position" could not express for a hex highlight - tests: change-images reconstruction (before/after per event, later changes undone, records isolated, observation-only events, unknown gaps), the image endpoint (200/404/400), and Node tests for the hex-image helper (highlight classes, unknown gaps, ASCII, row limit) and the modal rendering - v2.4.0; SW cache simtrace-analyser-v65
This commit is contained in:
1 parent
87b6811adf
commit
cad3999307
12 files changed
+617
-120
No files matched your search
@@ -141,6 +141,9 @@ class RequestHandler(BaseHTTPRequestHandler):
|
||||
elif path.startswith('/api/sessions/') and path.endswith('/pcap'):
|
||||
session_id = int(path.split('/')[-2])
|
||||
self._handle_get_session_pcap(session_id)
|
||||
elif path.startswith('/api/sessions/') and path.endswith('/files/image'):
|
||||
session_id = int(path.split('/')[-3])
|
||||
self._handle_session_files_image(session_id, params)
|
||||
elif path.startswith('/api/sessions/') and path.endswith('/files'):
|
||||
session_id = int(path.split('/')[-2])
|
||||
self._handle_session_files(session_id)
|
||||
@@ -475,6 +478,29 @@ class RequestHandler(BaseHTTPRequestHandler):
|
||||
f'files={len(data["files"])} operations={data["timeline_total"]}')
|
||||
self._send_json(data)
|
||||
|
||||
def _handle_session_files_image(self, session_id, params):
|
||||
"""Before/after images of one change (the Files view's Details)."""
|
||||
session = self.db.get_session(session_id)
|
||||
if session is None:
|
||||
self._send_error(404, 'Session not found')
|
||||
return
|
||||
key = (params.get('key', [''])[0]).strip()
|
||||
try:
|
||||
idx = int(params.get('change', ['0'])[0])
|
||||
except ValueError:
|
||||
self._send_error(400, 'change must be an index')
|
||||
return
|
||||
if not key or idx < 0:
|
||||
self._send_error(400, 'key and change are required')
|
||||
return
|
||||
data = self.db.change_images(session_id, key, idx)
|
||||
if data is None:
|
||||
self._send_error(404, 'No such file or change')
|
||||
return
|
||||
_log(f'Session file change: session={session_id} key={key} '
|
||||
f'change={idx} op={data["op"]} index={data["index"]}')
|
||||
self._send_json(data)
|
||||
|
||||
def _handle_rename_session(self, session_id, name):
|
||||
self.db.rename_session(session_id, name)
|
||||
self._send_json({'ok': True})
|
||||
|
||||
Reference in new issue
Block a user