Commit Graph

375 Commits

Author SHA1 Message Date
Isaac Connor
5561829450 fix: include username in auth relay and fix stale auth in stream restart
- Add user= parameter to get_auth_relay() so zms can use the indexed
  Username column instead of iterating all users to validate the hash
- Apply the same fix to Event.php getStreamSrc() and getThumbnailSrc()
- Tighten Monitor.php from isset() to !empty() for consistency
- In MonitorStream.js start(), check if the auth hash in the img src
  matches the current auth_hash before resuming via CMD_PLAY. If stale,
  fall through to rebuild the URL with fresh auth_relay. This prevents
  long-running montage pages from spawning zms with expired credentials.
- Downgrade zms auth failure from Error to Warning

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 10:01:47 -04:00
Isaac Connor
3dfe185260 fix: resolve role-based group permissions not granting stream access
The C++ User class (used by zms for streaming) had no awareness of
roles. It only checked user-direct permissions from Monitors_Permissions
and Groups_Permissions tables, completely ignoring Role_Monitors_Permissions,
Role_Groups_Permissions, and User_Roles base permissions. This caused
users who received camera permissions via Roles to be denied live stream
access, even though the PHP web interface (which has its own role-aware
checks in visibleMonitor()) showed the monitors correctly.

Changes:
- Add role_id to C++ User class, loaded via COALESCE(RoleId, 0) in all
  SQL queries (find, zmLoadTokenUser, zmLoadAuthUser)
- Add loadRoleBasePermissions() to merge role's Stream/Events/Monitors/
  etc. as fallback when user's own permission is PERM_NONE
- Add findByRole() to Group_Permission and Monitor_Permission classes
  to query Role_Groups_Permissions and Role_Monitors_Permissions tables
- Extend User::canAccess() to check role monitor and group permissions
  after user-direct permissions, matching the PHP visibleMonitor() logic
- Fix Monitor::canView() in PHP to also check role permissions when
  called for a user other than the global $user
- Fix off-by-one in zmLoadTokenUser where dbrow[10] read TokenMinExpiry
  out of bounds (was at index 9); adding RoleId shifts it to index 10

Fixes #4692

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 15:07:14 -04:00
Isaac Connor
419846c875 fix: sanitize monitor Device path to prevent command injection (GHSA-g66m-77fq-79v9)
The Device field from the Monitors table was interpolated directly into
shell commands (qx(), backticks, exec()) without sanitization, allowing
authenticated users with monitor-edit permissions to execute arbitrary
commands as www-data via the Device Path field.

Defense in depth:
- Input validation: reject Device values not matching /^\/dev\/[\w\/.\-]+$/
  at save time in both web UI and REST API
- Output sanitization: use escapeshellarg() in PHP and quote validated
  values in Perl at every shell execution point

Affected locations:
- scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm (control, zmcControl)
- scripts/zmpkg.pl.in (system startup)
- web/includes/Monitor.php (zmcControl)
- web/includes/functions.php (zmcStatus, zmcCheck, validDevicePath)
- web/includes/actions/monitor.php (save action)
- web/api/app/Model/Monitor.php (daemonControl, validation rules)
- web/api/app/Controller/MonitorsController.php (daemonStatus)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 13:19:03 -04:00
Isaac Connor
44acdd9b95 fix: guard ModelId access with property_exists in Monitor::Model()
Prevents 'Undefined property' PHP warning when the Monitor object was
loaded from a database that doesn't yet have the ModelId column. Matches
the existing property_exists pattern used later in the same method.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:50:40 -05:00
Isaac Connor
a90a3bccea fix: auto-detect and convert pixel zone coordinates to percentages in web layer
When zone coordinates are stored as pixel values (e.g. from a missed DB
migration), the web layer now detects values > 100 and converts them to
percentages using the monitor's dimensions, mirroring the existing C++
detection logic in zm_zone.cpp. This prevents limitPoints() from clamping
pixel values to 0-100 and zones rendering incorrectly in SVG overlays.

