mirror of
https://github.com/StuffAnThings/qbit_manage.git
synced 2025-10-12 23:08:31 +08:00
# Requirements Updated - "retrying==1.4.2", # New Features - **Web UI**: Implement dynamic schedule management via web UI/API - **Share Limits**: Add limit upload speed when share limits are reached (New config option: `upload_speed_on_limit_reached`) (Fixes #731, #737, #703) - **Share Limits**: Add min/max torrent size filters (New config option: `min_torrent_size` / `max_torrent_size`) (Fixes #472) - **Remove Unregistered**: Add grace period for unregistered torrent removal (New config option: `rem_unregistered_grace_minutes`) (Fixes #898) - **Scheduler (Web API)**: Implement dynamic schedule management via web API # Improvements - **Mover Script**: Allow granular control with pause, resume and move args - **web UI**: When saving, don’t delete config comments and empty lines (Fixes #890) # Bug Fixes - Fix Error acquiring lock: cannot assign to field '_last_run_start' (Fixes #895) - Fix remove_orphaned not working correctly with `remote_dir` and reporting 0 files removed - fix(web-ui): prevent XSS vulnerabilities and prototype pollution - Potential fix for code scanning alert no. 13: Client-side cross-site scripting (#896) **Full Changelog**: https://github.com/StuffAnThings/qbit_manage/compare/v4.5.2...v4.5.3 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
86 lines
3 KiB
JavaScript
86 lines
3 KiB
JavaScript
/**
|
|
* General Utility Module
|
|
* Provides common utility functions.
|
|
*/
|
|
|
|
/**
|
|
* Gets a nested value from an object using a dot-separated path.
|
|
* @param {object} obj - The object to query.
|
|
* @param {string} path - The dot-separated path (e.g., 'parent.child.property').
|
|
* @returns {*} The value at the specified path, or undefined if not found.
|
|
*/
|
|
export function getNestedValue(obj, path) {
|
|
return path.split('.').reduce((current, key) => {
|
|
return current && current[key] !== undefined ? current[key] : undefined;
|
|
}, obj);
|
|
}
|
|
|
|
/**
|
|
* Escape a string for safe insertion into HTML/attribute context.
|
|
* Encodes &, <, >, ", ' to their HTML entities.
|
|
* This should be used whenever inserting user-controlled content via innerHTML
|
|
* or into attribute values.
|
|
* @param {any} str - Input value to escape
|
|
* @returns {string} Escaped HTML-safe string
|
|
*/
|
|
export function escapeHtml(str) {
|
|
if (str === null || str === undefined) return '';
|
|
return String(str)
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''')
|
|
.replace(/\//g, '/');
|
|
}
|
|
|
|
/**
|
|
* Sets a nested value in an object using a dot-separated path.
|
|
* Creates intermediate objects if they don't exist.
|
|
* If the value is null, undefined, or an empty string, the property is deleted.
|
|
* @param {object} obj - The object to modify.
|
|
* @param {string} path - The dot-separated path (e.g., 'parent.child.property').
|
|
* @param {*} value - The value to set.
|
|
*/
|
|
export function setNestedValue(obj, path, value) {
|
|
const keys = path.split('.');
|
|
const lastKey = keys.pop();
|
|
const target = keys.reduce((current, key) => {
|
|
if (!current[key] || typeof current[key] !== 'object') {
|
|
current[key] = {};
|
|
}
|
|
return current[key];
|
|
}, obj);
|
|
|
|
if (value === null || value === undefined || value === '') {
|
|
delete target[lastKey];
|
|
} else {
|
|
target[lastKey] = value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Basic host validation - IP address or hostname
|
|
* @param {string} host - The host string to validate.
|
|
* @returns {boolean} True if the host is valid, false otherwise.
|
|
*/
|
|
export function isValidHost(host) {
|
|
const ipRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
const hostnameRegex = /^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
|
|
return ipRegex.test(host) || hostnameRegex.test(host) || host === 'localhost';
|
|
}
|
|
/**
|
|
* Debounces a function, so it only runs after a specified delay.
|
|
* @param {function} func - The function to debounce.
|
|
* @param {number} delay - The delay in milliseconds.
|
|
* @returns {function} The debounced function.
|
|
*/
|
|
export function debounce(func, delay) {
|
|
let timeout;
|
|
return function(...args) {
|
|
const context = this;
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(() => func.apply(context, args), delay);
|
|
};
|
|
}
|