Relay Extension + Python Receiver — Documentație Completă

EN Sistem de captură + dispatch real-time pentru Amazon Relay loadboard.
Data: 2026-05-25 · Componente: extensie Chrome MV3 + receiver Python (FastAPI + WebSocket)

📑 Cuprins

  1. Arhitectura generală
  2. Extensie Chrome MV3 — fișiere, flow capture/polling/book, popup
  3. Python Receiver — endpoints, env vars, safety
  4. Ce poate detecta Amazon — analiză honestă, comparație Rocket Relay
  5. Configurare end-to-end
  6. Pro / Contra de design
  7. Operațional — deploy, debug, monitoring
  8. Limitări cunoscute
  9. Glosar
  10. Backup-uri

1. Arhitectura generală

┌─────────────────────────────────────────────────────────────────┐ │ BROWSER │ │ │ │ Tab Amazon Relay (relay.amazon.com / mock relay-api.myvio.eu) │ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────┐ │ │ │ PAGE world │ │ ISOLATED world │ │ SERVICE │ │ │ │ │ │ │ │ WORKER │ │ │ │ injected.js │←→│ content_script │←→│ background │ │ │ │ (fetch/XHR │ │ (bridge IPC) │ │ .js (WS conn │ │ │ │ monkey-patch, │ │ │ │ + polling) │ │ │ │ UI inject, │ │ │ │ │ │ │ │ book click) │ │ │ │ │ │ │ └──────────────────┘ └──────────────────┘ └──────┬───────┘ │ └──────────────────────────────────────────────────────┼──────────┘ │ WebSocket ↓ ┌─────────────────────────────────────────────────────────────────┐ │ PYTHON RECEIVER (FastAPI) │ │ HOST: 192.168.0.31:9001 (typical) │ │ │ │ ws://...:9001/ws/stream │ │ ├─ EXT_CLIENTS (extensii care PUSH-uiesc capturile) │ │ └─ DISPATCHERS (pagini browser care RECV broadcasts) │ │ │ │ HTTP /admin/* (stats, insights, raw-ring, reports, ...) │ │ │ │ Memorie: │ │ POOL{} — tururi active (deduplicated) │ │ LAST_SEEN{} — TTL per tour (grace period cleanup) │ │ POLL_HISTORY — last 200 captures metadata │ │ LATENCIES — last 100 ext→recv ms │ │ LATENCIES_OUT — last 100 recv→UI ms (browser reports) │ │ RAW_RING — last N raw JSON bodies (configurable) │ │ reports_db (SQLite) — book history, snapshots, events │ └──────────────────────┬──────────────────────────────────────────┘ │ WS broadcast ↓ ┌─────────────────────────────────────┐ │ BOOKER-ADMIN UI (relay_tours, │ │ relay_ws_sources, mock_tuning) │ │ Conexiuni multiple dispatchers │ └─────────────────────────────────────┘

2. Extensie Chrome MV3

2.1 Structura fișierelor

