proto(woo): per-browser Woo creds via X-Woo-* request headers
Prototype routing so 2–3 owners can share one store URL with different WP application passwords. Device creds live in localStorage; server uses request override → Settings fallback and never writes overrides into the Settings row. Inference stays on shared Settings. See PROTOTYPE.md for UAT with two browsers and known LAN forge risk.
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
# Prototype: per-user Woo credentials
|
||||
|
||||
Branch: `proto-per-user-woo-creds` (cut from `overnight-whole-app`).
|
||||
|
||||
## Goal
|
||||
|
||||
2–3 owners can share one SlabUploader install and one Woo store URL, each using
|
||||
their own WordPress user + application password. Inference URL/key stay global.
|
||||
No full auth, ACL, or publish mutex in this prototype.
|
||||
|
||||
## Credential scheme
|
||||
|
||||
| Layer | What |
|
||||
| --- | --- |
|
||||
| Browser | `localStorage` keys `slabuploader.woo.device.username` / `…appPassword` |
|
||||
| HTTP | Headers `X-Woo-Username` + `X-Woo-App-Password` on Woo-touching calls |
|
||||
| Server | `client_for_request(conn, headers)` → override if both headers non-blank, else Settings singleton |
|
||||
| Settings | Shop-default `woo_wp_username` / encrypted `woo_app_password` — **never** updated by the device-creds path |
|
||||
|
||||
Woo-touching calls that attach headers:
|
||||
|
||||
- `POST /api/v1/slabs/{id}/publish`
|
||||
- `POST /api/v1/admin/taxonomy/sync`
|
||||
- `POST /api/v1/settings/test-woo`
|
||||
|
||||
Inference / Call 2 / Settings PUT for inference keys are unchanged (shared Settings).
|
||||
|
||||
## Flow (request → WooClient)
|
||||
|
||||
1. Frontend reads device creds from localStorage (`wooDeviceCreds.ts`).
|
||||
2. `withWooHeaders()` merges `X-Woo-*` onto the fetch.
|
||||
3. Backend `client_for_request` builds a **new** `WooClient` for that request only
|
||||
(Basic auth from override plaintext, or decrypt Settings password).
|
||||
4. Publish / taxonomy / media use that client instance — no process-global
|
||||
“current user”.
|
||||
|
||||
## UAT with two browsers
|
||||
|
||||
1. Build/run this branch locally (do **not** deploy over partner UAT :10890; never :10880).
|
||||
2. In WordPress, create two application passwords for two WP users on the same store.
|
||||
3. Browser A (or profile A): Settings → **This device’s Woo credentials** → enter
|
||||
user A + app password → **Save on this device** → **Test WooCommerce connection**.
|
||||
4. Browser B: same for user B (separate localStorage).
|
||||
5. Confirm Test Woo succeeds for both, and that **Save Changes** on shop-default
|
||||
fields was not used to store the other user’s password.
|
||||
6. Publish different slabs from each browser (do not work the same slab concurrently).
|
||||
7. Optional: clear device creds and confirm fallback to shop-default Settings.
|
||||
|
||||
## Intentional fallback
|
||||
|
||||
- Missing or partial `X-Woo-*` headers → shop-default Settings credentials.
|
||||
- Device localStorage empty → same fallback.
|
||||
- Health probe (`woo_reachable`) always uses shop-default Settings (no request).
|
||||
|
||||
## Risks left (prototype)
|
||||
|
||||
- **LAN can forge headers** — there is no app login; any client on the network can
|
||||
send arbitrary `X-Woo-*` values. Treat as trusted LAN only.
|
||||
- Device passwords sit in **localStorage** (XSS-readable). Acceptable for this
|
||||
prototype only.
|
||||
- No slab ownership ACL / taxonomy mutex / publish CAS — operators must not edit
|
||||
the same slab at once.
|
||||
- Taxonomy cache remains shared; a sync from either user refreshes the same rows.
|
||||
Reference in New Issue
Block a user