Skip to content

Commit eea10c6

Browse files
committed
v1.9.22: audit round — bug fixes, /file route regression, timer leaks
Reverts a security regression introduced in v1.9.21 and hardens several bug classes uncovered in a full QA pass. Backend: - /file preview route: restore realpath allowlist (temp dir + ~/.opencut) that was dropped in v1.9.21. The MIME-type check is kept as defence-in-depth. Prevents same-browser attackers from enumerating arbitrary local media via <img>/<audio> tags. - safe_bool() hardening: reject NaN/inf floats, decode bytes/bytearray through the string parser, and refuse to coerce lists/tuples/sets/ dicts/arbitrary objects. Previously non-string containers silently returned True. - Complete the safe_bool sweep that v1.9.21 started: 15 more flag reads across audio.py, captions.py, system.py, video_ai.py, video_core.py, and video_editing.py — including watermark transparent/preview/auto_import, export audio_only, thumbnail use_faces, batch parallel, full_pipeline skip_*/remove_fillers, diarize, word_timestamps, include_context_fillers, remove_silence, alpha_only, and whisper cpu_mode on the install route. core/highlights.py: - Handle None / missing-attribute LLM responses instead of crashing when the provider is unreachable mid-request. mcp_server.py: - Wrap response serialisation in try/except; non-JSON-serialisable tool results now return a proper JSON-RPC error instead of leaving the client hanging. Frontend (CEP panel): - mediaScanTimer and _statusTimer no longer leak after the first disconnect/reconnect cycle. cleanupTimers() killed them but only the initial bootstrap restarted them — after one server restart the panel would silently stop polling project media and system status until full reload. Introduced startBackgroundPollers() called from both the init path and the health-check reconnect branch. - initStatusBar() is now idempotent (skips if _statusTimer exists). - Removed the duplicate var _statusTimer declaration that shadowed the module-scope hoisted timer. UXP panel: - Utility .oc-hidden and .oc-chat-history classes added to style.css. - Cut tab a11y fix: aria-labelledby now links to a real button id. Tests: - test_boolean_coercion: 25-case parametrized unit test for safe_bool covering native bools, numerics, strings, bytes/bytearray, NaN/inf, containers, and arbitrary objects. - test_new_features: TestPreviewFileServing now also asserts that a media file OUTSIDE tempdir + ~/.opencut is 403'd, regardless of MIME type.
1 parent cef498d commit eea10c6

29 files changed

Lines changed: 256 additions & 72 deletions

Install.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ Write-Host " \___/| .__/ \___|_| |_|\____\__,_|\__|" -ForegroundColor Cyan
155155
Write-Host " |_| " -ForegroundColor Cyan
156156
Write-Host ""
157157
Write-Host " Open Source Video Editing Automation" -ForegroundColor DarkGray
158-
Write-Host " Installer v1.9.21" -ForegroundColor DarkGray
158+
Write-Host " Installer v1.9.22" -ForegroundColor DarkGray
159159

