mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-12 20:57:42 +02:00
[eric] browser: borrow the user's existing browser sign-in at a login wall (opt-in)
This commit is contained in:
@@ -3,7 +3,9 @@ import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Button from '@mui/material/Button';
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import Switch from '@mui/material/Switch';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import type { AppSettings } from '@/shared/state/settingsSlice';
|
||||
import { useClaudeTokens } from '@/shared/styles/ThemeContext';
|
||||
import { API_BASE } from '@/shared/config';
|
||||
import type { SettingsStyles } from '../settingsStyles';
|
||||
@@ -11,7 +13,11 @@ import type { SettingsStyles } from '../settingsStyles';
|
||||
const ERASE_WORD = 'ERASE';
|
||||
|
||||
// The iOS Reset menu, two actions only: "Reset All Settings" (preferences back to defaults, your stuff + sign-in stay) and "Erase All Content and Settings" (factory wipe + relaunch). Flat rows, not a boxed "danger zone": red lives only on the destructive label, and the real friction is the typed-confirm in the dialog.
|
||||
const DataPrivacySection: React.FC<{ styles: SettingsStyles }> = ({ styles }) => {
|
||||
const DataPrivacySection: React.FC<{
|
||||
form: AppSettings;
|
||||
setForm: React.Dispatch<React.SetStateAction<AppSettings>>;
|
||||
styles: SettingsStyles;
|
||||
}> = ({ form, setForm, styles }) => {
|
||||
const c = useClaudeTokens();
|
||||
const { sectionSx, labelSx, descSx } = styles;
|
||||
|
||||
@@ -122,6 +128,21 @@ const DataPrivacySection: React.FC<{ styles: SettingsStyles }> = ({ styles }) =>
|
||||
<Button variant="outlined" size="small" onClick={() => { setErr(null); setResetOpen(true); }} sx={rowBtnSx}>Reset</Button>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ ...rowSx, borderBottom: `1px solid ${c.border.subtle}` }}>
|
||||
<Box sx={{ mr: 3 }}>
|
||||
<Typography sx={labelSx}>Use my sign-ins from my other browser</Typography>
|
||||
<Typography sx={descSx}>When an agent hits a site you're not signed into here, borrow the sign-in you already have in Chrome, Arc, Brave, or Edge instead of stopping to ask you. Reads only the site it's stuck on, and never asks for a password. Off by default.</Typography>
|
||||
</Box>
|
||||
<Switch
|
||||
checked={form.browser_import_signins}
|
||||
onChange={(e) => setForm({ ...form, browser_import_signins: e.target.checked })}
|
||||
sx={{
|
||||
'& .MuiSwitch-switchBase.Mui-checked': { color: c.accent.primary },
|
||||
'& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': { bgcolor: c.accent.primary },
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ ...rowSx, borderBottom: `1px solid ${c.border.subtle}` }}>
|
||||
<Box>
|
||||
<Typography sx={labelSx}>Clear browsing data</Typography>
|
||||
|
||||
@@ -43,7 +43,7 @@ const GeneralTab: React.FC<{
|
||||
|
||||
<GeneralAdvanced form={form} setForm={setForm} styles={styles} />
|
||||
|
||||
<DataPrivacySection styles={styles} />
|
||||
<DataPrivacySection form={form} setForm={setForm} styles={styles} />
|
||||
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -1867,6 +1867,22 @@ async function handleSessionCookies(params: Record<string, any>): Promise<Record
|
||||
}
|
||||
}
|
||||
|
||||
// Load the user's own existing sign-in for a site into the browser partition, so an agent stuck at
|
||||
// a login wall can carry on as them instead of interrupting to ask for a password. Like the cookie
|
||||
// bridge above this needs no webview: it writes straight to the main-process cookie store.
|
||||
async function handleImportSession(params: Record<string, any>): Promise<Record<string, any>> {
|
||||
const bridge = (window as any).openswarm?.setPartitionCookies as
|
||||
| ((domain: string, cookies: Record<string, any>[]) => Promise<{ ok: boolean; set: number; error?: string }>)
|
||||
| undefined;
|
||||
if (!bridge) return { ok: false, set: 0, error: 'Session import unavailable (desktop app only)' };
|
||||
const cookies = Array.isArray(params.cookies) ? params.cookies : [];
|
||||
try {
|
||||
return await bridge(String(params.domain || ''), cookies);
|
||||
} catch (err: any) {
|
||||
return { ok: false, set: 0, error: `Session import failed: ${err?.message || String(err)}` };
|
||||
}
|
||||
}
|
||||
|
||||
// Drive a session-borrow site's own already-open card: resolve the webview by its live domain
|
||||
// (no browser_id, like the cookie bridge), then run a small navigate/evaluate step sequence.
|
||||
// The shims use this for writes on sites that sign every HTTP request (TikTok).
|
||||
@@ -1905,6 +1921,11 @@ async function runBrowserCommand(
|
||||
dashboardWs.send('browser:result', { request_id, ...result });
|
||||
return;
|
||||
}
|
||||
if (action === 'import_session') {
|
||||
const result = await handleImportSession(params);
|
||||
dashboardWs.send('browser:result', { request_id, ...result });
|
||||
return;
|
||||
}
|
||||
const wv = await awaitWebview(browser_id, tab_id || undefined);
|
||||
if (!wv) {
|
||||
dashboardWs.send('browser:result', {
|
||||
|
||||
@@ -51,6 +51,7 @@ export interface AppSettings {
|
||||
openrouter_api_key?: string | null;
|
||||
custom_providers?: CustomProvider[];
|
||||
browser_homepage: string;
|
||||
browser_import_signins: boolean;
|
||||
auto_select_mode_on_new_agent: boolean;
|
||||
expand_new_chats_in_dashboard: boolean;
|
||||
auto_reveal_sub_agents: boolean;
|
||||
@@ -127,6 +128,7 @@ export const DEFAULT_SETTINGS: AppSettings = {
|
||||
new_agent_shortcut: 'Meta+l',
|
||||
anthropic_api_key: null,
|
||||
browser_homepage: 'https://duckduckgo.com',
|
||||
browser_import_signins: false,
|
||||
auto_select_mode_on_new_agent: false,
|
||||
expand_new_chats_in_dashboard: true,
|
||||
auto_reveal_sub_agents: true,
|
||||
|
||||
Reference in New Issue
Block a user