1use serde::{Deserialize, Serialize};
2use serde_json::{Map, Value};
3
4pub const AUTH_LEASE_VERSION: i32 = 1;
5pub const AUTH_LEASE_PROTOCOL_VERSION: i32 = 1;
6pub const AUTH_LEASE_ALG_ES256: &str = "ES256";
7pub const AUTH_LEASE_TYP: &str = "syncular-auth-lease+jws";
8
9pub const AUTH_LEASE_CODE_MISSING: &str = "sync.auth_lease_missing";
10pub const AUTH_LEASE_CODE_INVALID: &str = "sync.auth_lease_invalid";
11pub const AUTH_LEASE_CODE_EXPIRED: &str = "sync.auth_lease_expired";
12pub const AUTH_LEASE_CODE_SCHEMA_MISMATCH: &str = "sync.auth_lease_schema_mismatch";
13pub const AUTH_LEASE_CODE_SCOPE_MISMATCH: &str = "sync.auth_lease_scope_mismatch";
14pub const AUTH_LEASE_CODE_SCOPE_REVOKED: &str = "sync.auth_lease_scope_revoked";
15pub const AUTH_LEASE_CODE_BUSINESS_REJECTED: &str = "sync.auth_lease_business_rejected";
16
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
18#[serde(rename_all = "camelCase")]
19pub struct AuthLeaseProtectedHeader {
20 pub alg: String,
21 pub kid: String,
22 pub typ: String,
23}
24
25impl AuthLeaseProtectedHeader {
26 pub fn es256(kid: impl Into<String>) -> Self {
27 Self {
28 alg: AUTH_LEASE_ALG_ES256.to_string(),
29 kid: kid.into(),
30 typ: AUTH_LEASE_TYP.to_string(),
31 }
32 }
33}
34
35#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
36#[serde(rename_all = "camelCase")]
37pub struct AuthLeasePayload {
38 pub version: i32,
39 pub lease_id: String,
40 pub issuer: String,
41 pub audience: String,
42 pub actor_id: String,
43 #[serde(default, skip_serializing_if = "Map::is_empty")]
44 pub subject: Map<String, Value>,
45 pub schema_version: i32,
46 pub protocol_version: i32,
47 pub issued_at_ms: i64,
48 pub not_before_ms: i64,
49 pub expires_at_ms: i64,
50 pub max_clock_skew_ms: i64,
51 pub scopes: Vec<AuthLeaseScope>,
52 pub capabilities: AuthLeaseCapabilities,
53}
54
55#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
56#[serde(rename_all = "camelCase")]
57pub struct AuthLeaseScope {
58 pub subscription_id: String,
59 pub table: String,
60 pub values: Map<String, Value>,
61 pub operations: Vec<String>,
62}
63
64#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
65#[serde(rename_all = "camelCase")]
66pub struct AuthLeaseIssueRequest {
67 pub schema_version: i32,
68 #[serde(skip_serializing_if = "Option::is_none")]
69 pub ttl_ms: Option<i64>,
70 pub scopes: Vec<AuthLeaseScope>,
71}
72
73#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
74#[serde(rename_all = "camelCase")]
75pub struct AuthLeaseIssueResponse {
76 pub ok: bool,
77 pub token: String,
78 pub protected_header: AuthLeaseProtectedHeader,
79 pub payload: AuthLeasePayload,
80}
81
82#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
83#[serde(rename_all = "camelCase")]
84pub struct AuthLeaseCapabilities {
85 pub allow_blobs: bool,
86 pub allow_crdt: bool,
87 pub allow_encrypted_fields: bool,
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
91#[serde(rename_all = "camelCase")]
92pub struct AuthLeaseValidationResult {
93 pub ok: bool,
94 #[serde(rename = "leaseId", skip_serializing_if = "Option::is_none")]
95 pub lease_id: Option<String>,
96 #[serde(skip_serializing_if = "Option::is_none")]
97 pub kid: Option<String>,
98 #[serde(skip_serializing_if = "Option::is_none")]
99 pub code: Option<String>,
100 #[serde(skip_serializing_if = "Option::is_none")]
101 pub message: Option<String>,
102 #[serde(rename = "expiresAtMs", skip_serializing_if = "Option::is_none")]
103 pub expires_at_ms: Option<i64>,
104}
105
106impl AuthLeaseValidationResult {
107 pub fn accepted(
108 lease_id: impl Into<String>,
109 kid: impl Into<String>,
110 expires_at_ms: i64,
111 ) -> Self {
112 Self {
113 ok: true,
114 lease_id: Some(lease_id.into()),
115 kid: Some(kid.into()),
116 code: None,
117 message: None,
118 expires_at_ms: Some(expires_at_ms),
119 }
120 }
121
122 pub fn rejected(code: impl Into<String>, message: impl Into<String>) -> Self {
123 Self {
124 ok: false,
125 lease_id: None,
126 kid: None,
127 code: Some(code.into()),
128 message: Some(message.into()),
129 expires_at_ms: None,
130 }
131 }
132}
133
134#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
135#[serde(rename_all = "camelCase")]
136pub struct AuthLeaseProvenance {
137 pub lease_id: String,
138 pub lease_expires_at_ms: i64,
139 pub lease_status_at_enqueue: String,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 pub lease_scope_summary_json: Option<String>,
142 #[serde(rename = "leaseToken", skip_serializing_if = "Option::is_none")]
143 pub lease_token: Option<String>,
144}