160160
$isAdmin = Test-IsAdmin
161161
if ($isAdmin) {

OpenCut.iss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; Fully self-contained installer — bundles server exe, ffmpeg, and CEP extension
33

44
#define MyAppName "OpenCut"
5-
#define MyAppVersion "1.9.21"
5+
#define MyAppVersion "1.9.22"
66
#define MyAppPublisher "SysAdminDoc"
77
#define MyAppURL "https://github.com/SysAdminDoc/OpenCut"
88

extension/com.opencut.panel/CSXS/manifest.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
<ExtensionManifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
33
Version="7.0"
44
ExtensionBundleId="com.opencut.panel"
5-
ExtensionBundleVersion="1.9.21"
5+
ExtensionBundleVersion="1.9.22"
66
ExtensionBundleName="OpenCut">
77

88
<ExtensionList>
9-
<Extension Id="com.opencut.panel.main" Version="1.9.21" />
9+
<Extension Id="com.opencut.panel.main" Version="1.9.22" />
1010
</ExtensionList>
1111

1212
<ExecutionEnvironment>

extension/com.opencut.panel/client/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3524,7 +3524,7 @@ <h3 class="media-sidecar-title">No media in the workspace yet.</h3>
35243524
<div class="card-header"><div class="card-title" data-i18n="settings.about">About OpenCut</div></div>
35253525
<div class="settings-row">
35263526
<span class="settings-label">Version</span>
3527-
<span class="settings-value">1.9.21</span>
3527+
<span class="settings-value">1.9.22</span>
35283528
</div>
35293529
<div class="about-links">
35303530
<a href="https://github.com/SysAdminDoc/opencut" class="about-link" target="_blank">GitHub</a>

extension/com.opencut.panel/client/main.js

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* ============================================================
2-
OpenCut CEP Panel - Main Controller v1.9.21
2+
OpenCut CEP Panel - Main Controller v1.9.22
33
6-Tab Professional Toolkit
44
============================================================ */
55
(function () {
@@ -68,6 +68,29 @@
6868
if (_wsReconnectTimer) { clearTimeout(_wsReconnectTimer); _wsReconnectTimer = null; }
6969
}
7070

71+
// ---- Background poller restart hook ----
72+
//
73+
// cleanupTimers() nukes mediaScanTimer / _statusTimer on every disconnect.
74+
// Without this hook only the initial init path would restart them, so
75+
// after the first disconnect/reconnect cycle the media scan and system
76+
// status bar would stop polling forever. Called from checkHealth() on
77+
// every reconnect and from the DOMContentLoaded bootstrap.
78+
var MEDIA_POLL_MS = 20000; // 20 seconds
79+
function startBackgroundPollers() {
80+
if (!mediaScanTimer) {
81+
mediaScanTimer = setInterval(function () {
82+
if (!currentJob && (inPremiere || connected)) {
83+
scanProjectMedia();
84+
}
85+
}, MEDIA_POLL_MS);
86+
}
87+
// initStatusBar() is idempotent — it guards against duplicate timers
88+
// via its own _statusTimer check, so it is safe to call on reconnect.
89+
if (typeof initStatusBar === "function" && !_statusTimer) {
90+
initStatusBar();
91+
}
92+
}
93+
7194
// ---- Style Preview CSS Map (loaded from backend) ----
7295
var stylePreviewMap = {};
7396

@@ -1482,6 +1505,10 @@
14821505
el.backendPort.textContent = BACKEND.replace("http://127.0.0.1:", "Port ");
14831506
updateButtons();
14841507
loadCapabilities();
1508+
// Restart media scan + status bar pollers after a reconnect.
1509+
// cleanupTimers() killed them on the preceding disconnect and
1510+
// without this they would never come back until full reload.
1511+
startBackgroundPollers();
14851512
// Auto-connect WebSocket if available
14861513
if (!_wsConnected && capabilities.websocket !== false) {
14871514
wsConnect();
@@ -7705,7 +7732,8 @@
77057732
// ================================================================
77067733
// Status Bar — Health Monitoring (Phase 4.3)
77077734
// ================================================================
7708-
var _statusTimer = null;
7735+
// NOTE: _statusTimer is declared once at module scope (line ~49) so
7736+
// cleanupTimers() can clear it. Do NOT redeclare it here.
77097737
var _STATUS_POLL_MS = 5000;
77107738

77117739
var _statusBarRetries = 0;
@@ -7718,6 +7746,10 @@
77187746
}
77197747
return;
77207748
}
7749+
// Idempotent: skip if a poller is already running (re-entry from
7750+
// startBackgroundPollers() on reconnect, or from a second init call).
7751+
if (_statusTimer) return;
7752+
_statusBarRetries = 0;
77217753
pollSystemStatus();
77227754
_statusTimer = setInterval(pollSystemStatus, _STATUS_POLL_MS);
77237755
}
@@ -10695,13 +10727,10 @@
1069510727
populateRecentFiles();
1069610728

1069710729
// Periodic soft re-scan: picks up media imported outside OpenCut
10698-
// (e.g. user dragging files into Premiere, or Media Browser imports)
10699-
var MEDIA_POLL_MS = 20000; // 20 seconds
10700-
mediaScanTimer = setInterval(function () {
10701-
if (!currentJob && (inPremiere || connected)) {
10702-
scanProjectMedia();
10703-
}
10704-
}, MEDIA_POLL_MS);
10730+
// (e.g. user dragging files into Premiere, or Media Browser imports).
10731+
// Shared helper so the reconnect path can restart this after
10732+
// cleanupTimers() kills it on disconnect.
10733+
startBackgroundPollers();
1070510734

