feat(audit): L51 + L64 — daily-sync time picker + aria2c connection tuning
Two small self-contained features from the audit's deferred list: - L51: the Task Scheduler daily sync is no longer pinned to 09:00. New Settings.syncTime (24h HH:MM) with a native time input beside the Library "Daily sync" switch — persists on change, re-registers the task on blur (schtasks /Create /F overwrite is the time-change mechanism). The value reaches the schtasks /ST argv, so a shared isValidSyncTime guards it at both the settings write and in schedule.ts (unit-tested incl. injection-shaped input). Live-verified against the machine's real task. - L64: aria2c connection count (-x/-s) is user-tunable. New Settings.aria2cConnections (1-16, aria2c's own ceiling) exposed as a SpinButton in Settings -> Network while the aria2c toggle is on. ARIA2C_ARGS became the pure aria2cArgs(n?) with a defensive clamp; threaded through AccessOptions. The -k 1M split floor stays fixed — a free-text field would bypass the custom-command consent gate. typecheck + 309 tests + eslint + production build green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+34
-1
@@ -8,7 +8,40 @@ import {
|
||||
isValidSource,
|
||||
isValidMediaItem
|
||||
} from '../src/main/validation'
|
||||
import type { HistoryEntry, ErrorLogEntry, Source, MediaItem } from '@shared/ipc'
|
||||
import {
|
||||
isValidSyncTime,
|
||||
type HistoryEntry,
|
||||
type ErrorLogEntry,
|
||||
type Source,
|
||||
type MediaItem
|
||||
} from '@shared/ipc'
|
||||
|
||||
// --- L51: daily-sync time (reaches `schtasks /ST`) ---------------------------
|
||||
|
||||
describe('isValidSyncTime', () => {
|
||||
it('accepts well-formed 24h HH:MM times', () => {
|
||||
expect(isValidSyncTime('00:00')).toBe(true)
|
||||
expect(isValidSyncTime('09:00')).toBe(true)
|
||||
expect(isValidSyncTime('19:30')).toBe(true)
|
||||
expect(isValidSyncTime('23:59')).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects out-of-range, partial, and 12h forms', () => {
|
||||
expect(isValidSyncTime('24:00')).toBe(false)
|
||||
expect(isValidSyncTime('12:60')).toBe(false)
|
||||
expect(isValidSyncTime('9:00')).toBe(false) // must be zero-padded
|
||||
expect(isValidSyncTime('09:0')).toBe(false)
|
||||
expect(isValidSyncTime('9am')).toBe(false)
|
||||
expect(isValidSyncTime('')).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects non-strings and injection-shaped values', () => {
|
||||
expect(isValidSyncTime(undefined)).toBe(false)
|
||||
expect(isValidSyncTime(900)).toBe(false)
|
||||
expect(isValidSyncTime('09:00 /TN evil')).toBe(false) // nothing may trail the time
|
||||
expect(isValidSyncTime('09:00\n')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
// --- S4: filename template path-traversal -----------------------------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user