mirror of
https://github.com/Cacti/cacti.git
synced 2026-11-02 18:17:00 +09:00
security-batch-12
654
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e3d3dff6d3 |
merge: retain current develop graph menu in SpikeKill forward port
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
401cda07c8 |
fix(spikekill): bind menu requests and protect mutations on develop
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
8acc5ec916 |
feature: theme-aware graph drilldown action menu (per-theme CSS palette) (#8355)
Label the open graph drilldown strip (layout.js labelGraphDrilldownIcons), shorten the action titles, and restyle the strip as a table menu. Each theme's main.css declares the --cacti-dd-* custom properties (foreground, hamburger/panel backgrounds, hairline border, hover accent) that include/css/graph_drilldown.css consumes via var() with a dark fallback, so each theme gets an appropriate light or dark look with its own accent and the hamburger reads correctly on light themes. Themes without a block (e.g. midwinter) use the dark fallback. Regenerates the affected locales/po/cacti.pot entries for the shortened titles. Co-authored-by: TheWitness <1439914+TheWitness@users.noreply.github.com> |
||
|
|
5f72f1a03c |
fix(security): [develop] require protected POSTs for administrative mutation endpoints (#8331)
* fix(csrf): require POST for administrative mutation endpoints Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(csrf): support token-checking mutation helper Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
9a3a7dfce0 |
fix(graphs): [develop] correct opacity, redraw and realtime retries (#8328)
* fix(theme): enable graph opacity without selectmenu Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs(changelog): describe theme fix Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(graph): restore redraw URLs and retry realtime failures Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
6e5078c929 |
fix(theme): [develop] restore Midwinter navigation, search and filter controls (#8327)
* fix(theme): restore Midwinter navigation and kiosk controls Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs(changelog): describe theme fix Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(navigation): preserve filters and restore search and keyboard controls Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
f28071eb67 |
fix(theme): [develop] restore Midwinter login controls, form state and notifications (#8326)
* fix(theme): preserve Midwinter authentication controls Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs(changelog): describe theme fix Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(ui): preserve form state and notification lifecycles Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix: replace the blinking timer during skin setup Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
f39e74c65c |
Graph drilldown: keep hamburger fixed, icons reachable, hide on graph leave (#8315)
* Graph drilldown: keep hamburger fixed, icons reachable, hide on graph leave The action-icon strip now slides down below the hamburger (flex column) instead of the hamburger dropping to the bottom of the icons. Closing is driven by leaving the whole graph rather than the small icon strip, so the mouse can move from the hamburger onto the icons without the strip closing. Leaving the graph also blurs the hamburger so it no longer lingers after interacting with it. * changelog: graph drilldown interaction fixes (#8315) * Graph drilldown: tolerate tooltip-induced mouseleave, drop hamburger title A native tooltip appearing over a drilldown icon fires a spurious mouseleave on the graph (relatedTarget null), which closed the strip. Defer the close and re-check the graph is genuinely not hovered first, so the icon tooltips no longer destabilize it. Also drop the hamburger's redundant title (its aria-label stays). * Graph drilldown: widen the close grace period to 500ms * Graph drilldown: tie hamburger visibility to the graph image Reveal the hamburger while the pointer is over the graph image (or the toggle overlaid on it) rather than anywhere in the graph cell, so moving off the image hides it after the grace period. Entering a different graph now immediately hides and closes any other graph's open strip. * Graph drilldown: lift the open graph so its strip clears thumbnails below With thumbnails a short graph's open icon strip overflows onto the graph below; sibling graphs paint in DOM order, so that graph rendered on top of the strip, making the icons unclickable and stealing the hover (which closed the strip). Raise the open graph (.graphDrillActive, position:relative; z-index) so its overflowing strip stays on top and the graph beneath is not hovered. * Graph drilldown: reveal via :focus-visible and stop blurring to preserve keyboard focus * fix(ui): preserve graph action focus during pointer navigation Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(ui): cover graph drilldown interactions and gate PR coverage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: measure committed PR changes on a policy-compliant runner Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
97e67c6777 |
security: harden browser rendering and review CodeQL boundaries (#8298)
* security: harden browser history and dependency option merging Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: record CodeQL triage decisions and follow-up scope Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: wait for history reload before inspecting browser storage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: isolate HTMX history from the legacy navigation handler Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: build CodeQL assets through controlled dependency installs Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: render form validation messages as plain text Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: verify drag rows and color input security boundaries Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: verify tree navigation rename and datetime input boundaries Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: harden menu rendering and complete CodeQL caller review Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: centralize menu rendering and stabilize certificate CI Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: align certificate expectation with parallel web PR Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: TheWitness <thewitness@cacti.net> |
||
|
|
08d0f94f24 |
Fix develop client behavior, popup isolation and PHP method visibility (#8292)
* fix(core): correct client state and declare public method contracts Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(security): isolate Midwinter external homepage popup Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(client): isolate menu state and simplify validated JavaScript guards Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(auth): use certificate expiry truth in rendering assertions Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * refactor(js): remove unused local storage while retaining initializer calls Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(js): encode inline translated values through the shared JSON boundary Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * style(js): wrap encoded translation literals without changing messages Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(client): remove unused checkbox reads from graph resizing Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * refactor(client): declare repeated function locals once Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(ui): run column width regression in browser CI Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
d7ec67c4cf |
Persist table column widths across request actions (#8309)
* Persist table column widths across request actions Column widths are stored in localStorage keyed by the table id, but html_start_box() derives that id from the request action/report/tab, so a filter refresh (action change/go) reloads the same table under a different id and the saved widths are not restored. Emit a stable, action-independent data-colsizing key on each cactiTable and use it in saveTableWidths(), while keeping the DOM id unchanged. * changelog: 8309 table column width persistence * Column width persist: keep per-view key, normalize only filter-refresh actions The previous key dropped the action/report/tab entirely, so distinct table schemas at the same page+ordinal (e.g. support.php processes vs background tabs, utilities.php view_snmp_cache vs view_poller_cache) collapsed into one localStorage entry and applied widths from the wrong schema. Retain the stable logical-view discriminator (tab/report, or a non-transient action) in the data-colsizing key and normalize only the transient filter-refresh actions (go/change/clear/reset), so widths still survive a filter change but never cross unrelated schemas. * Use short array syntax for the colsizing normalization list (php-cs-fixer) |
||
|
|
e25a67c31f |
Common graph drilldown hamburger toggle across all themes (#8308)
* Graph drilldown: common hamburger toggle across all themes The graph action icons were revealed by hovering to the right of the graph, implemented per-theme (dark/midwinter/sunrise main.js) and always-on elsewhere. Hide the icons by default behind a small fa-bars hamburger overlaid on the graph's top-right. Clicking it opens the icon strip, which stays until a second click, leaving the strip, or an outside click. The behaviour is now centralized in include/layout.js (initGraphDrilldown) and include/css/graph_drilldown.css, and the per-theme hover JS is removed. * changelog: 8308 feature fragment * Graph drilldown: address review (a11y, positioning, spikekill, POT) - Anchor the toggle to the shrink-wrapped graph holder (width:fit-content) so the hamburger sits on the graph's top-right, not the full-width column edge. - Keep the hamburger focusable while visually hidden (opacity instead of display:none); reveal on hover, keyboard focus, open, and hover-less devices. - Expose aria-expanded on the toggle and update it in every open/close path; add aria-haspopup/aria-label. - Close any open SpikeKill submenu (spikeKillClose) when the strip closes or switches, matching the removed per-theme handlers. - Remove the now-duplicate Midwinter top-right ellipsis pseudo-element. - Add the new 'Graph Actions' msgid to locales/po/cacti.pot. |
||
|
|
bfa3efb7a9 |
Add a jQuery rebind() helper and roll it out across the core UI (#8279)
* Add a jQuery rebind() helper and roll it out across the core UI Add $.fn.rebind(events[, selector], handler...) to include/layout.js as a shorthand for the common off(events).on(events, ...) re-attach idiom, then convert the matching chained calls across the core JavaScript and inline PHP handlers to use it. Only pairs whose off() and on() events (and delegated selector) match are converted; off() with no arguments is left as-is since it intentionally clears every handler. * changelog: add 8279.feature fragment * tests: update layout.js JS tests for the rebind() helper * tests: assert the cactiPostAction handler via rebind() * rebind: preserve the delegated selector for the two-argument event-map overload; add helper tests |
||
|
|
40d648cef3 |
fix: The horizontal scroll bar should not be visible unless it has to be (#8212)
* fix: horizontal scroll bar should not be visible unless it has to be Port of #8211 to develop. Let overflow-x fall back to 'auto' instead of 'visible' so a horizontal scroll bar only appears when content actually overflows, and drop the resizable handle from the last visible column in applyTableSizing() so resizing it cannot force the page wider than the viewport. * Fix resizable destruction for visible table headers Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: TheWitness <larry@thewitness.org> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
1dc9961e03 | fix displayin js code after last collapsible row (#8200) | ||
|
|
4298f2ae33 |
feature: Search box on the modern filter bar + null-safe tablesorter trim (#8194)
* Surface the Search box on the modern filter bar Route the Search textbox (filter/rfilter) onto the modern filter bar, just right of the Rows selector, instead of only inside the Edit dialog. Pressing Enter in it applies the filter via the page's configured change function (filter=/rfilter= as appropriate), bound with event delegation so it survives ajax content reloads. field_is_bar() now keeps the search textbox on the bar and it is ordered Rows, Search, Refresh. * Null-safe tablesorter $.trim rewrite in the sync-js transform The jQuery 4 compatibility rewrite turned \$.trim(x) into (x).trim(), which throws when a custom textExtraction/parser returns a non-string or null (jQuery coerced values and mapped nullish to ''). Rewrite to String((x) ?? '').trim() - the inner parens keep || expressions from forming an illegal unparenthesized 'a || b ?? ''' - and regenerate include/js/jquery.tablesorter.js. Updates the sync-js fixture test accordingly. * Add changelog entries for the modern-bar Search and tablesorter trim fix * Add a Clear glyph button to the modern filter bar Place an eraser (ti ti-eraser) Clear button just right of Refresh on the modern bar, wired to the page's clear action, so the filter can be reset without opening the Edit dialog. The eraser matches the timespan/generic Clear glyph and stays visually distinct from Delete's trash glyph. * Give bar-routed Search a persistent label when a page omits friendly_name The log viewer (clog) defines rfilter without a friendly_name because it shared the adjacent matches field's Search label. Routed onto the modern bar it would show only the placeholder, which disappears after entry. Default a bar-routed filter/rfilter without a friendly_name to Search, scoped to the modern bar so legacy pages are unchanged. * Apply the filter when the search glyph is clicked The ti ti-search magnifying glass added after filter/rfilter inputs was decorative. A delegated click now submits the input's form, or on the modern bar (no form) triggers Enter, so clicking it applies the filter. * Use the legacy filter on Console > Management > Sites The Sites list gains nothing from saved layouts; set render_layouts = false so it renders the classic legacy filter. * Restore Search in the Edit dialog and glyph-ify Purge Mirror the bar Search into the Edit dialog (synced to the canonical bar input on open and on edit) so a saved layout's search term is visible and editable there without duplicating the input id; the bar stays the source of truth and nothing persists to a layout until it is saved. Also force a ti ti-flame glyph for the page-action Purge button. * Order Search before Rows on the modern bar to match legacy filters * Narrow the modern-bar regex Search to the normal filter width The rfilter (regex Search) input on the modern bar renders at size=55, much wider than the size=30 normal filter. Cap it at 30ch via .cactiFilterModernBar input#rfilter in every theme except Midwinter, which the user asked to leave as-is. * Document the modern-bar Clear, Purge glyph, dialog Search, and Sites legacy filter in the changelog * Glyph-ify the clog Rotate button Force a ti ti-rotate glyph for the page-action Rotate button (clog log rotation), matching the Purge/Save/Clear glyph treatment. --------- Co-authored-by: TheWitness <TheWitness@users.noreply.github.com> |
||
|
|
2a44c7a791 |
feature: modern filter bar polish (Rows/Refresh on bar, dialog button labels, separators) (#8191)
* fix: label modern dialog apply/clear with the page button text; show Rows on the bar
The dialog apply button was hardcoded 'Search', which mismatched the page's submit label (e.g. 'Go') and collided with pages that have a filter field named Search (clog). It now uses the configured go/clear button display text. Also route the 'rows' field to the modern bar alongside timespan/refresh so the per-page Rows selector stays visible.
* feature: always label the row-count selector 'Rows'
emit_field() forces the 'rows' field friendly_name to Rows regardless of page-specific naming (Devices, Trees, ...), in both legacy and modern filters. Refresh already renders on the modern bar via field_is_bar.
* feature: order modern bar selectors (Rows, Refresh) and separate them from the buttons
Rows renders first and Refresh second on the modern filter bar, and a vertical separator now divides the selectors (Layouts, Rows, Refresh) from the layout action buttons.
* changelog: 8191.feature fragment for modern filter bar polish
* jQuery 4: replace removed $.isFunction in bundled plugins
jQuery 4.0 removed $.isFunction. contextMenu, colorpicker and timepicker are hand-vendored orphans fixed in place; tablesorter is npm-managed, so it is also rewritten at sync time in build/sync-js.mjs so a rebuild reproduces the fix (no-ops once the upstream fix is released and the pin is bumped).
* Render the Thumbnails and Business Hours graph filter checkboxes as Cacti toggles
* fix: address review — update modern JS docblock and strengthen bar/label tests
Rewrite the create_modern_javascript docblock to describe the page-configured apply/clear labels (and document the change/clear callback params). Extend FilterLayoutsTest to assert the selector|button separator, the applied Rows-then-Refresh ordering, and both go/clear label lookups, and that the hardcoded Search dialog label is gone.
* Filter bar polish: toggle-style filter checkboxes and flicker-free layout buttons
Render the shared filter_checkbox field as a Cacti toggle switch (.checkboxSwitch/.checkboxSlider) so every page's filter checkboxes match the rest of the UI, and start the layout Rename/Delete/Save As buttons hidden so layoutUpdateButtons() reveals them only when applicable instead of flashing visible on load.
* Modern filter: move the timespan selector onto its own second filter line
Timespan controls were rendered inline on the single modern filter bar. Route method=timespan fields into a separate group and emit them as a second filterTable row so the bar isn't overcrowded, matching the legacy multi-row layout. Applies to every modern filter with a timespan (the graph view pages).
* Modern filter: keep toggle checkboxes on the bar with a visible label and tooltip
filter_checkbox fields now count as bar fields so the Thumbnails/Business Hours toggles sit on the single bar instead of the Edit dialog. Their label used .checkboxLabel (display:none by design for forms), which hid the text; switch to .checkboxLabelWanted and always set a title tooltip from the field's title/friendly_name so each toggle is self-describing.
* Modern filter: toggles back in the dialog, restrict auto-apply to bar fields, drop dialog Clear
- Move filter_checkbox toggles back into the Edit dialog (field_is_bar no longer claims them) and render them as a form row: friendly name in the label column, toggle in the value column.
- In modern mode only bar selectors (Rows, Refresh) and the Layout selector auto-trigger a filter change; dialog field changes/clicks no longer call applyFilter (gate changeChain/clickChain on !use_modern_filter() || field_is_bar). Legacy keeps auto-applying on change (text inputs still excluded).
- Remove the Clear button from the modern Edit dialog and the now-unused clearLabel; update the dialog-labels test accordingly.
* Fix filter toggle vertical alignment across themes
The generic .filterTable .filterColumn label { vertical-align: -10% } nudge (meant for text labels) out-specified .checkboxSwitch and dragged the toggle switch down, which also pulled the adjacent label baseline low in the Edit dialog and misaligned the toggle on the legacy filter bar. Add a higher-specificity label.checkboxSwitch { vertical-align: middle } in every theme carrying the rule (midwinter has no such rule).
* Hide the filter search glyph in the modern Edit dialog
Theme main.js appends a ti-search glyph after #rfilter, positioned for a table cell; in the modern Edit dialog #rfilter sits in a wide div (no td), so the glyph wraps below the field. Skip the injection when #rfilter is inside .cactiFilterEditTable (modern dialog); legacy, which has no such ancestor, keeps the glyph.
* jQuery 4: full removed-API sweep of bundled plugins
Replace every jQuery-4-removed helper across the vendored plugins: \$.trim -> String.prototype.trim, \$.isArray -> Array.isArray, \$.proxy -> Function.prototype.bind, \$.parseJSON -> JSON.parse, \$.type -> typeof/\$.isPlainObject, \$.isWindow -> native window check (plus the earlier \$.isFunction). Orphans (colorpicker, timepicker, multiselect, multiselect.filter, tableDnD) are fixed in place; the npm-managed tablesorter core+widgets are rewritten at sync time in build/sync-js.mjs so a rebuild reproduces the fix.
* Modern filter dialog: non-modal, Apply gated on save, Save keeps dialog open
- Rename the dialog apply action to Apply and disable it until the (new or changed) filter is saved (layoutDirty tracking); Close just closes without applying.
- Save no longer reloads the page: it reflects the saved layout in the selector and re-enables Apply, keeping the dialog open.
- Dialogs are now modal: false.
- Switch the layout selector change from a full document.location reload to an AJAX loadUrl().
- Vertically center the modern bar cells so the barSep separator lines up between the buttons.
* Modern filter: add layout to the filter's session variable structure
Register layout (FILTER_VALIDATE_INT, default 0) in sanitize_filter_variables() alongside page so the selected layout is validated and stored in the filter's session object and persists across page views.
* Modern filter: Graph Template amalgam on line 2, timespan on line 3
Tag the Graph Template + Source/Order/CF/Measure group ('bar' => true on graph_template_id and the html_graph_order_filter_array() metrics) so create_modern_filter renders it as its own second filter line on Graph View and Tree View, pushing the timespan to the third line. These bar fields also auto-trigger the filter so the Template->Source->Order callback chain works on the main bar.
* Fix graph_template_id multi-select: allow comma lists, type get_host_graph_list correctly
get_host_graph_list() immediately transforms graph_template_id via html_transform_graph_template_ids() (handles cg_/dq_ prefixes and comma lists), so its parameter is a string, not an int -- correct the type hint and docblock. Also widen the preview and listview graph_template_id validation regexp to accept a comma-separated list like 'cg_118,cg_106,cg_119', matching the tree filter.
* Modern filter: hide the whole cell for hidden layout buttons to even out bar separator spacing
The Rename/Delete/Save As buttons hid only the <button>, leaving their table-cell (with padding) in the bar, so the separator after them was pushed away from Edit. Put the display:none on the .filterColumnButton cell and toggle the cell in layoutUpdateButtons so hidden buttons take no space and the separators sit evenly between the visible buttons.
* Remove legacy .drop-callback/makeCallbacks() autocomplete widget
The Device dropdown and other form_callback() lookups now always use the
ajax-backed select2 selectmenu. Drop the old makeCallbacks() jQuery-UI
autocomplete entirely and have form_callback() render the select2-callback
<select> by default, keeping the plain full-list <select> only when the
'autocomplete' config option is enabled.
* Carry selected layout through the modern dialog Apply action
The layout_save callback already returns the new layout id (and url), and
layoutDialogSave() selects it in #filter_layout. The dialog Apply button,
however, ran the plain filter apply (applyFilter()) which rebuilds the URL
from the field values and omits filter_layout, so the page reloaded as
(New Filter). Apply now navigates to the selected layout's data-url (which
includes filter_layout=<id>) when a layout is selected, falling back to the
normal filter apply when none is.
* Fix Filter Layouts manage page table and use jQuery UI dialogs for delete/rename
The management table was opened with html_start_box(\ = true), emitting a
<div> instead of a <table>, so the header and rows rendered unstyled and
run-together. Switch it to table mode.
Replace the generic confirm()-based delete with a CDEF-style jQuery UI
confirmation dialog loaded over ajax, and add a Rename action that opens a
matching jQuery UI dialog with a name field. Both post to the existing
layout_delete/layout_rename handlers on confirm.
* Use jQuery UI dialogs for filter-bar layout rename/delete; drop rename from manage page
The filter bar (modern and legacy) was still using native prompt()/confirm()
for the layout Rename and Delete actions - convert both to jQuery UI dialogs
(a name-entry dialog for rename, a confirm dialog for delete).
On the Filter Layouts management page, remove the rename action entirely and
instead link the layout name to its page (with filter_layout set) as an edit
link; keep the Delete confirmation dialog and Publish action.
* Rework Layouts manage page: preset filter bar + actions dropdown; rename to Layouts
Model layouts.php on the preset pages (CDEFs, etc.): add the standard
CactiTableFilter search bar in the legacy look, a sortable list with a
checkbox column, a pager, and a draw_actions_dropdown with Delete, Make
Global (publish), and Make Local (reassign to the current user). The
unimpressive per-row action icons and ajax dialogs are replaced by the
checkbox/confirmation flow. Make Global/Make Local are admin-only.
Treat layouts.php as a filter_layouts preset page so its own filter bar
does not offer the layout dropdown. Rename the page title and Console
Presets menu entry from 'Filters'/'Filter Layouts' to 'Layouts'.
* Show friendly page name in the Layouts list Page column
Map the stored page basename to the Console navigation title (e.g. host.php
=> Devices) via a layouts_page_name() lookup against \, falling
back to the raw basename. The Page column is now nosort since the displayed
label no longer matches the sortable database value.
* Fix filter search TypeError: use filter_options key in default search field
sanitize_filter_variables() reads a field's callback options from the
'filter_options' key, but the default search field in create_default() stored
them under 'options', so the key never reached validate_store_request_vars().
That left FILTER_CALLBACK with no callback and raised 'filter_var(): Option
must be a valid callback' whenever a table filter was searched.
* Address PR scan findings: tablesorter useless conditional + layouts SQL
- jquery.tablesorter.js: drop the redundant 'str &&' guard inside the
already-truthy 'str ?' branch of the digit and currency parsers (CodeQL
useless-conditional). Add a matching sync-js transform rule so a rebuild
from upstream keeps the simplification.
- layouts.php: fully parameterize the management list queries with bound
'?' parameters for the search term and user id, and build the LIMIT from
explicit (int) page/rows, so no request variable reaches the SQL string
(Semgrep cacti-request-var-in-sql).
* Address PR review: colorpicker trim, tablesorter JSON guard, bar separator, i18n
- jquery.colorpicker.js: _setAltField() iterated index <= properties.length, so
the last pass read properties[undefined]; \$.trim(undefined) was '' but native
.trim() throws. Iterate with < so no TypeError.
- jquery.tablesorter.widgets.js: the retrieveValue feature-check still tested the
removed \$.parseJSON; under jQuery 4 it was always falsy so saved widget state
never loaded. Test native window.JSON.parse instead, and add a matching
build/sync-js.mjs transform rule so a rebuild keeps the guard.
- html_filter.php: the Layouts selector is always rendered, so emit the
selector-to-button separator unconditionally (graph preview routes fields to
the amalgam/timespan lines, leaving the bar line without it before).
- changelog/i18n: reword 8191.feature to describe the Apply (save-gated) dialog
action, and add the new layouts.php/html_filter.php msgids to cacti.pot.
* Add tablesorter transform coverage to the sync-js test
Feed a fixture containing every removed jQuery 4 utility (\$.isFunction,
\$.trim, \$.type ===string/object, \$.isWindow, \$.isArray, \$.parseJSON calls
and the bare if (\$.parseJSON) guard) plus the CodeQL str && simplification
through syncAssets, and assert the synced tablesorter output contains the
native equivalents and none of the removed APIs. Previously the transform ran
against a generic stub, so an incomplete rewrite could pass unnoticed.
* Apply php-cs-fixer: comment style, alignment, and single-quote strings
Run through the project php-cs-fixer config (the mandatory pre-PR check):
line comments for the input-validation banners, aligned assignment, and
single-quoted strings where no interpolation is used. No behaviour change.
* Render the filter Go action as a refresh glyph button (modern + legacy)
Replace the 'Go' text submit with a compact 'ti ti-refresh' glyph button
titled 'Refresh page' for every page filter:
- emit_field() forces the glyph/title on any 'go' submit, so both the shared
default and pages that define their own 'go' get it on the legacy filter.
- The modern bar (which has no form) gets a JS-wired #layout_refresh glyph
button right of Edit that loadUrl()s the selected layout url (carrying
filter_layout) or the page change callback.
Add the 'Refresh page' msgid to cacti.pot and note it in 8191.feature.
* Add a Tabler .icon-rotate spin class and use it for refreshing icons
Tabler ships only the icon webfont, with no fa-spin equivalent, so spinning
reload icons stopped animating (e.g. the Troubleshooting > Data Sources
auto-refresh indicator). Define .icon-rotate in every theme (reusing the
globally loaded fa-spin keyframes) and apply it:
- the modern filter refresh button spins while it loads,
- the realtime graph drill-down loader switches from fa-spin to icon-rotate,
- the data_debug auto-refresh indicators spin again.
* tests: sync FilterLayouts assertions with the reworded separator comment and dw.addClass
The source scan expected the old 'Separate the selectors' comment and a chained
.dialog('widget').addClass() form; update to the current reworded comment and
the 'var dw' + dw.addClass('cactiFilterDialog') the dialog now uses.
* Glyph-ify the timespan Refresh/Clear and the generic Clear action
Replace the timespan 'Refresh' text button with a spinning ti ti-refresh glyph
and 'Clear' with a ti ti-eraser glyph (also fixing a stray double </span>), and
make the generic filter Clear a ti ti-eraser glyph button across legacy and
modern via emit_field (button case now honours a 'glyph' key). The timespan
refresh icon spins (icon-rotate) while it reloads.
* Glyph-ify filter Import/Export, layout, and modern-bar action buttons
Force ti-table-import / ti-table-export glyphs for any filter button named import/export (centralized in emit_field like go/clear), so page-defined Import/Export buttons and the modern bar's always-visible action strip render consistent Tabler glyphs. Add a glyph parameter to layout_button() and glyph the Edit/Rename/Delete/Save As/Save/New/Publish buttons across the modern bar and legacy layouts row.
* Use table-import/table-export glyphs for cactiTableButton Import/Export icons
The filter header Export/Import icons injected into cactiTableButton used generic chevron-down/chevron-up glyphs; switch them to ti ti-table-export / ti ti-table-import to match the rest of the glyph theme.
* Glyph-ify the Save Filter Defaults button on the filter bar
The has_save 'Save' action rendered as a text button on the modern bar (and legacy filter); force a ti ti-device-floppy glyph via emit_field like go/clear/import/export so it matches the rest of the glyph theme.
* Regenerate tree-view graphs when applying a saved filter layout
The modern layout selector loaded a layout's saved data-url (action=tree) directly, so on the Graph Tree view it pulled the tree shell instead of regenerating graphs. Route the layout-url loads (selector change, refresh button, and dialog Apply) through correctUrlParameters() so action=tree becomes action=tree_content and graphs reload into #main, matching applyGraphFilter(). No-op on non-tree pages.
* Keep timespan controls working after ajax reloads and tip custom date fields
On the Graph Preview page the predefined_timespan change and tsrefresh/tsclear/shift click handlers were bound directly inside the filter's inline ready script, so an ajax content reload that replaced the timespan controls dropped the bindings (a full page refresh restored them). Bind them with namespaced event delegation on document so they survive content replacement and never double-bind. Add tooltips to the custom start/end date inputs telling the user to click Refresh to apply the range, plus POT entries and a changelog note.
* Record layouts.php static redirect in the sink inventory baseline
The sink and architectural hotspot guard flagged inventory drift: layouts.php's static header('Location: layouts.php') redirect (no request input) was never added to the tracked baseline. Refresh the baseline via tests/security/build_sink_inventory.sh to record it.
* Fix layout Save-As dialog state and use cacti_redirect in layouts.php
Address review findings: (1) use cacti_redirect('layouts.php') instead of a raw header()+exit so the standard redirect checks run (and drop the now-unneeded sink-inventory entry); (2) reset the dialog's force-new flag after the first successful save so later saves update the created layout instead of creating duplicates; (3) preserve an existing dirty state when reopening the Edit dialog so pending edits are not silently discarded by Apply.
* Drop stale layout msgids from the translation template
Remove the Filter Layouts, Published to all users, Publish to all users, and No Filter Layouts Found msgids that this PR replaced (now Layouts, Make Global, Make Local, No Layouts Found); all four are absent from PHP. Keeps the surgically-maintained POT in sync with the shipped strings.
---------
Co-authored-by: TheWitness <TheWitness@users.noreply.github.com>
|
||
|
|
41e6d9e033 |
security: consolidate verified GHSA fixes for develop (batch 4) (#8145)
* security: consolidate verified GHSA fixes for develop (batch 4) Develop counterparts of the 1.2.x batch-4 fixes in #8144, re-verified against current develop HEAD. - GHSA-4rmr-wvjq-qxc2: include/auth.php Basic Auth and guest branches fall through to the per-page realm check instead of returning early. - GHSA-j67j-wpm4-9g3x: the pre-dispatch update_policy branch in user_admin.php and user_group_admin.php requires a CSRF-token POST. The denylist -> allowlist redesign is tracked for 1.3 in #8143. - GHSA-2p3x-f5jm-rg6p: the View-Graphs -> poller RCE chain is broken by the realm check (4rmr), the update_policy guard (j67j) and shell-free webhits (x5pw). - GHSA-x5pw-cg7j-mj4r: scripts/webhits.pl runs wc through a shell-free list-form open. - GHSA-9737-rqh3-h7fh: names interpolated into raise_message() now use __esc() across the UI; URL- and HTML-bearing messages are excluded. - GHSA-9x9h-2577-9w86: the colordropdown input is built as a node and the label is no longer round-tripped through parseHTML (the list item already used createTextNode on develop). - GHSA-h96j-8xhc-2p3w: remote_agent.php authorizes on $_SERVER['REMOTE_ADDR'], not get_client_addr(), which honours client-settable proxy headers. Regression guards under tests/Unit/Security/{Auth,Csrf,Xss,ShellInjection}. php -l, check-changelog.py and the sink/architectural baselines all pass. * chore: reference PR #8145 on the batch-4 1.3.0-dev CHANGELOG entries * security: resolve develop merge - keep id-only xmlerror unescaped (matches #8141 h745 test) * security(GHSA-j67j): use REQUEST_METHOD POST guard instead of raw \ (hardening-pattern-guard) * security(GHSA-9737): fix review findings - drop double-encoding in __esc, escape missed name sinks, correct plugins format-arg count |
||
|
|
f956ea5a5c |
Convert generic <select> elements to select2(), with new class helpers (#8053)
* feat: convert generic <select> elements to select2, with new class helpers
Replaces the jQuery UI selectmenu() catch-all in setSelectMenus() with select2,
applied uniformly to single and multi selects. Fewer than 10 options disables
the search box (minimumResultsForSearch: Infinity); 10 or more enables it -
same threshold now applied to the existing select2/select2-multi classes.
New layout.js class helper: select2-multi-count, a multi-select whose
selection summary reads "N Selected"/"All Selected" instead of one chip per
option (generic multiSelectAllText/multiSelectCountText strings in html.php,
overridable per-field via data-select-all-text/data-select-count-text/
data-select-all-value). graph_template_id (html_graph.php x2, html_tree.php)
now uses it in place of the jquery.multiselect-based .graph-multiselect,
preserving the existing "All Graph Templates"/"N Templates Selected" wording
and the -1 "all" sentinel behavior (reimplemented via select2:select/unselect
events in setSelectMenus()). The old .graph-multiselect jquery.multiselect
init block is left in place (now unreachable for core's own markup) in case
a plugin/theme still emits that class itself.
select2-callback is reworked from its previously-unused static-URL contract
into an ajax-backed replacement for the legacy .drop-callback/makeCallbacks()
autocomplete widget: data-action + data-variables build the query the same
way makeCallbacks() already did (pageName + action + live values of other
named fields + search term), and data-callback still names a JS function to
invoke on selection, matching form_callback()'s existing $on_change/$class
contract. form_callback() only renders the new <select> markup when its
$class parameter contains select2-callback (opt-in); every existing caller
that doesn't request it keeps the exact legacy output. html_graph.php's
host_id filter (both places) opts in. form_multi_dropdown() gained optional
$select_all_text/$select_count_text/$select_all_value parameters (all
additive/backward compatible) to plumb the graph_template_id wording through.
Compatibility: an org-wide code search found no plugin depending on the
.select2-callback/.graph-multiselect/.drop-callback/makeCallbacks() internals
being changed here (form_callback()'s default output is unchanged; the
.graph-multiselect jquery.multiselect init stays available). Everywhere else
in core that assumed the old jQuery UI selectmenu widget on elements now
covered by the broadened catch-all (disableField()/enableField(), the SNMP
security-level/protocol refresh logic, realtime.js's ds_step/graph_start/size
refresh, api_aggregate.php's field enable/disable, and html_reports.php's
branch_id/site_id/host_template_id handling) now branches on
.select2-hidden-accessible and uses select2's own refresh mechanism
(.trigger('change.select2')) instead, alongside the untouched legacy
selectmenu branch. #user_language and #i18n_default_language (which get
their own bespoke flag-icon languageselect widget) are excluded from the
catch-all, same as before.
The install wizard (install/install.js) has its own independent selectmenu
initialization and is intentionally left untouched.
* fix: use json_encode for select2 multi-select JS translation strings
* fix: make select2 initializers idempotent to stop duplicate widgets
applySkin() (which calls setSelectMenus(), where every select2/select2-multi/
select2-multi-count/select2-callback/catch-all initializer lives) runs more
than once per page view - once from cactiReady() on initial load, and again
from the generic AJAX-completion handler after any loadUrl()/postUrl() call,
which most list/filter pages already trigger during their own initial load.
Since calling .select2() a second time on an element that already has it
initialized creates a second, independent .select2-container next to the
first (select2 does not no-op or tear down the previous instance), every
affected <select> ended up rendering twice. Guard every initializer (plus
the graph_template_id -1 sentinel's event bindings, now namespaced and
unbound first) so a second setSelectMenus() pass skips elements already
marked .select2-hidden-accessible.
* fix: match select2 dropdown styling to the dark theme's real button look
border-radius was 4px (should be 6px, matching .ui-corner-all used
everywhere else); the selection box and dropdown panel were flat black
instead of this theme's actual .ui-button/.ui-widget-content backgrounds
(a subtle gradient-highlight image and a repeating texture image,
respectively). Also add a min-width and force the selected text/dropdown
option list to a single line instead of wrapping.
* fix: match select2 dropdown styling to each theme's real button look
Same fix as the earlier dark theme commit, applied to the remaining themes.
Every theme's select2 override previously used generic placeholder colors
(border-radius: 4px, background: #ffffff/#222222) that did not match that
theme's actual .ui-state-default/.ui-button/.ui-widget-content styling:
- cacti, carrot, hollyberry, raspberry, modern, paw: selection box now uses
the real button gradient-image background instead of flat white; dropdown
panel background already matched and is unchanged.
- sunrise: selection box background corrected to transparent (matching its
real button style) and the dropdown panel to its real black background,
instead of flat white for both.
- paper-plane: selection box background corrected to this theme's real
near-black button color instead of flat white.
- midwinter: switched from hardcoded generic colors to this theme's own
CSS custom properties (var(--border-color), var(--background-content),
var(--text-color-lighter), etc.), matching jquery-ui.midwinter.css.
border-radius is now 6px everywhere, matching .ui-corner-all. All themes
also gained a min-width and forced the selected text/dropdown option list
onto a single line instead of wrapping.
* fix: default select2's dropdownAutoWidth to true
The legacy jQuery UI selectmenu widget always sized its open dropdown to fit
the widest option, regardless of how narrow the closed control itself was.
Select2 defaults to matching the dropdown's width to the control's, so wide
option text was wrapping/truncating inside a narrow panel. Set this as a
global default once instead of touching every individual select2() call.
fix: destroy any existing select2 widget before re-initializing
applySkin() runs more than once per page view. The existing
:not(.select2-hidden-accessible) guards were meant to make re-running the
select2 initializers a no-op, but duplicate widgets were still being
reported. Explicitly tear down any select2 instance still attached right
before the initializers run again, so a widget can never end up duplicated
regardless of why applySkin() re-ran.
fix: don't select2-ify a select a plugin already widget-ified with selectmenu
Symmetric to the above: if a plugin's own script already deliberately
applied jQuery UI selectmenu to one of its selects (a few do, for their own
dynamically-created fields), skip converting it to select2 too.
* fix: convert the Device filter's legacy drop-callback widget to select2-callback
html_host_filter()'s autocomplete-enabled branch never got the select2
treatment applied to every other filter field - it still built its own
<input class='drop-callback'> wired up by the older makeCallbacks()/jQuery UI
autocomplete widget (styled with the legacy ui-selectmenu-button markup),
instead of opting into form_callback()'s newer select2-callback rendering like
everything else. Left side-by-side with now-modernized neighboring filters,
this old widget stood out as a leftover "old select". Switch it to the same
select2-callback select markup (data-action='ajax_hosts',
data-variables='site_id') the 1.2.x branch already uses, reusing the existing
ajax_hosts handlers and get_allowed_ajax_hosts()'s id/label response shape.
* fix: restore select2's gradient after closing without selecting, shrink its height, and drop the now-unneeded min-width
Every theme's active/open select2 style also matched .select2-container--focus,
but select2 leaves that class on the container after the dropdown closes (it
only drops --open), so the flat "active" background stuck around until the
next selection instead of the gradient returning right away. Scope the active
look to --open only.
Also shrink the single-select control from select2's stock 28px down to 24px
(and its arrow/rendered text to match) so it sits closer to the jQuery UI
button height it's replacing, and drop the min-width: 160px placeholder added
earlier to keep wide option text from being clipped - dropdownAutoWidth now
sizes the open dropdown to its content regardless of the closed control's
width, so the constraint is no longer needed.
* feat: add configurable select2 search threshold; drop autocomplete_enabled on develop
Add the same Select Search Minimum Rows setting added on 1.2.x, wiring it
through as the select2SearchRows JS global (include/global_session.php) and
replacing the hardcoded 10-option cutoff in every select2 initializer in
layout.js.
Remove Autocomplete Enabled entirely on develop: it only ever existed to let
the Classic theme opt out of the ajax-backed callback widgets, and Classic
doesn't exist as a develop theme. html_host_filter() and the Graph Items data
source field now always use the ajax-backed rendering (select2-callback /
drop_callback) unconditionally instead of branching on the removed setting.
* fix: keep the first 20 select2 results visible before scrolling
Select2's stock results list only guaranteed ~7-8 rows (200px) before
scrolling. Pin each result row to a consistent 24px (matching the shrunk
control height) and size the list's max-height to fit 20 of them before the
scrollbar kicks in.
* fix: repair layout.js corruption from the select2SearchRows commit, and exclude .multiselect from the catch-all
A faulty automated edit in
|
||
|
|
2e05b98b1f |
Add select2 for enhanced/searchable dropdowns (#8051)
* feat: add select2 for enhanced/searchable dropdowns Vendors select2 4.1.0 (MIT, https://select2.org) as a new front-end dependency, following this branch's existing npm-synced-to-include/js convention: - package.json: added "select2": "4.1.0" to dependencies (alongside the other npm-tracked front-end libs, so Dependabot can track it). - build/sync-js.mjs: added node_modules/select2/dist/js/select2.full.js -> include/js/select2.js to the asset map (the "full" build bundles its jquery-mousewheel dependency, so no extra package is needed). - include/js/select2.js: the synced output (select2.full.js, unminified, matching this repo's "vendor unminified where possible" convention). CSS, following the existing per-theme vendor-CSS convention (jquery-ui.css, jquery.multiselect.css, etc. - none of which are npm-synced either): - include/themes/<theme>/select2.css: the upstream select2.css (structural/ functional rules), copied unmodified into all 10 themes. - lib/html.php: wired both the JS and (per-theme) CSS into the page header, next to the other jQuery UI plugin includes. - include/themes/<theme>/main.css: since Select2 4.x publishes no jQuery UI theme/adapter, appended a small override block per theme (widget border/ background/text, hover, and active/highlighted colors) reusing each theme's own jquery-ui.css/.ui-state-active colors, so Select2 dropdowns match that theme's native jQuery UI look instead of Select2's generic default styling. * feat: initialize select2() widgets in applySkin() Wires up the select2/select2-nosearch/select2-tags/select2-multi/ select2-multi-tags/select2-callback marker classes so pages can opt in to a Select2-enhanced dropdown just by adding the class, matching the existing markup-driven convention used by other jQuery UI widget setup in this function. Dialog-hosted selects pass dropdownParent so the dropdown attaches to the ui-dialog widget instead of escaping under it (a well-known Select2 + jQuery UI dialog z-index/stacking issue). * fix: remove accidental theme:'bootstrap' from select2-multi init * fix: address Copilot review findings on the select2 PR - package-lock.json: added the select2@4.1.0 entry (registry resolved URL + integrity hash) so `npm ci` no longer rejects the package.json/lockfile mismatch. - .gitignore / include/js/select2.js: select2.js is a generated npm-synced build output like the other managed libraries, so it belongs in the generated-asset ignore list, not committed. Untracked the copy that had been committed; `npm run build:js` regenerates it locally. - build/README.md: documented select2 among the npm-managed libraries, and clarified that the per-theme select2.css copies are committed unmodified upstream CSS (unlike jquery-ui/jstree's Cacti-owned theme CSS). - include/themes/paper-plane/main.css: highlighted/focused Select2 options were the same white as the dropdown background, giving no visible focus indicator; changed to the theme's own hover color (#dadada / #212121). - include/themes/sunrise/main.css: same issue; changed to this theme's established menu focus color (#3C8A3C, matching .ui-menu .ui-state-focus) with white text. * fix: address 3 material Copilot review findings on select2 init - Exclude the select2/select2-nosearch/select2-tags/select2-multi/ select2-multi-tags/select2-callback marker classes from setSelectMenus()'s generic $('select')... loop, so Select2-marked single-selects are no longer first hidden/wrapped by jQuery UI Selectmenu before Select2 wraps them again. - select2-callback: Select2 calls the ajax.url callback with a context that is not the original <select>, so $(this).data('callback') read undefined inside it. Capture the element's callback URL into a local variable before calling .select2() and use that instead. - select2-callback: it was the only initializer that never checked for a jQuery UI dialog ancestor, so its dropdown always appended to body and could be hidden behind a dialog's overlay. Set dropdownParent the same way the other five initializers do. * fix: proactively apply 2 material findings from the 1.2.x PR review Copilot's review of the companion 1.2.x PR (#8052) found 2 bugs in this same select2-init code that also apply here unchanged: - Select2 renders its replacement as <span class="select2 select2-container">, so the plain class selectors (.select2, .select2-nosearch, etc.) also matched Select2's own generated wrappers on every later applySkin() call (e.g. during AJAX navigation), re-initializing and nesting wrappers. Scoped all six selectors to `select.<marker-class>` so only the original <select> elements are ever matched. - select2-callback's ajax response was never normalized: Cacti's existing callback endpoints (e.g. lib/auth.php) return a plain array of {label, value, id} objects, but Select2 requires {results: [{id, text}]}. Added a processResults mapping so callback-backed dropdowns actually populate. - select2-callback now also sets dropdownParent unconditionally (dialog ancestor, or document.body otherwise) instead of leaving it unset outside dialogs. |
||
|
|
d34fbaacc4 |
fix: Restore base javascript files for testing (#8037)
* fix: Restore base javascript files for testing * fix: screenfull 6.0.2 is missing screenfull.js * fix: Restoring screenful after discovering how the files are managed * fix: Remove node modules directory after installing modules * fix: Change in screenfull.js behavior affects cacti * fix: Restore jQuery 4 compatibility in the tablesorter pager plugin $.isArray()/$.trim() were removed in jQuery 4.0, which this PR pins in package.json. The restored jquery.tablesorter.pager.js still called E.isArray(...)/E.trim(...), so any Ajax pager response threw before rendering. Also fix a TypeError in the countChildRows branch, which indexed into `a` while it was still an undeclared var. Add patches/tablesorter+2.32.0.patch so the fix survives the next `npm run build:js` sync from node_modules, following the existing pace-js patch-package precedent. * fix: Rewrite screenfull's ESM export during sync-js instead of downgrading screenfull 6+ ships ESM-only (`export default screenfull;` in node_modules/screenfull/index.js), which throws "export declarations may only appear at top level of a module" when the copied file is loaded as a classic <script>. Add a post-copy transform step to build/sync-js.mjs that rewrites that line to `window.screenfull = screenfull;` for include/js/screenfull.js, so the 6.0.2 pin in package.json can be kept instead of reverting to 5.2.0. Throws if the expected export line isn't found, so a future screenfull release changing its export shape fails the build loudly rather than silently shipping a broken asset. Updates tests/js/sync_js.test.mjs to cover the transform and its failure mode. |
||
|
|
a2c8df612e |
fix(csrf): require POST tokens for state-changing actions (#7991)
* fix(csrf): require POST tokens for item actions * test(csrf): cover every guarded action path * test(csrf): keep legacy guard contract extensible * fix(csrf): hide POST-only targets from crawlers * test(csrf): reject every crawlable state-action link * fix(csrf): fail closed without logging crawler probes * fix(csrf): post data-query item actions safely Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): normalize stripped token separators Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): distinguish method and token failures Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): escape POST action URL attributes Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): delegate POST action events Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): post data template add action Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * style(html): align POST button class Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
1fdf9acf3b | Fix detached select menus on scroll (#8000) | ||
|
|
80fbb802a3 | fix: allow graph tree sidebar to shrink (#7837) | ||
|
|
41eda4cd42 |
fix(xss): resolve the two first-party CodeQL JS findings (#7234)
* fix(xss): build textWidth span via .text() and load example iframe over https Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(xss): build DOM-sourced UI elements safely instead of via html string interpolation Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
b2bf39b8dc |
fix(sqli): sanitize sort_column and enforce sort_direction in ORDER BY clauses (#7162)
* fix: correct grammar and possessive errors in English source strings (batch 2) (#1) * fix: correct grammar and possessive errors in English source strings (batch 2) Seven errors found via cacti.pot audit: - automation_networks.php: "senders name" → "sender\'s name" (line 839) - automation_networks.php: "senders Email" → "sender\'s Email" (line 848) - automation_templates.php: "devices sysDescr" → "device\'s sysDescr" (line 1060) - automation_templates.php: "devices sysName" → "device\'s sysName" (line 1067) - automation_templates.php: "devices sysOid" → "device\'s sysOid" (line 1074) - data_templates.php: garbled "it either it value...critical data Data Query" → "its value...Data Query" (line 903) - package_repos.php: "Package Repositorites" → "Package Repositories" (line 436) All changes are to UI description strings inside __() / __esc() calls. cacti.pot should be regenerated via build_gettext.sh after merge. * fix: correct grammar and possessive errors in English source strings (batch 2) Seven errors found via cacti.pot audit: - automation_networks.php: "senders name" → "sender\'s name" (line 839) - automation_networks.php: "senders Email" → "sender\'s Email" (line 848) - automation_templates.php: "devices sysDescr" → "device\'s sysDescr" (line 1060) - automation_templates.php: "devices sysName" → "device\'s sysName" (line 1067) - automation_templates.php: "devices sysOid" → "device\'s sysOid" (line 1074) - data_templates.php: garbled string → "its value...Data Query" (line 903) - package_repos.php: "Package Repositorites" → "Package Repositories" (line 436) All changes are to UI description strings inside __() / __esc() calls. cacti.pot should be regenerated via build_gettext.sh after merge. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: add dependabot config with npm and github-actions * ci: add CodeQL (JS/TS, excludes PHP) with workflow_dispatch * ci: update CodeQL for javascript-typescript, python * fix(ci): use specific runner labels, fix codeql concurrency * Improve IPv6 support in RRDtool proxy and ping utilities (#2) * Improve IPv6 support in RRDtool proxy and ping utilities - Fix RRDtool proxy to dynamically detect IPv6 addresses and use AF_INET6 sockets instead of hardcoded AF_INET (IPv4-only), enabling connections to IPv6 RRDtool proxy servers including backup servers - Strip brackets from IPv6 addresses before passing to socket_connect - Properly close failed sockets before creating new ones for failover - Replace fragile str_contains(':') IPv6 detection in ping with filter_var(FILTER_FLAG_IPV6) for more robust address validation https://claude.ai/code/session_01SbuDigvAkYvPKvdcougsdo * Fix JS code quality: implicit globals, deprecated APIs, loose equality - Add var declarations to prevent implicit globals in install.js (element, enabled, button, buttonCheck) - Remove console.log debug output left in production (install.js) - Replace deprecated jQuery .unbind() with .off() (layout.js) - Fix "depreciated" typo to "deprecated" in deprecation warnings - Convert == / != to === / !== for null, boolean, string, typeof, and numeric comparisons across install.js and realtime.js https://claude.ai/code/session_01SbuDigvAkYvPKvdcougsdo * Replace deprecated jQuery shorthand event methods in layout.js Replace .click(), .keyup(), .keydown(), .mousedown(), .mouseenter(), .mouseleave(), .submit(), .resize() with .on() equivalents. Replace .focus(), .change() trigger calls with .trigger(). These shorthands were deprecated in jQuery 3.5. https://claude.ai/code/session_01SbuDigvAkYvPKvdcougsdo * Replace deprecated jQuery methods in realtime.js Replace .bind() with .on() and .change() trigger calls with .trigger('change'). .bind() was deprecated in jQuery 3.0 and shorthand triggers in jQuery 3.5. https://claude.ai/code/session_01SbuDigvAkYvPKvdcougsdo * Replace deprecated jQuery methods in install.js and fix ===/!== errors Replace .click(), .change(), .focus() with .on()/.trigger() equivalents. Also fix !=== and ==== operators that were incorrectly introduced by a prior replace-all of == to === within existing !== and === expressions. https://claude.ai/code/session_01SbuDigvAkYvPKvdcougsdo * Restore == null where needed to catch both null and undefined In JavaScript, == null matches both null and undefined, which is an intentional idiom. The prior === null conversion broke cases where values come from jQuery .val(), .data(), $.urlParam(), or object property access that may return undefined rather than null. Revert those specific cases while keeping === null where variables are explicitly initialized to null. https://claude.ai/code/session_01SbuDigvAkYvPKvdcougsdo * Replace deprecated jQuery methods in all theme main.js files Replace .unbind().click() with .off('click').on('click'), convert .hover() to .on('mouseenter').on('mouseleave'), replace .change(), .scroll(), .click() shorthands with .on() equivalents, and .blur() with .trigger('blur') across all 10 theme files. https://claude.ai/code/session_01SbuDigvAkYvPKvdcougsdo * Convert string concatenation to template literals Replace 'str' + var + 'str' patterns with ES6 template literals in realtime.js and install.js. Improves readability especially for URL construction and HTML building. Also replace $.parseJSON() with native JSON.parse() in realtime.js. https://claude.ai/code/session_01SbuDigvAkYvPKvdcougsdo * Convert var to const for single-assignment variables Replace var with const where the variable is assigned once and never reassigned within its scope, in install.js and realtime.js. Keeps var for variables that are conditionally reassigned (e.g. size, url). https://claude.ai/code/session_01SbuDigvAkYvPKvdcougsdo --------- Co-authored-by: Claude <noreply@anthropic.com> * fix(sqli): sanitize sort_column and enforce sort_direction in ORDER BY clauses Closes GHSA-q9xg-p762-9jm3 and GHSA-72vr-jr4v-55vf. - Add sanitize_sql_column() to lib/functions.php stripping all chars outside [a-zA-Z0-9_().] from user-supplied column names - Apply sanitize_sql_column() at every ORDER BY concatenation in api_automation.php and html_reports.php - Enforce direction to literal ASC/DESC in html_reports.php, api_automation.php, and html_utility.php (update_order_string, get_order_string) - Add tests/Unit/SafeSortTest.php with 22 stub-based regression tests Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(docs): move sanitize_sql_column above sanitize_search_string docblock The sanitize_search_string docblock was orphaned after sanitize_sql_column was inserted between it and the function body. Reorder so each function follows its own docblock directly. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(sqli): escape apostrophes in automation_templates and harden sort_direction in display_matching_hosts Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(sqli): restore allowlist guard, sanitize session keys, add sanitize_sql_column default Restore the preg_match allowlist guard in get_order_string() that was removed by the PR, re-opening the ORDER BY injection surface. When the request var is empty after sanitization, return '' rather than building a malformed ORDER BY clause. Sanitize sort_column before storing as SESSION array key in update_order_string() and add read-time guard in the inplace loop that rebuilds ORDER BY from stored keys. Add $default parameter to sanitize_sql_column() so callers get a safe fallback instead of an empty string that produces 'ORDER BY ASC'. Fix inconsistent INET_ATON substitution in display_matching_hosts(). Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Improve sanitize_sql_column function Fix regex to sanitize SQL column names properly. * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: TheWitness <thewitness@cacti.net> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
255667b49d |
chore(assets): update jQuery UI and theme assets (#7082)
* chore(assets): update jQuery UI and theme assets Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(codex): restore jQuery UI compatibility and fix PHPStan issues * fix(midwinter): restore full-width multiselect button rules dropped in jquery-ui rebuild Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: ignore phpstan function.alreadyNarrowedType identifier Clears the level 6 alreadyNarrowedType error on lib/data_query.php:2591 that develop currently emits, matching the sibling narrowing identifiers already ignored. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: TheWitness <thewitness@cacti.net> |
||
|
|
d5a070f7ef |
fix(ui): tooltip pin behavior and jQuery compatibility cleanup (#7040)
* fix(ui): pin explanation tooltips on click * fix(ui): avoid duplicate tooltip pin handlers * fix(js): replace deprecated jQuery APIs with modern equivalents * fix(ui): restore decimal-safe numeric parsing in zoom deserialize * chore(vendor): bump tablesorter and jquery-validation assets * test(e2e): add jquery vendor smoke coverage with playwright |
||
|
|
7919efd137 |
Issues found in testing (#6595)
* QA: Add database session clear out to change password * QA: Can not determine average fully loaded * QA: Synchornize Spikekill with 1.2.x * Removing Variance as it's not mathmatically correct * Removing Variance as it's not mathmatically correct * Properly re-draw graph |
||
|
|
27919c50d7 | Updating Copyrights to 2026 (#6578) | ||
|
|
1627c7a150 | Font Awesome Icons to Tabler Icons migration | ||
|
|
b9334a15d9 | QA: Updates for files for php-cs-fixer and some php-doc changes | ||
|
|
0e361fbf45 |
QA: Fix #6300 - Change Settings Not Working
* This is due to the change in how SelectMenu's render. For some reason they are not included in the Serialized Array. So, having to augment the array. |
||
|
|
115d9daebf |
MidWinter
- Elements on Top: Actions, Pagination as well as table title will stay on top - introduce dialogues. (requires alignment with other Cacti core developers) |
||
|
|
d73ea2edbf | QA: Language switch not wrking and two memory leaks | ||
|
|
1433ecdc50 | QA: Remove deprecated escape() function | ||
|
|
5fd1ab4f37 |
MidWinter
- colors - close to final. - introduce sticky Container holding Table Title and Buttons. |
||
|
|
44bdd44466 | Minor Lint Checking Fixes | ||
|
|
2c779273f9 | Copyright Updates and PHP-CS-Fixer updates | ||
|
|
b409adc8bc | QA: Doing secondary sorts select text | ||
|
|
b027f6a93a | QA: External Links broken | ||
|
|
d88d3acd30 | reverting FontAwesome till better solution has been identified. | ||
|
|
1cc3e01ec7 | QA: Fix: #6058 - Login Page Issues | ||
|
|
27a531e406 | QA: Theme tweaks for Tabler | ||
|
|
2735f37838 | QA: Fix Page Refresh. Don't use eval() | ||
|
|
5be7d7f18b | Migrating icons from FontAwesome to Tabler | ||
|
|
3016744e41 | QA: Finish work on Filter Table Show/Hide | ||
|
|
83b13183c0 | QA: function loadUrl() does not handle JSON responses | ||
|
|
42a85d2b6a | QA: Default Search width too large | ||
|
|
e89214ff1f | QA: When on auth_profile.php top tab not working |