Commit Graph
89 Commits
Author SHA1 Message Date
Isaac ConnorandClaude Opus 4.7 7b9c1ee1d2 fix: derive event end time from Length when EndDateTime is missing
When zmc is killed or crashes without writing EndDateTime, three code
paths invent a fake end of NOW(), so an event from hours ago appears to
extend across the entire down-time. Montage review then paints a bar
that makes it look like recorded video exists where it doesn't.

Length is flushed to the DB every few seconds during recording, so even
crashed events have an accurate last-known duration. Fall back to
StartDateTime + Length when EndDateTime IS NULL, and only fall back to
NOW() when Length is also 0 (event has no recorded data yet).

- web/api/app/Model/Event.php: EndTimeSecs and EndTime virtual fields,
  which is what the montagereview JS actually reads via the API.
- web/ajax/events.php: same fix in the AJAX events list SQL.
- web/skins/classic/views/montagereview.php: \$eventsSql kept in sync
  even though it is no longer executed directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 06:46:01 -04:00
Isaac ConnorandClaude Opus 4.7 c4073c964c feat: encoder parameter templates with editor + REST API closes #4778 closes #4802
Adds a curated, per-encoder parameter-template library to ZoneMinder:

- Monitor edit page: a new Template row above the EncoderParameters
  textarea offers per-encoder templates (Balanced / Archival / Low
  Power / Low CPU). Apply merges the template's params into the
  textarea, preserving user-only keys. Advisory lint flags option
  keys that aren't recognised for the selected encoder. Switching
  encoders offers a same-name template on the new encoder via a
  native confirm.

- Options page: a new Encoder Templates tab with full CRUD —
  list / edit / copy / delete — backed by a new CakePHP REST API
  at /api/encoder_templates.

- Storage: a new EncoderTemplates DB table seeded with 14 shipped
  defaults across libx264 / libx265 / h264_nvenc / hevc_nvenc /
  h264_vaapi / hevc_vaapi. The table is mutable; ZM upgrades do not
  re-seed user-edited rows.

- valid_keys (the lint allow-list) stays in PHP code as ffmpeg
  vocabulary, not user data.

- Default params explicitly include pix_fmt to avoid the yuvj420p
  HEVC HW-decode rejection issue we hit earlier.

No C++ change. The textarea content is parsed by the existing
av_dict_parse_string call in src/zm_videostore.cpp.

version.txt -> 1.39.6.

Specs: docs/superpowers/specs/2026-05-0{1,2}-*.md
Plans: docs/superpowers/plans/2026-05-0{1,2}-*.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 17:24:17 -04:00
Isaac ConnorandClaude Opus 4.6 bb9e74a2f9 fix: only validate Device path for Local monitors
Follow-up to 419846c87 (GHSA-g66m-77fq-79v9). The Device path check was
applied to all monitor Types in three places, but the Device column is
only passed to a shell for Type='Local'. Non-Local monitors (Ffmpeg,
Remote, Libvlc, cURL, VNC) may legitimately hold legacy values such as
an RTSP URL in that column and should not be rejected or warned about.

- scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm: control() dropped the
  spurious Warning for non-Local monitors that was flooding zmwatch
  logs. The Error/early-return path is preserved for Local.
- web/includes/actions/monitor.php: save action only runs
  validDevicePath() when Type=='Local'.
- web/api/app/Model/Monitor.php: replaced the unconditional regex rule
  with a validDevicePath() method that checks Type before enforcing
  the /dev/ pattern.

Also add client-side validation matching the server rule, so Local
monitors get immediate feedback instead of a round-trip error:

- web/skins/classic/views/monitor.php: HTML5 pattern attribute on the
  Device input. Escaped for the v-flag regex engine used by pattern=.
- web/skins/classic/views/js/monitor.js.php: validateForm() now also
  rejects Device values that don't match the /dev/ pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 08:44:07 -04:00
Isaac ConnorandClaude Opus 4.6 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
Pliable PixelsandClaude Opus 4.6 fea1c850ac fix: address Copilot review feedback on Notifications API refs #4684
- Revert accidental Users.RoleId FK change from CASCADE back to SET NULL
- Remove System != 'None' gate in beforeFilter; any authenticated user
  can manage their own notifications, per-row ownership checks suffice
