From 585891697df6840de8d69e7bb5436f5c4d9c8d99 Mon Sep 17 00:00:00 2001 From: meryacine Date: Sun, 24 Apr 2022 18:01:48 +0200 Subject: [PATCH 1/2] feat: Option for reverting to old tower keys This will allow the user to use old tower secret keys given their ids --- README.md | 4 ++-- teos/src/conf_template.toml | 2 +- teos/src/config.rs | 23 +++++++++++++++++------ teos/src/dbm.rs | 36 ++++++++++++++++++++++-------------- teos/src/main.rs | 17 +++++++++++------ 5 files changed, 53 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index fb2a936e..eadeb906 100644 --- a/README.md +++ b/README.md @@ -69,9 +69,9 @@ btc_network = regtest ### Tower id and signing key -`teos` needs a pair of keys that will serve as tower id and signing key. The former can be used by users to identify the tower, whereas the latter is used by the tower to sign responses. These keys are automatically generated on the first run, and can be refreshed by running `teos` with the `--overwritekey` flag. Notice that once a key is overwritten you won't be able to use the previous key again*. +`teos` needs a pair of keys that will serve as tower id and signing key. The former can be used by users to identify the tower, whereas the latter is used by the tower to sign responses. These keys are automatically generated on the first run, and can be refreshed by running `teos` with the `--usenewkey` flag. -\* Old keys are actually kept in the tower's database as a fail safe in case you overwrite them by mistake. However, there is no automated way of switching back to and old key. Feel free to open an issue if you overwrote your key by mistake and need support to recover it. +You can use an old key with the `--usekey ` option, where `keyindex` is the index of the desired secret key. The first tower secret key will have `keyindex` equal to `1` and subsequent keys will have their `keyindex` auto-incremented. ## Interacting with a TEOS Instance diff --git a/teos/src/conf_template.toml b/teos/src/conf_template.toml index 5b578aae..23f97d67 100644 --- a/teos/src/conf_template.toml +++ b/teos/src/conf_template.toml @@ -15,7 +15,7 @@ btc_rpc_port = 8332 # Flags debug = false -overwrite_key = false +use_new_key = false # General subscription_slots = 10000 diff --git a/teos/src/config.rs b/teos/src/config.rs index d621536e..ca3f08b8 100644 --- a/teos/src/config.rs +++ b/teos/src/config.rs @@ -101,9 +101,16 @@ pub struct Opt { #[structopt(long)] pub debug: bool, - /// Overwrites the tower secret key. THIS IS IRREVERSIBLE AND WILL CHANGE YOUR TOWER ID + /// Generates a new secret key for the tower. This will change your tower ID #[structopt(long)] - pub overwrite_key: bool, + pub use_new_key: bool, + + /// Index of the tower's secret key [default: None] + /// + /// keyindex is the index of the secret key starting from 1 and is auto-incremented with each new key used. + /// Not specifying this option will let the tower choose the last known secret key. + #[structopt(long, conflicts_with = "usenewkey", name = "keyindex")] + pub use_key: Option, } /// Holds all configuration options. @@ -132,9 +139,10 @@ pub struct Config { // Flags pub debug: bool, - pub overwrite_key: bool, + pub use_new_key: bool, // General + pub use_key: Option, pub subscription_slots: u32, pub subscription_duration: u32, pub expiry_delta: u32, @@ -178,7 +186,8 @@ impl Config { } self.debug |= options.debug; - self.overwrite_key = options.overwrite_key; + self.use_new_key = options.use_new_key; + self.use_key = options.use_key; } /// Verifies that [Config] is properly built. @@ -239,7 +248,8 @@ impl Default for Config { btc_rpc_port: 0, debug: false, - overwrite_key: false, + use_new_key: false, + use_key: None, subscription_slots: 10000, subscription_duration: 4320, expiry_delta: 6, @@ -270,7 +280,8 @@ mod tests { data_dir: String::from("~/.teos"), debug: false, - overwrite_key: false, + use_new_key: false, + use_key: None, } } } diff --git a/teos/src/dbm.rs b/teos/src/dbm.rs index 83729f5e..94e14cda 100644 --- a/teos/src/dbm.rs +++ b/teos/src/dbm.rs @@ -7,7 +7,9 @@ use std::str::FromStr; use rusqlite::ffi::{SQLITE_CONSTRAINT_FOREIGNKEY, SQLITE_CONSTRAINT_PRIMARYKEY}; use rusqlite::limits::Limit; -use rusqlite::{params, params_from_iter, Connection, Error as SqliteError, ErrorCode, Params}; +use rusqlite::{ + params, params_from_iter, Connection, Error as SqliteError, ErrorCode, Params, Row, +}; use bitcoin::consensus::deserialize; use bitcoin::hashes::Hash; @@ -571,22 +573,28 @@ impl DBM { self.store_data(query, params![sk.to_string()]) } - /// Loads the last known tower secret key from the database. + /// Loads a tower secret key from the database. /// - /// Loads the key with higher id from the database. Old keys are not overwritten just in case a recovery is needed, - /// but they are not accessible from the API either. - pub fn load_tower_key(&self) -> Result { - let mut stmt = self - .connection - .prepare( - "SELECT key FROM keys WHERE id = (SELECT seq FROM sqlite_sequence WHERE name=(?))", - ) - .unwrap(); - - stmt.query_row(["keys"], |row| { + /// Loads the secret key whose in-database id matches the index parameter. + /// If no index was passed, this will load the key with greatest id found in the database. + pub fn load_tower_key(&self, index: Option) -> Result { + let placeholder = match index { + Some(_) => "?", + None => "SELECT seq FROM sqlite_sequence WHERE name=('keys')", + }; + + let sql = format!("SELECT key FROM keys WHERE id = ({})", placeholder); + let mut stmt = self.connection.prepare(&sql).unwrap(); + + let f = |row: &Row| { let sk: String = row.get(0).unwrap(); Ok(SecretKey::from_str(&sk).unwrap()) - }) + }; + + match index { + Some(id) => stmt.query_row([id], f), + None => stmt.query_row([], f), + } .map_err(|_| Error::NotFound) } } diff --git a/teos/src/main.rs b/teos/src/main.rs index e1564c75..02f28f8f 100644 --- a/teos/src/main.rs +++ b/teos/src/main.rs @@ -97,19 +97,24 @@ async fn main() { DBM::new(path_network.join("teos_db.sql3")).unwrap(), )); - // Load tower secret key or create a fresh one if none is found. If overwrite key is set, create a new + // Load tower secret key or create a fresh one if none is found. If use_new_key is set, create a new // key straightaway let (tower_sk, tower_pk) = { let locked_db = dbm.lock().unwrap(); - if conf.overwrite_key { - log::info!("Overwriting tower keys"); + if conf.use_new_key { + log::info!("Generating new tower keys"); create_new_tower_keypair(&locked_db) } else { - match locked_db.load_tower_key() { + match locked_db.load_tower_key(conf.use_key) { Ok(sk) => (sk, PublicKey::from_secret_key(&Secp256k1::new(), &sk)), Err(_) => { - log::info!("Tower keys not found. Creating a fresh set"); - create_new_tower_keypair(&locked_db) + if let Some(sk_index) = conf.use_key { + eprintln!("No tower key of index {} found in the database.", sk_index); + std::process::exit(1); + } else { + log::info!("Tower keys not found. Creating a fresh set"); + create_new_tower_keypair(&locked_db) + } } } } From c07867555c797fd9dbf8696f8e097fa175ebce8c Mon Sep 17 00:00:00 2001 From: meryacine Date: Mon, 25 Apr 2022 14:54:10 +0200 Subject: [PATCH 2/2] renaming variables use_new_key -> generate_new_key use_key -> tower_key --- README.md | 4 ++-- teos/src/conf_template.toml | 2 +- teos/src/config.rs | 22 +++++++++++----------- teos/src/main.rs | 10 +++++----- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index eadeb906..72213b02 100644 --- a/README.md +++ b/README.md @@ -69,9 +69,9 @@ btc_network = regtest ### Tower id and signing key -`teos` needs a pair of keys that will serve as tower id and signing key. The former can be used by users to identify the tower, whereas the latter is used by the tower to sign responses. These keys are automatically generated on the first run, and can be refreshed by running `teos` with the `--usenewkey` flag. +`teos` needs a pair of keys that will serve as tower id and signing key. The former can be used by users to identify the tower, whereas the latter is used by the tower to sign responses. These keys are automatically generated on the first run, and can be refreshed by running `teos` with the `--generatenewkey` flag. -You can use an old key with the `--usekey ` option, where `keyindex` is the index of the desired secret key. The first tower secret key will have `keyindex` equal to `1` and subsequent keys will have their `keyindex` auto-incremented. +You can use an old key with the `--towerkey ` option, where `keyindex` is the index of the desired secret key. The first tower secret key will have `keyindex` equal to `1` and subsequent keys will have their `keyindex` auto-incremented. ## Interacting with a TEOS Instance diff --git a/teos/src/conf_template.toml b/teos/src/conf_template.toml index 23f97d67..de140796 100644 --- a/teos/src/conf_template.toml +++ b/teos/src/conf_template.toml @@ -15,7 +15,7 @@ btc_rpc_port = 8332 # Flags debug = false -use_new_key = false +generate_new_key = false # General subscription_slots = 10000 diff --git a/teos/src/config.rs b/teos/src/config.rs index ca3f08b8..b8d259af 100644 --- a/teos/src/config.rs +++ b/teos/src/config.rs @@ -103,14 +103,14 @@ pub struct Opt { /// Generates a new secret key for the tower. This will change your tower ID #[structopt(long)] - pub use_new_key: bool, + pub generate_new_key: bool, /// Index of the tower's secret key [default: None] /// /// keyindex is the index of the secret key starting from 1 and is auto-incremented with each new key used. /// Not specifying this option will let the tower choose the last known secret key. - #[structopt(long, conflicts_with = "usenewkey", name = "keyindex")] - pub use_key: Option, + #[structopt(long, conflicts_with = "generatenewkey", name = "keyindex")] + pub tower_key: Option, } /// Holds all configuration options. @@ -139,10 +139,10 @@ pub struct Config { // Flags pub debug: bool, - pub use_new_key: bool, + pub generate_new_key: bool, // General - pub use_key: Option, + pub tower_key: Option, pub subscription_slots: u32, pub subscription_duration: u32, pub expiry_delta: u32, @@ -186,8 +186,8 @@ impl Config { } self.debug |= options.debug; - self.use_new_key = options.use_new_key; - self.use_key = options.use_key; + self.generate_new_key = options.generate_new_key; + self.tower_key = options.tower_key; } /// Verifies that [Config] is properly built. @@ -248,8 +248,8 @@ impl Default for Config { btc_rpc_port: 0, debug: false, - use_new_key: false, - use_key: None, + generate_new_key: false, + tower_key: None, subscription_slots: 10000, subscription_duration: 4320, expiry_delta: 6, @@ -280,8 +280,8 @@ mod tests { data_dir: String::from("~/.teos"), debug: false, - use_new_key: false, - use_key: None, + generate_new_key: false, + tower_key: None, } } } diff --git a/teos/src/main.rs b/teos/src/main.rs index 02f28f8f..ab86ad10 100644 --- a/teos/src/main.rs +++ b/teos/src/main.rs @@ -97,19 +97,19 @@ async fn main() { DBM::new(path_network.join("teos_db.sql3")).unwrap(), )); - // Load tower secret key or create a fresh one if none is found. If use_new_key is set, create a new + // Load tower secret key or create a fresh one if none is found. If generate_new_key is set, create a new // key straightaway let (tower_sk, tower_pk) = { let locked_db = dbm.lock().unwrap(); - if conf.use_new_key { + if conf.generate_new_key { log::info!("Generating new tower keys"); create_new_tower_keypair(&locked_db) } else { - match locked_db.load_tower_key(conf.use_key) { + match locked_db.load_tower_key(conf.tower_key) { Ok(sk) => (sk, PublicKey::from_secret_key(&Secp256k1::new(), &sk)), Err(_) => { - if let Some(sk_index) = conf.use_key { - eprintln!("No tower key of index {} found in the database.", sk_index); + if let Some(key_index) = conf.tower_key { + eprintln!("No tower key of index {} found in the database.", key_index); std::process::exit(1); } else { log::info!("Tower keys not found. Creating a fresh set");