diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2025-11-08 16:28:10 -0500 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2025-11-08 16:28:10 -0500 |
| commit | fc6914831743f6d683c59adb367479defe6f8b3a (patch) | |
| tree | 5b997adac55f47b52f30022013b8ec3b2c10bcc5 /src/vapid/ser.rs | |
| parent | 0ef69c7d256380e660edc45ace7f1d6151226340 (diff) | |
| parent | 6bab5b4405c9adafb2ce76540595a62eea80acc0 (diff) | |
Integrate the prototype push notification support.
We're going to move forwards with this for now, as low-utility as it is, so that we can more easily iterate on it in a real-world environment (hi.grimoire.ca).
Diffstat (limited to 'src/vapid/ser.rs')
| -rw-r--r-- | src/vapid/ser.rs | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/src/vapid/ser.rs b/src/vapid/ser.rs new file mode 100644 index 0000000..02c77e1 --- /dev/null +++ b/src/vapid/ser.rs @@ -0,0 +1,63 @@ +pub mod key { + use std::fmt; + + use base64::{Engine as _, engine::general_purpose::URL_SAFE}; + use p256::ecdsa::VerifyingKey; + use serde::{Deserializer, Serialize as _, de}; + + // This serialization - to a URL-safe base-64-encoded string and back - is based on my best + // understanding of RFC 8292 and the corresponding browser APIs. Particularly, it's based on + // section 3.2: + // + // > The "k" parameter includes an ECDSA public key [FIPS186] in uncompressed form [X9.62] that + // > is encoded using base64url encoding [RFC7515]. + // + // <https://datatracker.ietf.org/doc/html/rfc8292#section-3.2> + // + // I believe this is also supported by MDN's explanation: + // + // > `applicationServerKey` + // > + // > A Base64-encoded string or ArrayBuffer containing an ECDSA P-256 public key that the push + // > server will use to authenticate your application server. If specified, all messages from + // > your application server must use the VAPID authentication scheme, and include a JWT signed + // > with the corresponding private key. This key IS NOT the same ECDH key that you use to + // > encrypt the data. For more information, see "Using VAPID with WebPush". + // + // <https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe#applicationserverkey> + + pub fn serialize<S>(key: &VerifyingKey, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + let key = key.to_sec1_bytes(); + let key = URL_SAFE.encode(key); + key.serialize(serializer) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result<VerifyingKey, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(Visitor) + } + + struct Visitor; + impl de::Visitor<'_> for Visitor { + type Value = VerifyingKey; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string containing a VAPID key") + } + + fn visit_str<E>(self, key: &str) -> Result<Self::Value, E> + where + E: de::Error, + { + let key = URL_SAFE.decode(key).map_err(E::custom)?; + let key = VerifyingKey::from_sec1_bytes(&key).map_err(E::custom)?; + + Ok(key) + } + } +} |
