1use std::net::IpAddr;
14
15use mas_data_model::{Client, User};
16use oauth2_types::{registration::VerifiedClientMetadata, scope::Scope};
17use schemars::JsonSchema;
18use serde::{Deserialize, Serialize};
19
20#[derive(Serialize, Deserialize, Debug, Clone, Copy, JsonSchema, PartialEq, Eq)]
23#[serde(tag = "code", rename_all = "kebab-case")]
24pub enum ViolationVariant {
25 UsernameTooShort,
27
28 UsernameTooLong,
30
31 UsernameInvalidChars,
33
34 UsernameAllNumeric,
36
37 UsernameBanned,
39
40 UsernameNotAllowed,
42
43 EmailDomainNotAllowed,
45
46 EmailDomainBanned,
48
49 EmailNotAllowed,
51
52 EmailBanned,
54
55 AdminScopeNotAllowed,
57
58 ClientNotAllowed,
60
61 TooManySessions {
63 need_to_remove: u32,
65 },
66}
67
68impl ViolationVariant {
69 #[must_use]
71 pub fn as_str(&self) -> &'static str {
72 match self {
73 Self::UsernameTooShort => "username-too-short",
74 Self::UsernameTooLong => "username-too-long",
75 Self::UsernameInvalidChars => "username-invalid-chars",
76 Self::UsernameAllNumeric => "username-all-numeric",
77 Self::UsernameBanned => "username-banned",
78 Self::UsernameNotAllowed => "username-not-allowed",
79 Self::EmailDomainNotAllowed => "email-domain-not-allowed",
80 Self::EmailDomainBanned => "email-domain-banned",
81 Self::EmailNotAllowed => "email-not-allowed",
82 Self::EmailBanned => "email-banned",
83 Self::AdminScopeNotAllowed => "admin-scope-not-allowed",
84 Self::ClientNotAllowed => "client-not-allowed",
85 Self::TooManySessions { .. } => "too-many-sessions",
86 }
87 }
88}
89
90#[derive(Serialize, Deserialize, Debug, JsonSchema)]
92pub struct Violation {
93 pub msg: String,
94 pub redirect_uri: Option<String>,
95 pub field: Option<String>,
96
97 #[serde(flatten)]
102 pub variant: Option<ViolationVariant>,
103}
104
105#[derive(Deserialize, Debug)]
107pub struct EvaluationResult {
108 #[serde(rename = "result")]
109 pub violations: Vec<Violation>,
110}
111
112impl std::fmt::Display for EvaluationResult {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 let mut first = true;
115 for violation in &self.violations {
116 if first {
117 first = false;
118 } else {
119 write!(f, ", ")?;
120 }
121 write!(f, "{}", violation.msg)?;
122 }
123 Ok(())
124 }
125}
126
127impl EvaluationResult {
128 #[must_use]
130 pub fn valid(&self) -> bool {
131 self.violations.is_empty()
132 }
133}
134
135#[derive(Serialize, Debug, Default, JsonSchema)]
137#[serde(rename_all = "snake_case")]
138pub struct Requester {
139 pub ip_address: Option<IpAddr>,
141
142 pub user_agent: Option<String>,
144}
145
146#[derive(Serialize, Debug, JsonSchema)]
147pub enum RegistrationMethod {
148 #[serde(rename = "password")]
149 Password,
150
151 #[serde(rename = "upstream-oauth2")]
152 UpstreamOAuth2,
153}
154
155#[derive(Serialize, Debug, JsonSchema)]
157#[serde(tag = "registration_method")]
158pub struct RegisterInput<'a> {
159 pub registration_method: RegistrationMethod,
160
161 pub username: &'a str,
162
163 #[serde(skip_serializing_if = "Option::is_none")]
164 pub email: Option<&'a str>,
165
166 pub requester: Requester,
167}
168
169#[derive(Serialize, Debug, JsonSchema)]
171#[serde(rename_all = "snake_case")]
172pub struct ClientRegistrationInput<'a> {
173 #[schemars(with = "std::collections::HashMap<String, serde_json::Value>")]
174 pub client_metadata: &'a VerifiedClientMetadata,
175 pub requester: Requester,
176}
177
178#[derive(Serialize, Debug, JsonSchema)]
179#[serde(rename_all = "snake_case")]
180pub enum GrantType {
181 AuthorizationCode,
182 ClientCredentials,
183 #[serde(rename = "urn:ietf:params:oauth:grant-type:device_code")]
184 DeviceCode,
185}
186
187#[derive(Serialize, Debug, JsonSchema)]
189#[serde(rename_all = "snake_case")]
190pub struct AuthorizationGrantInput<'a> {
191 #[schemars(with = "Option<std::collections::HashMap<String, serde_json::Value>>")]
192 pub user: Option<&'a User>,
193
194 pub session_counts: Option<SessionCounts>,
197
198 #[schemars(with = "std::collections::HashMap<String, serde_json::Value>")]
199 pub client: &'a Client,
200
201 #[schemars(with = "String")]
202 pub scope: &'a Scope,
203
204 pub grant_type: GrantType,
205
206 pub requester: Requester,
207}
208
209#[derive(Serialize, Debug, JsonSchema)]
211#[serde(rename_all = "snake_case")]
212pub struct CompatLoginInput<'a> {
213 #[schemars(with = "std::collections::HashMap<String, serde_json::Value>")]
214 pub user: &'a User,
215
216 pub session_counts: SessionCounts,
218
219 pub session_replaced: bool,
221
222 pub login: CompatLogin,
225
226 pub requester: Requester,
227}
228
229#[derive(Serialize, Debug, JsonSchema)]
230#[serde(tag = "type")]
231pub enum CompatLogin {
232 #[serde(rename = "m.login.sso")]
234 Sso { redirect_uri: String },
235
236 #[serde(rename = "m.login.token")]
238 Token,
239
240 #[serde(rename = "m.login.password")]
242 Password,
243}
244
245#[derive(Serialize, Debug, JsonSchema)]
247pub struct SessionCounts {
248 pub total: u64,
249
250 pub oauth2: u64,
251 pub compat: u64,
252 pub personal: u64,
253}
254
255#[derive(Serialize, Debug, JsonSchema)]
257#[serde(rename_all = "snake_case")]
258pub struct EmailInput<'a> {
259 pub email: &'a str,
260
261 pub requester: Requester,
262}