use openapiv3::APIKeyLocation;
use openapiv3::ReferenceOr;
use openapiv3::SecurityRequirement;
use openapiv3::SecurityScheme as OasSecurityScheme;
use crate::ir::SecurityScheme;
use crate::ir::SecuritySchemeKind;
use crate::loader::Spec;
use crate::naming::Case;
use crate::naming::to_ident;
pub fn scheme_catalogue(spec: &Spec) -> Vec<SecurityScheme> {
let mut schemes = Vec::new();
for (key, entry) in spec.security_schemes() {
let (kind, doc) = match entry {
ReferenceOr::Item(scheme) => lower_scheme(scheme),
ReferenceOr::Reference { reference } => (
SecuritySchemeKind::Unsupported(format!(
"security scheme `{key}` is a `$ref` (`{reference}`), which is not supported"
)),
None,
),
};
schemes.push(SecurityScheme {
key: key.clone(),
field: to_ident(key, Case::Snake),
kind,
doc,
});
}
return schemes;
}
fn lower_scheme(scheme: &OasSecurityScheme) -> (SecuritySchemeKind, Option<String>) {
match scheme {
OasSecurityScheme::HTTP {
scheme, description, ..
} => {
let kind = if scheme.eq_ignore_ascii_case("bearer") {
SecuritySchemeKind::HttpBearer
} else if scheme.eq_ignore_ascii_case("basic") {
SecuritySchemeKind::HttpBasic
} else {
SecuritySchemeKind::Unsupported(format!("HTTP authentication scheme `{scheme}` is not supported"))
};
return (kind, description.clone());
}
OasSecurityScheme::APIKey {
location,
name,
description,
..
} => {
let kind = match location {
APIKeyLocation::Header => SecuritySchemeKind::ApiKeyHeader(name.clone()),
APIKeyLocation::Query => SecuritySchemeKind::ApiKeyQuery(name.clone()),
APIKeyLocation::Cookie => SecuritySchemeKind::ApiKeyCookie(name.clone()),
};
return (kind, description.clone());
}
OasSecurityScheme::OAuth2 { description, .. } => {
return (
SecuritySchemeKind::Unsupported("OAuth2 security is not supported by the client generator".to_owned()),
description.clone(),
);
}
OasSecurityScheme::OpenIDConnect { description, .. } => {
return (
SecuritySchemeKind::Unsupported(
"OpenID Connect security is not supported by the client generator".to_owned(),
),
description.clone(),
);
}
}
}
pub fn effective_requirements<'a>(
operation_security: Option<&'a [SecurityRequirement]>,
global_security: Option<&'a [SecurityRequirement]>,
) -> Option<&'a [SecurityRequirement]> {
return operation_security.or(global_security);
}
pub fn required_keys(requirements: &[SecurityRequirement]) -> Vec<String> {
let mut keys: Vec<String> = Vec::new();
for requirement in requirements {
for key in requirement.keys() {
if !keys.iter().any(|existing| return existing == key) {
keys.push(key.clone());
}
}
}
return keys;
}