1use std::collections::HashMap;
2
3use serde::de::DeserializeOwned;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use time::{serde::iso8601, OffsetDateTime};
7
8use crate::error::Result;
9use crate::utils::aes256gcm::{decrypt, Encryption};
10
11#[derive(Deserialize)]
16#[serde(untagged)]
17pub enum ApiResponse<T> {
18 Ok(T),
19 Err(ErrorResponse),
20}
21
22pub struct GetMyUserRequest {
24 pub base_url: String,
26}
27
28#[derive(Deserialize)]
30pub struct GetMyUserResponse {
31 pub user: User,
33}
34
35#[derive(Deserialize, Clone, Debug)]
37#[serde(rename_all = "camelCase")]
38pub struct User {
39 #[serde(alias = "_id")]
40 pub id: String,
41 pub email: String,
42 pub first_name: String,
43 pub last_name: String,
44 pub public_key: String,
45 pub encrypted_private_key: String,
46 pub salt: String,
47 pub iv: String,
48 pub tag: String,
49 #[serde(alias = "__v")]
50 pub v: u8,
51 pub devices: Vec<UserDevice>,
52 pub encryption_version: Option<u8>,
53 pub is_mfa_enabled: bool,
54 pub mfa_methods: Vec<String>,
55 #[serde(flatten)]
56 pub audit: Audit,
57}
58
59#[derive(Deserialize, Clone, Debug)]
60#[serde(rename_all = "camelCase")]
61pub struct SimpleUser {
62 #[serde(alias = "_id")]
63 pub id: String,
64 pub email: String,
65 pub first_name: String,
66 pub last_name: String,
67 #[serde(alias = "__v")]
68 pub v: u8,
69 pub devices: Vec<UserDevice>,
70 pub encryption_version: Option<u8>,
71 pub is_mfa_enabled: bool,
72 pub mfa_methods: Vec<String>,
73 #[serde(flatten)]
74 pub audit: Audit,
75}
76
77#[derive(Deserialize, Clone, Debug)]
78#[serde(rename_all = "camelCase")]
79pub struct UserDevice {
80 pub ip: String,
81 pub user_agent: String,
82 #[serde(alias = "_id")]
83 pub id: String,
84}
85
86pub struct GetMyOrganizationsRequest {
87 pub base_url: String,
89}
90
91#[derive(Deserialize)]
92pub struct GetOrganizationsResponse {
93 pub organizations: Vec<Organization>,
94}
95
96#[derive(Deserialize)]
97pub struct Organization {
98 #[serde(alias = "_id")]
99 pub id: String,
100 pub name: String,
101 #[serde(alias = "customerId")]
102 pub customer_id: String,
103 #[serde(flatten)]
104 pub audit: Audit,
105}
106
107pub struct GetOrganizationMembershipsRequest {
108 pub base_url: String,
110 pub organization_id: String,
111}
112
113#[derive(Deserialize)]
114pub struct GetOrganizationMembershipsResponse {
115 pub memberships: Vec<OrganizationMembership>,
116}
117
118#[derive(Deserialize)]
119pub struct OrganizationMembership {
120 #[serde(alias = "_id")]
121 pub id: String,
122 pub organization: String,
123 pub role: String,
124 pub status: String,
125 pub user: SimpleUser,
126 #[serde(flatten)]
127 pub audit: Audit,
128}
129
130pub struct UpdateOrganizationMembershipRequest {
131 pub base_url: String,
133 pub organization_id: String,
134 pub membership_id: String,
135 pub role: String,
136}
137
138#[derive(Deserialize)]
139pub struct UpdateOrganizationMembershipResponse {
140 pub membership: OrganizationMembership,
141}
142
143pub struct DeleteOrganizationMembershipRequest {
144 pub base_url: String,
146 pub organization_id: String,
147 pub membership_id: String,
148}
149
150pub struct DeleteOrganizationMembershipResponse {
151 pub membership: OrganizationMembership,
152}
153
154pub struct GetProjectsRequest {
155 pub base_url: String,
157 pub organization_id: String,
158}
159
160#[derive(Deserialize)]
161pub struct GetProjectsResponse {
162 pub workspaces: Vec<Workspace>,
163}
164
165#[derive(Deserialize)]
166pub struct Workspace {
167 #[serde(alias = "_id")]
168 pub id: String,
169 pub name: String,
170 pub organization: String,
171 pub environments: Vec<Environment>,
172}
173
174#[derive(Deserialize)]
175pub struct Environment {
176 pub name: String,
177 pub slug: String,
178}
179
180pub struct GetProjectMembershipsRequest {
181 pub base_url: String,
182 pub workspace_id: String,
183}
184
185#[derive(Deserialize)]
186pub struct GetProjectMembershipsResponse {
187 pub memberships: Vec<ProjectMembership>,
188}
189
190#[derive(Deserialize)]
191pub struct ProjectMembership {
192 #[serde(alias = "_id")]
193 pub id: String,
194 pub role: String,
195 pub user: SimpleUser,
196 pub workspace: String,
197 #[serde(flatten)]
198 pub audit: Audit,
199 #[serde(alias = "deniedPermissions")]
200 pub denied_permissions: Vec<String>,
201}
202
203pub struct UpdateProjectMembershipRequest {
204 pub base_url: String,
205 pub workspace_id: String,
206 pub membership_id: String,
207 pub role: String,
208}
209
210#[derive(Deserialize)]
211pub struct UpdateProjectMembershipResponse {
212 pub membership: ProjectMembership,
213}
214
215pub struct DeleteProjectMembershipRequest {
216 pub base_url: String,
217 pub workspace_id: String,
218 pub membership_id: String,
219}
220
221#[derive(Deserialize)]
222pub struct DeleteProjectMembershipResponse {
223 pub membership: ProjectMembership,
224}
225
226pub struct GetProjectKeyRequest {
227 pub base_url: String,
228 pub workspace_id: String,
229}
230
231#[derive(Deserialize)]
232#[serde(rename_all = "camelCase")]
233pub struct GetProjectKeyResponse {
234 pub encrypted_key: String,
235 pub nonce: String,
236 pub sender: Sender,
237 pub receiver: String,
238 pub workspace: String,
239}
240
241#[derive(Deserialize)]
242pub struct Sender {
243 #[serde(alias = "publicKey")]
244 pub public_key: String,
245}
246
247pub struct GetProjectLogsRequest {
248 pub base_url: String,
249 pub workspace_id: String,
250 pub user_id: String,
251 pub offset: String,
252 pub limit: String,
253 pub sort_by: String,
254 pub action_names: String,
255}
256
257#[derive(Deserialize)]
258pub struct GetProjectLogsResponse {
259 pub logs: Vec<ProjectLog>,
260}
261
262#[derive(Deserialize)]
263pub struct ProjectLog {
264 #[serde(alias = "_id")]
265 pub id: String,
266 pub user: SimpleUser,
268 pub workspace: String,
269 #[serde(alias = "actionNames")]
270 pub action_names: Vec<String>,
271 pub actions: Vec<ProjectLogAction>,
272 pub channel: String,
273 #[serde(alias = "ipAddress")]
274 pub ip_address: String,
275 #[serde(flatten)]
276 pub audit: Audit,
277}
278
279#[derive(Deserialize)]
280pub struct ProjectLogAction {
281 pub name: String,
282 pub user: String,
283 pub workspace: String,
284 pub payload: Vec<ProjectLogActionPayload>,
285}
286
287#[derive(Deserialize)]
288pub struct ProjectLogActionPayload {
289 #[serde(alias = "oldSecretVersion")]
290 pub old_secret_version: String,
291 #[serde(alias = "newSecretVersion")]
292 pub new_secret_version: String,
293}
294
295#[derive(Serialize)]
296pub struct GetProjectSnapshotsRequest {
297 #[serde(skip)]
298 pub base_url: String,
299 #[serde(skip)]
300 pub workspace_id: String,
301 pub offset: String,
302 pub limit: String,
303}
304
305#[derive(Deserialize)]
306pub struct GetProjectSnapshotsResponse {
307 #[serde(alias = "secretSnapshots")]
308 pub secret_snapshots: Vec<SecretSnapshot>,
309}
310
311#[derive(Deserialize)]
312pub struct SecretSnapshot {
313 #[serde(alias = "_id")]
314 pub id: String,
315 pub workspace: String,
316 pub version: u8,
317 #[serde(alias = "secretVersions")]
318 pub secret_versions: Vec<String>,
319}
320
321#[derive(Deserialize)]
322pub struct ProjectSecretVersion {
323 #[serde(alias = "_id")]
324 pub id: String,
325}
326
327pub struct RollbackProjectToSnapshotRequest {
328 pub base_url: String,
329 pub workspace_id: String,
330 pub version: u8,
331}
332
333#[derive(Deserialize)]
334pub struct RollbackProjectToSnapshotResponse {
335 pub secrets: Vec<EncryptedSecret>,
336}
337
338#[derive(Deserialize)]
339pub struct RollbackSecret {
340 #[serde(alias = "_id")]
341 pub id: String,
342 pub version: u8,
343 pub workspace: String,
344 #[serde(alias = "type")]
345 pub secret_type: Option<String>,
346 #[serde(skip_serializing_if = "Option::is_none")]
347 pub user: Option<SimpleUser>,
348 #[serde(flatten)]
349 pub encrypted_secret: EncryptedSecret,
350 #[serde(flatten)]
351 pub audit: Audit,
352}
353
354#[derive(Serialize)]
355pub struct CreateProjectSecretsRequest {
356 pub base_url: String,
357 #[serde(rename = "workspaceId")]
358 pub workspace_id: String,
359 pub environment: String,
360 pub secrets: Vec<SecretToCreate>,
361}
362
363#[derive(Serialize)]
364pub struct SecretToCreate {
365 #[serde(rename = "type")]
366 pub secret_type: String,
367 #[serde(flatten)]
368 pub key: EncryptedKey,
369 #[serde(flatten)]
370 pub value: EncryptedValue,
371 #[serde(flatten)]
372 pub comment: EncryptedComment,
373}
374
375#[derive(Deserialize)]
376pub struct CreateProjectSecretsResponse {
377 pub secrets: Vec<EncryptedSecret>,
378}
379
380pub struct UpdateSecretsRequest {
381 pub base_url: String,
382 pub secrets: Vec<SecretToUpdate>,
383}
384
385#[derive(Serialize)]
386pub struct SecretToUpdate {
387 pub id: String,
388 #[serde(flatten)]
389 pub key: EncryptedKey,
390 #[serde(flatten)]
391 pub value: EncryptedValue,
392}
393
394#[derive(Deserialize)]
395pub struct UpdateSecretsResponse {
396 pub secrets: Vec<EncryptedSecret>,
397}
398
399#[derive(Serialize, Debug)]
400#[serde(rename_all = "camelCase")]
401pub struct GetProjectSecretsRequest {
402 #[serde(skip)]
403 pub base_url: String,
404 pub workspace_id: String,
405 pub environment: String,
406 pub content: String,
407}
408
409#[derive(Deserialize)]
410pub struct GetProjectSecretsResponse {
411 pub secrets: Vec<EncryptedSecret>,
412}
413
414pub struct DeleteProjectSecretsRequest {
415 pub base_url: String,
416 pub secret_ids: Vec<String>,
417}
418
419#[derive(Deserialize)]
420pub struct DeleteProjectSecretsResponse {
421 pub secrets: Vec<EncryptedSecret>,
422}
423
424pub struct GetProjectSecretVersionsRequest {
425 pub base_url: String,
426 pub secret_id: String,
427 pub offset: String,
428 pub limit: String,
429}
430
431#[derive(Deserialize)]
432pub struct GetProjectSecretVersionsResponse {
433 #[serde(alias = "secretVersions")]
434 pub secret_versions: Vec<SecretVersion>,
435}
436
437#[derive(Deserialize)]
438pub struct SecretVersion {
439 pub tags: Vec<String>,
440 #[serde(alias = "_id")]
441 pub id: String,
442 pub secret: String,
443 pub version: u8,
444 pub workspace: String,
445 #[serde(alias = "type")]
446 pub secret_type: String,
447 pub environment: String,
448 #[serde(alias = "isDeleted")]
449 pub is_deleted: bool,
450 #[serde(flatten)]
451 pub key: EncryptedKey,
452 #[serde(flatten)]
453 pub value: EncryptedValue,
454 #[serde(alias = "__v")]
455 pub v: u8,
456 #[serde(flatten)]
457 pub audit: Audit,
458}
459
460pub struct RollbackProjectSecretToVersionRequest {
461 pub base_url: String,
462 pub secret_id: String,
463 pub version: u8,
464}
465
466pub struct RollbackProjectSecretToVersionResponse {
467 pub secret: EncryptedSecret,
468}
469
470#[derive(Deserialize)]
471pub struct EncryptedSecret {
472 #[serde(alias = "_id")]
473 pub id: String,
474 pub version: u8,
475 pub workspace: String,
476 #[serde(alias = "type")]
477 pub type_name: String,
478 #[serde(flatten)]
479 pub key: EncryptedKey,
480 #[serde(flatten)]
481 pub value: EncryptedValue,
482 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
483 pub comment: Option<EncryptedComment>,
484 #[serde(flatten)]
486 pub audit: Audit,
487}
488
489#[derive(Deserialize)]
490pub struct SecretTag {
491 tag: String,
492 slug: String,
493}
494
495#[derive(Debug)]
496pub struct DecryptedSecret {
497 pub id: String,
498 pub version: u8,
499 pub workspace: String,
500 pub type_name: String,
501 pub key: String,
502 pub value: String,
503 pub comment: Option<String>,
504 pub audit: Audit,
505}
506
507impl EncryptedSecret {
508 pub fn decrypt(secret: &EncryptedSecret, private_key: &str) -> Result<DecryptedSecret> {
509 let mut comment = None::<String>;
510 let key = decrypt(
511 &secret.key.ciphertext,
512 &secret.key.iv,
513 &secret.key.tag,
514 private_key,
515 )?;
516 let value = decrypt(
517 &secret.value.ciphertext,
518 &secret.value.iv,
519 &secret.value.tag,
520 private_key,
521 )?;
522
523 if let Some(encrypted_comment) = &secret.comment {
524 comment = Some(decrypt(
525 &encrypted_comment.ciphertext,
526 &encrypted_comment.iv,
527 &encrypted_comment.tag,
528 private_key,
529 )?);
530 }
531
532 Ok(DecryptedSecret {
533 id: secret.id.clone(),
534 version: secret.version,
535 workspace: secret.workspace.clone(),
536 type_name: secret.type_name.clone(),
537 key,
538 value,
539 comment,
540 audit: secret.audit.clone(),
541 })
542 }
543}
544
545#[derive(Deserialize, Serialize)]
546pub struct EncryptedKey {
547 #[serde(rename = "secretKeyCiphertext")]
548 pub ciphertext: String,
549 #[serde(rename = "secretKeyIV")]
550 pub iv: String,
551 #[serde(rename = "secretKeyTag")]
552 pub tag: String,
553}
554
555#[derive(Deserialize, Serialize)]
556pub struct EncryptedValue {
557 #[serde(rename = "secretValueCiphertext")]
558 pub ciphertext: String,
559 #[serde(rename = "secretValueIV")]
560 pub iv: String,
561 #[serde(rename = "secretValueTag")]
562 pub tag: String,
563}
564
565#[derive(Deserialize, Serialize)]
566pub struct EncryptedComment {
567 #[serde(rename = "secretCommentCiphertext")]
568 pub ciphertext: String,
569 #[serde(rename = "secretCommentIV")]
570 pub iv: String,
571 #[serde(rename = "secretCommentTag")]
572 pub tag: String,
573}
574
575impl From<Encryption> for EncryptedComment {
576 fn from(encryption: Encryption) -> EncryptedComment {
577 EncryptedComment {
578 ciphertext: encryption.text,
579 tag: encryption.tag,
580 iv: encryption.nonce,
581 }
582 }
583}
584
585impl From<Encryption> for EncryptedValue {
586 fn from(encryption: Encryption) -> EncryptedValue {
587 EncryptedValue {
588 ciphertext: encryption.text,
589 tag: encryption.tag,
590 iv: encryption.nonce,
591 }
592 }
593}
594
595impl From<Encryption> for EncryptedKey {
596 fn from(encryption: Encryption) -> EncryptedKey {
597 EncryptedKey {
598 ciphertext: encryption.text,
599 tag: encryption.tag,
600 iv: encryption.nonce,
601 }
602 }
603}
604
605#[derive(Deserialize, Clone, Debug)]
606#[serde(rename_all = "camelCase")]
607pub struct Audit {
608 #[serde(with = "iso8601")]
609 pub updated_at: OffsetDateTime,
610 #[serde(with = "iso8601")]
611 pub created_at: OffsetDateTime,
612}
613
614pub struct GetServiceTokensRequest {
615 pub base_url: String,
616}
617
618#[derive(Deserialize)]
619#[serde(rename_all = "camelCase")]
620pub struct GetServiceTokensResponse {
621 pub service_token_data: ServiceToken,
622}
623
624#[derive(Deserialize)]
625#[serde(rename_all = "camelCase")]
626pub struct ServiceToken {
627 #[serde(alias = "_id")]
628 pub id: String,
629 pub name: String,
630 pub workspace: String,
631 pub environment: String,
632 pub user: SimpleUser,
635 #[serde(with = "iso8601")]
636 pub expires_at: OffsetDateTime,
637 pub encrypted_key: String,
638 pub iv: String,
639 pub tag: String,
640 #[serde(flatten)]
641 pub audit: Audit,
642}
643
644#[derive(Deserialize, Debug)]
645pub struct ErrorResponse {
646 #[serde(alias = "type")]
647 pub type_name: String,
648 pub message: String,
649 pub context: HashMap<String, Value>,
650 pub level: i16,
651 pub level_name: String,
652 pub status_code: i16,
653 pub datetime_iso: String,
654 pub application: String,
655 pub extra: Vec<String>,
656}