mz_catalog/durable/upgrade/
v77_to_v78.rs1use crate::durable::upgrade::MigrationAction;
11use crate::durable::upgrade::objects_v77 as v77;
12use base64::prelude::*;
13use mz_ore::now::SYSTEM_TIME;
14
15fn migrate_scram_client_to_stored(hash_old: &str) -> Option<String> {
18 let parts: Vec<&str> = hash_old.split('$').collect();
19 if parts.len() != 3 || parts[0] != "SCRAM-SHA-256" {
20 return None;
21 }
22 let iters_salt = parts[1];
23 let key_parts: Vec<&str> = parts[2].split(':').collect();
24 if key_parts.len() != 2 {
25 return None;
26 }
27 let first_key_b64 = key_parts[0];
28 let server_key_b64 = key_parts[1];
29
30 let Ok(first_key) = BASE64_STANDARD.decode(first_key_b64) else {
31 tracing::warn!("failed to decode base64 client key during scram migration");
32 return None;
33 };
34 if first_key.len() != 32 {
35 tracing::warn!("unexpected client key length during scram migration");
36 return None;
37 }
38
39 let stored_key = openssl::sha::sha256(&first_key);
40 let stored_key_b64 = BASE64_STANDARD.encode(stored_key);
41
42 Some(format!(
43 "SCRAM-SHA-256${}${}:{}",
44 iters_salt, stored_key_b64, server_key_b64
45 ))
46}
47
48pub fn upgrade(
49 snapshot: Vec<v77::StateUpdateKind>,
50) -> Vec<MigrationAction<v77::StateUpdateKind, v77::StateUpdateKind>> {
51 let mut migrations = Vec::new();
52 for update in snapshot {
53 match update.kind {
54 Some(v77::state_update_kind::Kind::RoleAuth(old_role_auth)) => {
55 let Some(ref value) = old_role_auth.value else {
56 continue;
57 };
58 let Some(ref hashed_password) = value.password_hash else {
59 continue;
60 };
61 let Some(new_hash) = migrate_scram_client_to_stored(hashed_password) else {
62 continue;
63 };
64
65 let new_role_auth = v77::state_update_kind::RoleAuth {
66 key: old_role_auth.key.clone(),
67 value: Some(v77::RoleAuthValue {
68 password_hash: Some(new_hash),
69 updated_at: Some(v77::EpochMillis {
70 millis: SYSTEM_TIME(),
71 }),
72 }),
73 };
74 let old_role_auth = v77::StateUpdateKind {
75 kind: Some(v77::state_update_kind::Kind::RoleAuth(old_role_auth)),
76 };
77 let new_role_auth = v77::StateUpdateKind {
78 kind: Some(v77::state_update_kind::Kind::RoleAuth(new_role_auth)),
79 };
80 let migration = MigrationAction::Update(old_role_auth, new_role_auth);
81 migrations.push(migration);
82 }
83 _ => {}
84 }
85 }
86 migrations
87}