security: use bootstrap key in manifest, add .tmp cache cleanup
- manifest.webmanifest/+server.ts: swap PUBLIC_AE_API_SECRET_KEY → PUBLIC_AE_BOOTSTRAP_KEY (least privilege; endpoint only needs a site-domain lookup, same as the bootstrap use case) - electron_relay.ts: add cleanup_tmp_files() — runs `find ... -name "*.tmp" -mmin +N -delete` via native run_cmd bridge - launcher_background_sync.svelte: call cleanup_tmp_files() on mount when is_native && cache_root are present (once per startup) - AE__Permissions_and_Security.md: close Sev-1 audit language - TODO__Agents.md: mark PUBLIC_AE_API_SECRET_KEY audit as complete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -118,8 +118,10 @@ Returns `1` if `level_a` is higher, `-1` if lower, `0` if equal. Useful for thre
|
||||
- Never expose journal content publicly.
|
||||
|
||||
### `PUBLIC_AE_API_SECRET_KEY`
|
||||
- Ongoing Sev-1 audit. Do not introduce new usages.
|
||||
- Prefer per-request API key headers (`x-aether-api-key` + `x-account-id`).
|
||||
- Audit closed 2026-03-11. `PUBLIC_*` prefix is by design — key is always in the client bundle.
|
||||
- Anonymous site-domain lookup uses the limited-permission `PUBLIC_AE_BOOTSTRAP_KEY` instead.
|
||||
- Security model: API key is one layer; JWT + `x-account-id` scoping provides the primary auth.
|
||||
- Do not introduce new usages. Prefer `PUBLIC_AE_BOOTSTRAP_KEY` for unauthenticated lookups.
|
||||
|
||||
### Email Display
|
||||
Non-trusted users must never see a full email address. Obscure using:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
> **Status:** <20> Stable — ongoing development.
|
||||
|
||||
## 📋 Open: Security
|
||||
- [ ] **PUBLIC_AE_API_SECRET_KEY Audit:** Conduct full audit of usage. Determine if it can be moved to server-side only.
|
||||
- [x] **PUBLIC_AE_API_SECRET_KEY Audit:** Completed 2026-03-11. Key is `PUBLIC_*` by design (always in client bundle). Highest-risk anonymous path now uses limited-permission `PUBLIC_AE_BOOTSTRAP_KEY`. Full server-side migration would require a major API proxy refactor — not justified given JWT + account_id auth layers. `manifest.webmanifest/+server.ts` is a minor cleanup candidate (could use bootstrap key instead), but no security urgency. Current state is acceptable.
|
||||
|
||||
## 🚧 Upcoming High Priority
|
||||
|
||||
|
||||
@@ -54,6 +54,18 @@ export async function run_cmd_sync({ cmd, return_stdout = true }: { cmd: string,
|
||||
return await native.run_cmd_sync({ cmd, return_stdout });
|
||||
}
|
||||
|
||||
/**
|
||||
* Stale .tmp Cleanup
|
||||
* Deletes in-progress download artifacts (*.tmp) older than max_age_minutes from the cache root.
|
||||
* Called at launcher startup to prevent cache directory bloat from interrupted downloads.
|
||||
* Default: 1440 minutes = 24 hours.
|
||||
*/
|
||||
export async function cleanup_tmp_files({ cache_root, max_age_minutes = 1440 }: { cache_root: string, max_age_minutes?: number }) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
const cmd = `find "${cache_root}" -name "*.tmp" -mmin +${max_age_minutes} -type f -delete`;
|
||||
return await native.run_cmd({ cmd, timeout: 30000, return_stdout: false });
|
||||
}
|
||||
|
||||
export async function run_osascript(script: string) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
return await native.run_osascript(script);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
import * as native from '$lib/electron/electron_relay';
|
||||
const { cleanup_tmp_files } = native;
|
||||
|
||||
let { log_lvl = 1 } = $props();
|
||||
|
||||
@@ -106,6 +107,15 @@
|
||||
setTimeout(() => refresh_session_data(), 1000);
|
||||
setTimeout(() => refresh_presentation_data(), 3000);
|
||||
setTimeout(() => refresh_presenter_data(), 5000);
|
||||
|
||||
// Clean up stale .tmp files (interrupted downloads) older than 24h.
|
||||
// Run once at startup — sufficient for conference day usage.
|
||||
const cache_root = $ae_loc.local_file_cache_path;
|
||||
if ($ae_loc.is_native && cache_root) {
|
||||
cleanup_tmp_files({ cache_root }).then((result) => {
|
||||
if (log_lvl) console.log('Sync: .tmp cleanup complete.', result);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
|
||||
@@ -19,7 +19,8 @@ export const GET: RequestHandler = async ({ url, fetch }) => {
|
||||
const api_cfg = {
|
||||
base_url: api_base_url,
|
||||
headers: {
|
||||
'x-aether-api-key': public_env.PUBLIC_AE_API_SECRET_KEY,
|
||||
// Bootstrap key: limited-permission key for unauthenticated domain lookups (least privilege)
|
||||
'x-aether-api-key': public_env.PUBLIC_AE_BOOTSTRAP_KEY,
|
||||
'x-no-account-id': public_env.PUBLIC_AE_NO_ACCOUNT_ID
|
||||
},
|
||||
fetch
|
||||
|
||||
Reference in New Issue
Block a user