g1t/crates/contracts/src/identity.rs

265 lines7,085 bytesCodeBlame
1//! The identity service: accounts, credentials and sessions.
2//!
3//! Each `*Args` struct is the argument of the method of the same name,
4//! served at `POST /rpc/<method>`.
5
6use serde::{Deserialize, Serialize};
7
8use crate::User;
9
10#[derive(Clone, Debug, Serialize, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct SshKey {
13 pub id: String,
14 pub title: String,
15 pub fingerprint: String,
16 /// RFC 3339.
17 pub created_at: String,
18}
19
20#[derive(Clone, Debug, Serialize, Deserialize)]
21#[serde(rename_all = "camelCase")]
22pub struct AccessToken {
23 pub id: String,
24 pub name: String,
25 /// RFC 3339.
26 pub created_at: String,
27}
28
29/// `sign_in`: verifies a username and password for website sign-in.
30/// Returns `Outcome<SignedIn>`.
31#[derive(Debug, Serialize, Deserialize)]
32pub struct SignInArgs {
33 pub username: String,
34 pub password: String,
35}
36
37#[derive(Debug, Serialize, Deserialize)]
38#[serde(rename_all = "camelCase")]
39pub struct SignedIn {
40 pub user: User,
41 pub session_token: String,
42}
43
44/// `sign_out` and `user_for_session`.
45#[derive(Debug, Serialize, Deserialize)]
46#[serde(rename_all = "camelCase")]
47pub struct SessionArgs {
48 pub session_token: String,
49}
50
51/// `user_for_git_credentials`: the account password or an access token.
52#[derive(Debug, Serialize, Deserialize)]
53pub struct GitCredentialsArgs {
54 pub username: String,
55 pub secret: String,
56}
57
58/// `user_for_access_token`.
59#[derive(Debug, Serialize, Deserialize)]
60pub struct TokenArgs {
61 pub token: String,
62}
63
64/// `user_for_ssh_key`.
65#[derive(Debug, Serialize, Deserialize)]
66pub struct FingerprintArgs {
67 pub fingerprint: String,
68}
69
70/// `user_by_username`.
71#[derive(Debug, Serialize, Deserialize)]
72pub struct UsernameArgs {
73 pub username: String,
74}
75
76/// `list_ssh_keys` and `list_access_tokens`.
77#[derive(Debug, Serialize, Deserialize)]
78pub struct UserArgs {
79 pub user: User,
80}
81
82/// `add_ssh_key`: `public_key` is one line in OpenSSH format.
83/// Returns `Outcome<SshKey>`.
84#[derive(Debug, Serialize, Deserialize)]
85#[serde(rename_all = "camelCase")]
86pub struct AddSshKeyArgs {
87 pub user: User,
88 pub title: String,
89 pub public_key: String,
90}
91
92/// `remove_ssh_key` and `remove_access_token`.
93#[derive(Debug, Serialize, Deserialize)]
94pub struct RemoveArgs {
95 pub user: User,
96 pub id: String,
97}
98
99/// `create_access_token`.
100#[derive(Debug, Serialize, Deserialize)]
101#[serde(rename_all = "camelCase")]
102pub struct CreateAccessTokenArgs {
103 pub user: User,
104 pub name: String,
105 /// When set, the token stops working after this many seconds and is
106 /// left out of the user's token list. Used for hosted attempts.
107 #[serde(default)]
108 pub ttl_seconds: Option<u64>,
109}
110
111/// The plaintext token is returned once and never stored.
112#[derive(Debug, Serialize, Deserialize)]
113pub struct CreatedAccessToken {
114 pub token: String,
115 pub info: AccessToken,
116}
117
118/// `register`: creates an account and signs it in.
119/// Returns `Outcome<SignedIn>`.
120#[derive(Debug, Serialize, Deserialize)]
121pub struct RegisterArgs {
122 pub username: String,
123 pub email: String,
124 pub password: String,
125}
126
127/// `verify_email`: the token from the emailed link. Returns `Outcome<User>`.
128#[derive(Debug, Serialize, Deserialize)]
129pub struct EmailTokenArgs {
130 pub token: String,
131}
132
133/// `request_password_reset`. Always succeeds, so it cannot be used to find
134/// out which addresses have accounts.
135#[derive(Debug, Serialize, Deserialize)]
136pub struct EmailArgs {
137 pub email: String,
138}
139
140/// `reset_password`: sets a new password and ends every session.
141/// Returns `Outcome<User>`.
142#[derive(Debug, Serialize, Deserialize)]
143pub struct ResetPasswordArgs {
144 pub token: String,
145 pub password: String,
146}
147
148/// `device_start`: begins a device sign-in. Returns `DeviceStart`.
149#[derive(Debug, Serialize, Deserialize)]
150#[serde(rename_all = "camelCase")]
151pub struct DeviceStartArgs {
152 /// What is asking, shown to the person approving, e.g. "Claude Code".
153 pub client_name: String,
154}
155
156#[derive(Debug, Serialize, Deserialize)]
157#[serde(rename_all = "camelCase")]
158pub struct DeviceStart {
159 /// Secret held by the tool and exchanged for a token once approved.
160 pub device_code: String,
161 /// Short code shown to the person, e.g. `WDJB-MJHT`.
162 pub user_code: String,
163 /// Seconds until both codes stop working.
164 pub expires_in: u32,
165 /// Seconds the tool should wait between polls.
166 pub interval: u32,
167}
168
169/// `device_lookup`: what a user code is asking for, or null if it is not
170/// valid. Returns `Option<DeviceRequest>`.
171#[derive(Debug, Serialize, Deserialize)]
172#[serde(rename_all = "camelCase")]
173pub struct DeviceLookupArgs {
174 pub user_code: String,
175}
176
177#[derive(Debug, Serialize, Deserialize)]
178#[serde(rename_all = "camelCase")]
179pub struct DeviceRequest {
180 pub user_code: String,
181 pub client_name: String,
182}
183
184/// `device_resolve`: the signed-in person approves or denies a request.
185/// Returns `Outcome<bool>`.
186#[derive(Debug, Serialize, Deserialize)]
187#[serde(rename_all = "camelCase")]
188pub struct DeviceResolveArgs {
189 pub user_code: String,
190 pub user: User,
191 pub approve: bool,
192}
193
194/// `device_claim`: the tool asks whether its request was approved.
195#[derive(Debug, Serialize, Deserialize)]
196#[serde(rename_all = "camelCase")]
197pub struct DeviceClaimArgs {
198 pub device_code: String,
199}
200
201/// The answer to a `device_claim`.
202#[derive(Debug, Serialize, Deserialize)]
203#[serde(tag = "status", rename_all = "snake_case")]
204pub enum DeviceClaim {
205 /// Nobody has approved or denied it yet; ask again after the interval.
206 Pending,
207 Denied,
208 /// The code was never issued, has expired, or was already used.
209 Expired,
210 /// The access token, returned once.
211 Approved {
212 token: String,
213 user: User,
214 },
215}
216
217/// A workspace: the owner of repositories, and the first segment of their
218/// URLs. A person's own space and a team's are the same thing.
219#[derive(Clone, Debug, Serialize, Deserialize)]
220#[serde(rename_all = "camelCase")]
221pub struct Workspace {
222 pub id: String,
223 pub slug: String,
224 pub name: String,
225 /// RFC 3339.
226 pub created_at: String,
227 pub member_count: u32,
228}
229
230#[derive(Clone, Debug, Serialize, Deserialize)]
231pub struct Member {
232 pub username: String,
233 pub role: crate::Role,
234}
235
236/// `create_workspace`. Returns `Outcome<Workspace>`.
237#[derive(Debug, Serialize, Deserialize)]
238pub struct CreateWorkspaceArgs {
239 pub user: User,
240 pub slug: String,
241 #[serde(default)]
242 pub name: String,
243}
244
245/// `get_workspace`: public details, or null. Returns `Option<Workspace>`.
246#[derive(Debug, Serialize, Deserialize)]
247pub struct SlugArgs {
248 pub slug: String,
249}
250
251/// `list_members`: members only. Returns `Outcome<Vec<Member>>`.
252#[derive(Debug, Serialize, Deserialize)]
253pub struct ListMembersArgs {
254 pub slug: String,
255 pub viewer: crate::Viewer,
256}
257
258/// `add_member` and `remove_member`: owners only.
259/// Each returns `Outcome<bool>`.
260#[derive(Debug, Serialize, Deserialize)]
261pub struct MemberArgs {
262 pub actor: User,
263 pub slug: String,
264 pub username: String,
265}