FișierWorldRol
manifest.jsonDeclarații extensiei (perms, content_scripts, SW)
background.jsService WorkerWS connection persistent, polling scheduler, message router
content_script.jsISOLATEDBridge între page world și service worker (acces chrome.* API)
injected.jsPAGEMonkey-patch fetch/XHR, capture body+headers, UI inject, book click
popup.html + popup.jspopupSetări utilizator (rate, jitter, target host, pull mode, etc)
book_unlock.jsonfilesystemSafety gate: dacă lipsește/false → toate book-urile blocate
assets/audio/*.mp3Sunete pentru new/price/booked alerts

2.2 Flow capture (passive)

  1. Pagina Amazon JS face fetch('/api/loadboard/search', {...})
  2. injected.js window.fetch override prinde apelul:
    • Pre-cache: clone request → salvează body + headers (incluzând x-csrf-token)
    • Apoi await origFetch.apply(this, args) → cererea reală merge la Amazon
    • Măsoară fetch_ms = performance.now() - t0 (local, fără telemetrie)
    • Clone response → send()
  3. send() trimite window.postMessage({__relay_capture: true, body, ts, fetch_ms, ...}, "*")
  4. content_script.js ascultă window.message → forward la background via chrome.runtime.sendMessage
  5. background.js trimite payload prin WebSocket la receiver (sau cozează dacă WS offline)

2.3 Flow polling (active)

  1. background.js timer (rate configurabil din popup) trimite trigger_active_fetch la fiecare tab eligibil
  2. content_script.js forward via postMessage({__relay_active: true, pull_via_ui_click, ...})
  3. injected.js handler:
    • DEFAULT pull_via_ui_click=true (Rocket Relay style): găsește butonul Refresh prin #utility-bar .refresh-and-chat-box button + SVG path filter M20.128 2, apoi btn.click() SIMPLU (NU MouseEvent dispatchEvent) — React Amazon răspunde corect. NU există fallback la fetch direct.
    • pull_via_ui_click=false: doFetch direct la URL-ul cached
  4. Răspunsul revine via flow passive (mock/Amazon face fetch ca răspuns la click → capture obișnuit)

2.4 Flow book (DOM click style)

Toate cele 10 gates trebuie să treacă, altfel book-ul e blocat:

  1. book_unlock.json exists + enabled: true
  2. Popup toggle "Book ENABLED" = ON
  3. BOOK_HARDCODED_CONFIG.enabled = true (în code)
  4. Tour ID în lock (__relay_book_in_progress)
  5. Card există în DOM (verificat la click time)
  6. URL fetch verify (URL conține EXACT tour_id-ul din lock)
  7. dom_click_mode = true
  8. fetch_url_verify = true
  9. LEVEL 4 fetch global block: orice /api/loadboard/{tid}/{v}/option/{oid}/majorVersion/{mv} URL care nu trece gate-urile → fake response cu errorCode: work_opportunity_not_available (cod nativ Amazon, fără string custom suspect)
  10. LEVEL 4 XHR global block: idem pentru XMLHttpRequest

2.5 Configurare popup

SettingDefaultEffect
enabledtrueMaster toggle — OFF = nimic nu se trimite la receiver
active_modefalseON = polling automat la poll_rate
poll_rate2.0sInterval bază între polls
poll_jitter0± random pentru anti-bot rate signature
pull_via_ui_clicktrueClick pe butonul Refresh (telemetrie nativă) — NU există fallback fetch
poll_only_when_activefalsePolluiază doar tab activ + fereastra focusată
target_hostautoFiltru tab-uri (relay.amazon.es/de/it/fr/uk/com, relay-api.myvio.eu)
override_result_size0Force resultSize în body (0 = lasă natural)
auto_paginatetrueAggregate pages prin nextItemToken până la 20 pagini
alerts_enabledfalseMove-to-top + highlight CSS pe tururi noi
alerts_audio_ontrueSunete (new.mp3, price.mp3, successbook.mp3)
simulation_modefalseDry-run book: highlight 15s + sunet, NU click real
fast_book_button_enabledfalseInjectează buton "🚀 Fast Book" pe fiecare card
book_user_enabledfalseToggle în popup pentru book autorizat

3. Python Receiver

3.1 Structura fișierelor

FișierRol
receiver.pyApp FastAPI principală — WS + HTTP endpoints
config.pyEnv vars + .env loader (no external deps)
book_authorization.pyGate file pentru book live (lazy import)
book_unlock.jsonStatus unlock per receiver (separate de extension)
reports_db.pySQLite local pentru book history, snapshots, event log
captures/*.jsonOptional disk dump (dacă SAVE_RAW_ENABLED=true)

3.2 Endpoints HTTP

EndpointReturnsFolosit pentru
GET /HTML dashboardQuick view în browser
GET /admin/statstenant, target, pool_size, ws_clients, ext_clients, uptime, counters, memory (RSS, ring bytes)Stats overview
GET /admin/insightsrecent_polls (last 30), avg_latency_ms, avg_latency_out_ms, recent_latency_out_ms, polls_per_minute, consecutive_fails, fail_auto_stop_threshold, latest_poolUI charts
GET /admin/raw-ring/listMetadata pentru toate item-urile din ring (fara body-uri)Lista UI tab Raw
GET /admin/raw-ring/zip?limit=NZIP cu ultimele N JSON-uri + _manifest.jsonDownload bulk export
GET /admin/raw-ring/{idx}Body complet pt un itemPreview UI
GET /admin/last-responseUltimul response captatQuick inspection
GET /admin/reports/book-historyDB SQLite — istoricul book-urilor
GET /admin/reports/snapshotsDB SQLite — snapshots orare
GET /admin/reports/eventsDB SQLite — event log (info/warn/error)

3.3 Endpoints WebSocket

Path: WS /ws/stream — Multiplex: ext (push captures) sau dispatcher (recv broadcasts) după primul mesaj identify

Mesaje ext → receiver

Mesaje receiver → dispatcher

Mesaje dispatcher → receiver

3.4 Variabile de mediu (config.py)

Env VarDefaultEffect
RECEIVER_PORT9001Port HTTP+WS
RECEIVER_HOST0.0.0.0Bind addr
GRACE_PERIOD_S1.5Cât timp un tur nevăzut rămâne în POOL înainte de TTL cleanup
POOL_MAX_SIZE0LRU cap pe POOL (0 = nelimitat)
EXT_MAX_MSG_BYTES10MBLimită mesaj WS de la extensie
BOOK_UNLOCK_FILE./book_unlock.jsonPath la gate file
BOOK_AUDIT_ENABLEDtrueLog book attempts în SQLite
SAVE_RAW_ENABLEDfalseDisk dump capturi în ./captures/
SAVE_RAW_DIR./capturesFolder pentru dump
SAVE_RAW_MAX_FILES5000FIFO rotation
RAW_RING_SIZE50Ring buffer JSON-uri raw în RAM (1000 = ~140MB)
FAIL_AUTO_STOP_THRESHOLD0Auto-stop receiver după N fails consecutive (0 = OFF)

3.5 Safety: book_unlock.json

{
  "enabled": false,
  "token": "",
  "note": "Schimba enabled: true + reload pentru a permite book-uri"
}

Dacă fișierul lipsește SAU enabled !== true → toate book paths blocate (gate redundant cu cel din extension). Token-ul opțional e dovadă suplimentară.


4. Ce poate detecta Amazon — analiză honestă

4.1 Ce VEDE Amazon (telemetria lor)

DetectabilCumMitigare
Cererile HTTP la /api/loadboard/searchStandard logging server-sideInevitabil — userul oricum face cererea via UI. Rate matters: 0.5s × 5 tabs = ~10 req/sec validat empiric pe B_PLUS
Headers normale (cookie, csrf, UA)Server logPass-through, neschimbate de extensie
Click events native pe butoane (Reservar, Confirm, Refresh)Pendo, csa.ContentInteraction, optimusTRUSTED click events emitate de browser când userul/extensia face btn.click() — telemetria primește event-ul. Asta e BUN pentru noi: arată activitate de user normal.
window.fetch wrappedTeoretic detectabil prin fetch.toString()În practică, anti-bot prod nu face asta. Rocket Relay rulează ani de zile fără probleme.
Pagina rămâne deschisă mult timpTime-on-page metricsPolluare doar pe tab activ + focusat (poll_only_when_active) reduce signature

4.2 Ce NU VEDE Amazon

InvizibilDe ce
Mesajele postMessage interne (__relay_capture: true)Doar dacă au window.addEventListener('message', ...) cu filtrare exact pe flag — nu fac asta în prod
performance.now() măsurători localeFuncție stdlib, nu generează rețea
Body-ul captat de extensieRămâne pe device + WebSocket spre LAN-ul tău
WebSocket-ul către receiver (ws://192.168.0.31:9001/)LAN privat, neaccesibil din amazon.com origin
Modificările DOM (move-to-top, CSS classes adăugate)Doar dacă au MutationObserver activ — în prod nu observă tot DOM-ul
Click-uri programatice btn.click() vs trusted clicksNative event listeners se trigerează identic. Doar dacă React onClick verifică event.isTrusted (rar) ar fi diferit. Rocket Relay confirmă că btn.click() merge pe Amazon real.
Fast Book button injectatElement extra în DOM, dar fără chemări la API care să raporteze "extension detected"

4.3 Comparație cu Rocket Relay (audit reverse-engineering)

Audit-ul din /var/www/booker-admin/audit/kcnegnbacaohnhpmeckfakhlnahliklf/8.91_0/ confirmă:

Concluzie: profilul de risc al extensiei noastre = identic cu Rocket Relay. Singurul "tell" semnificativ ar fi RATE de polling agresiv (peste 2-3 req/sec sustained per account).

4.4 Bot signatures pe care le evităm


5. Configurare end-to-end

5.1 Setup extensie

  1. Load unpacked din chrome://extensions → "Load unpacked" → selectează folder chrome-extension
  2. book_unlock.json lângă manifest:
    {"enabled": true, "token": "ceva-secret"}
    Restartează extensia (chrome://extensions → 🔄) după modificare.
  3. Popup: setează Receiver URL = ws://192.168.0.31:9001/ws/stream
  4. Bifează Mod activ + Pull via UI click (default ON)
  5. Save

5.2 Setup receiver

cd python-receiver/app
python3 -m venv venv && source venv/bin/activate
pip install fastapi uvicorn  # + opțional: psutil

# .env (lângă receiver.py)
RECEIVER_PORT=9001
RAW_RING_SIZE=1000
FAIL_AUTO_STOP_THRESHOLD=20
GRACE_PERIOD_S=1.5

# book_unlock.json
{"enabled": true, "token": ""}

# Start
python3 receiver.py

Pe Windows:

5.3 Setup booker-admin UI

INSERT INTO relay_ws_sources (user_id, name, url, active)
VALUES (1, 'LocalReceiver', 'ws://192.168.0.31:9001/ws/stream', 1);

Apoi pe /relay_ws_sources → click pe stats icon → modal cu:


6. Pro / Contra de design

✅ Pro

AspectDetaliu
Decuplare PAGE/ISOLATED/SWRespectă strict modelul MV3, nu accesează chrome.* din PAGE world
Cross-tab orchestrationBackground SW are vedere globală — alegere tab pentru book bazat pe cine are turul în DOM
CSRF auto-captureCached din fetch real, niciodată hardcoded
Multi-host supporttarget_host: auto acoperă es/de/it/fr/uk/com + mock myvio.eu
Pull via UI click defaultTelemetrie naturală, indistinguibilă de user real
Safety chain 10-gates pentru bookDefense in depth — book_unlock.json + popup + hardcoded + DOM verify + URL verify + LEVEL 4 fetch/XHR block
Receiver = single source of truthMai mulți dispatcheri pot consuma simultan (UI, agent, etc)
Reports DBSQLite local pentru audit retroactiv (book history, snapshots, events)
Raw ring în RAM + ZIP exportDebug live fără disk overhead, descărcabil oricând
Auto-stop pe fails consecutiveCircuit breaker când Amazon ne blochează
Memory monitoring multi-platformLinux /proc, Windows ctypes, macOS resource — fără dependinte

⚠️ Contra / Compromisuri

AspectDe ce e un trade-offMitigare
MV3 service worker poate adormiChrome oprește SW după 30s idlechrome.alarms keepalive la 20s + rescheduleActiveFetch() la fiecare wake
Fetch wrapper detectabil prin fetch.toString()Anti-bot teoretic poate verificaÎn practică, nu se întâmplă (Rocket Relay confirmă)
Niciun fallback la fetch direct când pull_via_ui_click ONDacă click eșuează, refresh nu se faceFail loud — log în console, user vede imediat. Trade-off: zero risk de bot signature din fetch fără telemetrie
Receiver e single point of failureDacă cade → toți dispatcherii orbiQueue în background.js (200 mesaje) + reconnect cu backoff
RAW_RING e volatilPierdut la restartActivează SAVE_RAW_ENABLED pentru persistență disc + rotation FIFO
CSRF expiră la restart container mockVALID_SESSIONS în memorieF5 pagina pentru sesiune nouă; pentru prod persistență, ar trebui SQLite/Redis
Polling rate fix per receiverToți tabs partajează aceeași ratăNu suportăm rate per-tab momentan
Mixed content blockingBrowser HTTPS nu poate fetch HTTP receiverProxy PHP server-side (deja implementat în relay_ws_sources_api.php)
WebSocket scalingUn receiver = un proces PythonPentru multi-tenant scaling trebuie sticky session / sharding
No backpressureDacă receiver e overloaded, ext continuă să trimităAcceptabil pentru 1-5 ext clients; pentru 100+ ar trebui rate limiting

🔍 Comparativ cu alternative

StrategieProContra
Direct fetch din extensie (no UI click)Mai rapid (~50ms)Bot signature: no telemetry pe Pendo, lipsa csa.ContentInteraction events
Pull via UI click (CURRENT)Telemetrie naturală, indistinguibil de user~100-200ms overhead per refresh (extra round-trip prin React lifecycle)
Headless puppeteer externCross-browser, scriptableDetectabil prin navigator.webdriver, headless flag
MITM proxy (mitmproxy / Burp)Acces total request/responseManual configurat, nu portabil

7. Operațional

7.1 Deploy

Extension (Chrome dev mode)

  1. Modifică fișiere local
  2. chrome://extensions → 🔄 Reload la "Relay Tour Catcher"
  3. F5 pe tab-urile deschise (content scripts nu re-injectează la reload extensie!)

Receiver (Windows 192.168.0.31)

# Stop curent
# (taskkill /F /IM python.exe sau Ctrl+C în consolă)
# Copy fișiere noi
scp receiver.py user@192.168.0.31:/path/to/app/
# Restart
python receiver.py

Booker-admin UI

7.2 Debug

ProblemăVerificare
Extensia nu trimite la receiverService worker logs (chrome://extensions → Relay → "service worker")
Polling nu porneșteÎn popup: Mod activ ON? Save apăsat? pull_via_ui_click ON?
"Receiver process —"Deploy ultima versiune receiver.py (ctypes Windows fallback)
"stale" în healthLAST_POLL_AT se update-ează doar la status=200; verifică consecutive_fails
Mixed content errorsBrowser HTTPS nu poate http://192.168.0.31. Folosește PHP proxy (q=stats&id=X)
ZIP coruptVerifică PHP ob_end_clean() + headers Content-Encoding: identity
422 pe /admin/raw-ring/zipOrdine rute FastAPI — /zip trebuie ÎNAINTE de /{idx}

7.3 Monitoring


8. Limitări cunoscute

  1. Auto-paginate max 20 pagini — dacă userul cere resultSize=50 și sunt 2000 tururi, se opresc la 1000 (20 × 50)
  2. POLL_HISTORY in-memory — pierdut la restart receiver
  3. RAW_RING in-memory — idem
  4. Reports DB SQLite — single-writer; pentru concurrent receivers trebuie PostgreSQL
  5. Book click fallback unic — DOM click; fetch direct e disabled by design (riscant)
  6. CSRF generat dynamic la mock — token expiră la restart container

9. Glosar


10. Backup-uri

Toate modificările majore au backup în /var/www/booker-admin/backups/:

Pentru rollback complet: copy din backup în loc.


Document generat automat pe baza codului din /var/www/booker-admin/relay-extension/.
Vezi și varianta Markdown: DOCS.md