fix(push): RFC 8620 §7.2 verification response + best-effort verify API call
Two issues preventing push verification from completing:
1. Response to Stalwart's verification request was 204 (empty body),
but RFC 8620 §7.2 requires a JSON body containing exactly
{"verificationCode": "..."}. Stalwart likely checks the body
and rejects empty responses → subscription stays unverified →
no event pushes ever sent.
2. verify_push_subscription (JMAP API PushSubscription/verify) was
hard-fail (503 on error). This non-standard method may not be
supported by Stalwart; a failure blocks verification entirely.
Made best-effort: warn on failure, continue storing the key.
Per RFC 8620, verification is done by the callback response,
not by a separate API call.
This commit is contained in:
parent
7331cb7d31
commit
f9160c0dbb
|
|
@ -1290,13 +1290,17 @@ async fn jmap_push(State(app): State<AppState>, body: Bytes) -> Response {
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if app
|
// RFC 8620 §7.2: verification is done by responding to the
|
||||||
|
// callback with the verificationCode. The JMAP API call is
|
||||||
|
// best-effort — some servers (including Stalwart) may not support
|
||||||
|
// PushSubscription/verify; failing it must not block verification.
|
||||||
|
if let Err(e) = app
|
||||||
.worker
|
.worker
|
||||||
.verify_push_subscription(subscription, code)
|
.verify_push_subscription(subscription, code)
|
||||||
.await
|
.await
|
||||||
.is_err()
|
|
||||||
{
|
{
|
||||||
return error_response(StatusCode::SERVICE_UNAVAILABLE, "push_verify_failed", true);
|
tracing::warn!(error = ?e, subscription = %subscription,
|
||||||
|
"push verify API call failed; continuing (RFC 8620 §7.2 verification is via callback response)");
|
||||||
}
|
}
|
||||||
if app
|
if app
|
||||||
.state
|
.state
|
||||||
|
|
@ -1332,6 +1336,14 @@ async fn jmap_push(State(app): State<AppState>, body: Bytes) -> Response {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if push.account_id.is_none() && push.email_id.is_none() {
|
if push.account_id.is_none() && push.email_id.is_none() {
|
||||||
|
// RFC 8620 §7.2: verification request response MUST be a JSON body
|
||||||
|
// containing exactly the verificationCode property (not 204).
|
||||||
|
if let Some(code) = push.verification_code.as_deref() {
|
||||||
|
return axum::Json(serde_json::json!({
|
||||||
|
"verificationCode": code
|
||||||
|
}))
|
||||||
|
.into_response();
|
||||||
|
}
|
||||||
return StatusCode::NO_CONTENT.into_response();
|
return StatusCode::NO_CONTENT.into_response();
|
||||||
}
|
}
|
||||||
let (Some(account), Some(email)) = (push.account_id, push.email_id) else {
|
let (Some(account), Some(email)) = (push.account_id, push.email_id) else {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue