passport 0.4.0

Crate for signing and validating PASSporT (RFC8225) tokens
Documentation
use std::fmt::Debug;

use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey};
use serde::{Deserialize, Serialize};

use crate::{make_decoding_key, make_encoding_key};

/// Passport options for config files with keys parsed for `jsonwebtoken`
#[derive(Clone)]
pub struct JwtParsedKeyConfig {
	/// Signing algorithm to use
	pub algorithm: Algorithm,
	/// Optional offset for token expiry in seconds
	pub expires_in: Option<u32>,
	/// Key used for verification of passports
	pub public_key: DecodingKey,
	/// Key used for signing of passports
	pub private_key: EncodingKey,
	/// Unparsed key used for verification of passports
	pub unparsed_public_key: String,
	/// Unparsed key used for singing of passports
	pub unparsed_private_key: String,
}

impl Debug for JwtParsedKeyConfig {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		f.debug_struct("JwtParsedKeyConfig")
			.field("algorithm", &self.algorithm)
			.field("expires_in", &self.expires_in)
			.field("public_key", &"<hidden>")
			.field("private_key", &"<hidden>")
			.field("unparsed_public_key", &self.unparsed_public_key)
			.field("unparsed_private_key", &self.unparsed_private_key)
			.finish()
	}
}

impl<'de> Deserialize<'de> for JwtParsedKeyConfig {
	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
	where
		D: serde::Deserializer<'de>,
	{
		JwtKeyConfig::deserialize(deserializer)?
			.parse_keys()
			.map_err(|e| serde::de::Error::custom(e.to_string()))
	}
}

/// Passport options for config files
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct JwtKeyConfig {
	/// Signing algorithm to use
	pub algorithm: Algorithm,
	/// Optional offset for token expiry in seconds
	pub expires_in: Option<u32>,
	/// Key used for signature verification of passports
	pub public_key: String,
	/// Key used for signing of passports (and verification in symmetric
	/// cryptography)
	pub private_key: String,
}

impl JwtKeyConfig {
	/// Parses the keys for `jsonwebtoken` and returns a new
	/// `JwtParsedKeyConfig`
	pub fn parse_keys(&self) -> jsonwebtoken::errors::Result<JwtParsedKeyConfig> {
		Ok(JwtParsedKeyConfig {
			algorithm: self.algorithm,
			expires_in: self.expires_in,
			public_key: self.decoding_key()?,
			private_key: self.encoding_key()?,
			unparsed_public_key: self.public_key.clone(),
			unparsed_private_key: self.private_key.clone(),
		})
	}

	/// Parses the encoding key for `jsonwebtoken`
	pub fn encoding_key(&self) -> jsonwebtoken::errors::Result<EncodingKey> {
		make_encoding_key(self.private_key.as_bytes(), self.algorithm)
	}

	/// Parses the decoding key for `jsonwebtoken`
	pub fn decoding_key(&self) -> jsonwebtoken::errors::Result<DecodingKey> {
		make_decoding_key(self.public_key.as_bytes(), self.algorithm)
	}
}