1070610735
// Re-scan when panel regains focus or becomes visible
1070710736
document.addEventListener("visibilitychange", function () {

extension/com.opencut.panel/client/style.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* ============================================================
2-
OpenCut CEP Panel v1.9.21 - ULTRA PREMIUM EDITION
2+
OpenCut CEP Panel v1.9.22 - ULTRA PREMIUM EDITION
33
Next-Generation AI Editing Suite for Adobe Premiere Pro
44
============================================================ */
55

extension/com.opencut.panel/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "opencut-panel",
3-
"version": "1.9.21",
3+
"version": "1.9.22",
44
"private": true,
55
"description": "OpenCut CEP Panel for Adobe Premiere Pro",
66
"scripts": {

extension/com.opencut.uxp/index.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<path d="M4 2.5a3 3 0 00-1.76 5.43L7.33 11l-5.09 3.07A3 3 0 104.8 19.5a3 3 0 001.76-5.43L8.93 12.6 16.5 17V5L8.93 9.4 6.56 7.93A3 3 0 004 2.5z" fill="var(--accent)"/>
1717
</svg>
1818
<span class="oc-logo">OpenCut</span>
19-
<span class="oc-version">v1.9.21</span>
19+
<span class="oc-version">v1.9.22</span>
2020
</div>
2121
<div class="oc-header-right">
2222
<div class="oc-connection" id="connectionStatus" title="Backend connection status">
@@ -44,7 +44,7 @@
4444

4545
<!-- ===== TAB NAVIGATION ===== -->
4646
<nav class="oc-tabs" role="tablist" aria-label="Feature tabs" id="tabNav">
47-
<button class="oc-tab active" data-tab="cut" role="tab" aria-selected="true" aria-controls="tab-cut">
47+
<button type="button" class="oc-tab active" data-tab="cut" role="tab" aria-selected="true" aria-controls="tab-cut" id="tabBtnCut">
4848
<svg width="13" height="13" viewBox="0 0 16 16" fill="currentColor"><path d="M4 1.5a2.5 2.5 0 00-1.47 4.53L6.47 8 2.53 9.97A2.5 2.5 0 104 14.5a2.5 2.5 0 001.47-4.53L7.44 8.99 13.5 12V4L7.44 7.01 5.47 5.97A2.5 2.5 0 004 1.5z"/></svg>
4949
<span>Cut</span>
5050
</button>
@@ -82,7 +82,7 @@
8282
<main class="oc-content" id="mainContent">
8383

8484
<!-- ==================== CUT & CLEAN TAB ==================== -->
85-
<div class="oc-tab-panel active" id="tab-cut" role="tabpanel" aria-labelledby="">
85+
<div class="oc-tab-panel active" id="tab-cut" role="tabpanel" aria-labelledby="tabBtnCut">
8686

8787
<div class="oc-section-title">Clip Input</div>
8888
<div class="oc-card">
@@ -550,7 +550,7 @@
550550
</select>
551551
</div>
552552
<button class="oc-btn oc-btn-primary oc-btn-full" id="runDepthBtnUxp">Apply Depth Effect</button>
553-
<div class="oc-hint" id="depthHintUxp" style="display:none;">Depth Anything V2 not installed. <button class="oc-btn oc-btn-sm" id="installDepthBtnUxp">Install</button></div>
553+
<div class="oc-hint oc-hidden" id="depthHintUxp">Depth Anything V2 not installed. <button type="button" class="oc-btn oc-btn-sm" id="installDepthBtnUxp">Install</button></div>
554554
</div>
555555
</div>
556556

@@ -585,7 +585,7 @@
585585
<svg class="oc-chevron" width="10" height="10" viewBox="0 0 16 16" fill="currentColor"><path d="M1.646 4.646a.5.5 0 01.708 0L8 10.293l5.646-5.647a.5.5 0 01.708.708l-6 6a.5.5 0 01-.708 0l-6-6a.5.5 0 010-.708z"/></svg>
586586
</div>
587587
<div class="oc-card-body" id="chatEditorBody">
588-
<div class="oc-chat-area" id="chatHistory" style="max-height:200px;overflow-y:auto;margin-bottom:8px;">
588+
<div class="oc-chat-area oc-chat-history" id="chatHistory">
589589
<p class="oc-hint">Chat with OpenCut's AI to edit your video using natural language.</p>
590590
</div>
591591
<div class="oc-field-row">
@@ -968,7 +968,7 @@
968968
</select>
969969
</div>
970970
<button class="oc-btn oc-btn-primary oc-btn-full" id="runNlpBtn">Execute Command</button>
971-
<div class="oc-result-area" id="nlpResultArea" style="display:none;">
971+
<div class="oc-result-area oc-hidden" id="nlpResultArea">
972972
<div class="oc-result-header">Parsed Action</div>
973973
<pre class="oc-code-block" id="nlpResultBody"></pre>
974974
<button class="oc-btn oc-btn-secondary oc-btn-sm" id="applyNlpBtn">Apply to Timeline</button>

extension/com.opencut.uxp/main.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const HEALTH_CHECK_MS = 8000;
2626
const HEALTH_MAX_MS = 60000;
2727
const MEDIA_SCAN_MS = 30000;
2828
const SSE_AVAILABLE = typeof EventSource !== "undefined";
29-
const VERSION = "1.9.21";
29+
const VERSION = "1.9.22";
3030

3131
async function detectBackend() {
3232
// Try ports 5679-5689 like CEP panel does
@@ -398,7 +398,7 @@ const BackendClient = (() => {
398398
};
399399
for (const [id, available] of Object.entries(hints)) {
400400
const el = document.getElementById(id);
401-
if (el) el.style.display = available ? "none" : "block";
401+
if (el) el.classList.toggle("oc-hidden", available);
402402
}
403403
}
404404

@@ -1571,7 +1571,7 @@ function showNlpResult(result) {
15711571
const area = document.getElementById("nlpResultArea");
15721572
const body = document.getElementById("nlpResultBody");
15731573
if (!area || !body) return;
1574-
area.style.display = "flex";
1574+
area.classList.remove("oc-hidden");
15751575
body.textContent = JSON.stringify(result.action ?? result, null, 2);
15761576
}
15771577

extension/com.opencut.uxp/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "com.opencut.uxp",
33
"name": "OpenCut UXP",
4-
"version": "1.9.21",
4+
"version": "1.9.22",
55
"main": "index.html",
66
"host": [
77
{

0 commit comments

Comments
 (0)