use axum::body::Body;
use axum::http::{Request, StatusCode};
use homecore::HomeCore;
use homecore_api::{router, LongLivedTokenStore, SharedState};
use tower::ServiceExt;
async fn provisioned_state(valid: &str) -> SharedState {
let store = LongLivedTokenStore::empty();
store.register(valid).await;
SharedState::with_tokens(HomeCore::new(), "Home", "test", store)
}
#[tokio::test]
async fn provisioned_bin_rejects_wrong_bearer() {
let app = router(provisioned_state("the_real_token").await);
let resp = app
.oneshot(
Request::builder()
.uri("/api/states")
.header("Authorization", "Bearer the_wrong_token")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(
resp.status(),
StatusCode::UNAUTHORIZED,
"a provisioned token store must reject a wrong bearer (HC-WS-08)"
);
}
#[tokio::test]
async fn provisioned_bin_accepts_correct_bearer() {
let app = router(provisioned_state("the_real_token").await);
let resp = app
.oneshot(
Request::builder()
.uri("/api/states")
.header("Authorization", "Bearer the_real_token")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
#[tokio::test]
async fn from_env_path_enforces_whitelist() {
std::env::set_var("HOMECORE_TOKENS", "env_token_1, env_token_2");
let store = LongLivedTokenStore::from_env();
std::env::remove_var("HOMECORE_TOKENS");
assert!(store.is_valid("env_token_1").await);
assert!(store.is_valid("env_token_2").await);
assert!(!store.is_valid("not_in_whitelist").await);
assert!(!store.is_dev_mode().await, "from_env must NOT be dev mode");
}
#[tokio::test]
async fn api_root_rejects_missing_bearer() {
let app = router(provisioned_state("the_real_token").await);
let resp = app
.oneshot(
Request::builder()
.uri("/api/")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(
resp.status(),
StatusCode::UNAUTHORIZED,
"GET /api/ with NO bearer must be 401 (HC-API-AUTH-01) — HA's \
APIStatusView requires_auth=True; a 200 here lets an \
unauthenticated party confirm a live endpoint and tells a \
token-validation probe a bad token is good"
);
}
#[tokio::test]
async fn api_root_rejects_wrong_bearer() {
let app = router(provisioned_state("the_real_token").await);
let resp = app
.oneshot(
Request::builder()
.uri("/api/")
.header("Authorization", "Bearer the_wrong_token")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(
resp.status(),
StatusCode::UNAUTHORIZED,
"GET /api/ with a WRONG bearer must be 401 (HC-API-AUTH-01)"
);
}
#[tokio::test]
async fn api_root_accepts_correct_bearer() {
let app = router(provisioned_state("the_real_token").await);
let resp = app
.oneshot(
Request::builder()
.uri("/api/")
.header("Authorization", "Bearer the_real_token")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(
resp.status(),
StatusCode::OK,
"GET /api/ with the correct bearer must still return 200 (API running.)"
);
}