- Add allowMethod('post', 'put') guard to edit() for consistent REST behavior
- Change PushState validation from allowEmpty to required=false

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:39:54 -05:00
Pliable PixelsandClaude Opus 4.6 c6effc12ab fix: add FK constraint, auth guard, and belongsTo for Notifications refs #4684
- Add FOREIGN KEY on UserId -> Users.Id with ON DELETE CASCADE
  (both in fresh schema and migration)
- Reject push token registration when auth is disabled
  (UserId would be null, violating NOT NULL constraint)
- Add $belongsTo association to User in Notification model

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:04:03 -05:00
Pliable PixelsandClaude Opus 4.6 de1f31c6e2 feat: add Notification model, controller, and route refs #4684
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 19:47:29 -05:00
Nic Boet d27b565a8d fix: correct App::uses package path in CameraModel
App::uses('AppModel', 'CameraModel') tells CakePHP to look for AppModel
in a non-existent 'CameraModel' package. The correct second argument is
'Model', which points to app/Model/AppModel.php where the base class
actually lives.

This was likely a copy-paste error — every other model in the codebase
correctly uses App::uses('AppModel', 'Model'). The bug may go unnoticed
when another model loads AppModel first via CakePHP's autoloader, but
causes a fatal error if CameraModel is the first model resolved in a
request (e.g. hitting the camera models API endpoint directly).
2026-02-15 15:38:08 -05:00
Isaac ConnorandClaude Opus 4.5 4e60cb96a7 feat: add User Roles feature for reusable permission templates
Add a User Roles system where roles define reusable permission templates.
When a user has a role assigned, the role provides fallback permissions
(user's direct permissions take precedence; role is used when user has 'None').

Database changes:
- Add User_Roles table with same permission fields as Users
- Add Role_Groups_Permissions table for per-role group overrides
- Add Role_Monitors_Permissions table for per-role monitor overrides
- Add RoleId foreign key to Users table

Permission resolution order:
1. User's direct Monitor/Group permissions (if not 'Inherit')
2. Role's Monitor/Group permissions (if user has role)
3. Role's base permission (if user's is 'None')
4. User's base permission (fallback)

