refactor(quota): secure managed provider credentials (#2160)

- add shared owner-only credential storage for OpenCode Go, Ollama Cloud, and Cursor
- validate credentials before atomic writes using 0700 directories and 0600 files
- replace provider-specific credential routes with an allowlisted lifecycle API
- stop automatically reading Ollama's legacy cookie file
- stop reading or modifying Cursor's database during regular quota requests
- add explicit one-time Cursor credential import without mutating Cursor storage
- persist refreshed Cursor credentials only in OpenChamber-managed storage
- add Ollama Cloud and Cursor credential controls to provider settings
- preserve OpenCode Go tracking through the shared credential flow
- add VS Code credential management and Cursor quota parity
- reject authentication redirects, enforce request timeouts, and fail on unparseable usage pages
- mask stored secrets in API responses and extend quota security coverage
- update quota provider documentation
This commit is contained in:
Bohdan Triapitsyn
2026-07-12 16:21:38 +03:00
committed by GitHub
parent 3b92d97795
commit b09614fd68
20 changed files with 431 additions and 368 deletions
+4 -3
View File
@@ -1041,11 +1041,12 @@ const handleLocalApiRequest = async (input: RequestInfo | URL, url: URL, init: R
}
}
if (pathname === '/api/quota/credentials/opencode-go' || pathname === '/api/quota/credentials/opencode-go/validate') {
const quotaCredentialMatch = pathname.match(/^\/api\/quota\/credentials\/(opencode-go|ollama-cloud|cursor)(?:\/(validate|import))?$/);
if (quotaCredentialMatch) {
try {
const body = method === 'PUT' ? await extractJsonBody(input, init, method) : undefined;
const bridgeMethod = pathname.endsWith('/validate') ? 'VALIDATE' : method;
const data = await sendBridgeMessage('api:quota:opencode-go-credentials', { method: bridgeMethod, credential: body });
const bridgeMethod = quotaCredentialMatch[2]?.toUpperCase() || method;
const data = await sendBridgeMessage('api:quota:credentials', { providerId: quotaCredentialMatch[1], method: bridgeMethod, credential: body });
return new Response(JSON.stringify(data), { status: 200, headers: { 'Content-Type': 'application/json' } });
} catch (error) {
const message = error instanceof Error ? error.message : String(error);