You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Align credential storage with the implemented threat model
The Rust app currently writes provider credentials to a local plaintext JSON file, while repository guidance and file headers still described a Keychain-backed vault. This records the product choice explicitly, documents the local-file security boundary, adds a settings-page notice, and limits raw credential read/write IPC to the main window instead of exposing it to auxiliary windows by default.
Constraint: Issue #230 asks to resolve the mismatch without leaving docs, implementation, and threat model contradictory.
Rejected: Reintroduce platform Keychain storage | larger cross-platform migration and dependency change outside the minimal fix.
Confidence: high
Scope-risk: narrow
Directive: Do not describe credentials as Keychain-backed unless the persistence implementation actually changes to a platform credential vault.
Tested: npm run -s build; cargo check --manifest-path src-tauri/Cargo.toml; git diff --check; grep for stale Keychain-first wording.
Not-tested: Manual Settings window credential editing in a packaged Tauri app.
Related: #230
-**Bundle ID `com.openless.app`** is hard-coded in `openless-all/app/src-tauri/tauri.conf.json` and `CredentialsVault.serviceName`. Changing it breaks Keychain lookups *and* every existing TCC grant.
94
+
-**Bundle ID `com.openless.app`** is hard-coded in `openless-all/app/src-tauri/tauri.conf.json`. Changing it breaks existing TCC grants.
95
95
-**TCC**: Microphone + Accessibility + AppleEvents. `NSMicrophoneUsageDescription` / `NSAccessibilityUsageDescription` / `NSAppleEventsUsageDescription` live in `openless-all/app/src-tauri/Info.plist`. After a fresh build that resets TCC, the app must be **fully quit and relaunched** after granting Accessibility before the global hotkey tap installs.
96
-
-**Credentials** live in Keychain under accounts in `CredentialAccount` (`volcengine.app_key`, `volcengine.access_key`, `volcengine.resource_id`, `ark.api_key`, `ark.model_id`, `ark.endpoint`). The plaintext fallback at`~/.openless/credentials.json` is read on first launch so legacy users keep their creds without re-entering. Never hard-code keys.
96
+
-**Credentials** live in a local plaintext JSON file, not Keychain / Credential Manager / Secret Service. macOS / Linux use`~/.openless/credentials.json`; Windows uses `%APPDATA%\OpenLess\credentials.json`. Unix builds set the directory to `0700` and the file to `0600`, which reduces cross-user exposure but does not protect against same-user processes, backups, sync tools, or diagnostics. Never hard-code keys or include this file in logs, exports, build artifacts, or bug reports.
97
97
-**Per-user data**:
98
98
- macOS: `~/Library/Application Support/OpenLess/{history.json, preferences.json, dictionary.json}` — capped at 200 history entries. **Do not rename `dictionary.json` to `vocab.json`** (drops user data).
-**Bundle ID `com.openless.app`** is hard-coded in `openless-all/app/src-tauri/tauri.conf.json` and `CredentialsVault.serviceName`. Changing it breaks Keychain lookups *and* every existing TCC grant.
94
+
-**Bundle ID `com.openless.app`** is hard-coded in `openless-all/app/src-tauri/tauri.conf.json`. Changing it breaks existing TCC grants.
95
95
-**TCC**: Microphone + Accessibility + AppleEvents. `NSMicrophoneUsageDescription` / `NSAccessibilityUsageDescription` / `NSAppleEventsUsageDescription` live in `openless-all/app/src-tauri/Info.plist`. After a fresh build that resets TCC, the app must be **fully quit and relaunched** after granting Accessibility before the global hotkey tap installs.
96
-
-**Credentials** live in Keychain under accounts in `CredentialAccount` (`volcengine.app_key`, `volcengine.access_key`, `volcengine.resource_id`, `ark.api_key`, `ark.model_id`, `ark.endpoint`). The plaintext fallback at`~/.openless/credentials.json` is read on first launch so legacy users keep their creds without re-entering. Never hard-code keys.
96
+
-**Credentials** live in a local plaintext JSON file, not Keychain / Credential Manager / Secret Service. macOS / Linux use`~/.openless/credentials.json`; Windows uses `%APPDATA%\OpenLess\credentials.json`. Unix builds set the directory to `0700` and the file to `0600`, which reduces cross-user exposure but does not protect against same-user processes, backups, sync tools, or diagnostics. Never hard-code keys or include this file in logs, exports, build artifacts, or bug reports.
97
97
-**Per-user data**:
98
98
- macOS: `~/Library/Application Support/OpenLess/{history.json, preferences.json, dictionary.json}` — capped at 200 history entries. **Do not rename `dictionary.json` to `vocab.json`** (drops user data).
Credentials live in the local Keychain (service = `com.openless.app`). A plaintext JSON file at `~/.openless/credentials.json` (mode 0600, dir 0700) is kept as a dev-mode fallback when Keychain is unavailable.
198
+
OpenLess stores provider credentials in a local plaintext JSON file, not in Keychain / Credential Manager / Secret Service:
199
199
200
-
The repository contains no API keys, tokens, or private endpoints.
200
+
```text
201
+
macOS / Linux: ~/.openless/credentials.json # file 0600, parent dir 0700 on Unix
202
+
Windows: %APPDATA%\OpenLess\credentials.json
203
+
```
204
+
205
+
Those permissions reduce cross-user reads, but same-user processes, backups, sync tools, and diagnostics can still access the file. Do not include it in logs, exports, build artifacts, or bug reports. The repository contains no API keys, tokens, or private endpoints.
llmProviderDesc: 'Selecting a preset auto-fills the default Base URL.',
294
+
credentialStorageNotice: 'Credentials are stored in a local plaintext JSON file. File permissions reduce cross-user access, but same-user processes and backups may still read it.',
294
295
asrProviderDesc: 'Switching providers automatically loads the matching credentials.',
295
296
asrTitle: 'ASR (transcription)',
296
297
asrDesc: 'Used to turn speech into text in real time.',
0 commit comments