console fill: never copy Google session cookies by default (device-bound); own profile in a Chrome started without automation switches

Google binds its session cookies to the device (Device Bound Session Credentials) and signs out
sessions whose cookies look stolen, which can sign the owner out of their real Chrome. The default is
now storebound's own profile per store; storebound starts Chrome itself (--user-data-dir,
--remote-debugging-port=0, no --enable-automation, navigator.webdriver false) and attaches over CDP.
--use-chrome-session google|apple is an explicit opt-in that warns. /signin/rejected is said plainly.
This commit is contained in:
CRTkafa 2026-10-12 07:46:04 +08:00
parent e0bef82b06
commit 0035931734
22 changed files with 456 additions and 156 deletions

View file

@ -261,7 +261,7 @@ pub fn dialog_labels(kind: Kind, title: &str) -> (String, String) {
/// the uncertain ones marked for the owner, and the note that the owner reviews and saves in the browser.
pub fn console_fill_dialog(project: &str, data: &Value) -> (String, String, String) {
let title = data["title"].as_str().unwrap_or("Console form");
let mut s = format!("{title} · {project}\n\nA browser window opens on the console page. It uses your Chrome sign-in: storebound copies only your Chrome cookies for App Store Connect and Play Console into a temporary profile and deletes it when the window closes (passwords, history and extensions are never copied; macOS may ask once for Keychain access). If you are not signed in, sign in there yourself. storebound opens the form, fills the fields below and marks the ones you answer.\n\n{}\n", policy::CONSOLE_FILL_NOTE);
let mut s = format!("{title} · {project}\n\nA browser window opens on the console page. It uses storebound's own browser profile: the first time, sign in there yourself (storebound never types passwords); the sign-in is kept for the next runs. Your own Chrome's cookies are never copied (Google ties them to your device and could sign you out). storebound opens the form, fills the fields below and marks the ones you answer.\n\n{}\n", policy::CONSOLE_FILL_NOTE);
let answers = data["answers"].as_array().cloned().unwrap_or_default();
let mut lines: Vec<String> = answers
.iter()

View file

@ -72,7 +72,7 @@ fn console_fill_is_a_dry_run_from_the_window_and_its_dialog_lists_the_answers()
assert_eq!(title, "Fill in console: Age rating");
assert_eq!(ok, "Open the browser");
assert!(text.contains("Prism Puddle") && text.contains(CONSOLE_FILL_NOTE));
assert!(text.contains("uses your Chrome sign-in") && text.contains("deletes it when the window closes"));
assert!(text.contains("uses storebound's own browser profile") && text.contains("cookies are never copied"));
assert!(text.contains("- Cartoon violence: None") && text.contains("- Simulated gambling: you answer this"));
let (_, empty, _) = console_fill_dialog("A", &json!(null));
assert!(empty.contains("every field is yours"));