Skip to content

Commit 84587e5

Browse files
committed
Merge branches 'quenting/syn2mas/reader-writer-owned', 'quenting/syn2mas/ignore-things' and 'quenting/syn2mas/ignore-as-users' into quenting/syn2mas/merge-base
3 parents 65b3741 + 1c99829 + 2385d09 commit 84587e5

File tree

3 files changed

+48
-35
lines changed

3 files changed

+48
-35
lines changed

crates/syn2mas/src/migration.rs

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ bitflags::bitflags! {
7474
const IS_SYNAPSE_ADMIN = 0b0000_0001;
7575
const IS_DEACTIVATED = 0b0000_0010;
7676
const IS_GUEST = 0b0000_0100;
77+
const IS_APPSERVICE = 0b0000_1000;
7778
}
7879
}
7980

@@ -89,6 +90,10 @@ impl UserFlags {
8990
const fn is_synapse_admin(self) -> bool {
9091
self.contains(UserFlags::IS_SYNAPSE_ADMIN)
9192
}
93+
94+
const fn is_appservice(self) -> bool {
95+
self.contains(UserFlags::IS_APPSERVICE)
96+
}
9297
}
9398

9499
#[derive(Debug, Clone, Copy)]
@@ -188,6 +193,20 @@ async fn migrate_users(
188193
if bool::from(user.is_guest) {
189194
flags |= UserFlags::IS_GUEST;
190195
}
196+
if user.appservice_id.is_some() {
197+
flags |= UserFlags::IS_APPSERVICE;
198+
199+
// Special case for appservice users: we don't insert them into the database
200+
// We just record the user's information in the state and continue
201+
state.users.insert(
202+
CompactString::new(&mas_user.username),
203+
UserInfo {
204+
mas_user_id: Uuid::nil(),
205+
flags,
206+
},
207+
);
208+
continue;
209+
}
191210

192211
state.users.insert(
193212
CompactString::new(&mas_user.username),
@@ -247,15 +266,16 @@ async fn migrate_threepids(
247266
.into_extract_localpart(synapse_user_id.clone())?
248267
.to_owned();
249268
let Some(user_infos) = state.users.get(username.as_str()).copied() else {
250-
if is_likely_appservice(&username) {
251-
continue;
252-
}
253269
return Err(Error::MissingUserFromDependentTable {
254270
table: "user_threepids".to_owned(),
255271
user: synapse_user_id,
256272
});
257273
};
258274

275+
if user_infos.flags.is_appservice() {
276+
continue;
277+
}
278+
259279
if medium == "email" {
260280
email_buffer
261281
.write(
@@ -325,15 +345,16 @@ async fn migrate_external_ids(
325345
.into_extract_localpart(synapse_user_id.clone())?
326346
.to_owned();
327347
let Some(user_infos) = state.users.get(username.as_str()).copied() else {
328-
if is_likely_appservice(&username) {
329-
continue;
330-
}
331348
return Err(Error::MissingUserFromDependentTable {
332349
table: "user_external_ids".to_owned(),
333350
user: synapse_user_id,
334351
});
335352
};
336353

354+
if user_infos.flags.is_appservice() {
355+
continue;
356+
}
357+
337358
let Some(&upstream_provider_id) = state.provider_id_mapping.get(&auth_provider) else {
338359
return Err(Error::MissingAuthProviderMapping {
339360
synapse_id: auth_provider,
@@ -403,16 +424,16 @@ async fn migrate_devices(
403424
.into_extract_localpart(synapse_user_id.clone())?
404425
.to_owned();
405426
let Some(user_infos) = state.users.get(username.as_str()).copied() else {
406-
if is_likely_appservice(&username) {
407-
continue;
408-
}
409427
return Err(Error::MissingUserFromDependentTable {
410428
table: "devices".to_owned(),
411429
user: synapse_user_id,
412430
});
413431
};
414432

415-
if user_infos.flags.is_deactivated() || user_infos.flags.is_guest() {
433+
if user_infos.flags.is_deactivated()
434+
|| user_infos.flags.is_guest()
435+
|| user_infos.flags.is_appservice()
436+
{
416437
continue;
417438
}
418439

@@ -428,7 +449,9 @@ async fn migrate_devices(
428449
// As we're using a real IP type in the MAS database, it is possible
429450
// that we encounter invalid IP addresses in the Synapse database.
430451
// In that case, we should ignore them, but still log a warning.
431-
let last_active_ip = ip.and_then(|ip| {
452+
// One special case: Synapse will record '-' as IP in some cases, we don't want
453+
// to log about those
454+
let last_active_ip = ip.filter(|ip| ip != "-").and_then(|ip| {
432455
ip.parse()
433456
.map_err(|e| {
434457
tracing::warn!(
@@ -497,16 +520,16 @@ async fn migrate_unrefreshable_access_tokens(
497520
.into_extract_localpart(synapse_user_id.clone())?
498521
.to_owned();
499522
let Some(user_infos) = state.users.get(username.as_str()).copied() else {
500-
if is_likely_appservice(&username) {
501-
continue;
502-
}
503523
return Err(Error::MissingUserFromDependentTable {
504524
table: "access_tokens".to_owned(),
505525
user: synapse_user_id,
506526
});
507527
};
508528

509-
if user_infos.flags.is_deactivated() || user_infos.flags.is_guest() {
529+
if user_infos.flags.is_deactivated()
530+
|| user_infos.flags.is_guest()
531+
|| user_infos.flags.is_appservice()
532+
{
510533
continue;
511534
}
512535

@@ -609,16 +632,16 @@ async fn migrate_refreshable_token_pairs(
609632
.into_extract_localpart(synapse_user_id.clone())?
610633
.to_owned();
611634
let Some(user_infos) = state.users.get(username.as_str()).copied() else {
612-
if is_likely_appservice(&username) {
613-
continue;
614-
}
615635
return Err(Error::MissingUserFromDependentTable {
616636
table: "refresh_tokens".to_owned(),
617637
user: synapse_user_id,
618638
});
619639
};
620640

621-
if user_infos.flags.is_deactivated() || user_infos.flags.is_guest() {
641+
if user_infos.flags.is_deactivated()
642+
|| user_infos.flags.is_guest()
643+
|| user_infos.flags.is_appservice()
644+
{
622645
continue;
623646
}
624647

@@ -715,15 +738,3 @@ fn transform_user(
715738

716739
Ok((new_user, mas_password))
717740
}
718-
719-
/// Returns true if and only if the given localpart looks like it would belong
720-
/// to an application service user.
721-
/// The rule here is that it must start with an underscore.
722-
/// Synapse reserves these by default, but there is no hard rule prohibiting
723-
/// other namespaces from being reserved, so this is not a robust check.
724-
// TODO replace with a more robust mechanism, if we even care about this sanity check
725-
// e.g. read application service registration files.
726-
#[inline]
727-
fn is_likely_appservice(localpart: &str) -> bool {
728-
localpart.starts_with('_')
729-
}

crates/syn2mas/src/synapse_reader/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl FullUserId {
7373
return Err(ExtractLocalpartError::NoAtSigil);
7474
};
7575

76-
let Some((localpart, server_name)) = without_sigil.split_once(':') else {
76+
let Some((localpart, server_name)) = without_sigil.rsplit_once(':') else {
7777
return Err(ExtractLocalpartError::NoSeparator);
7878
};
7979

@@ -192,6 +192,8 @@ pub struct SynapseUser {
192192
/// account!
193193
pub is_guest: SynapseBool,
194194
// TODO do we care about upgrade_ts (users who upgraded from guest accounts to real accounts)
195+
/// The ID of the appservice that created this user, if any.
196+
pub appservice_id: Option<String>,
195197
}
196198

197199
/// Row of the `user_threepids` table in Synapse.
@@ -369,9 +371,8 @@ impl<'conn> SynapseReader<'conn> {
369371
sqlx::query_as(
370372
"
371373
SELECT
372-
name, password_hash, admin, deactivated, creation_ts, is_guest
374+
name, password_hash, admin, deactivated, creation_ts, is_guest, appservice_id
373375
FROM users
374-
WHERE appservice_id IS NULL
375376
",
376377
)
377378
.fetch(&mut *self.txn)
@@ -416,7 +417,7 @@ impl<'conn> SynapseReader<'conn> {
416417
SELECT
417418
user_id, device_id, display_name, last_seen, ip, user_agent
418419
FROM devices
419-
WHERE NOT hidden
420+
WHERE NOT hidden AND device_id != 'guest_device'
420421
",
421422
)
422423
.fetch(&mut *self.txn)

crates/syn2mas/src/synapse_reader/snapshots/syn2mas__synapse_reader__test__read_users.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ expression: users
2222
is_guest: SynapseBool(
2323
false,
2424
),
25+
appservice_id: None,
2526
},
2627
}

0 commit comments

Comments
 (0)