feat(05-10): OAuth fetch + Nextcloud edit fix + Edit on ERROR + text overflow
- client.js: add initiateOAuth() and getConnectionConfig() helpers
- SettingsCloudTab: replace window.location.href with initiateOAuth() + fetch/JWT
- SettingsCloudTab: add Edit button to ACTIVE and ERROR blocks for non-OAuth providers
- SettingsCloudTab: wrap ConfirmBlock in w-full overflow-hidden div
- CloudCredentialModal: add existing prop, edit-mode pre-population via /config endpoint
- CloudCredentialModal: add showAdvanced + customEndpoint for Nextcloud custom paths
- ConfirmBlock: add break-words class to message paragraph
- cloud.py: add GET /api/cloud/connections/{id}/config endpoint (non-secret fields)
This commit is contained in:
@@ -642,6 +642,57 @@ async def list_connections(
|
||||
return {"items": [CloudConnectionOut.model_validate(c).model_dump() for c in connections]}
|
||||
|
||||
|
||||
# ── GET /api/cloud/connections/{connection_id}/config ────────────────────────
|
||||
|
||||
|
||||
@router.get("/connections/{connection_id}/config")
|
||||
async def get_connection_config(
|
||||
connection_id: uuid.UUID,
|
||||
session: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_regular_user),
|
||||
) -> dict:
|
||||
"""Return non-secret configuration fields for a WebDAV/Nextcloud connection.
|
||||
|
||||
Returns server_url and connection_username (not password) so the frontend
|
||||
can pre-populate the Edit modal without exposing credentials.
|
||||
|
||||
Only applicable to WebDAV / Nextcloud connections (not OAuth providers).
|
||||
Returns 404 for wrong-owner or unknown connections (prevents ID enumeration).
|
||||
Returns 400 for OAuth providers (no non-secret config to return).
|
||||
|
||||
Security:
|
||||
- Only connection owned by current_user.id is returned (T-05-05-04)
|
||||
- password is never included in the response (D-18)
|
||||
- Returns 404 for wrong-owner connections (prevents ID enumeration)
|
||||
"""
|
||||
conn = await session.get(CloudConnection, connection_id)
|
||||
if conn is None or conn.user_id != current_user.id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Connection not found")
|
||||
|
||||
if conn.provider not in VALID_WEBDAV_PROVIDERS:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Connection config is only available for WebDAV/Nextcloud connections",
|
||||
)
|
||||
|
||||
master_key = settings.cloud_creds_key.encode()
|
||||
try:
|
||||
credentials = decrypt_credentials(master_key, str(current_user.id), conn.credentials_enc)
|
||||
except Exception:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="Failed to decrypt connection credentials",
|
||||
)
|
||||
|
||||
# Return non-secret fields only — never expose the password
|
||||
return {
|
||||
"id": str(conn.id),
|
||||
"provider": conn.provider,
|
||||
"server_url": credentials.get("server_url", ""),
|
||||
"connection_username": credentials.get("username", ""),
|
||||
}
|
||||
|
||||
|
||||
# ── DELETE /api/cloud/connections/{connection_id} ─────────────────────────────
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user