1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-31 09:24:31 +03:00

Multiple IANA codegen enhancement

- JWS/JWE algorithms are properly splitted
 - Enums now have a proper description
 - They implement FromStr and Display
 - mas-jose does not reexport mas-iana anymore
This commit is contained in:
Quentin Gliech
2022-01-12 10:58:27 +01:00
parent d9b1ef3ded
commit 2844706bb1
21 changed files with 401 additions and 497 deletions

View File

@ -14,7 +14,10 @@
use serde::Deserialize;
use crate::EnumEntry;
use crate::{
traits::{s, Section},
EnumEntry,
};
#[derive(Debug, Deserialize, PartialEq, Eq)]
enum Usage {
@ -60,13 +63,41 @@ pub struct WebEncryptionSignatureAlgorithm {
impl EnumEntry for WebEncryptionSignatureAlgorithm {
const URL: &'static str =
"https://www.iana.org/assignments/jose/web-signature-encryption-algorithms.csv";
const SECTIONS: &'static [&'static str] =
&["JsonWebSignatureAlgorithm", "JsonWebEncryptionAlgorithm"];
const SECTIONS: &'static [Section] = &[
s(
"JsonWebSignatureAlg",
r#"JSON Web Signature "alg" parameter"#,
),
s(
"JsonWebEncryptionAlg",
r#"JSON Web Encryption "alg" parameter"#,
),
s(
"JsonWebEncryptionEnc",
r#"JSON Web Encryption "enc" parameter"#,
),
];
fn key(&self) -> Option<&'static str> {
match self.usage {
Usage::Alg => Some("JsonWebSignatureAlgorithm"),
Usage::Enc => Some("JsonWebEncryptionAlgorithm"),
Usage::Alg => {
// RFC7518 has one for signature algs and one for encryption algs. The other two
// RFCs are additional Elliptic curve signature algs
if self.reference.contains("RFC7518, Section 3")
|| self.reference.contains("RFC8037")
|| self.reference.contains("RFC8812")
{
Some("JsonWebSignatureAlg")
} else if self.reference.contains("RFC7518, Section 4")
|| self.reference.contains("WebCryptoAPI")
{
Some("JsonWebEncryptionAlg")
} else {
tracing::warn!("Unknown reference {} for JWA", self.reference);
None
}
}
Usage::Enc => Some("JsonWebEncryptionEnc"),
_ => None,
}
}
@ -96,7 +127,10 @@ pub struct WebEncryptionCompressionAlgorithm {
impl EnumEntry for WebEncryptionCompressionAlgorithm {
const URL: &'static str =
"https://www.iana.org/assignments/jose/web-encryption-compression-algorithms.csv";
const SECTIONS: &'static [&'static str] = &["JsonWebEncryptionCompressionAlgorithm"];
const SECTIONS: &'static [Section] = &[s(
"JsonWebEncryptionCompressionAlgorithm",
"JSON Web Encryption Compression Algorithm",
)];
fn key(&self) -> Option<&'static str> {
Some("JsonWebEncryptionCompressionAlgorithm")
@ -128,7 +162,7 @@ pub struct WebKeyType {
impl EnumEntry for WebKeyType {
const URL: &'static str = "https://www.iana.org/assignments/jose/web-key-types.csv";
const SECTIONS: &'static [&'static str] = &["JsonWebKeyType"];
const SECTIONS: &'static [Section] = &[s("JsonWebKeyType", "JSON Web Key Type")];
fn key(&self) -> Option<&'static str> {
Some("JsonWebKeyType")
@ -160,8 +194,16 @@ pub struct WebKeyEllipticCurve {
impl EnumEntry for WebKeyEllipticCurve {
const URL: &'static str = "https://www.iana.org/assignments/jose/web-key-elliptic-curve.csv";
const SECTIONS: &'static [&'static str] =
&["JsonWebKeyEcEllipticCurve", "JsonWebKeyOkpEllipticCurve"];
const SECTIONS: &'static [Section] = &[
s(
"JsonWebKeyEcEllipticCurve",
"JSON Web Key EC Elliptic Curve",
),
s(
"JsonWebKeyOkpEllipticCurve",
"JSON Web Key OKP Elliptic Curve",
),
];
fn key(&self) -> Option<&'static str> {
if self.name.starts_with("P-") || self.name == "secp256k1" {
@ -195,7 +237,7 @@ pub struct WebKeyUse {
impl EnumEntry for WebKeyUse {
const URL: &'static str = "https://www.iana.org/assignments/jose/web-key-use.csv";
const SECTIONS: &'static [&'static str] = &["JsonWebKeyUse"];
const SECTIONS: &'static [Section] = &[s("JsonWebKeyUse", "JSON Web Key Use")];
fn key(&self) -> Option<&'static str> {
Some("JsonWebKeyUse")
@ -225,7 +267,7 @@ pub struct WebKeyOperation {
impl EnumEntry for WebKeyOperation {
const URL: &'static str = "https://www.iana.org/assignments/jose/web-key-operations.csv";
const SECTIONS: &'static [&'static str] = &["JsonWebKeyOperation"];
const SECTIONS: &'static [Section] = &[s("JsonWebKeyOperation", "JSON Web Key Operation")];
fn key(&self) -> Option<&'static str> {
Some("JsonWebKeyOperation")

View File

@ -27,8 +27,7 @@ struct File {
client: Arc<Client>,
registry_name: &'static str,
registry_url: &'static str,
sections: Vec<&'static str>,
sources: Vec<&'static str>,
sections: Vec<Section>,
items: HashMap<&'static str, Vec<EnumMember>>,
}
@ -46,7 +45,6 @@ impl File {
client,
registry_name,
registry_url,
sources: Vec::new(),
sections: Vec::new(),
items: HashMap::new(),
}
@ -55,8 +53,7 @@ impl File {
#[tracing::instrument(skip_all, fields(url))]
async fn load<T: EnumEntry>(mut self) -> anyhow::Result<Self> {
tracing::Span::current().record("url", &T::URL);
self.sections.extend_from_slice(T::SECTIONS);
self.sources.push(T::URL);
self.sections.extend(T::sections());
for (key, value) in T::fetch(&self.client).await? {
self.items.entry(key).or_default().push(value);
}
@ -99,43 +96,43 @@ impl Display for File {
//! Enums from the {:?} IANA registry
//! See <{}>
//!
//! Generated from:"#,
// Do not edit this file manually
use parse_display::{{Display, FromStr}};
use schemars::JsonSchema;
use serde::{{Deserialize, Serialize}};"#,
self.registry_name, self.registry_url,
)?;
for source in &self.sources {
writeln!(f, "//! - <{}>", source)?;
}
writeln!(
f,
r#"
// Do not edit this file manually
use schemars::JsonSchema;
use serde::{{Deserialize, Serialize}};"#
)?;
for key in &self.sections {
let list = if let Some(list) = self.items.get(key) {
for section in &self.sections {
let list = if let Some(list) = self.items.get(section.key) {
list
} else {
continue;
};
writeln!(f)?;
writeln!(
write!(
f,
"#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]"
r#"
/// {}
///
/// Source: <{}>
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema,
)]
pub enum {} {{"#,
section.doc,
section.url.unwrap(),
section.key,
)?;
write!(f, "pub enum {} {{", key)?;
for member in list {
writeln!(f)?;
if let Some(description) = &member.description {
writeln!(f, " /// {}", description)?;
}
writeln!(f, " #[serde(rename = \"{}\")]", member.value)?;
writeln!(f, " #[display(\"{}\")]", member.value)?;
writeln!(f, " {},", member.enum_name)?;
}
writeln!(f, "}}")?;

View File

@ -14,7 +14,10 @@
use serde::Deserialize;
use crate::EnumEntry;
use crate::{
traits::{s, Section},
EnumEntry,
};
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
@ -30,7 +33,7 @@ pub struct TokenTypeHint {
impl EnumEntry for TokenTypeHint {
const URL: &'static str =
"https://www.iana.org/assignments/oauth-parameters/token-type-hint.csv";
const SECTIONS: &'static [&'static str] = &["OAuthTokenTypeHint"];
const SECTIONS: &'static [Section] = &[s("OAuthTokenTypeHint", "OAuth Token Type Hint")];
fn key(&self) -> Option<&'static str> {
Some("OAuthTokenTypeHint")
@ -54,7 +57,10 @@ pub struct AuthorizationEndpointResponseType {
impl EnumEntry for AuthorizationEndpointResponseType {
const URL: &'static str = "https://www.iana.org/assignments/oauth-parameters/endpoint.csv";
const SECTIONS: &'static [&'static str] = &["OAuthAuthorizationEndpointResponseType"];
const SECTIONS: &'static [Section] = &[s(
"OAuthAuthorizationEndpointResponseType",
"OAuth Authorization Endpoint Response Type",
)];
fn key(&self) -> Option<&'static str> {
Some("OAuthAuthorizationEndpointResponseType")
@ -79,7 +85,10 @@ pub struct TokenEndpointAuthenticationMethod {
impl EnumEntry for TokenEndpointAuthenticationMethod {
const URL: &'static str =
"https://www.iana.org/assignments/oauth-parameters/token-endpoint-auth-method.csv";
const SECTIONS: &'static [&'static str] = &["OAuthTokenEndpointAuthenticationMethod"];
const SECTIONS: &'static [Section] = &[s(
"OAuthTokenEndpointAuthenticationMethod",
"OAuth Token Endpoint Authentication Method",
)];
fn key(&self) -> Option<&'static str> {
Some("OAuthTokenEndpointAuthenticationMethod")
@ -104,7 +113,8 @@ pub struct PkceCodeChallengeMethod {
impl EnumEntry for PkceCodeChallengeMethod {
const URL: &'static str =
"https://www.iana.org/assignments/oauth-parameters/pkce-code-challenge-method.csv";
const SECTIONS: &'static [&'static str] = &["PkceCodeChallengeMethod"];
const SECTIONS: &'static [Section] =
&[s("PkceCodeChallengeMethod", "PKCE Code Challenge Method")];
fn key(&self) -> Option<&'static str> {
Some("PkceCodeChallengeMethod")

View File

@ -18,6 +18,21 @@ use convert_case::{Case, Casing};
use reqwest::Client;
use serde::de::DeserializeOwned;
#[derive(Debug, Clone)]
pub struct Section {
pub key: &'static str,
pub doc: &'static str,
pub url: Option<&'static str>,
}
pub const fn s(key: &'static str, doc: &'static str) -> Section {
Section {
key,
doc,
url: None,
}
}
#[derive(Debug)]
pub struct EnumMember {
pub value: String,
@ -28,7 +43,17 @@ pub struct EnumMember {
#[async_trait]
pub trait EnumEntry: DeserializeOwned + Send + Sync {
const URL: &'static str;
const SECTIONS: &'static [&'static str];
const SECTIONS: &'static [Section];
fn sections() -> Vec<Section> {
Self::SECTIONS
.iter()
.map(|s| Section {
url: Some(Self::URL),
..*s
})
.collect()
}
fn key(&self) -> Option<&'static str>;
fn name(&self) -> &str;