Skip to main content

comindly_api/
account.rs

1//! Signing in, members, access tokens, secrets and the audit log (`/api/v1/auth/*`, `/members`,
2//! `/tokens`, `/secrets`, `/audit`).
3
4use serde::{Deserialize, Serialize};
5
6pub use crate::server::{
7    AccessToken, AuditEntry, AuditPage, AuditQuery, DeviceRequest, Invite, Member, Role,
8    SecretInfo, SignIn,
9};
10
11/// `GET /api/v1/auth/me`: who is signed in, or `local` on this machine.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13#[serde(tag = "mode", rename_all = "lowercase")]
14pub enum Me {
15    Local,
16    Server {
17        signed_in: bool,
18        email: Option<String>,
19        role: Option<Role>,
20        /// One way to sign in, for older clients; `sign_in_methods` lists them all.
21        sign_in: SignIn,
22        #[serde(default)]
23        sign_in_methods: Vec<SignIn>,
24        /// The provider's name for the sign-in button, when members sign in through one.
25        #[serde(default, skip_serializing_if = "Option::is_none")]
26        oidc_label: Option<String>,
27        /// `microsoft` or `google` when the issuer is theirs, for the button's logo.
28        #[serde(default, skip_serializing_if = "Option::is_none")]
29        oidc_brand: Option<String>,
30        public_url: String,
31        /// The gateway agents connect through with the organisation's sign-in, when there is one.
32        #[serde(default, skip_serializing_if = "Option::is_none")]
33        gateway_url: Option<String>,
34    },
35}
36
37/// `{ email }`: request a sign-in link, reset a code, remove a member or withdraw an invitation.
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct EmailRequest {
40    pub email: String,
41}
42
43/// `POST /api/v1/auth/redeem`: a sign-in link's token, an invitation or the admin token.
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct RedeemRequest {
46    pub token: String,
47}
48
49/// `POST /api/v1/auth/code`: sign in with an email address and a code.
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct CodeRequest {
52    pub email: String,
53    pub code: String,
54}
55
56/// A change that hands out a sign-in code: signing in with an invitation, or a reset.
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct WithCode {
59    pub ok: bool,
60    pub message: String,
61    pub code: Option<String>,
62}
63
64/// `POST /api/v1/members/invite` and `/members/role`.
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct MemberRole {
67    pub email: String,
68    pub role: Role,
69}
70
71/// An invitation sent: by email, or with a `code` the admin hands over.
72#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct Invited {
74    pub ok: bool,
75    pub message: String,
76    #[serde(default, skip_serializing_if = "Option::is_none")]
77    pub code: Option<String>,
78}
79
80/// `GET /api/v1/members`.
81#[derive(Debug, Serialize, Deserialize)]
82pub struct Members {
83    pub members: Vec<Member>,
84    pub invites: Vec<Invite>,
85    pub sign_in: SignIn,
86    #[serde(default)]
87    pub sign_in_methods: Vec<SignIn>,
88}
89
90/// `GET /api/v1/tokens`: your personal access tokens.
91#[derive(Debug, Serialize, Deserialize)]
92pub struct Tokens {
93    pub tokens: Vec<AccessToken>,
94}
95
96fn default_token_days() -> Option<u32> {
97    Some(crate::server::TOKEN_DAYS)
98}
99
100/// `POST /api/v1/tokens`: absent `expires_in_days` means 90 days, `null` never.
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct NewToken {
103    pub name: String,
104    #[serde(default = "default_token_days")]
105    pub expires_in_days: Option<u32>,
106}
107
108/// A personal access token, shown once.
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct TokenCreated {
111    pub ok: bool,
112    pub message: String,
113    pub token: String,
114}
115
116/// `GET /api/v1/secrets`: where each token and key comes from, never its value.
117#[derive(Debug, Serialize, Deserialize)]
118pub struct Secrets {
119    pub secrets: Vec<SecretState>,
120    pub can_store: bool,
121}
122
123/// One secret: stored here with its details, or from the deployment or nowhere.
124#[derive(Debug, Serialize, Deserialize)]
125#[serde(untagged)]
126pub enum SecretState {
127    Elsewhere(SecretSource),
128    Stored {
129        #[serde(flatten)]
130        info: SecretInfo,
131        label: String,
132        /// The deployment provides one too; this one is used instead.
133        #[serde(default, skip_serializing_if = "std::ops::Not::not")]
134        replaces_deployment: bool,
135    },
136}
137
138/// A secret the deployment provides (`deployment`) or nobody set (`none`).
139#[derive(Debug, Serialize, Deserialize)]
140#[serde(deny_unknown_fields)]
141pub struct SecretSource {
142    pub source: String,
143    pub name: String,
144    pub label: String,
145}
146
147/// `POST /api/v1/secrets`: an empty value removes it.
148#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct SecretRequest {
150    pub name: String,
151    #[serde(default)]
152    pub value: String,
153}
154
155/// `POST /api/v1/auth/device/start`: a command line asks to sign in.
156#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct DeviceStartRequest {
158    pub client: String,
159}
160
161/// Where to approve the sign-in, and how often to poll.
162#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct DeviceStart {
164    pub device_code: String,
165    pub user_code: String,
166    pub verify_url: String,
167    pub interval: u64,
168    pub expires_in: u64,
169}
170
171/// `POST /api/v1/auth/device/token`: what the command line polls with.
172#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct DeviceTokenRequest {
174    pub device_code: String,
175}
176
177/// Pending, or the token once a member approved; denied and expired are errors.
178#[derive(Debug, Clone, Serialize, Deserialize)]
179#[serde(tag = "status", rename_all = "lowercase")]
180pub enum DeviceToken {
181    Pending,
182    Approved {
183        token: String,
184        email: String,
185        expires: Option<String>,
186    },
187}
188
189/// `GET /api/v1/auth/device?code=`.
190#[derive(Debug, Clone, Serialize, Deserialize)]
191pub struct DeviceCodeQuery {
192    pub code: String,
193}
194
195/// `POST /api/v1/auth/device/approve`.
196#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct DeviceApprove {
198    pub code: String,
199    pub approve: bool,
200}