Normalize fingerprints everywhere: strip colons from URLs and DB keys
Client: strip colons before putting fingerprints in URL paths (colons in URLs confuse axum path matching). Server: normalize fingerprints in message routes too. All fingerprint storage and lookup is now hex-only, case-insensitive. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -59,11 +59,12 @@ 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 fp_clean: String = fingerprint.chars().filter(|c| c.is_ascii_hexdigit()).collect();
|
||||||
let response = self
|
let response = self
|
||||||
.client
|
.client
|
||||||
.get(format!(
|
.get(format!(
|
||||||
"{}/v1/keys/{}",
|
"{}/v1/keys/{}",
|
||||||
self.base_url, fingerprint
|
self.base_url, fp_clean
|
||||||
))
|
))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
@@ -93,10 +94,11 @@ impl ServerClient {
|
|||||||
|
|
||||||
/// Send an encrypted message to the server for delivery.
|
/// Send an encrypted message to the server for delivery.
|
||||||
pub async fn send_message(&self, to: &str, message: &[u8]) -> Result<()> {
|
pub async fn send_message(&self, to: &str, message: &[u8]) -> Result<()> {
|
||||||
|
let to_clean: String = to.chars().filter(|c| c.is_ascii_hexdigit()).collect();
|
||||||
self.client
|
self.client
|
||||||
.post(format!("{}/v1/messages/send", self.base_url))
|
.post(format!("{}/v1/messages/send", self.base_url))
|
||||||
.json(&SendRequest {
|
.json(&SendRequest {
|
||||||
to: to.to_string(),
|
to: to_clean,
|
||||||
message: message.to_vec(),
|
message: message.to_vec(),
|
||||||
})
|
})
|
||||||
.send()
|
.send()
|
||||||
@@ -107,11 +109,12 @@ impl ServerClient {
|
|||||||
|
|
||||||
/// Poll for messages addressed to us.
|
/// Poll for messages addressed to us.
|
||||||
pub async fn poll_messages(&self, fingerprint: &str) -> Result<Vec<Vec<u8>>> {
|
pub async fn poll_messages(&self, fingerprint: &str) -> Result<Vec<Vec<u8>>> {
|
||||||
|
let fp_clean: String = fingerprint.chars().filter(|c| c.is_ascii_hexdigit()).collect();
|
||||||
let resp: Vec<String> = self
|
let resp: Vec<String> = self
|
||||||
.client
|
.client
|
||||||
.get(format!(
|
.get(format!(
|
||||||
"{}/v1/messages/poll/{}",
|
"{}/v1/messages/poll/{}",
|
||||||
self.base_url, fingerprint
|
self.base_url, fp_clean
|
||||||
))
|
))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -21,11 +21,15 @@ struct SendRequest {
|
|||||||
message: Vec<u8>,
|
message: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn normalize_fp(fp: &str) -> String {
|
||||||
|
fp.chars().filter(|c| c.is_ascii_hexdigit()).collect::<String>().to_lowercase()
|
||||||
|
}
|
||||||
|
|
||||||
async fn send_message(
|
async fn send_message(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Json(req): Json<SendRequest>,
|
Json(req): Json<SendRequest>,
|
||||||
) -> AppResult<Json<serde_json::Value>> {
|
) -> AppResult<Json<serde_json::Value>> {
|
||||||
let key = format!("queue:{}", req.to);
|
let key = format!("queue:{}", normalize_fp(&req.to));
|
||||||
state.db.messages.insert(
|
state.db.messages.insert(
|
||||||
format!("{}:{}", key, uuid::Uuid::new_v4()).as_bytes(),
|
format!("{}:{}", key, uuid::Uuid::new_v4()).as_bytes(),
|
||||||
req.message,
|
req.message,
|
||||||
@@ -37,7 +41,7 @@ async fn poll_messages(
|
|||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path(fingerprint): Path<String>,
|
Path(fingerprint): Path<String>,
|
||||||
) -> AppResult<Json<Vec<String>>> {
|
) -> AppResult<Json<Vec<String>>> {
|
||||||
let prefix = format!("queue:{}", fingerprint);
|
let prefix = format!("queue:{}", normalize_fp(&fingerprint));
|
||||||
let mut messages = Vec::new();
|
let mut messages = Vec::new();
|
||||||
for item in state.db.messages.scan_prefix(prefix.as_bytes()) {
|
for item in state.db.messages.scan_prefix(prefix.as_bytes()) {
|
||||||
let (_, value) = item?;
|
let (_, value) = item?;
|
||||||
|
|||||||
Reference in New Issue
Block a user