diff --git a/backend/canisters/user_index/CHANGELOG.md b/backend/canisters/user_index/CHANGELOG.md index 7870e2549f..9737a497bd 100644 --- a/backend/canisters/user_index/CHANGELOG.md +++ b/backend/canisters/user_index/CHANGELOG.md @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [unreleased] +### Changed + +- Log error if any users have duplicate usernames or principals ([#5645](https://github.com/open-chat-labs/open-chat/pull/5645)) + ## [[2.0.1129](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.1129-user_index)] - 2024-04-05 ### Added diff --git a/backend/canisters/user_index/impl/src/lifecycle/post_upgrade.rs b/backend/canisters/user_index/impl/src/lifecycle/post_upgrade.rs index 4edf400e09..0d46d1a7a2 100644 --- a/backend/canisters/user_index/impl/src/lifecycle/post_upgrade.rs +++ b/backend/canisters/user_index/impl/src/lifecycle/post_upgrade.rs @@ -1,11 +1,11 @@ use crate::lifecycle::{init_env, init_state}; use crate::memory::get_upgrades_memory; -use crate::Data; +use crate::{read_state, Data}; use canister_logger::LogEntry; use canister_tracing_macros::trace; use ic_cdk_macros::post_upgrade; use stable_memory::get_reader; -use tracing::info; +use tracing::{error, info}; use user_index_canister::post_upgrade::Args; use utils::cycles::init_cycles_dispenser_client; @@ -24,4 +24,30 @@ fn post_upgrade(args: Args) { init_state(env, data, args.wasm_version); info!(version = %args.wasm_version, "Post-upgrade complete"); + + read_state(|state| { + let users_with_duplicate_usernames: Vec<_> = state + .data + .users + .users_with_duplicate_usernames + .iter() + .map(|(u1, u2)| (u1.to_string(), u2.to_string())) + .collect(); + + let users_with_duplicate_principals: Vec<_> = state + .data + .users + .users_with_duplicate_principals + .iter() + .map(|(u1, u2)| (u1.to_string(), u2.to_string())) + .collect(); + + if !users_with_duplicate_usernames.is_empty() { + error!(?users_with_duplicate_usernames); + } + + if !users_with_duplicate_principals.is_empty() { + error!(?users_with_duplicate_principals); + } + }) } diff --git a/backend/canisters/user_index/impl/src/model/user_map.rs b/backend/canisters/user_index/impl/src/model/user_map.rs index a57c703384..45c6b13daf 100644 --- a/backend/canisters/user_index/impl/src/model/user_map.rs +++ b/backend/canisters/user_index/impl/src/model/user_map.rs @@ -18,6 +18,10 @@ pub struct UserMap { principal_to_user_id: HashMap, #[serde(skip)] user_referrals: HashMap>, + #[serde(skip)] + pub users_with_duplicate_usernames: Vec<(UserId, UserId)>, + #[serde(skip)] + pub users_with_duplicate_principals: Vec<(UserId, UserId)>, suspected_bots: BTreeSet, suspended_or_unsuspended_users: BTreeSet<(TimestampMillis, UserId)>, } @@ -330,8 +334,13 @@ impl From for UserMap { user_map.user_referrals.entry(referred_by).or_default().push(*user_id); } - user_map.username_to_user_id.insert(&user.username, *user_id); - user_map.principal_to_user_id.insert(user.principal, *user_id); + if let Some(other_user_id) = user_map.username_to_user_id.insert(&user.username, *user_id) { + user_map.users_with_duplicate_usernames.push((*user_id, other_user_id)); + } + + if let Some(other_user_id) = user_map.principal_to_user_id.insert(user.principal, *user_id) { + user_map.users_with_duplicate_principals.push((*user_id, other_user_id)); + } } user_map