Skip to main content

aep_core/
model.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::validation::deserialize_optional_non_null;
7
8pub type AdditionalMembers = BTreeMap<String, Value>;
9
10macro_rules! closed_string_enum {
11    ($name:ident { $($variant:ident => $value:literal),+ $(,)? }) => {
12        #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
13        pub enum $name {
14            $(#[serde(rename = $value)] $variant),+
15        }
16
17        impl $name {
18            pub const fn as_str(self) -> &'static str {
19                match self {
20                    $(Self::$variant => $value),+
21                }
22            }
23        }
24    };
25}
26
27macro_rules! extensible_string_enum {
28    ($name:ident { $($variant:ident => $value:literal),+ $(,)? }) => {
29        #[derive(Clone, Debug, Eq, Hash, PartialEq)]
30        pub enum $name {
31            $($variant),+,
32            Other(String),
33        }
34
35        impl $name {
36            pub fn as_str(&self) -> &str {
37                match self {
38                    $(Self::$variant => $value),+,
39                    Self::Other(value) => value,
40                }
41            }
42        }
43
44        impl From<&str> for $name {
45            fn from(value: &str) -> Self {
46                match value {
47                    $($value => Self::$variant),+,
48                    other => Self::Other(other.to_owned()),
49                }
50            }
51        }
52
53        impl From<String> for $name {
54            fn from(value: String) -> Self {
55                Self::from(value.as_str())
56            }
57        }
58
59        impl Serialize for $name {
60            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
61            where
62                S: serde::Serializer,
63            {
64                serializer.serialize_str(self.as_str())
65            }
66        }
67
68        impl<'de> Deserialize<'de> for $name {
69            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
70            where
71                D: serde::Deserializer<'de>,
72            {
73                Ok(Self::from(String::deserialize(deserializer)?))
74            }
75        }
76    };
77}
78
79extensible_string_enum!(Command {
80    Inspect => "inspect",
81    Enroll => "enroll",
82    Grant => "grant",
83    Revoke => "revoke",
84    Status => "status",
85});
86
87closed_string_enum!(AssertionOperation {
88    Enroll => "enroll",
89    Grant => "grant",
90    Revoke => "revoke",
91    Status => "status",
92    Authenticate => "authenticate",
93});
94
95extensible_string_enum!(SigningAlgorithm {
96    EdDsa => "EdDSA",
97    Es256 => "ES256",
98});
99
100extensible_string_enum!(GrantType {
101    OAuthBearer => "oauth-bearer",
102    ApiKey => "api-key",
103    Basic => "basic",
104});
105
106extensible_string_enum!(AuthenticationMethod {
107    AepJwt => "aep-jwt",
108    OAuthBearer => "oauth-bearer",
109    ApiKey => "api-key",
110    Basic => "basic",
111});
112
113extensible_string_enum!(Binding { Http => "http" });
114extensible_string_enum!(IdentityMethod { DidWeb => "did:web" });
115
116extensible_string_enum!(ClaimName {
117    ContactAddressPrimary => "contact.address.primary",
118    ContactEmail => "contact.email",
119    ContactMobile => "contact.mobile",
120    PersonBirthdate => "person.birthdate",
121    PersonFirstName => "person.first_name",
122    PersonLastName => "person.last_name",
123    PersonUsername => "person.username",
124});
125
126extensible_string_enum!(ErrorCode {
127    EnrollmentFailed => "enrollment_failed",
128    InvalidRequest => "invalid_request",
129    NotRecognized => "not_recognized",
130    IdentitySuspended => "identity_suspended",
131    IdentityTerminated => "identity_terminated",
132    IdentityUnavailable => "identity_unavailable",
133    VerificationPending => "verification_pending",
134    VerificationTimeout => "verification_timeout",
135    RequirementsUnmet => "requirements_unmet",
136    RateLimited => "rate_limited",
137    UnsupportedGrantType => "unsupported_grant_type",
138    IdempotencyConflict => "idempotency_conflict",
139    AuthenticationRequired => "authentication_required",
140    UnsupportedAuthenticationMethod => "unsupported_authentication_method",
141    InsufficientScope => "insufficient_scope",
142});
143
144closed_string_enum!(EnrollmentDecisionStatus {
145    Active => "active",
146    Pending => "pending",
147    Rejected => "rejected",
148});
149
150pub type EnrollmentStatus = EnrollmentDecisionStatus;
151
152closed_string_enum!(AgentStatus {
153    Active => "active",
154    Pending => "pending",
155    Rejected => "rejected",
156    Suspended => "suspended",
157    Terminated => "terminated",
158    Unavailable => "unavailable",
159});
160
161closed_string_enum!(StringBoolean { True => "true", False => "false" });
162closed_string_enum!(OpenApiTrailingSlash { Strict => "strict", Equivalent => "equivalent" });
163closed_string_enum!(AuthorizationCarrier {
164    Standard => "Authorization",
165    Dedicated => "AEP-Authorization",
166});
167closed_string_enum!(CredentialScheme { Aep => "AEP", Bearer => "Bearer", Basic => "Basic" });
168
169#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
170#[serde(deny_unknown_fields)]
171pub struct Authentication {
172    pub methods: Vec<AuthenticationMethod>,
173}
174
175#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
176pub struct Bindings {
177    pub supported: Vec<Binding>,
178    #[serde(flatten)]
179    pub additional: AdditionalMembers,
180}
181
182#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
183pub struct InspectClaims {
184    #[serde(default, skip_serializing_if = "Vec::is_empty")]
185    pub required: Vec<ClaimName>,
186    #[serde(default, skip_serializing_if = "Vec::is_empty")]
187    pub preferred: Vec<ClaimName>,
188    #[serde(default, skip_serializing_if = "Vec::is_empty")]
189    pub optional: Vec<ClaimName>,
190    #[serde(flatten)]
191    pub additional: AdditionalMembers,
192}
193
194#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
195pub struct GrantTypeConfig {
196    #[serde(
197        default,
198        deserialize_with = "deserialize_optional_non_null",
199        skip_serializing_if = "Option::is_none"
200    )]
201    pub supports_per_credential_revoke: Option<StringBoolean>,
202    #[serde(flatten)]
203    pub additional: AdditionalMembers,
204}
205
206#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
207pub struct Commands {
208    pub supported: Vec<Command>,
209    #[serde(default, skip_serializing_if = "Vec::is_empty")]
210    pub grant_types: Vec<GrantType>,
211    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
212    pub grant_types_config: BTreeMap<String, GrantTypeConfig>,
213    #[serde(flatten)]
214    pub additional: AdditionalMembers,
215}
216
217#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
218pub struct CoreConfiguration {
219    pub signing_algorithms: Vec<SigningAlgorithm>,
220    #[serde(flatten)]
221    pub additional: AdditionalMembers,
222}
223
224#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
225pub struct Extensions {
226    #[serde(default, skip_serializing_if = "Vec::is_empty")]
227    pub supported: Vec<String>,
228    #[serde(flatten)]
229    pub additional: AdditionalMembers,
230}
231
232#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
233#[serde(deny_unknown_fields)]
234pub struct OpenApiPathMatching {
235    pub trailing_slash: OpenApiTrailingSlash,
236}
237
238#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
239#[serde(deny_unknown_fields)]
240pub struct OpenApiReference {
241    pub url: String,
242    pub path_matching: OpenApiPathMatching,
243}
244
245#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
246pub struct HttpConfiguration {
247    #[serde(
248        default,
249        deserialize_with = "deserialize_optional_non_null",
250        skip_serializing_if = "Option::is_none"
251    )]
252    pub endpoint_base: Option<String>,
253    #[serde(
254        default,
255        deserialize_with = "deserialize_optional_non_null",
256        skip_serializing_if = "Option::is_none"
257    )]
258    pub openapi: Option<OpenApiReference>,
259    #[serde(flatten)]
260    pub additional: AdditionalMembers,
261}
262
263#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
264pub struct Identity {
265    pub methods: Vec<IdentityMethod>,
266    #[serde(flatten)]
267    pub additional: AdditionalMembers,
268}
269
270#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
271pub struct ServiceIdentity {
272    pub did: String,
273    #[serde(flatten)]
274    pub additional: AdditionalMembers,
275}
276
277#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
278pub struct InspectDocument {
279    pub aep_version: String,
280    #[serde(
281        default,
282        deserialize_with = "deserialize_optional_non_null",
283        skip_serializing_if = "Option::is_none"
284    )]
285    pub authentication: Option<Authentication>,
286    pub bindings: Bindings,
287    #[serde(
288        default,
289        deserialize_with = "deserialize_optional_non_null",
290        skip_serializing_if = "Option::is_none"
291    )]
292    pub claims: Option<InspectClaims>,
293    pub commands: Commands,
294    pub core: CoreConfiguration,
295    #[serde(
296        default,
297        deserialize_with = "deserialize_optional_non_null",
298        skip_serializing_if = "Option::is_none"
299    )]
300    pub extensions: Option<Extensions>,
301    pub http: HttpConfiguration,
302    pub identity: Identity,
303    pub service: ServiceIdentity,
304    #[serde(flatten)]
305    pub additional: AdditionalMembers,
306}
307
308#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
309pub struct ContactAddressPrimary {
310    #[serde(
311        default,
312        deserialize_with = "deserialize_optional_non_null",
313        skip_serializing_if = "Option::is_none"
314    )]
315    pub city: Option<String>,
316    pub country: String,
317    pub first_name: String,
318    pub last_name: String,
319    pub line1: String,
320    #[serde(
321        default,
322        deserialize_with = "deserialize_optional_non_null",
323        skip_serializing_if = "Option::is_none"
324    )]
325    pub line2: Option<String>,
326    #[serde(
327        default,
328        deserialize_with = "deserialize_optional_non_null",
329        skip_serializing_if = "Option::is_none"
330    )]
331    pub line3: Option<String>,
332    #[serde(
333        default,
334        deserialize_with = "deserialize_optional_non_null",
335        skip_serializing_if = "Option::is_none"
336    )]
337    pub postcode: Option<String>,
338    #[serde(
339        default,
340        deserialize_with = "deserialize_optional_non_null",
341        skip_serializing_if = "Option::is_none"
342    )]
343    pub region: Option<String>,
344    #[serde(flatten)]
345    pub additional: AdditionalMembers,
346}
347
348#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
349pub struct ClaimValues {
350    #[serde(
351        default,
352        deserialize_with = "deserialize_optional_non_null",
353        rename = "contact.address.primary",
354        skip_serializing_if = "Option::is_none"
355    )]
356    pub contact_address_primary: Option<ContactAddressPrimary>,
357    #[serde(
358        default,
359        deserialize_with = "deserialize_optional_non_null",
360        rename = "contact.email",
361        skip_serializing_if = "Option::is_none"
362    )]
363    pub contact_email: Option<String>,
364    #[serde(
365        default,
366        deserialize_with = "deserialize_optional_non_null",
367        rename = "contact.mobile",
368        skip_serializing_if = "Option::is_none"
369    )]
370    pub contact_mobile: Option<String>,
371    #[serde(
372        default,
373        deserialize_with = "deserialize_optional_non_null",
374        rename = "person.birthdate",
375        skip_serializing_if = "Option::is_none"
376    )]
377    pub person_birthdate: Option<String>,
378    #[serde(
379        default,
380        deserialize_with = "deserialize_optional_non_null",
381        rename = "person.first_name",
382        skip_serializing_if = "Option::is_none"
383    )]
384    pub person_first_name: Option<String>,
385    #[serde(
386        default,
387        deserialize_with = "deserialize_optional_non_null",
388        rename = "person.last_name",
389        skip_serializing_if = "Option::is_none"
390    )]
391    pub person_last_name: Option<String>,
392    #[serde(
393        default,
394        deserialize_with = "deserialize_optional_non_null",
395        rename = "person.username",
396        skip_serializing_if = "Option::is_none"
397    )]
398    pub person_username: Option<String>,
399    #[serde(flatten)]
400    pub additional: AdditionalMembers,
401}
402
403#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
404pub struct EnrollRequest {
405    pub agent_did: String,
406    #[serde(
407        default,
408        deserialize_with = "deserialize_optional_non_null",
409        skip_serializing_if = "Option::is_none"
410    )]
411    pub claims: Option<ClaimValues>,
412    #[serde(
413        default,
414        deserialize_with = "deserialize_optional_non_null",
415        skip_serializing_if = "Option::is_none"
416    )]
417    pub idempotency_key: Option<String>,
418    #[serde(flatten)]
419    pub additional: AdditionalMembers,
420}
421
422fn owner_action_is_not_true(value: &Option<StringBoolean>) -> bool {
423    !matches!(value, Some(StringBoolean::True))
424}
425
426#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
427pub struct EnrollResponse {
428    pub status: AgentStatus,
429    #[serde(
430        default,
431        deserialize_with = "deserialize_optional_non_null",
432        skip_serializing_if = "owner_action_is_not_true"
433    )]
434    pub owner_action_required: Option<StringBoolean>,
435    #[serde(
436        default,
437        deserialize_with = "deserialize_optional_non_null",
438        skip_serializing_if = "Option::is_none"
439    )]
440    pub verification_pending: Option<Vec<String>>,
441    #[serde(
442        default,
443        deserialize_with = "deserialize_optional_non_null",
444        skip_serializing_if = "Option::is_none"
445    )]
446    pub requirements_pending: Option<Vec<String>>,
447    #[serde(flatten)]
448    pub additional: AdditionalMembers,
449}
450
451#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
452pub struct StatusResponse {
453    pub status: AgentStatus,
454    #[serde(
455        default,
456        deserialize_with = "deserialize_optional_non_null",
457        skip_serializing_if = "owner_action_is_not_true"
458    )]
459    pub owner_action_required: Option<StringBoolean>,
460    #[serde(
461        default,
462        deserialize_with = "deserialize_optional_non_null",
463        skip_serializing_if = "Option::is_none"
464    )]
465    pub verification_pending: Option<Vec<String>>,
466    #[serde(
467        default,
468        deserialize_with = "deserialize_optional_non_null",
469        skip_serializing_if = "Option::is_none"
470    )]
471    pub requirements_pending: Option<Vec<String>>,
472    #[serde(
473        default,
474        deserialize_with = "deserialize_optional_non_null",
475        skip_serializing_if = "Option::is_none"
476    )]
477    pub since: Option<String>,
478    #[serde(flatten)]
479    pub additional: AdditionalMembers,
480}
481
482#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
483pub struct GrantRequest {
484    pub grant_type: GrantType,
485    #[serde(default, skip_serializing_if = "Vec::is_empty")]
486    pub requested_scopes: Vec<String>,
487    #[serde(flatten)]
488    pub additional: AdditionalMembers,
489}
490
491#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
492pub struct RevokeRequest {
493    #[serde(
494        default,
495        deserialize_with = "deserialize_optional_non_null",
496        skip_serializing_if = "Option::is_none"
497    )]
498    pub grant_type: Option<GrantType>,
499    #[serde(
500        default,
501        deserialize_with = "deserialize_optional_non_null",
502        skip_serializing_if = "Option::is_none"
503    )]
504    pub credential_id: Option<String>,
505    #[serde(
506        default,
507        deserialize_with = "deserialize_optional_non_null",
508        skip_serializing_if = "Option::is_none"
509    )]
510    pub all_grant_types: Option<StringBoolean>,
511    #[serde(flatten)]
512    pub additional: AdditionalMembers,
513}
514
515#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
516#[serde(deny_unknown_fields)]
517pub struct RevokeResponse {}
518
519#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
520pub struct IdempotencyMetadata {
521    #[serde(
522        default,
523        deserialize_with = "deserialize_optional_non_null",
524        skip_serializing_if = "Option::is_none"
525    )]
526    pub agent_did: Option<String>,
527    pub idempotency_key: String,
528    #[serde(
529        default,
530        deserialize_with = "deserialize_optional_non_null",
531        skip_serializing_if = "Option::is_none"
532    )]
533    pub first_body_hash: Option<String>,
534    #[serde(
535        default,
536        deserialize_with = "deserialize_optional_non_null",
537        skip_serializing_if = "Option::is_none"
538    )]
539    pub second_body_hash: Option<String>,
540    #[serde(flatten)]
541    pub additional: AdditionalMembers,
542}
543
544#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
545pub struct OpenApiAepSecurityScheme {
546    #[serde(rename = "x-aep-authentication-method")]
547    pub authentication_method: AuthenticationMethod,
548    #[serde(flatten)]
549    pub additional: AdditionalMembers,
550}
551
552#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
553pub struct ClientAssertionClaims {
554    pub aud: String,
555    pub exp: i64,
556    pub iat: i64,
557    pub iss: String,
558    pub jti: String,
559    pub op: AssertionOperation,
560    #[serde(
561        default,
562        deserialize_with = "deserialize_optional_non_null",
563        skip_serializing_if = "Option::is_none"
564    )]
565    pub resource: Option<String>,
566    pub sub: String,
567    #[serde(flatten)]
568    pub additional: AdditionalMembers,
569}
570
571#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
572pub struct ProblemDetails {
573    #[serde(rename = "type")]
574    pub problem_type: String,
575    pub title: String,
576    pub status: i64,
577    #[serde(
578        default,
579        deserialize_with = "deserialize_optional_non_null",
580        skip_serializing_if = "Option::is_none"
581    )]
582    pub detail: Option<String>,
583    #[serde(
584        default,
585        deserialize_with = "deserialize_optional_non_null",
586        skip_serializing_if = "Option::is_none"
587    )]
588    pub instance: Option<String>,
589    pub code: ErrorCode,
590    #[serde(
591        default,
592        deserialize_with = "deserialize_optional_non_null",
593        skip_serializing_if = "owner_action_is_not_true"
594    )]
595    pub owner_action_required: Option<StringBoolean>,
596    #[serde(
597        default,
598        deserialize_with = "deserialize_optional_non_null",
599        skip_serializing_if = "Option::is_none"
600    )]
601    pub requirements_pending: Option<Vec<String>>,
602    #[serde(
603        default,
604        deserialize_with = "deserialize_optional_non_null",
605        skip_serializing_if = "Option::is_none"
606    )]
607    pub verification_pending: Option<Vec<String>>,
608    #[serde(flatten)]
609    pub additional: AdditionalMembers,
610}
611
612fn deserialize_nullable_scopes<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
613where
614    D: serde::Deserializer<'de>,
615{
616    Ok(Option::<Vec<String>>::deserialize(deserializer)?.unwrap_or_default())
617}
618
619#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
620pub struct OAuthBearerGrantResponse {
621    pub access_token: String,
622    pub credential_id: String,
623    pub expires_at: String,
624    #[serde(default, deserialize_with = "deserialize_nullable_scopes")]
625    pub scopes: Vec<String>,
626    pub token_type: String,
627    #[serde(flatten)]
628    pub additional: AdditionalMembers,
629}
630
631#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
632pub struct ApiKeyGrantResponse {
633    pub api_key: String,
634    pub credential_id: String,
635    pub expires_at: String,
636    pub header: String,
637    #[serde(default, deserialize_with = "deserialize_nullable_scopes")]
638    pub scopes: Vec<String>,
639    #[serde(flatten)]
640    pub additional: AdditionalMembers,
641}
642
643#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
644pub struct BasicGrantResponse {
645    pub credential_id: String,
646    pub expires_at: String,
647    pub password: String,
648    #[serde(
649        default,
650        deserialize_with = "deserialize_optional_non_null",
651        skip_serializing_if = "Option::is_none"
652    )]
653    pub realm: Option<String>,
654    #[serde(default, deserialize_with = "deserialize_nullable_scopes")]
655    pub scopes: Vec<String>,
656    pub username: String,
657    #[serde(flatten)]
658    pub additional: AdditionalMembers,
659}
660
661#[derive(Clone, Debug, PartialEq)]
662pub enum BuiltInGrantResponse {
663    OAuthBearer(OAuthBearerGrantResponse),
664    ApiKey(ApiKeyGrantResponse),
665    Basic(BasicGrantResponse),
666}
667
668impl BuiltInGrantResponse {
669    pub fn grant_type(&self) -> GrantType {
670        match self {
671            Self::OAuthBearer(_) => GrantType::OAuthBearer,
672            Self::ApiKey(_) => GrantType::ApiKey,
673            Self::Basic(_) => GrantType::Basic,
674        }
675    }
676}
677
678#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
679#[serde(deny_unknown_fields)]
680pub struct ProtectedResourceAuthorization {
681    pub carrier: AuthorizationCarrier,
682    pub scheme: CredentialScheme,
683    pub credentials: String,
684}