mirror of
https://github.com/chatmail/core.git
synced 2026-04-28 19:06:35 +03:00
refactor(sql): recreate keypairs table
Removed unused `addr` and `created` field. `is_default` boolean flag is moved into `config` row pointing to the current default key.
This commit is contained in:
@@ -18,7 +18,7 @@ use crate::log::LogExt;
|
||||
use crate::mimefactory::RECOMMENDED_FILE_SIZE;
|
||||
use crate::provider::{get_provider_by_id, Provider};
|
||||
use crate::sync::{self, Sync::*, SyncData};
|
||||
use crate::tools::{get_abs_path, improve_single_line_input, EmailAddress};
|
||||
use crate::tools::{get_abs_path, improve_single_line_input};
|
||||
|
||||
/// The available configuration keys.
|
||||
#[derive(
|
||||
@@ -343,6 +343,10 @@ pub enum Config {
|
||||
/// until `chat_id.accept()` is called.
|
||||
#[strum(props(default = "0"))]
|
||||
VerifiedOneOnOneChats,
|
||||
|
||||
/// Row ID of the key in the `keypairs` table
|
||||
/// used for signatures, encryption to self and included in `Autocrypt` header.
|
||||
KeyId,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -627,8 +631,6 @@ impl Context {
|
||||
///
|
||||
/// This should only be used by test code and during configure.
|
||||
pub(crate) async fn set_primary_self_addr(&self, primary_new: &str) -> Result<()> {
|
||||
let old_addr = self.get_config(Config::ConfiguredAddr).await?;
|
||||
|
||||
// add old primary address (if exists) to secondary addresses
|
||||
let mut secondary_addrs = self.get_all_self_addrs().await?;
|
||||
// never store a primary address also as a secondary
|
||||
@@ -642,17 +644,6 @@ impl Context {
|
||||
self.set_config(Config::ConfiguredAddr, Some(primary_new))
|
||||
.await?;
|
||||
|
||||
if let Some(old_addr) = old_addr {
|
||||
let old_addr = EmailAddress::new(&old_addr)?;
|
||||
let old_keypair = crate::key::load_keypair(self, &old_addr).await?;
|
||||
|
||||
if let Some(mut old_keypair) = old_keypair {
|
||||
old_keypair.addr = EmailAddress::new(primary_new)?;
|
||||
crate::key::store_self_keypair(self, &old_keypair, crate::key::KeyPairUse::Default)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1318,6 +1318,7 @@ mod tests {
|
||||
"socks5_port",
|
||||
"socks5_user",
|
||||
"socks5_password",
|
||||
"key_id",
|
||||
];
|
||||
let t = TestContext::new().await;
|
||||
let info = t.get_info().await.unwrap();
|
||||
|
||||
@@ -670,7 +670,7 @@ async fn export_self_keys(context: &Context, dir: &Path) -> Result<()> {
|
||||
let keys = context
|
||||
.sql
|
||||
.query_map(
|
||||
"SELECT id, public_key, private_key, is_default FROM keypairs;",
|
||||
"SELECT id, public_key, private_key, id=(SELECT value FROM config WHERE keyname='key_id') FROM keypairs;",
|
||||
(),
|
||||
|row| {
|
||||
let id = row.get(0)?;
|
||||
|
||||
76
src/key.rs
76
src/key.rs
@@ -18,7 +18,7 @@ use crate::constants::KeyGenType;
|
||||
use crate::context::Context;
|
||||
use crate::log::LogExt;
|
||||
use crate::pgp::KeyPair;
|
||||
use crate::tools::{time, EmailAddress};
|
||||
use crate::tools::EmailAddress;
|
||||
|
||||
/// Convenience trait for working with keys.
|
||||
///
|
||||
@@ -82,10 +82,9 @@ pub(crate) async fn load_self_public_key(context: &Context) -> Result<SignedPubl
|
||||
match context
|
||||
.sql
|
||||
.query_row_optional(
|
||||
r#"SELECT public_key
|
||||
FROM keypairs
|
||||
WHERE addr=(SELECT value FROM config WHERE keyname="configured_addr")
|
||||
AND is_default=1"#,
|
||||
"SELECT public_key
|
||||
FROM keypairs
|
||||
WHERE id=(SELECT value FROM config WHERE keyname='key_id')",
|
||||
(),
|
||||
|row| {
|
||||
let bytes: Vec<u8> = row.get(0)?;
|
||||
@@ -106,10 +105,9 @@ pub(crate) async fn load_self_secret_key(context: &Context) -> Result<SignedSecr
|
||||
match context
|
||||
.sql
|
||||
.query_row_optional(
|
||||
r#"SELECT private_key
|
||||
FROM keypairs
|
||||
WHERE addr=(SELECT value FROM config WHERE keyname="configured_addr")
|
||||
AND is_default=1"#,
|
||||
"SELECT private_key
|
||||
FROM keypairs
|
||||
WHERE id=(SELECT value FROM config WHERE keyname='key_id')",
|
||||
(),
|
||||
|row| {
|
||||
let bytes: Vec<u8> = row.get(0)?;
|
||||
@@ -132,8 +130,7 @@ pub(crate) async fn load_self_secret_keyring(context: &Context) -> Result<Vec<Si
|
||||
.query_map(
|
||||
r#"SELECT private_key
|
||||
FROM keypairs
|
||||
WHERE addr=(SELECT value FROM config WHERE keyname="configured_addr")
|
||||
ORDER BY is_default DESC"#,
|
||||
ORDER BY id=(SELECT value FROM config WHERE keyname='key_id') DESC"#,
|
||||
(),
|
||||
|row| row.get::<_, Vec<u8>>(0),
|
||||
|keys| keys.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||
@@ -233,13 +230,10 @@ pub(crate) async fn load_keypair(
|
||||
let res = context
|
||||
.sql
|
||||
.query_row_optional(
|
||||
r#"
|
||||
SELECT public_key, private_key
|
||||
FROM keypairs
|
||||
WHERE addr=?1
|
||||
AND is_default=1;
|
||||
"#,
|
||||
(addr,),
|
||||
"SELECT public_key, private_key
|
||||
FROM keypairs
|
||||
WHERE id=(SELECT value FROM config WHERE keyname='key_id')",
|
||||
(),
|
||||
|row| {
|
||||
let pub_bytes: Vec<u8> = row.get(0)?;
|
||||
let sec_bytes: Vec<u8> = row.get(1)?;
|
||||
@@ -288,42 +282,44 @@ pub async fn store_self_keypair(
|
||||
keypair: &KeyPair,
|
||||
default: KeyPairUse,
|
||||
) -> Result<()> {
|
||||
context
|
||||
let mut config_cache_lock = context.sql.config_cache.write().await;
|
||||
let new_key_id = context
|
||||
.sql
|
||||
.transaction(|transaction| {
|
||||
let public_key = DcKey::to_bytes(&keypair.public);
|
||||
let secret_key = DcKey::to_bytes(&keypair.secret);
|
||||
transaction
|
||||
.execute(
|
||||
"DELETE FROM keypairs WHERE public_key=? OR private_key=?;",
|
||||
(&public_key, &secret_key),
|
||||
)
|
||||
.context("failed to remove old use of key")?;
|
||||
if default == KeyPairUse::Default {
|
||||
transaction
|
||||
.execute("UPDATE keypairs SET is_default=0;", ())
|
||||
.context("failed to clear default")?;
|
||||
}
|
||||
|
||||
let is_default = match default {
|
||||
KeyPairUse::Default => i32::from(true),
|
||||
KeyPairUse::ReadOnly => i32::from(false),
|
||||
KeyPairUse::Default => true,
|
||||
KeyPairUse::ReadOnly => false,
|
||||
};
|
||||
|
||||
let addr = keypair.addr.to_string();
|
||||
let t = time();
|
||||
|
||||
transaction
|
||||
.execute(
|
||||
"INSERT INTO keypairs (addr, is_default, public_key, private_key, created)
|
||||
VALUES (?,?,?,?,?);",
|
||||
(addr, is_default, &public_key, &secret_key, t),
|
||||
"INSERT OR REPLACE INTO keypairs (public_key, private_key)
|
||||
VALUES (?,?)",
|
||||
(&public_key, &secret_key),
|
||||
)
|
||||
.context("failed to insert keypair")?;
|
||||
.context("Failed to insert keypair")?;
|
||||
|
||||
Ok(())
|
||||
if is_default {
|
||||
let new_key_id = transaction.last_insert_rowid();
|
||||
transaction.execute(
|
||||
"INSERT OR REPLACE INTO config (keyname, value) VALUES ('key_id', ?)",
|
||||
(new_key_id,),
|
||||
)?;
|
||||
Ok(Some(new_key_id))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
|
||||
if let Some(new_key_id) = new_key_id {
|
||||
// Update config cache if transaction succeeded and changed current default key.
|
||||
config_cache_lock.insert("key_id".to_string(), Some(new_key_id.to_string()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -804,6 +804,36 @@ CREATE INDEX msgs_status_updates_index2 ON msgs_status_updates (uid);
|
||||
.await?;
|
||||
}
|
||||
|
||||
if dbversion < 107 {
|
||||
sql.execute_migration(
|
||||
"CREATE TABLE new_keypairs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
private_key UNIQUE NOT NULL,
|
||||
public_key UNIQUE NOT NULL
|
||||
);
|
||||
INSERT OR IGNORE INTO new_keypairs SELECT id, private_key, public_key FROM keypairs;
|
||||
|
||||
INSERT OR IGNORE
|
||||
INTO config (keyname, value)
|
||||
VALUES
|
||||
('key_id', (SELECT id FROM new_keypairs
|
||||
WHERE private_key=
|
||||
(SELECT private_key FROM keypairs
|
||||
WHERE addr=(SELECT value FROM config WHERE keyname='configured_addr')
|
||||
AND is_default=1)));
|
||||
|
||||
-- We do not drop the old `keypairs` table for now,
|
||||
-- but move it to `old_keypairs`. We can remove it later
|
||||
-- in next migrations. This may be needed for recovery
|
||||
-- in case something is wrong with the migration.
|
||||
ALTER TABLE keypairs RENAME TO old_keypairs;
|
||||
ALTER TABLE new_keypairs RENAME TO keypairs;
|
||||
",
|
||||
107,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
let new_version = sql
|
||||
.get_raw_config_int(VERSION_CFG)
|
||||
.await?
|
||||
|
||||
Reference in New Issue
Block a user