- Add convertPixelPointsToPercent() helper in functions.php
- Call conversion before limitPoints() in zone.php and zones.php
- Update Zone::svg_polygon() to accept monitor dimensions and convert
- Pass ViewWidth/ViewHeight to svg_polygon() from Monitor::getStreamHTML()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 17:49:14 -05:00
Isaac Connor
9ebf48da35 Add Create to canEdit 2026-02-26 07:22:31 -05:00
Isaac Connor
c0016fa00b feat: store zone coordinates as percentages for resolution independence
Convert zone coordinates from absolute pixel values to percentages
(0.00-100.00) so zones automatically adapt when monitor resolution
changes. This eliminates the need to manually reconfigure zones after
resolution adjustments.

Changes:
- Add DB migration (zm_update-1.37.81.sql) to convert existing pixel
  coords to percentages, recalculate area, and update Units default
- Add Zone::ParsePercentagePolygon() in C++ to parse percentage coords
  and convert to pixels at runtime using monitor dimensions
- Backwards compat: C++ Zone::Load() checks Units column and uses old
  pixel parser for legacy 'Pixels' zones
- Update PHP coordsToPoints/mapCoords/getPolyArea for float coords,
  replace scanline area algorithm with shoelace formula
- Update JS zone editor to work in percentage coordinate space with
  SVG viewBox "0 0 100 100" and non-scaling-stroke for consistent
  line thickness
- Position zone SVG overlay inside imageFeed container via JS to align
  with image only (not status bar)
- Support array of zone IDs in Monitor::getStreamHTML zones option
- Update monitor resize handler: percentage coords don't need rescaling,
  only threshold pixel counts are adjusted
- Add 8 Catch2 unit tests for ParsePercentagePolygon

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:19:20 -05:00
Isaac Connor
eae89025ee refactor: rename RTSP2WebStream to StreamChannel
Rename applies to Go2RTC, Janus, and RTSP2Web streaming options.
Update enum values from Primary/Secondary to Restream/CameraDirectPrimary/CameraDirectSecondary.

