fix: show human-readable login errors instead of raw HTML

When the server returns an HTML response (wrong URL, redirect to a
login page), the error dialog previously showed the full HTML body.
Now detect HTML responses and show a short actionable message:
- 404 with HTML: 'API endpoint not found. Check your server URL.'
- 401/403 with HTML: 'Wrong username or password.'
- 200 with HTML (no Auth= token): explain the endpoint is not FreshRSS
- Non-HTML bodies are shown as-is (they are already readable)
This commit is contained in:
Jeena 2026-03-20 12:21:01 +00:00
parent 5dee5cc52b
commit 141f9ee32d

View file

@ -73,13 +73,26 @@ impl Api {
let body = resp.text().await.map_err(|e| e.to_string())?; let body = resp.text().await.map_err(|e| e.to_string())?;
if !status.is_success() { if !status.is_success() {
return Err(format!("Login failed ({}): {}", status, body.trim())); let msg = human_error(&body, status.as_u16());
return Err(format!("Login failed ({}): {}", status.as_u16(), msg));
} }
let auth_token = body let auth_token = body
.lines() .lines()
.find_map(|l| l.strip_prefix("Auth=")) .find_map(|l| l.strip_prefix("Auth="))
.ok_or_else(|| "No Auth token in response".to_string())? .ok_or_else(|| {
// The server returned 200 but not the expected API response —
// most likely the URL points to a web page, not a FreshRSS API.
if looks_like_html(&body) {
format!(
"The server at {} does not appear to be a FreshRSS \
Google Reader API endpoint. Check your server URL.",
base
)
} else {
format!("Unexpected response from server: {}", body.trim())
}
})?
.to_string(); .to_string();
Ok(Self { Ok(Self {
@ -195,6 +208,28 @@ impl Api {
} }
} }
fn looks_like_html(body: &str) -> bool {
let trimmed = body.trim_start();
trimmed.starts_with("<!") || trimmed.to_ascii_lowercase().starts_with("<html")
}
fn human_error(body: &str, status: u16) -> String {
if looks_like_html(body) {
match status {
401 | 403 => "Wrong username or password.".to_string(),
404 => "API endpoint not found. Check your server URL.".to_string(),
_ => format!("Server returned HTTP {status}. Check your server URL."),
}
} else {
let trimmed = body.trim();
if trimmed.is_empty() {
format!("Server returned HTTP {status} with no message.")
} else {
trimmed.to_string()
}
}
}
fn plain_text_excerpt(html: &str, max_chars: usize) -> String { fn plain_text_excerpt(html: &str, max_chars: usize) -> String {
// Very simple HTML stripper — remove tags, collapse whitespace // Very simple HTML stripper — remove tags, collapse whitespace
let mut out = String::with_capacity(html.len()); let mut out = String::with_capacity(html.len());