JMAP/changes: Update newState with last changeId if an invalid fromChangeId is provided

This commit is contained in:
mdecimus
2026-01-19 07:53:29 -03:00
parent 1fbc7c04bf
commit 4b661d5d1f
2 changed files with 33 additions and 38 deletions

View File

@@ -199,7 +199,6 @@ fn validate_identity_value(
identity: &mut ParticipantIdentity, identity: &mut ParticipantIdentity,
allowed_emails: &AHashSet<String>, allowed_emails: &AHashSet<String>,
) -> Result<(), SetError<ParticipantIdentityProperty>> { ) -> Result<(), SetError<ParticipantIdentityProperty>> {
let mut changed_address = None;
for (property, value) in update.into_expanded_object() { for (property, value) in update.into_expanded_object() {
let Key::Property(property) = property else { let Key::Property(property) = property else {
return Err(SetError::invalid_properties() return Err(SetError::invalid_properties()
@@ -213,7 +212,27 @@ fn validate_identity_value(
} }
(ParticipantIdentityProperty::CalendarAddress, Value::Str(value)) => { (ParticipantIdentityProperty::CalendarAddress, Value::Str(value)) => {
if identity.calendar_address != value { if identity.calendar_address != value {
changed_address = Some(value); let email = if let Some(email) = value.strip_prefix("mailto:") {
sanitize_email(email)
} else {
sanitize_email(&value)
};
if let Some(email) = email {
if allowed_emails.iter().any(|e| e == &email) {
identity.calendar_address = format!("mailto:{email}");
} else {
return Err(SetError::invalid_properties()
.with_property(ParticipantIdentityProperty::CalendarAddress)
.with_description(
"Calendar address not configured for this account.".to_string(),
));
}
} else {
return Err(SetError::invalid_properties()
.with_property(ParticipantIdentityProperty::CalendarAddress)
.with_description("Invalid or missing calendar address.".to_string()));
}
} }
} }
(property, _) => { (property, _) => {
@@ -223,34 +242,10 @@ fn validate_identity_value(
} }
} }
} }
// Validate email address // Validate email address
if !identity.calendar_address.is_empty() { if !identity.calendar_address.is_empty() {
if let Some(new_address) = changed_address { Ok(())
let email = if let Some(email) = new_address.strip_prefix("mailto:") {
sanitize_email(email)
} else {
sanitize_email(&new_address)
};
if let Some(email) = email {
if allowed_emails.iter().any(|e| e == &email) {
identity.calendar_address = format!("mailto:{email}");
Ok(())
} else {
Err(SetError::invalid_properties()
.with_property(ParticipantIdentityProperty::CalendarAddress)
.with_description(
"Calendar address not configured for this account.".to_string(),
))
}
} else {
Err(SetError::invalid_properties()
.with_property(ParticipantIdentityProperty::CalendarAddress)
.with_description("Invalid or missing calendar address.".to_string()))
}
} else {
Ok(())
}
} else { } else {
Err(SetError::invalid_properties() Err(SetError::invalid_properties()
.with_property(ParticipantIdentityProperty::CalendarAddress) .with_property(ParticipantIdentityProperty::CalendarAddress)

View File

@@ -63,14 +63,14 @@ impl Store {
pub async fn changes( pub async fn changes(
&self, &self,
account_id: u32, account_id: u32,
collection: LogCollection, collection_: LogCollection,
query: Query, query: Query,
) -> trc::Result<Changes> { ) -> trc::Result<Changes> {
let is_share_log = matches!( let is_share_log = matches!(
collection, collection_,
LogCollection::Sync(SyncCollection::ShareNotification) LogCollection::Sync(SyncCollection::ShareNotification)
); );
let collection = u8::from(collection); let collection = u8::from(collection_);
let (is_inclusive, from_change_id, to_change_id) = match query { let (is_inclusive, from_change_id, to_change_id) = match query {
Query::All => (true, 0, u64::MAX), Query::All => (true, 0, u64::MAX),
@@ -127,13 +127,13 @@ impl Store {
.await .await
.caused_by(trc::location!())?; .caused_by(trc::location!())?;
if changelog.changes.is_empty() { // A non-existing change id was requested, return the last change id
changelog.from_change_id = from_change_id; if changelog.changes.is_empty() && from_change_id != 0 && changelog.from_change_id == 0 {
changelog.to_change_id = if to_change_id != u64::MAX { changelog.from_change_id = self
to_change_id .get_last_change_id(account_id, collection_)
} else { .await?
from_change_id .unwrap_or_default();
}; changelog.to_change_id = changelog.from_change_id;
} }
Ok(changelog) Ok(changelog)