diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..6aae9b7ac2a253718a9bb2dca630a997e002d4f3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,54 @@ +# Changelog + +List of changelogs ordered from latest to oldest + +## [0.4.0] - 2025-02-xx +### Changed +- Old key files cannot be used directly anymore, they have to be migrated to the SQLite file database. You can use the following commands for that: + - `gcli vault list-files` lists _old_ key files from previous versions + - `gcli vault migrate` which allows to migrate _old_ key files into the vault database +- Some arguments and commands were adapted + - Arguments + - **SecretFormat** (`-S`): _cesium_ was renamed to _g1v1_ - but it will still work properly if using _cesium_ + - Several arguments were renamed for clarity. Examples: + - `<TARGET>` => `<USERNAME>` + - `<ACCOUNT_ID>` => `<ADDRESS>` + - Commands + - `gcli vault import` now has an optional **SecretFormat** `-S` argument with _substrate_ as default value + - It is now possible to import _substrate_ URI, _seed_, _g1v1_ id/secret (old "cesium") keys into the vault. + - `gcli vault list` now has sub-commands and only shows Addresses from the SQLite file database + +### Added +- Support for SQLite file database to persist vault data +- global `-v <NAME>` argument to select a vault Address by name (mutually exclusive with `-a <ADDRESS>` argument) +- Already mentioned in the "Changed" section above, but it is now possible to add different kind of keys to the vault when doing `vault import` + - Default providing _substrate_ URI (or `-S substrate`) : can be a mnemonic or a mini-secret ('0x' prefixed seed) together with optional derivation path; using Sr25519 crypto scheme + - `-S seed` : using the 32 character hexadecimal secret seed; using Sr25519 crypto scheme + - `-S g1v1` (or `-S cesium`) : allows to input G1v1 `id` and `secret`; using Ed25519 crypto scheme +- Added possibility to `derive` non _g1v1_/_cesium_ Addresses (see `gcli vault derive`) +- Some commands were added + - `gcli vault list all` List all \<Base\> SS58 Addresses and their linked derivations in the vault + - `gcli vault list for` List \<Base\> and Derivation SS58 Addresses linked to the selected one + - `gcli vault list base` List all \<Base\> SS58 Addresses in the vault + - `gcli vault use` Use specific SS58 Address (changes the config Address) + - `gcli vault derive` Add a derivation to an existing SS58 Address + - `gcli vault rename` Give a meaningful name to an SS58 Address in the vault + - `gcli vault remove` Remove an SS58 Address from the vault together with its linked derivations + - `gcli vault inspect` Inspect a vault entry, retrieving its Substrate URI (will provide more data in a future version) + - `gcli vault list-files` (deprecated) List available key files (needs to be migrated with command `vault migrate` in order to use them) + - `gcli vault migrate` (deprecated) Migrate old key files into db (will have to provide password for each key) + +### Fixed +- None + +### Deprecated +- Two commands are now deprecated and will be removed in a future release + - `gcli vault list-files` + - `gcli vault migrate` + +### Removed +- None + +## [0.3.0] - 2024-10-10 +### Added +- Previous version without changelog \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 43d375be8b97d9a7d24339affec5e94f481b14d8..a9cd348674c8f8da078884faf7c47ebf434def92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2338,7 +2338,7 @@ dependencies = [ [[package]] name = "gcli" -version = "0.3.0" +version = "0.4.0" dependencies = [ "age", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 31314799a82564928e1cbcf8fecb1e104ee31819..ce66a64826afe4979ebd7c56b1bcda4a1eaf34b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ license = "AGPL-3.0-only" name = "gcli" repository = "https://git.duniter.org/clients/rust/gcli-v2s" description = "A command-line interface for Duniter v2s uses" -version = "0.3.0" +version = "0.4.0" [dependencies] # subxt is main dependency diff --git a/README.md b/README.md index 42fc7b7bfdd1f5f00f0942a92ba8dd9a3448eb32..bf2a3b0e0a6d415a07e1ab8026e676e322181da1 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ List certifications and session keys that will expire within one month: cargo run -- --url wss://gdev.p2p.legal:443/ws smith expire --blocks 432000 -For more examples see [in the doc](./doc/). `cargo run --` is replaced by `gcli` as if the binary was added to your path. +For more examples see [in the doc](./doc). `cargo run --` is replaced by `gcli` as if the binary was added to your path. #### Log level @@ -76,3 +76,7 @@ Secret and/or public keys can always be passed using `--secret` and `--address`. Secret key format can be changed using `--secret-format` with the following values: * `substrate`: a Substrate secret address (optionally followed by a derivation path), or BIP39 mnemonic * `seed`: a 32-bytes seed in hexadecimal (Duniter v1 compatible) + +## Changelog + +For a detailed list of changes, see the [CHANGELOG](./CHANGELOG.md). \ No newline at end of file diff --git a/doc/config.md b/doc/config.md index fbe59f562c861634503e3cec9054e0936ed2c972..b8078aeb9b9a01666c78898167aa8f25525aa7e8 100644 --- a/doc/config.md +++ b/doc/config.md @@ -36,22 +36,74 @@ gcli account transfer 1 5Fxune7f71ZbpP2FoY3mhYcmM596Erhv1gRue4nsPwkxMR4n # no need for password to sign transaction ``` -`FIXME` Need to update documentation when vault changes are stable. +but in general usage, you want to store your secret in the local vault. -but in general usage, you want to store your secret in the local vault. This goes like this: +Here is an example adding a base _substrate_ account, adding a derivation on it, selecting that derivation Address and making a transfer from it ```sh -# list available keys in the vault -gcli vault list +# add a new secret to the vault using substrate uri +gcli vault import # [stdout] -# available keys: -# 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV +# gcli vault import +# Substrate URI can be a mnemonic or a mini-secret ('0x' prefixed seed) together with optional derivation path +# > Substrate URI: ******** +# +# Trying to import for SS58 address :'5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV' +# +# Enter password to protect the key +# > Password ******** +# (Optional) Enter a name for the vault entry +# > Name: test-mnemonic +# Creating <Base> account Base[address:5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV, name:Some("test-mnemonic"), crypto_scheme:Some(Sr25519)] +# Change done +``` -# add a new secret to the vault -gcli vault import +```sh +# add a derivation to that Address and give it name "firstDerive" +gcli vault derive -a 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV +# [stdout] +# Adding derivation to: Base[address:5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV, name:Some("test-mnemonic"), crypto_scheme:Some(Sr25519)] +# +# Its parent hierarchy is this: +# ┌─────────────────────────────────────────────────────────────────────────────────────┠+# │ SS58 Address/G1v1 public key Crypto Path Name │ +# ╞â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡ +# │ 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV sr25519 <Base> test-mnemonic │ +# └─────────────────────────────────────────────────────────────────────────────────────┘ +# +# The linked <Base> account is Base[address:5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV, name:Some("test-mnemonic"), crypto_scheme:Some(Sr25519)] +# Enter password to decrypt the <Base> account key +# > Password ******** +# +# > Derivation path: //1 +# +# Trying to create derivation with address '5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o' +# +# (Optional) Enter a name for the vault entry +# > Name: firstDerive +# Creating derivation account Derivation[address:5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o, name:Some("firstDerive"), path:Some("//1"), parent:Some("5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV")] +# Change done +``` + +```sh +# list available Addresses in the vault +gcli vault list all # [stdout] -# Mnemonic: <enter mnemonic> -# Password: <enter password> +# available SS58 Addresses: +# ┌───────────────────────────────────────────────────────────────────────────────────────┠+# │ SS58 Address/G1v1 public key Crypto Path Name │ +# ╞â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡ +# │ 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV sr25519 <Base> test-mnemonic │ +# │ ├─5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o //1 firstDerive │ +# └───────────────────────────────────────────────────────────────────────────────────────┘ +``` + +```sh +# Use "firstDerive" derivation Address (changes the config Address) +gcli vault use -v firstDerive +# [stdout] +# Using: Derivation[address:5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o, name:Some("firstDerive"), path:Some("//1"), parent:Some("5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV")] +# Configuration updated! ``` After saving your secret to the vault, you will be able to unlock it with the password: @@ -59,10 +111,10 @@ After saving your secret to the vault, you will be able to unlock it with the pa ```sh gcli account transfer 123 5Fxune7f71ZbpP2FoY3mhYcmM596Erhv1gRue4nsPwkxMR4n # [stdout] -# Enter password to unlock account 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV -# Password: <enter password> +# (Vault: Derivation[address:5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o, name:Some("firstDerive"), path:Some("//1"), parent:Some("5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV")]) +# > Password ******** # transaction submitted to the network, waiting 6 seconds... -# transfered 1.23 ÄžD (5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV → 5Fxune7f71ZbpP2FoY3mhYcmM596Erhv1gRue4nsPwkxMR4n) +# transfered 1.23 ÄžD (5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o → 5Fxune7f71ZbpP2FoY3mhYcmM596Erhv1gRue4nsPwkxMR4n) ``` You can display the secret files location: @@ -71,4 +123,95 @@ You can display the secret files location: gcli vault where # [stdout] # /home/hugo/.local/share/gcli +``` + +--- + +There are more commands and options available; please use `--help` argument in any of the commands to get their description. + +A few examples: + +```sh +gcli --help +# [stdout] +# A command-line interface for Duniter v2s uses +# +# Usage: gcli [OPTIONS] <COMMAND> +# +# Commands: +# account Account (balance, transfer...) +# identity Identity (get, create, confirm, revoke...) +# smith Smith (certify, go-online, go-offline...) +# tech Tech (list members, proposals, vote...) +# ud Universal Dividend (claim...) +# oneshot Oneshot account (balance, create, consume...) +# blockchain Blockchain (current block, runtime info...) +# indexer Indexer (check, latest block) +# config Config (show, save...) +# vault Key management (import, generate, list...) +# help Print this message or the help of the given subcommand(s) +# +# Options: +# -i, --indexer <INDEXER> Overwrite indexer endpoint +# --no-indexer Do not use indexer +# -s, --secret <SECRET> Secret key or BIP39 mnemonic (only used when secret format is compatible) (eventually followed by derivation path) +# -S, --secret-format <SECRET_FORMAT> Secret key format (seed, substrate, g1v1) +# -a <ADDRESS> SS58 Address +# -v <NAME> Name of an SS58 Address in the vault +# -u, --url <URL> Overwrite duniter websocket RPC endpoint +# -n, --network <NETWORK> Target network (local, gdev, gtest...) +# --no-wait prevent waiting for extrinsic completion +# -o, --output-format <OUTPUT_FORMAT> Output format (human, json, ...) [default: human] +# -h, --help Print help +# -V, --version Print version +``` + +```sh +gcli vault --help +# [stdout] +# Key management (import, generate, list...) +# +# Usage: gcli vault <COMMAND> +# +# Commands: +# list List available SS58 Addresses in the vault +# use Use specific SS58 Address (changes the config Address) +# generate Generate a mnemonic +# import Import key from (substrate uri) or other format with interactive prompt +# derive Add a derivation to an existing SS58 Address +# rename Give a meaningful name to an SS58 Address in the vault +# remove Remove an SS58 Address from the vault together with its linked derivations +# inspect Inspect a vault entry, retrieving its Substrate URI (will provide more data in a future version) +# list-files (deprecated) List available key files (needs to be migrated with command `vault migrate` in order to use them) +# migrate (deprecated) Migrate old key files into db (will have to provide password for each key) +# where Show where vault db (or old keys) is stored +# help Print this message or the help of the given subcommand(s) +# +# Options: +# -h, --help Print help +``` + +And some commands have a more detailed description when requesting `--help` from them. + +```sh +gcli vault derive --help +# [stdout] +# Add a derivation to an existing SS58 Address. +# +# Only "sr25519" crypto scheme is supported for derivations. +# +# Use command `vault list base` to see available <Base> account and their crypto scheme +# And then use command 'vault list for' to find all accounts linked to that <Base> account. +# +# Usage: gcli vault derive <-a <ADDRESS>|-v <NAME>> +# +# Options: +# -a <ADDRESS> +# SS58 Address +# +# -v <NAME> +# Name of an SS58 Address in the vault +# +# -h, --help +# Print help (see a summary with '-h') ``` \ No newline at end of file diff --git a/src/commands/vault.rs b/src/commands/vault.rs index 7bb6dfe0fd779429c8fa6bbab78e98d94d51deff..8d6de10f65b0529b449934d4e174cb7c25348151 100644 --- a/src/commands/vault.rs +++ b/src/commands/vault.rs @@ -42,8 +42,8 @@ pub enum Subcommand { #[clap(short = 'S', long, required = false, default_value = SecretFormat::Substrate)] secret_format: SecretFormat, }, - /// Add a derivation to an existing account - #[clap(long_about = "Add a derivation to an existing account.\n\ + /// Add a derivation to an existing SS58 Address + #[clap(long_about = "Add a derivation to an existing SS58 Address.\n\ \n\ Only \"sr25519\" crypto scheme is supported for derivations.\n\ \n\ @@ -89,7 +89,7 @@ pub enum Subcommand { #[derive(Clone, Default, Debug, clap::Parser)] pub enum ListChoice { - /// List all <Base> accounts and their linked derivations SS58 Addresses in the vault + /// List all <Base> SS58 Addresses and their linked derivations in the vault #[default] All, /// List <Base> and Derivation SS58 Addresses linked to the selected one @@ -225,7 +225,7 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE "The G1v1 public key for the provided secret is: '{}'", compute_g1v1_public_key(&vault_data_for_import.key_pair)? ); - let confirmed = inputs::confirm_action("Is it the correct one (if not, you should try again to input Cesium id/password) ?".to_string())?; + let confirmed = inputs::confirm_action("Is it the correct one (if not, you should try again to input G1v1 id/password) ?".to_string())?; if !confirmed { return Ok(()); } diff --git a/src/keys.rs b/src/keys.rs index 515814ca971cc5c0de94ab2f1039b9cc866d03ec..7b7babd095cd3b17230734bbd994a1de3bcf2680 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -204,7 +204,7 @@ pub fn pair_from_predefined(deriv: &str) -> Result<sr25519::Pair, GcliError> { pair_from_sr25519_str(&predefined_mnemonic(deriv)) } -/// get seed from Cesium id/pwd +/// get seed from G1v1 id/pwd (old "cesium") pub fn seed_from_cesium(id: &str, pwd: &str) -> [u8; 32] { let params = scrypt::Params::new(12u8, 16u32, 1u32, 32).unwrap(); let mut seed = [0u8; 32]; @@ -236,15 +236,15 @@ pub fn prompt_secret_cesium() -> ed25519::Pair { } pub fn prompt_secret_cesium_and_compute_keypair() -> (String, ed25519::Pair) { - let id = inputs::prompt_password_query("Cesium id: ").unwrap(); - let pwd = inputs::prompt_password_query("Cesium password: ").unwrap(); + let id = inputs::prompt_password_query("G1v1 id: ").unwrap(); + let pwd = inputs::prompt_password_query("G1v1 password: ").unwrap(); let seed = seed_from_cesium(&id, &pwd); let secret_suri = format!("0x{}", hex::encode(seed)); match pair_from_ed25519_str(&secret_suri) { Ok(pair) => (secret_suri, pair), - Err(_) => panic!("Could not compute KeyPair from Cesium id/pwd"), + Err(_) => panic!("Could not compute KeyPair from G1v1 id/pwd"), } }