2025-08-28 10:53:36 -07:00
|
|
|
use serde::de::{
|
|
|
|
|
Error,
|
|
|
|
|
Unexpected,
|
|
|
|
|
};
|
|
|
|
|
use serde_json::{
|
|
|
|
|
json,
|
|
|
|
|
Result,
|
|
|
|
|
Value
|
|
|
|
|
};
|
|
|
|
|
use bon::Builder;
|
2025-07-02 12:32:24 -07:00
|
|
|
|
2025-08-28 10:53:36 -07:00
|
|
|
trait Metadata {
|
|
|
|
|
fn format_metadata(self, required: RequiredMetadata) -> Result<Value>;
|
|
|
|
|
}
|
2025-07-02 12:32:24 -07:00
|
|
|
|
2025-08-28 10:53:36 -07:00
|
|
|
pub struct RequiredMetadata {
|
|
|
|
|
issuer: String,
|
|
|
|
|
authorization_endpoint: String,
|
|
|
|
|
token_endpoint: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RequiredMetadata {
|
|
|
|
|
fn new(
|
|
|
|
|
issuer: String,
|
|
|
|
|
authorization_endpoint: String,
|
|
|
|
|
token_endpoint: String
|
|
|
|
|
) -> Self {
|
|
|
|
|
RequiredMetadata {
|
|
|
|
|
issuer, authorization_endpoint, token_endpoint
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Builder)]
|
|
|
|
|
struct AtprotoMetadata {
|
|
|
|
|
additional_response_types_supported: Option<Vec<String>>,
|
|
|
|
|
additional_grant_types_supported: Option<Vec<String>>,
|
|
|
|
|
additional_code_challenge_methods_supported: Option<Vec<String>>,
|
|
|
|
|
additional_token_endpoint_auth_methods_supported: Option<Vec<String>>,
|
|
|
|
|
additional_token_endpoint_auth_signing_alg_values_supported: Option<Vec<String>>,
|
|
|
|
|
additional_scopes_supported: Option<Vec<String>>,
|
|
|
|
|
pushed_authorization_request_endpoint: String,
|
|
|
|
|
additional_dpop_signing_alg_values_supported: Option<Vec<String>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl AtprotoMetadata {
|
|
|
|
|
fn check_fields(&self) -> Result<()> {
|
|
|
|
|
// TODO: Issuer check (https scheme, no default port, no path segments
|
|
|
|
|
|
|
|
|
|
if self.additional_token_endpoint_auth_signing_alg_values_supported
|
|
|
|
|
.as_ref()
|
|
|
|
|
.is_none_or(|vec| vec.iter().any(|s| s == "none")) {
|
|
|
|
|
return Err(Error::invalid_value(
|
|
|
|
|
Unexpected::Other("\"none\" in token_endpoint_auth_signing_alg_values_supported"),
|
|
|
|
|
&"\"none\" to be omitted from token_endpoint_auth_signing_alg_values_supported"
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Metadata for AtprotoMetadata {
|
|
|
|
|
fn format_metadata(self, required: RequiredMetadata) -> Result<Value> {
|
|
|
|
|
self.check_fields()?;
|
|
|
|
|
Ok(json!({
|
|
|
|
|
"issuer": required.issuer,
|
|
|
|
|
"authorization_endpoint": required.authorization_endpoint,
|
|
|
|
|
"token_endpoint": required.token_endpoint,
|
|
|
|
|
"response_types_supported":
|
|
|
|
|
self.additional_response_types_supported.unwrap_or_default()
|
|
|
|
|
.extend(["code".to_string()]),
|
|
|
|
|
"grant_types_supported":
|
|
|
|
|
self.additional_grant_types_supported.unwrap_or_default()
|
|
|
|
|
.extend([
|
|
|
|
|
"authorization_code".to_string(),
|
|
|
|
|
"refresh_token".to_string()
|
|
|
|
|
]),
|
|
|
|
|
"code_challenge_methods_supported":
|
|
|
|
|
self.additional_code_challenge_methods_supported.unwrap_or_default()
|
|
|
|
|
.extend(["S256".to_string()]),
|
|
|
|
|
"token_endpoint_auth_methods_supported":
|
|
|
|
|
self.additional_token_endpoint_auth_methods_supported.unwrap_or_default()
|
|
|
|
|
.extend([
|
|
|
|
|
"none".to_string(),
|
|
|
|
|
"private_key_jwt".to_string()
|
|
|
|
|
]),
|
|
|
|
|
"token_endpoint_auth_signing_alg_values_supported":
|
|
|
|
|
self.additional_token_endpoint_auth_signing_alg_values_supported.unwrap_or_default()
|
|
|
|
|
.extend(["ES256".to_string()]),
|
|
|
|
|
"scopes_supported":
|
|
|
|
|
self.additional_scopes_supported.unwrap_or_default()
|
|
|
|
|
.extend(["atproto".to_string()]),
|
|
|
|
|
"authorization_response_iss_parameter_supported": true,
|
|
|
|
|
"require_pushed_authorization_requests": true,
|
|
|
|
|
"pushed_authorization_request_endpoint": self.pushed_authorization_request_endpoint,
|
|
|
|
|
"dpop_signing_alg_values_supported":
|
|
|
|
|
self.additional_dpop_signing_alg_values_supported.unwrap_or_default()
|
|
|
|
|
.extend(["ES256".to_string()]),
|
|
|
|
|
"client_id_metadata_document_supported": true,
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
}
|