auth.resource:
- add Login Via HTTP keyword for RequestsLibrary auth (CSRF-aware)
- fix session_duration_minutes type: bare int → ${60}
- add Process library import to common.resource
03_blocklist_import.robot:
- fix selector to button[data-testid] (was matching all buttons)
- use GET/POST On Session with auth session for blocklist API calls
- fix log response key: entries → items
- fix enabled=true → ${TRUE} for boolean type
- fix ${len(sources)} → Get Length keyword
- make Ensure Blocklist Source Exists accept session argument
- replace strict error assertion with specific error banner check
- add graceful Terminate Process teardown
02_ban_records.robot:
- add Process library import
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
102 lines
4.2 KiB
Plaintext
102 lines
4.2 KiB
Plaintext
*** Keywords ***
|
|
Login Via HTTP
|
|
[Documentation] Login via HTTP and store session cookie for RequestsLibrary.
|
|
... Call this before any RequestsLibrary keyword that needs auth.
|
|
${headers}= Create Dictionary X-BanGUI-Request 1
|
|
Create Session bangsess ${BACKEND_URL} headers=${headers}
|
|
${login_payload}= Create Dictionary password Hallo123!
|
|
${login_resp}= POST On Session bangsess /api/v1/auth/login
|
|
... json=${login_payload}
|
|
... expected_status=200
|
|
Log HTTP login done. cookies=${login_resp.cookies}
|
|
RETURN bangsess
|
|
|
|
Login As Admin
|
|
[Documentation] Creates a new context and page and logs in via UI.
|
|
... Caller should NOT call New Context/New Page before this.
|
|
# Check setup status via HTTP API.
|
|
${response}= GET ${BACKEND_URL}/api/v1/setup
|
|
${body}= Set Variable ${response.json()}
|
|
Log Setup completed: ${body}[completed]
|
|
|
|
IF not ${body}[completed]
|
|
# Complete setup wizard via HTTP API.
|
|
${setup_payload}= Create Dictionary
|
|
... master_password=Hallo123!
|
|
... database_path=bangui.db
|
|
... fail2ban_socket=/var/run/fail2ban/fail2ban.sock
|
|
... timezone=UTC
|
|
... session_duration_minutes=${60}
|
|
POST ${BACKEND_URL}/api/v1/setup json=${setup_payload}
|
|
Log Setup POST completed.
|
|
END
|
|
|
|
# Create browser context.
|
|
New Context
|
|
New Page
|
|
Go To ${FRONTEND_URL}
|
|
Wait For Load State domcontentloaded
|
|
|
|
# Wait for React to fully initialize before login attempt
|
|
Sleep 5s
|
|
|
|
# Use fetch to call login API with browser credentials so the session cookie
|
|
# gets stored in the browser context. Use relative URL so Vite proxy handles it.
|
|
${login_result}= Evaluate JavaScript ${None}
|
|
... async () => {
|
|
... try {
|
|
... // Wait for React to fully initialize.
|
|
... await new Promise(r => setTimeout(r, 2000));
|
|
... const res = await fetch('/api/v1/auth/login', {
|
|
... method: 'POST',
|
|
... headers: { 'Content-Type': 'application/json' },
|
|
... body: JSON.stringify({ password: 'Hallo123!' }),
|
|
... credentials: 'include'
|
|
... });
|
|
... const data = await res.json().catch(() => ({}));
|
|
... return { ok: res.ok, status: res.status, data };
|
|
... } catch(e) {
|
|
... return { ok: false, error: String(e) };
|
|
... }
|
|
... }
|
|
Log API login result: ${login_result}
|
|
|
|
# Check if login actually succeeded before marking as authenticated
|
|
${login_ok}= Set Variable ${login_result}[ok]
|
|
IF not ${login_ok}
|
|
Fatal Error Login API failed: ${login_result}
|
|
END
|
|
|
|
# Set sessionStorage so AuthProvider considers us authenticated without waiting
|
|
# for API re-validation on the next navigation.
|
|
Evaluate JavaScript ${None} () => sessionStorage.setItem('bangui_authenticated', 'true')
|
|
|
|
# Navigate directly to the dashboard instead of Reload. Reload causes a race
|
|
# where useSessionValidation's API call may redirect to /login before main renders.
|
|
# Going to / forces the SPA router to resolve routes while sessionStorage is already set.
|
|
Go To ${FRONTEND_URL}/
|
|
Wait For Load State domcontentloaded
|
|
|
|
# Poll for main to appear. The SPA remounts on navigation so domcontentloaded fires
|
|
# before React has finished authenticating and rendering the protected route.
|
|
${login_ok}= Set Variable ${TRUE}
|
|
FOR ${i} IN RANGE 1 16
|
|
${url}= Get URL
|
|
IF '/login' in '${url}'
|
|
# Still on /login after navigation — login did not succeed.
|
|
${login_ok}= Set Variable ${FALSE}
|
|
EXIT FOR LOOP
|
|
END
|
|
${found}= Run Keyword And Return Status Wait For Elements State css=main visible timeout=2s
|
|
IF ${found}
|
|
BREAK
|
|
END
|
|
END
|
|
|
|
IF not ${login_ok}
|
|
${last_result}= Set Variable ${login_result}
|
|
Fatal Error Login failed: ${last_result}
|
|
END
|
|
|
|
${final_url}= Get URL
|
|
Log Login complete. URL: ${final_url} |