feat(browser): unify site credentials with browser profiles (BR-2)

- Inject the site account Cookie (manual + auto-login session, session wins)
  into the camofox profile before the first tab opens; password accounts
  without a session run refresh-login first; API Key sites are skipped.
- Cookie expired after injection -> credential.status=expired; cookie
  accounts go to waiting/login_required ("log in once, applies site-wide").
- Write back site-domain cookies from the browser on handover, session close,
  every 10 min of activity, and from refresh-login when the stored cookie is
  invalid (verified before saving). user_info.cookieOrigin records
  source=browser; source shown as manual/login/browser in the origin view.
- New camofox plugin umt-cookies (GET/POST /umt/sessions/:userId/cookies
  under the access key); profile dir 0700/files 0600 in the desktop image.
- Single entry: sources-identity/service/credentials.ts.
- Real check: HHClub cookie injected into a fresh profile -> home page
  logged in (logout link present), 5 cookies read back.

Requires rebuilding umt-browser-desktop (docker compose build camofox &&
docker compose up -d camofox) to take effect.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-29 15:25:07 +08:00
1 parent 901b01d1a1
commit 28974d1e1a
58 files changed
+2843 -1112

No files matched your search

+8 -16
View File
@@ -1,6 +1,4 @@
import type { AgentRunStatus } from "@umt/contracts";
import { FlaskConical, ShieldCheck } from "lucide-react";
import { useState } from "react";
import { useNavigate } from "react-router";
import { toast } from "sonner";
import { agentMockEnabled, useCreateAgentRun } from "~/api/agent.ts";
@@ -11,7 +9,6 @@ import { Button } from "~/components/ui/button.tsx";
import { errorMessage } from "~/lib/api.ts";
export default function AgentPage() {
const [status, setStatus] = useState<"" | AgentRunStatus>("");
const create = useCreateAgentRun();
const navigate = useNavigate();
const mock = agentMockEnabled();
@@ -31,11 +28,11 @@ export default function AgentPage() {
</Button>
</div>
) : null}
<div className="grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,20rem)_minmax(0,1fr)]">
<div className="pg-slab order-2 rounded-xl p-3 lg:order-1 lg:max-h-[calc(100dvh-12rem)] lg:overflow-hidden">
<AgentSessionList status={status} onStatusChange={setStatus} className="h-full" />
<div className="grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,20rem)_minmax(0,1fr)] lg:items-start">
<div className="pg-slab order-2 rounded-xl p-3 lg:order-1 lg:h-[calc(100dvh-12rem)] lg:overflow-hidden">
<AgentSessionList hrefFor={(id) => `/console/agent/${id}${mock ? "?mock=1" : ""}`} className="h-full" />
</div>
<div className="order-1 space-y-4 lg:order-2">
<div className="order-1 mx-auto w-full max-w-[88ch] space-y-3 lg:order-2">
<div className="pg-slab rounded-xl p-4">
<h2 className="mb-3 text-body font-medium text-foreground">新会话</h2>
<GoalComposer
@@ -51,15 +48,10 @@ export default function AgentPage() {
}
/>
</div>
<div className="flex gap-3 rounded-xl border border-border/70 p-4 text-caption text-muted-foreground">
<ShieldCheck aria-hidden className="mt-0.5 size-4 shrink-0" />
<div className="space-y-1">
<p>
每次工具调用都经服务端授权校验。控制台发起的会话里,没有持续授权的下载、整理、策略发布会在对应步骤出审批卡。
</p>
<p>汇报分两栏:模型自述仅供参考,"系统核实的结果"取自下载计划、下载任务和整理记录。</p>
</div>
</div>
<p className="flex items-center gap-2 px-1 text-meta text-muted-foreground">
<ShieldCheck aria-hidden className="size-3.5 shrink-0" />
每次工具调用都经服务端授权校验,汇报以系统核实的结果为准。
</p>
</div>
</div>
</>