use reqwest::blocking::Client;
use serde_json::Value;
use crate::config::{FirebaseProjectInfo, TestResult};
pub fn test_realtime_db(
client: &Client,
_key: &str,
project_id: Option<&str>,
info: &mut FirebaseProjectInfo,
) -> TestResult {
let pid = match project_id {
Some(p) => p,
None => {
return TestResult::fail(
None,
"No project ID available",
Some("Provide --project-id to test Realtime Database".into()),
)
}
};
let url = format!(
"https://{}-default-rtdb.firebaseio.com/.json?shallow=true",
pid
);
let resp = match client.get(&url).send() {
Ok(r) => r,
Err(e) => return TestResult::fail(None, e.to_string(), None),
};
let status = resp.status().as_u16();
match status {
200 => {
let data: Value = resp.json().unwrap_or_default();
info.realtime_db_public_read = Some(true);
if data.is_null() || (data.is_object() && data.as_object().unwrap().is_empty()) {
TestResult::ok(status, "Database publicly readable but empty")
} else {
let preview = {
let s = data.to_string();
if s.len() > 200 {
format!("{}...", &s[..200])
} else {
s
}
};
TestResult::ok(status, "[CRITICAL] Database is PUBLICLY READABLE!")
.with_extra("data_preview", preview)
}
}
401 => {
info.realtime_db_public_read = Some(false);
TestResult::fail(
Some(status),
"Permission denied",
Some("Database requires authentication (properly secured)".into()),
)
}
404 => TestResult::fail(
Some(status),
"Not found",
Some("Realtime Database not enabled or different URL".into()),
),
_ => {
let text = resp.text().unwrap_or_default();
let detail = if text.is_empty() {
None
} else {
Some(text.chars().take(100).collect())
};
TestResult::fail(Some(status), format!("HTTP {}", status), detail)
}
}
}
pub fn test_firebase_storage(
client: &Client,
_key: &str,
project_id: Option<&str>,
info: &mut FirebaseProjectInfo,
) -> TestResult {
let pid = match project_id {
Some(p) => p,
None => {
return TestResult::fail(
None,
"No project_id",
Some("Provide --project-id to test Storage".into()),
)
}
};
let bucket = format!("{}.appspot.com", pid);
info.storage_bucket = Some(bucket.clone());
let url = format!(
"https://firebasestorage.googleapis.com/v0/b/{}/o",
bucket
);
let resp = match client.get(&url).send() {
Ok(r) => r,
Err(e) => return TestResult::fail(None, e.to_string(), None),
};
let status = resp.status().as_u16();
match status {
200 => {
let data: Value = resp.json().unwrap_or_default();
let items = data
.get("items")
.and_then(|v| v.as_array())
.cloned()
.unwrap_or_default();
info.storage_public = Some(true);
let item_names: Vec<String> = items
.iter()
.take(10)
.filter_map(|i| i.get("name").and_then(|n| n.as_str()).map(String::from))
.collect();
let mut result = TestResult::ok(
status,
format!(
"[CRITICAL] Storage bucket PUBLICLY LISTABLE! ({} items)",
items.len()
),
);
if !item_names.is_empty() {
result = result.with_extra("items", item_names.join(", "));
}
result
}
403 => {
info.storage_public = Some(false);
TestResult::fail(
Some(status),
"Access denied",
Some("Storage bucket properly secured".into()),
)
}
_ => TestResult::fail(Some(status), format!("HTTP {}", status), None),
}
}