refactor(web): secure Pico websocket access behind launcher auth

- stop exposing the raw Pico token to the frontend
- add /api/pico/info for non-secret Pico connection metadata
- proxy /pico/ws through the launcher with same-origin and dashboard auth checks
- inject the upstream Pico websocket protocol server-side
- update frontend chat connection flow and Vite websocket proxy path
- refresh related docs and tests
This commit is contained in:
wenjie
2026-04-16 16:47:23 +08:00
parent 6126ede963
commit 4b76196e2c
14 changed files with 253 additions and 171 deletions
+1 -11
View File
@@ -1,7 +1,6 @@
import { getDefaultStore } from "jotai"
import { toast } from "sonner"
import { getPicoToken } from "@/api/pico"
import {
loadSessionMessages,
mergeHistoryMessages,
@@ -131,7 +130,6 @@ export async function connectChat() {
updateChatStore({ connectionState: "connecting" })
try {
const { token } = await getPicoToken()
const sessionId = activeSessionIdRef
if (generation !== connectionGeneration) {
@@ -139,18 +137,10 @@ export async function connectChat() {
return
}
if (!token) {
console.error("No pico token available")
updateChatStore({ connectionState: "error" })
isConnecting = false
scheduleReconnect(generation, sessionId)
return
}
const wsScheme = window.location.protocol === "https:" ? "wss:" : "ws:"
const wsUrl = `${wsScheme}//${window.location.host}/pico/ws`
const url = `${wsUrl}?session_id=${encodeURIComponent(sessionId)}`
const socket = new WebSocket(url, [`token.${token}`])
const socket = new WebSocket(url)
if (generation !== connectionGeneration) {
isConnecting = false