Skip to content

Commit 47e1b06

Browse files
rrwang7Convex, Inc.
authored andcommitted
support any valid json values in custom claims (#28563)
GitOrigin-RevId: c9425165bc45f3f5d40ce008ac15cf9842433f17
1 parent e7ca3ee commit 47e1b06

File tree

3 files changed

+42
-10
lines changed

3 files changed

+42
-10
lines changed

sync_types/src/json.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ struct UserIdentityAttributesJson {
790790
#[serde(skip_serializing_if = "Option::is_none")]
791791
pub updated_at: Option<String>,
792792
#[serde(flatten)]
793-
pub custom_claims: Option<BTreeMap<String, String>>,
793+
pub custom_claims: Option<BTreeMap<String, JsonValue>>,
794794
}
795795

796796
impl TryFrom<JsonValue> for UserIdentityAttributes {
@@ -808,6 +808,13 @@ impl TryFrom<JsonValue> for UserIdentityAttributes {
808808
let custom_claims = raw
809809
.custom_claims
810810
.context("expected custom claims to be set")?;
811+
let custom_claims_string = custom_claims
812+
.into_iter()
813+
.map(|(key, value)| {
814+
let value_string = serde_json::to_string(&value)?;
815+
Ok((key, value_string))
816+
})
817+
.collect::<anyhow::Result<_>>()?;
811818

812819
Ok(UserIdentityAttributes {
813820
token_identifier,
@@ -831,7 +838,7 @@ impl TryFrom<JsonValue> for UserIdentityAttributes {
831838
phone_number_verified: raw.phone_number_verified,
832839
address: raw.address,
833840
updated_at: raw.updated_at,
834-
custom_claims,
841+
custom_claims: custom_claims_string,
835842
})
836843
}
837844
}
@@ -840,6 +847,14 @@ impl TryFrom<UserIdentityAttributes> for JsonValue {
840847
type Error = anyhow::Error;
841848

842849
fn try_from(value: UserIdentityAttributes) -> Result<Self, Self::Error> {
850+
let custom_claims_json = value
851+
.custom_claims
852+
.into_iter()
853+
.map(|(key, value)| {
854+
let value_json = serde_json::from_str(&value)?;
855+
Ok((key, value_json))
856+
})
857+
.collect::<anyhow::Result<_>>()?;
843858
let raw = UserIdentityAttributesJson {
844859
token_identifier: Some(value.token_identifier),
845860
issuer: value.issuer,
@@ -862,7 +877,7 @@ impl TryFrom<UserIdentityAttributes> for JsonValue {
862877
phone_number_verified: value.phone_number_verified,
863878
address: value.address,
864879
updated_at: value.updated_at,
865-
custom_claims: Some(value.custom_claims),
880+
custom_claims: Some(custom_claims_json),
866881
};
867882
Ok(serde_json::to_value(raw)?)
868883
}

sync_types/src/testing.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ pub fn arb_json() -> impl Strategy<Value = JsonValue> {
2222
".*".prop_map(JsonValue::String),
2323
];
2424
leaf.prop_recursive(
25-
8, // 8 levels deep
26-
256, // Shoot for maximum size of 256 nodes
27-
10, // We put up to 10 items per collection
25+
4, // 4 levels deep
26+
128, // Shoot for maximum size of 128 nodes
27+
5, // We put up to 5 items per collection
2828
|inner| {
2929
prop_oneof![
3030
// Take the inner strategy and make the two recursive cases.
31-
prop::collection::vec(inner.clone(), 0..10).prop_map(JsonValue::Array),
32-
prop::collection::hash_map(".*", inner, 0..10)
31+
prop::collection::vec(inner.clone(), 0..5).prop_map(JsonValue::Array),
32+
prop::collection::hash_map(".*", inner, 0..5)
3333
.prop_map(|m| JsonValue::Object(m.into_iter().collect())),
3434
]
3535
},

sync_types/src/types.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use serde::{
1717
use serde_json::Value as JsonValue;
1818
use uuid::Uuid;
1919

20+
#[cfg(any(test, feature = "testing"))]
21+
use crate::testing::arb_json;
2022
use crate::{
2123
Timestamp,
2224
UdfPath,
@@ -51,7 +53,17 @@ pub type IdentityVersion = u32;
5153
/// it's good enough for our tests here.
5254
#[cfg(any(test, feature = "testing"))]
5355
fn string_json_args_strategy() -> impl proptest::strategy::Strategy<Value = Vec<JsonValue>> {
54-
Vec::<String>::arbitrary().prop_map(|v| v.iter().map(|s| JsonValue::String(s.into())).collect())
56+
prop::collection::vec(any::<String>(), 0..2)
57+
.prop_map(|v| v.iter().map(|s| JsonValue::String(s.into())).collect())
58+
}
59+
60+
#[cfg(any(test, feature = "testing"))]
61+
fn custom_claims_strategy() -> impl proptest::strategy::Strategy<Value = BTreeMap<String, String>> {
62+
prop::collection::btree_map(
63+
any::<String>(),
64+
arb_json().prop_map(|v| serde_json::to_string(&v).unwrap()),
65+
0..2,
66+
)
5567
}
5668

5769
/// This strategy only generates a string (not arbitrary JSON) but
@@ -102,7 +114,7 @@ pub enum ClientMessage {
102114
new_version: QuerySetVersion,
103115
#[cfg_attr(
104116
any(test, feature = "testing"),
105-
proptest(strategy = "prop::collection::vec(any::<QuerySetModification>(), 0..8)")
117+
proptest(strategy = "prop::collection::vec(any::<QuerySetModification>(), 0..2)")
106118
)]
107119
modifications: Vec<QuerySetModification>,
108120
},
@@ -194,6 +206,11 @@ pub struct UserIdentityAttributes {
194206
pub address: Option<String>,
195207
/// Stored as RFC3339 string
196208
pub updated_at: Option<String>,
209+
210+
#[cfg_attr(
211+
any(test, feature = "testing"),
212+
proptest(strategy = "custom_claims_strategy()")
213+
)]
197214
pub custom_claims: BTreeMap<String, String>,
198215
}
199216

0 commit comments

Comments
 (0)