infisical_api/api/
models.rs

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/// An enum that represents the possible return values from the Infisical API
12///
13/// Infisical returns a 200 response even for errors on their side, but do provide a JSON response
14/// with traditional HTTP response codes and additional error information.
15#[derive(Deserialize)]
16#[serde(untagged)]
17pub enum ApiResponse<T> {
18    Ok(T),
19    Err(ErrorResponse),
20}
21
22/// Represents the expected request body for the `/v2/users/me` endpoint
23pub struct GetMyUserRequest {
24    /// The base url for the Infisical API
25    pub base_url: String,
26}
27
28/// Represents the successful response for the `/v2/users/me` endpoint
29#[derive(Deserialize)]
30pub struct GetMyUserResponse {
31    /// The Infisical user contained in the response
32    pub user: User,
33}
34
35/// An Infisical user representation
36#[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    /// The base url for the Infisical API
88    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    /// The base url for the Infisical API
109    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    /// The base url for the Infisical API
132    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    /// The base url for the Infisical API
145    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    /// The base url for the Infisical API
156    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    // This user does not have all fields that the User struct expects
267    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    // pub tags: Vec<SecretTag>,
485    #[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    // Current documentation does not claim a SimpleUser is returned, however the endpoint is not
633    // working for me so this is a placeholder until functionality is verified
634    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}