- Add db migration zm_update-1.37.79.sql to rename column and migrate data
- Update C++ enum StreamChannelOption and member stream_channel
- Update PHP getStreamChannelOptions() method
- Update all JavaScript references
- Auto-select CameraDirectPrimary when Restream option becomes disabled

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 19:37:08 -05:00
Isaac Connor
02685bff7e Pick up missed update for Restream and RTSP_User 2026-01-31 18:54:14 -05:00
Isaac Connor
010959c9d4 fix: only show monitor edit button if user has edit permission
The edit button overlay on the montage view stream is now conditionally
displayed based on the user's edit permission for that monitor.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 13:56:03 -05:00
Ben Dailey
c80542343a Remove Preview Rate Control. Disable BuiltIn Video controls. 2026-01-29 11:18:30 -05:00
Isaac Connor
e6c5bdb85d Use modern string interpolation style 2025-12-22 19:43:05 -05:00
Isaac Connor
254fd58c40 Use css style= to set width of video tag, and if height is specified, also set it. Fixes streams not having height. 2025-12-19 12:03:29 -05:00
Isaac Connor
6c2ad8d906 Use the same code for ImageStill and for ImageStream. Use ImageStream when mode == paused. Fixes #4491 2025-12-19 11:10:32 -05:00
Isaac Connor
736610d349 Simplify monitor state html, mostly to include the stream-info into the part that gets hidden with the other state info 2025-10-29 12:15:32 -04:00
Isaac Connor
9932c1f690 Add missing EncoderHWAccel fields 2025-10-27 09:40:06 -04:00
Isaac Connor
ecd37ae6c7 Revert change to assign 4 streams per port. It caused more trouble than it was worth 2025-10-16 12:13:53 -04:00
Isaac Connor
83800e8753 Test for existend of type in defaults to avoid warning 2025-10-10 13:26:57 -04:00
Isaac Connor
b5a10ca1ce Add +1 because we will now use 30000 instead of 30001.. so some existing configs may break. 2025-10-09 11:01:08 -04:00
Isaac Connor
1fc27261e1 Add initial_scale property 2025-10-07 21:02:30 -04:00
Isaac Connor
e04d38f83e When using MIN_SPREAMING_PORT, divide by 5 so we get 5 streams per port 2025-10-01 21:01:29 -04:00
Isaac Connor
3373fb71aa Simply zms option let's just assume that that we can stream 2025-09-25 17:36:13 -04:00
Isaac Connor
fe323e0aff Add DefaultPlayer support in getStreamSrc 2025-09-24 14:05:58 -04:00
Isaac Connor
063ec36106 Add DefaultPlayer to Monitor object 2025-09-24 09:54:19 -04:00
Isaac Connor
edf87d6463 Move stream-info off the video stream down to where the monitor status info is. 2025-09-05 09:35:53 -04:00
Isaac Connor
7bf2fb8fce Convert OutputCodec from int to varchar OutputCodecName. ffmpeg has different values for codec_id for different versions of ffmpeg. So just use the codec name instead. 2025-08-20 15:59:02 -04:00
IgorA100
66322e03f1 Chore: Extra semicolon (Monitor.php) 2025-08-04 20:52:51 +03:00
IgorA100
bfda588214 Transferring HTML code from video-stream.js (Monitor.php) 2025-08-03 01:03:33 +03:00
Isaac Connor
8be098cb89 Remove player stuff from streamMode as it doesn't belong. 2025-07-22 13:03:38 -04:00
Isaac Connor
835a3d74e3 Revert "Remove getStreamMode which was actually getPlayer and should just be replaced by a monitor field for defaultPlayer."
This reverts commit c05ee7e43c.
2025-07-22 13:02:43 -04:00
Isaac Connor
c05ee7e43c Remove getStreamMode which was actually getPlayer and should just be replaced by a monitor field for defaultPlayer. 2025-07-21 08:06:51 -04:00
Isaac Connor
68fa95d468 Move getStreamModeMonitors to monitor->getSTreamMode. Add Volume/Mute. Change behaviour of Play/Pause to only show one of them at a time. 2025-06-26 15:05:03 -04:00
Isaac Connor
fee01f9c9b Add Go2RTC support to monitor 2025-06-26 14:57:06 -04:00
Isaac Connor
e73cb52359 Add type=float for AnalysisFPSLimit 2025-04-29 16:02:44 -04:00
IgorA100
43ea5000c6 Remove extra space (Monitor.php) 2025-03-26 12:14:06 +03:00
IgorA100
640047b9dd Removed empty line (Monitor.php) 2025-03-26 12:11:23 +03:00
IgorA100
2194c87018 Let's do it as it was before. We'll move the control to JS (Monitor.php) 2025-03-26 12:09:51 +03:00
IgorA100
1932d53f0a Removed extra space and comma (Monitor.php) 2025-03-26 00:48:04 +03:00
IgorA100
9f0822af3d Fix: Stream Quality option should only show if a secondary stream is available (Monitor.php) 2025-03-26 00:41:27 +03:00
Isaac Connor
5cff2f0904 FIx name collision on RTSP2WebStream => RTSP2WebStreamOptions 2025-03-02 14:37:26 -05:00
IgorA100
8c586c47ce Added support for selecting Secondary stream for RTSP2Web (Monitor.php) 2025-02-22 19:49:55 +03:00
Isaac Connor
8c0c08694b Remove commas that cause problems on some php. Remove unreachable code. 2025-01-24 12:31:35 -05:00
Isaac Connor
5c01109f03 List monitor id in warning message about not being assigned a server. 2024-11-04 09:17:20 -05:00
Isaac Connor
1c0e03b813 Set the default for AnalysisFPSLimit to null so that we can empty it. Add an initial_default to use when creating a new monitor 2024-10-26 13:59:45 -04:00
Isaac Connor
eb117732a8 Rough in shm info and functions for triggering 2024-10-01 12:18:05 -04:00
Isaac Connor
328ce9fc0c Make no Status record found a debug instead of warning 2024-09-17 11:17:50 -04:00
Isaac Connor
b64461d518 Merge branch 'master' into only_stream_visible 2024-09-03 14:51:36 -04:00
Isaac Connor
b66e04024f Test for Path being empty to avoid warnings about passing null being deprecated 2024-09-03 09:39:03 -04:00
Isaac Connor
802a0854b5 Add getAnalysingStrings and getRecordingStrings and fix getStatusStrings, removing Tape 2024-08-18 12:18:44 -04:00
Isaac Connor
a3c73b414f Add WallCLockTimestamps to Monitor model 2024-07-06 08:51:37 -04:00