Fix bundle lookup: normalize fingerprints, handle 404 gracefully
Server: normalize fingerprints by stripping colons and lowercasing before storing/looking up in sled. Adds tracing for register/lookup. Client: check HTTP status before parsing JSON response body. Shows clear error when user is not registered instead of parse error. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -59,7 +59,7 @@ impl ServerClient {
|
|||||||
|
|
||||||
/// Fetch a user's pre-key bundle from the server.
|
/// Fetch a user's pre-key bundle from the server.
|
||||||
pub async fn fetch_bundle(&self, fingerprint: &str) -> Result<PreKeyBundle> {
|
pub async fn fetch_bundle(&self, fingerprint: &str) -> Result<PreKeyBundle> {
|
||||||
let resp: BundleResponse = self
|
let response = self
|
||||||
.client
|
.client
|
||||||
.get(format!(
|
.get(format!(
|
||||||
"{}/v1/keys/{}",
|
"{}/v1/keys/{}",
|
||||||
@@ -67,7 +67,17 @@ impl ServerClient {
|
|||||||
))
|
))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.context("failed to fetch bundle")?
|
.context("failed to fetch bundle")?;
|
||||||
|
|
||||||
|
if !response.status().is_success() {
|
||||||
|
anyhow::bail!(
|
||||||
|
"server returned {} — user {} may not be registered",
|
||||||
|
response.status(),
|
||||||
|
fingerprint
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let resp: BundleResponse = response
|
||||||
.json()
|
.json()
|
||||||
.await
|
.await
|
||||||
.context("failed to parse bundle response")?;
|
.context("failed to parse bundle response")?;
|
||||||
|
|||||||
@@ -13,10 +13,18 @@ pub fn routes() -> Router<AppState> {
|
|||||||
.route("/keys/{fingerprint}", get(get_bundle))
|
.route("/keys/{fingerprint}", get(get_bundle))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Normalize fingerprint: strip colons, lowercase.
|
||||||
|
fn normalize_fp(fp: &str) -> String {
|
||||||
|
fp.chars()
|
||||||
|
.filter(|c| c.is_ascii_hexdigit())
|
||||||
|
.collect::<String>()
|
||||||
|
.to_lowercase()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct RegisterRequest {
|
struct RegisterRequest {
|
||||||
fingerprint: String,
|
fingerprint: String,
|
||||||
bundle: Vec<u8>, // bincode-serialized PreKeyBundle
|
bundle: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
@@ -28,7 +36,9 @@ async fn register_keys(
|
|||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Json(req): Json<RegisterRequest>,
|
Json(req): Json<RegisterRequest>,
|
||||||
) -> Json<RegisterResponse> {
|
) -> Json<RegisterResponse> {
|
||||||
let _ = state.db.keys.insert(req.fingerprint.as_bytes(), req.bundle);
|
let key = normalize_fp(&req.fingerprint);
|
||||||
|
tracing::info!("Registering bundle for {}", key);
|
||||||
|
let _ = state.db.keys.insert(key.as_bytes(), req.bundle);
|
||||||
Json(RegisterResponse { ok: true })
|
Json(RegisterResponse { ok: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,11 +46,16 @@ async fn get_bundle(
|
|||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path(fingerprint): Path<String>,
|
Path(fingerprint): Path<String>,
|
||||||
) -> Result<Json<serde_json::Value>, axum::http::StatusCode> {
|
) -> Result<Json<serde_json::Value>, axum::http::StatusCode> {
|
||||||
match state.db.keys.get(fingerprint.as_bytes()) {
|
let key = normalize_fp(&fingerprint);
|
||||||
|
tracing::info!("Looking up bundle for {}", key);
|
||||||
|
match state.db.keys.get(key.as_bytes()) {
|
||||||
Ok(Some(data)) => Ok(Json(serde_json::json!({
|
Ok(Some(data)) => Ok(Json(serde_json::json!({
|
||||||
"fingerprint": fingerprint,
|
"fingerprint": fingerprint,
|
||||||
"bundle": base64::Engine::encode(&base64::engine::general_purpose::STANDARD, &data),
|
"bundle": base64::Engine::encode(&base64::engine::general_purpose::STANDARD, &data),
|
||||||
}))),
|
}))),
|
||||||
_ => Err(axum::http::StatusCode::NOT_FOUND),
|
_ => {
|
||||||
|
tracing::warn!("Bundle not found for {}", key);
|
||||||
|
Err(axum::http::StatusCode::NOT_FOUND)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user