Includes:
- PHP models: User_Role, Role_Group_Permission, Role_Monitor_Permission
- Role management UI in Options > Roles tab
- Role selector in user edit form
- REST API endpoints for roles CRUD
- Translation strings for en_gb

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 13:34:27 -05:00
Steve Gilvarry 58a0e68731 Add Tags to event search and return tag data with events 2026-01-05 21:43:27 +11:00
Isaac Connor d8ccd1cdfa Fix Monitor=>Frame in associations 2025-12-19 16:48:15 -05:00
Isaac Connor 2a11b14bce Remove Function reference 2025-09-06 11:34:09 -04:00
Isaac Connor 974e9fd0f2 When editing a monitor via api, if Capturing=None don't start zmc. Fixes #4348 2025-07-04 16:28:39 -04:00
Isaac Connor 46b27d9f78 Add Tags support to API 2023-11-03 13:33:28 -04:00
Isaac Connor c811f1bc90 Load event using find_one which does caching. 2023-06-09 10:52:39 -04:00
Isaac Connor 4472269f3c Finish roughing in UserPreference in api 2023-05-12 14:10:53 -04:00
Isaac Connor 0d561bbf73 Add StartTimeSecs and EndTimeSecs to returned data in Event 2023-05-12 14:10:53 -04:00
Isaac Connor dd6cc74da7 Rough in UserPreference api 2023-03-22 13:22:08 -04:00
Isaac Connor 8a6f0cbe1b Add ServerStats to api 2023-02-26 17:04:05 -05:00
Isaac Connor aa3bc1a28d Add TimeStampSecs to fields returned for Frames. 2023-01-18 10:07:41 -05:00
Isaac Connor 7fe10a4047 Fix the HABATM relationship in Snapshots 2022-12-07 15:01:08 -05:00
Isaac Connor c35b28a3d1 Rough in api support for snapshots 2022-11-30 15:11:04 -05:00
Isaac Connor c20a327eef Fixups to EventData model 2022-10-27 17:00:24 -04:00
Isaac Connor 6d073119cb Rough in views for EventData 2022-10-27 16:57:05 -04:00
Isaac Connor 586d43798f Rough in model and controller for Event_Data 2022-10-27 14:47:21 -04:00
Pliable Pixels 23ae004724 whoops fixed errant enum values I forgot to delete 2022-09-25 17:46:53 -04:00
Pliable Pixels 6218d065a5 make OutputCodec work in API 2022-09-25 12:41:07 -04:00
Isaac Connor 2a5a94b995 Fix monitors.json and monitor/.json use incorrect Id (mathing Monitor.Id instead of Monitor.ManufacturerId) to return Manufacturer and CameraModel: Fixes #3475 2022-05-01 13:25:42 -04:00
Isaac Connor fe734d4e1e Add Manufacturer and CameraModel hasOne relationships 2021-09-27 10:56:50 -04:00
Isaac Connor c66489fb30 rough in api support for Models and Manufacturers 2021-09-25 20:49:30 -04:00
Isaac Connor fd9bef228d It is okay to call daemonControl with function==None for command == stop. All others give a warning. Fixes monitors on other servers not stopping when set to None. 2021-06-12 12:21:44 -04:00
Isaac Connor 1abbc187e9 Merge pull request #3242 from connortechnology/fix_3232_api_monitor_event_summaries
Add Event_Summary model so that it is included in monitor listing
2021-05-19 20:32:50 -04:00
Isaac Connor 4385076e66 Fix encrypting password when saving User 2021-04-26 09:40:08 -04:00
Isaac Connor 15a769bcd1 add hashing of passwords on user save 2021-04-23 09:07:50 -04:00
Isaac Connor 2fa0fbe448 Upgrade cakephp to 2.10.24 2021-02-02 23:19:52 -05:00
Isaac Connor 105eff7a21 Remove references to zma 2021-02-01 17:29:16 -05:00
Isaac Connor 07fa507efe improve error message when trying to control a remote camera 2021-01-27 11:48:32 -05:00
Isaac Connor 3132820a71 Move daemonControl logic into the model. daemonControl needs to be called on the previous monitor data so that it knows which daemons to stop. 2020-12-23 13:48:12 -05:00
Isaac Connor 402b559b2c Add StartTime and EndTime virtual fields for backwards compatability 2020-11-06 11:15:12 -05:00
Isaac Connor 10c0a6617c Return Debug to a regular function to match other logging functions. Since we switched to using namespaces we no longer clash with cake_php. 2020-10-14 10:39:25 -04:00
Isaac Connor 7dbbb24db4 Update api Zone Saving. Fixes #3037 2020-09-10 13:31:39 -04:00
Isaac Connor 7e679809f2 Merge branch 'update_users_controller' 2020-08-17 19:31:30 -04:00
Isaac Connor bf163beedb Update permissions checking when viewing/editing users. Fixes #2982. Also add a beforeFind that will remove the Password field from the query so that we don't return passwords 2020-07-30 11:03:24 -04:00
Isaac Connor d716d1d686 Merge branch 'release-1.34' 2020-07-20 16:25:41 -04:00
Isaac Connor e839919b5e Add foreign key MonitorId validation 2020-07-20 16:25:08 -04:00
Isaac Connor 135bbb4190 remove unneeded config loading, just use defines. Spacing, remove commented out dead code 2020-07-19 17:51:28 -04:00
hax0kartik 1d3ad05bb5 Start implementing VNC 2020-03-25 23:21:34 -07:00
Isaac Connor d25a91ad13 Make Group containable 2019-12-20 14:56:14 -05:00
Isaac Connor 5f006421cc fix #2771. Correct relationship from hasMany to hasAndBelongsToMany for Monitors in Group Modelel. Use save Assiociated in Controller, and add code to handle backwards compatibility by turning MonitorIds into the appropriate Monitor array 2019-12-15 15:31:40 -05:00
Isaac Connor 393c25b4f2 fix array keys 2019-11-29 14:26:03 -05:00