- Add rbw integration to retrieve credentials from Bitwarden vault - Automate email/password entry with Selenium WebDriver - Handle 2FA by falling back to manual completion - Add clipboard support for Wayland (wl-copy) and X11 (xclip) - Add CLI flags: --entry, --no-copy, --manual - Add DESIGN.md documenting the implementation approach
135 lines
4.2 KiB
Markdown
135 lines
4.2 KiB
Markdown
# Design: Automated Google Login with rbw
|
|
|
|
## Overview
|
|
|
|
Automate the Google login flow for cookie extraction, using rbw (Bitwarden CLI) for credential lookup.
|
|
|
|
## Current State
|
|
|
|
- `selenium_cookie_extractor_json.py` opens Chrome incognito, navigates to chat.google.com
|
|
- User manually logs in, presses Enter
|
|
- Script extracts COMPASS, SSID, SID, OSID, HSID cookies and outputs JSON
|
|
|
|
## Proposed Changes
|
|
|
|
### 1. rbw Integration
|
|
|
|
```python
|
|
def check_rbw_unlocked() -> bool:
|
|
"""Check if rbw vault is unlocked."""
|
|
result = subprocess.run(['rbw', 'unlocked'], capture_output=True)
|
|
return result.returncode == 0
|
|
|
|
def prompt_rbw_unlock():
|
|
"""Prompt user to unlock rbw vault."""
|
|
print("rbw vault is locked. Please unlock it.")
|
|
subprocess.run(['rbw', 'unlock'], check=True)
|
|
|
|
def get_google_credentials(entry_name: str = "google.com") -> tuple[str, str]:
|
|
"""Get username and password from rbw."""
|
|
username = subprocess.run(
|
|
['rbw', 'get', '-f', 'username', entry_name],
|
|
capture_output=True, text=True, check=True
|
|
).stdout.strip()
|
|
|
|
password = subprocess.run(
|
|
['rbw', 'get', entry_name],
|
|
capture_output=True, text=True, check=True
|
|
).stdout.strip()
|
|
|
|
return username, password
|
|
```
|
|
|
|
### 2. Automated Login Flow
|
|
|
|
Google's login has multiple steps:
|
|
1. **Email page**: Enter email, click Next
|
|
2. **Password page**: Enter password, click Next
|
|
3. **Potential 2FA**: May require manual intervention
|
|
|
|
```python
|
|
def automate_login(driver, username: str, password: str):
|
|
"""Automate Google login flow."""
|
|
driver.get("https://accounts.google.com/signin")
|
|
|
|
# Enter email
|
|
email_input = WebDriverWait(driver, 10).until(
|
|
EC.presence_of_element_located((By.ID, "identifierId"))
|
|
)
|
|
email_input.send_keys(username)
|
|
email_input.send_keys(Keys.RETURN)
|
|
|
|
# Wait for password page and enter password
|
|
password_input = WebDriverWait(driver, 10).until(
|
|
EC.presence_of_element_located((By.NAME, "Passwd"))
|
|
)
|
|
password_input.send_keys(password)
|
|
password_input.send_keys(Keys.RETURN)
|
|
|
|
# Wait for successful login (presence of chat page or 2FA prompt)
|
|
# If 2FA required, prompt user to complete it manually
|
|
```
|
|
|
|
### 3. Clipboard Support
|
|
|
|
Add `wl-clipboard` and `xclip` to nix dependencies. Try Wayland first, fall back to X11:
|
|
|
|
```python
|
|
def copy_to_clipboard(text: str) -> bool:
|
|
"""Copy text to clipboard. Tries wl-copy (Wayland) first, falls back to xclip (X11)."""
|
|
try:
|
|
subprocess.run(['wl-copy'], input=text.encode(), check=True)
|
|
return True
|
|
except FileNotFoundError:
|
|
pass
|
|
# Fall back to xclip (X11)
|
|
process = subprocess.Popen(['xclip', '-selection', 'clipboard'], stdin=subprocess.PIPE)
|
|
process.communicate(text.encode())
|
|
return process.returncode == 0
|
|
```
|
|
|
|
### 4. CLI Interface
|
|
|
|
```
|
|
Usage: gcr [OPTIONS]
|
|
|
|
Options:
|
|
--copy, -c Copy cookie JSON to clipboard (default: true)
|
|
--entry NAME rbw entry name (default: "google.com")
|
|
--no-auto Skip auto-login, use manual flow
|
|
--help Show this message
|
|
```
|
|
|
|
## Implementation Steps
|
|
|
|
1. Add new dependencies to `flake.nix`: `xclip`
|
|
2. Add selenium wait helpers: `WebDriverWait`, `expected_conditions`
|
|
3. Implement rbw functions: check unlocked, prompt unlock, get credentials
|
|
4. Implement automated login: email step, password step, 2FA detection
|
|
5. Implement clipboard copy
|
|
6. Add CLI argument parsing with argparse
|
|
7. Update main flow to use automation by default
|
|
|
|
## Edge Cases
|
|
|
|
1. **rbw vault locked**: Prompt to unlock, fail gracefully if user cancels
|
|
2. **Wrong credentials in rbw**: Let login fail, user can retry manually
|
|
3. **2FA required**: Detect 2FA page, prompt user to complete manually, then continue
|
|
4. **Login timeout**: Add reasonable timeouts with clear error messages
|
|
5. **Multiple Google accounts**: Use `--entry` flag to specify which rbw entry
|
|
|
|
## Security Considerations
|
|
|
|
- Credentials are retrieved from rbw, never stored in script
|
|
- Incognito mode prevents cookie persistence
|
|
- Browser is closed promptly after extraction
|
|
|
|
## Testing Plan
|
|
|
|
1. Test with unlocked vault
|
|
2. Test with locked vault (unlock prompt)
|
|
3. Test with invalid rbw entry name
|
|
4. Test full login flow (requires real credentials)
|
|
5. Test 2FA flow (manual completion)
|
|
6. Test clipboard copy
|