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:
parent
e0bef82b06
commit
0035931734
22 changed files with 456 additions and 156 deletions
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
name: console-autofill
|
||||
description: AI-assisted autofill of App Store Connect and Google Play Console forms that have no API (the New App dialog, App Privacy, Play's Create app form, the Play IARC content rating questionnaire, Target audience and content plus the Ads declaration; the App Store age rating is shown as guidance because the API sets it) in a visible browser that reuses the owner's Chrome sign-in (or one they sign in to); storebound opens the form itself. Answers come only from storebound.config.ts; anything the config does not prove stays empty and highlighted. storebound moves through the pages itself (Next; App Privacy: Get Started, Edit, each data type and the draft Save; content rating: Save draft) and never signs in, submits or publishes: the owner presses the final button. Use when the user wants help filling one of these console forms, asks what to answer in them, or wants the answers as a checklist.
|
||||
description: AI-assisted autofill of App Store Connect and Google Play Console forms that have no API (the New App dialog, App Privacy, Play's Create app form, the Play IARC content rating questionnaire, Target audience and content plus the Ads declaration; the App Store age rating is shown as guidance because the API sets it) in a visible browser with storebound's own profile that the owner signs in to once (never a copy of the owner's Google cookies unless they opt in); storebound opens the form itself. Answers come only from storebound.config.ts; anything the config does not prove stays empty and highlighted. storebound moves through the pages itself (Next; App Privacy: Get Started, Edit, each data type and the draft Save; content rating: Save draft) and never signs in, submits or publishes: the owner presses the final button. Use when the user wants help filling one of these console forms, asks what to answer in them, or wants the answers as a checklist.
|
||||
---
|
||||
|
||||
# Console autofill (forms without an API)
|
||||
|
|
@ -11,8 +11,10 @@ CLI: `storebound` (or `bunx storebound` in a project that has it, or `bun <toolc
|
|||
answer in the wrong place. The owner reviews every field and presses the final button. storebound never types a
|
||||
password, never touches a sign-in page, never prints or sends a cookie, and never clicks Submit, Publish, Create, a
|
||||
final Save or anything that sends a form for review (English or Turkish console). It clicks only what moves through
|
||||
the form (see "What storebound clicks" below). It reuses the owner's
|
||||
Chrome sign-in through a temporary copy of only the console cookies (deleted at the end; `--fresh-profile` opts out).
|
||||
the form (see "What storebound clicks" below). It works in its own
|
||||
browser profile where the owner signs in once by hand. It never copies the owner's Google cookies unless the owner
|
||||
opts in (`--use-chrome-session google`), because Google binds them to the device and may sign the owner out of their
|
||||
real Chrome (step 3).
|
||||
It is not available over MCP.
|
||||
|
||||
## Forms
|
||||
|
|
@ -41,27 +43,44 @@ It is not available over MCP.
|
|||
```
|
||||
Age rating answers live in `apple.info.ageRating` (also `socialMedia`, `socialMediaAgeRestricted`).
|
||||
3. The owner runs `storebound console fill <form>` in a terminal (or presses the button in the desktop app). The
|
||||
first log line says which browser it uses, in this order:
|
||||
first log line says which browser it uses:
|
||||
- **profile** (the default): storebound's own profile (`~/.storebound/console-profile/<store>`, or `--profile <dir>`
|
||||
/ `STOREBOUND_CONSOLE_PROFILE`; one per store, not per account: every studio shares the one login). Nothing is
|
||||
read or copied from the owner's own Chrome. storebound starts Chrome itself as a normal window (its own
|
||||
`--user-data-dir`, a DevTools port on 127.0.0.1, no `--enable-automation`, `navigator.webdriver` false, Chrome's
|
||||
own user agent) and attaches to it. **First run:** the owner signs in there by hand, once (storebound never
|
||||
types passwords): Play: the Google account that owns the developer account, then "Stay signed in"; App Store
|
||||
Connect: Apple ID, password, two-factor code, "Keep me signed in" and "Trust" this browser. It is kept for the
|
||||
next runs. If Google shows "Couldn't sign you in" (`/signin/rejected`), storebound says "Google refused sign-in in
|
||||
this window"; try again, or open accounts.google.com in that window and sign in there first.
|
||||
- **attach**: Chrome already runs with remote debugging (a `DevToolsActivePort` file in Chrome's user data folder,
|
||||
or `--cdp http://127.0.0.1:<port>`): storebound opens one new tab there and closes only that tab.
|
||||
- **copy** (default on macOS with Google Chrome installed): the owner's existing Chrome sign-in, no second sign-in.
|
||||
storebound copies ONLY `Local State` and the profile's `Cookies` (+ `Cookies-journal`) into a temporary folder,
|
||||
deletes every cookie there except the ones App Store Connect and Play Console get (apple.com and google.com
|
||||
domains), and opens real Google Chrome on that copy. Never copied: passwords (`Login Data`), history, extensions,
|
||||
bookmarks or anything else. The temporary folder is deleted when the run ends (window closed, error, Ctrl+C, or
|
||||
Cancel in the desktop app). Chrome decrypts the cookies with its own Keychain key ("Chrome Safe Storage"); macOS
|
||||
may ask once to allow that. `--chrome-profile "Profile 1"` picks another Chrome profile (default: the last used).
|
||||
Cookies are never printed, logged or sent anywhere.
|
||||
- **profile** (`--fresh-profile`, `--profile <dir>`, `STOREBOUND_CONSOLE_PROFILE`, or when the other two do not
|
||||
work): storebound's own profile (`~/.storebound/console-profile/<store>`, one per store, not per account: every
|
||||
studio shares the one login). The owner signs in there once; it is kept for the next run.
|
||||
Keeping the sign-in: Apple's and Google's sign-in cookies are partly session cookies. storebound launches the copy
|
||||
and the own profile with `--restore-last-session` (so Chromium loads them again) and always closes the browser
|
||||
gracefully (window closed or Ctrl+C), so they are written to disk. Apple keeps a long sign-in only with "Keep me
|
||||
signed in" ticked and "Trust" chosen for the browser; Google with "Stay signed in"; storebound reminds the owner on
|
||||
the sign-in page. In copy mode the owner's Chrome Cookies file holds the session cookies only while that Chrome
|
||||
runs, or when Chrome's "On startup: Continue where you left off" is on; otherwise one sign-in in the window is
|
||||
needed.
|
||||
or `--cdp http://127.0.0.1:<port>`): storebound opens one new tab there and closes only that tab. That is the
|
||||
owner's own browser in place: no cookie leaves it.
|
||||
- **copy: opt-in only, NOT recommended for Google** (`--use-chrome-session google|apple`, macOS): a temporary copy
|
||||
of ONLY `Local State` and the profile's `Cookies` (+ journal), filtered to the ONE store's sign-in cookies
|
||||
(google: play.google.com / accounts.google.com; apple: apple.com hosts), opened in real Google Chrome and deleted
|
||||
when the run ends. Never copied: passwords, history, extensions, anything else. `--chrome-profile "Profile 1"`
|
||||
picks the Chrome profile. **Why opt-in:** Google binds its sign-in cookies to the device (Chrome's Device Bound
|
||||
Session Credentials: a key in the TPM / Secure Enclave that never leaves the machine; Google only renews the
|
||||
short-lived cookies for the browser that holds it; public on Windows from Chrome 146, rolling out on macOS from
|
||||
Chrome 147), and Google signs out sessions whose cookies look stolen: "the user is logged out of their account for
|
||||
that session and any related suspicious sessions on that device" and must verify again. A copy of the owner's
|
||||
Google cookies in a second Chrome is what that detection looks for: Google may answer `/signin/rejected`, AND it
|
||||
may sign the owner out of their real Chrome or flag the account. In real use (October 2026) a copied Google
|
||||
session reached Play Console once, then landed on `/v3/signin/rejected` and the account chooser. Apple publishes
|
||||
no device binding for its web sign-in (fastlane's `spaceauth` reuses Apple sessions on other machines; Apple ties
|
||||
them to a region), but it does not rule out a security check either, so the Apple copy is opt-in too. An agent
|
||||
never adds `--use-chrome-session` on its own; the owner chooses it after reading this.
|
||||
Sources: https://blog.google/security/protecting-cookies-with-device-bound-session-credentials/ ,
|
||||
https://developer.chrome.com/docs/web-platform/device-bound-session-credentials ,
|
||||
https://knowledge.workspace.google.com/admin/security/investigate-and-take-action-on-suspicious-session-cookies ,
|
||||
https://docs.fastlane.tools/getting-started/ios/authentication/
|
||||
`--fresh-profile` still works: it skips attach and copy.
|
||||
Keeping the sign-in: Apple's and Google's sign-in cookies are partly session cookies. storebound starts Chrome with
|
||||
`--restore-last-session` (so Chromium loads them again) and always closes it gracefully (CDP `Browser.close`,
|
||||
window closed or Ctrl+C), so they are written to disk. Apple keeps a long sign-in only with "Keep me signed in"
|
||||
ticked and "Trust" chosen for the browser; Google with "Stay signed in"; storebound reminds the owner on the
|
||||
sign-in page.
|
||||
Sign-in is detected by URL and by frame (App Store Connect `/login`, a frame from idmsa.apple.com /
|
||||
appleid.apple.com, accounts.google.com, Google `/signin`), by a visible password field in any frame, and by the
|
||||
form's own texts ("Sign in with Passkey", "Email or Phone Number", "Keep me signed in" and the Turkish ones):
|
||||
|
|
|
|||
|
|
@ -150,8 +150,8 @@ Each entry: **symptom** → cause → what to do → what guards it now. The ful
|
|||
while the owner is signed in; an older detector counted any frame on a sign-in host as a sign-in page.
|
||||
- **Do:** read the line "sign-in detected because: <rule> at <url>" and the heartbeats (they name the page). A
|
||||
top-level `accounts.google.com` / `idmsa.apple.com` / App Store Connect `/login` URL right after the launch means the
|
||||
copied Chrome session did not carry over (expired or tied to that device): sign in once in the window, or run with
|
||||
`--fresh-profile`. Anything else: re-run with `--debug-dump` (up to 3 dumps of the sign-in wait) and attach the
|
||||
copied Chrome session did not carry over (expired or tied to that device): sign in once in the window, or run
|
||||
without `--use-chrome-session` (pitfall 18). Anything else: re-run with `--debug-dump` (up to 3 dumps of the sign-in wait) and attach the
|
||||
folder after the owner looked at `screen.jpg`.
|
||||
- **Guard:** `signInReason` in `cli/console/fill.ts` (top-level URL, the main frame's password / email-entry form, a
|
||||
visible Apple sign-in frame; no other frame counts), the sign-in watchdog dump, `tests/console-fill.test.ts`.
|
||||
|
|
@ -167,6 +167,29 @@ Each entry: **symptom** → cause → what to do → what guards it now. The ful
|
|||
- **Guard:** `setUpAllowed` (`cli/lib/console-forms.ts`), `setUpClick` / `setUpType` (`cli/console/fill.ts`),
|
||||
`tests/console-flow.test.ts` with `tests/fixtures/console/apple-app-privacy-setup.html`.
|
||||
|
||||
## 18. Never copy Google session cookies: they are device-bound
|
||||
- **Symptom:** `console fill play-app-record` with the owner's copied Chrome cookies reached the Play account chooser
|
||||
once (22:32); between runs Google showed `accounts.google.com/v3/signin/rejected`; from 23:12 the same copy landed on
|
||||
the account chooser.
|
||||
- **Cause:** Google binds its session cookies to the device. Chrome's Device Bound Session Credentials keep a key in
|
||||
the TPM / Secure Enclave that cannot leave the machine; Google only renews the short-lived cookies for the browser
|
||||
that proves it holds that key (public on Windows from Chrome 146, rolling out on macOS from Chrome 147). Google also
|
||||
signs out sessions whose cookies look stolen ("logged out of their account for that session and any related
|
||||
suspicious sessions on that device", then an extra verification). Copied cookies in a second Chrome look exactly
|
||||
like cookie theft: the copy is refused, and the owner's REAL Chrome session can be signed out or the account asked
|
||||
to verify again.
|
||||
- **Do:** never copy Google cookies. The default is storebound's own profile (`~/.storebound/console-profile/<store>`):
|
||||
the owner signs in there once, by hand; it is kept. `--use-chrome-session google` exists only as an explicit owner
|
||||
opt-in that prints the warning; an agent never adds it. Apple publishes no such binding, but `--use-chrome-session
|
||||
apple` is opt-in too. If Google says "Couldn't sign you in" in storebound's window, storebound prints "Google refused
|
||||
sign-in in this window (/signin/rejected)": try again, or sign in at accounts.google.com first in that window.
|
||||
- **Guard:** `browserPlan` / `openConsoleBrowser` in `cli/console/session.ts` (no copy without the flag, the copy keeps
|
||||
only the form's own provider), Chrome started by storebound without `--enable-automation` and with
|
||||
`navigator.webdriver` false, `googleRejected`; `tests/console-session.test.ts`.
|
||||
- **Sources:** https://blog.google/security/protecting-cookies-with-device-bound-session-credentials/ ,
|
||||
https://developer.chrome.com/docs/web-platform/device-bound-session-credentials ,
|
||||
https://knowledge.workspace.google.com/admin/security/investigate-and-take-action-on-suspicious-session-cookies
|
||||
|
||||
## Adding a lesson
|
||||
Every bug found in real use gets an entry in `docs/pitfalls.md` and here, and, where possible, a check or a test
|
||||
that fails without the fix (see CONTRIBUTING.md).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue