security: remove dead session-restore, fix Rhai threat-model comment (ultra-fuzz)
try_restore_session guarded its whole body on session_info().is_some(), which
is always false at startup (the client is built with no session and nothing
ever calls restore_session), so it was dead code implying a session persistence
the app deliberately does not have — the auth JWT is memory-only, which is the
security-positive property to preserve. Delete the method and its call site,
documenting the intentional no-token-at-rest posture so the scaffolding can't
invite a future token-at-rest regression.
Also correct the Rhai wall-clock-limit comment: export/rename hooks run on the
GUI thread, so the 5 s cap bounds UI-freeze impact, not a background worker.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 files changed,
+16 insertions,
-16 deletions
| 250 |
250 |
|
let content_dir = data_dir.join("samples");
|
| 251 |
251 |
|
let manager = SyncManager::new(config, db_path, content_dir, runtime.clone());
|
| 252 |
252 |
|
manager.fetch_pricing();
|
| 253 |
|
- |
manager.try_restore_session();
|
|
253 |
+ |
// No session restore: the auth JWT is memory-only by design, so the user
|
|
254 |
+ |
// re-runs OAuth each launch (nothing is persisted to restore).
|
| 254 |
255 |
|
manager.start_scheduler();
|
| 255 |
256 |
|
Some(manager)
|
| 256 |
257 |
|
}
|
| 9 |
9 |
|
use crate::types::{self, RhaiExportContext, RhaiSampleInfo};
|
| 10 |
10 |
|
|
| 11 |
11 |
|
/// Wall-clock ceiling for a single script run. `set_max_operations` already
|
| 12 |
|
- |
/// bounds interpreter ops, but this also caps total elapsed time so a script
|
| 13 |
|
- |
/// that spends a long time across many operations can't hang the rename/import
|
| 14 |
|
- |
/// thread.
|
|
12 |
+ |
/// bounds interpreter ops; this also caps total elapsed time so a script that
|
|
13 |
+ |
/// spends a long time across many operations can't hang the thread that drives
|
|
14 |
+ |
/// the eval. Export/rename hooks currently run synchronously on the GUI thread,
|
|
15 |
+ |
/// so this limit is what bounds a runaway plugin's impact on UI responsiveness
|
|
16 |
+ |
/// (a worst case of ~5 s of frozen UI, not a frozen background worker).
|
| 15 |
17 |
|
const SCRIPT_WALL_CLOCK_LIMIT: Duration = Duration::from_secs(5);
|
| 16 |
18 |
|
|
| 17 |
19 |
|
thread_local! {
|
| 307 |
307 |
|
s.device_id = None;
|
| 308 |
308 |
|
}
|
| 309 |
309 |
|
|
| 310 |
|
- |
/// Try to restore a previous session from keychain on startup.
|
| 311 |
|
- |
#[instrument(skip_all)]
|
| 312 |
|
- |
pub fn try_restore_session(&self) {
|
| 313 |
|
- |
if self.client.session_info().is_some() {
|
| 314 |
|
- |
let has_key = self.client.try_load_key_from_keychain().unwrap_or(false);
|
| 315 |
|
- |
if has_key {
|
| 316 |
|
- |
let mut s = self.status.lock();
|
| 317 |
|
- |
s.state = SyncState::Ready;
|
| 318 |
|
- |
load_sync_settings_into_status(&self.db_path, &mut s);
|
| 319 |
|
- |
}
|
| 320 |
|
- |
}
|
| 321 |
|
- |
}
|
|
310 |
+ |
// Note: there is deliberately no startup session-restore. The auth JWT is
|
|
311 |
+ |
// held only in process memory and never persisted, so there is nothing to
|
|
312 |
+ |
// restore on launch — the user re-runs OAuth each session. This is a
|
|
313 |
+ |
// security choice (no auth token at rest to steal or log), not an
|
|
314 |
+ |
// oversight. A prior `try_restore_session` guarded its whole body on
|
|
315 |
+ |
// `session_info().is_some()`, which is always false at startup, so it was
|
|
316 |
+ |
// dead code that implied a persistence the app does not (and should not)
|
|
317 |
+ |
// have; it was removed. If persistent sessions are ever wanted, restore the
|
|
318 |
+ |
// token via the OS keychain only, never a file.
|
| 322 |
319 |
|
|
| 323 |
320 |
|
/// Fetch the pricing formula from the server (async, no JWT needed).
|
| 324 |
321 |
|
/// Stored on the status so UI code can quote a price for any cap locally.
|