use crate::cmds::createid::create_id; use crate::db::db_default; use crate::wrapper::wrapper; use std::process::exit; mod cmds; mod db; mod identity; mod wrapper; fn main() -> anyhow::Result<()> { let mut pargs = pico_args::Arguments::from_env(); if pargs.contains(["-h", "--help"]) { print_help(); exit(0); } let database = pargs .opt_value_from_str(["-D", "--database"])? .unwrap_or(db_default()); let Some(subcommand) = pargs.subcommand()? else { // run the wrapper return wrapper(pargs, &database); }; match subcommand.as_str() { "create-id" => { let Ok(name) = pargs.free_from_str() else { eprintln!("name is required, --help for help"); exit(1); }; let Ok(email) = pargs.free_from_str() else { eprintln!("email is required, --help for help"); exit(1); }; create_id(&database, name, email)?; } "ls" => { cmds::ls::list_keys( &database, pargs.contains(["-l", "--local"]), pargs.contains(["-p", "--peer"]), pargs.contains(["-f", "--full"]), )?; } "show" => { let Ok(search) = pargs.free_from_str() else { eprintln!("search term is required, --help for help"); exit(1); }; cmds::show::show_key(&database, search, pargs.contains(["-e", "--expose-secret"]))?; } "import" => { let Ok(key) = pargs.free_from_str() else { eprintln!("key is required, --help for help"); exit(1); }; cmds::import::import_key(&database, key, pargs.contains(["-i", "--import-anyway"]))?; } unknown => { eprintln!("Unknown subcommand: {}", unknown); print_help(); exit(1); } } Ok(()) } fn print_help() { let cf = db_default().display().to_string(); println!("{}", HELP.to_string().replace("{CONFIGFILE}", cf.as_str())); } const HELP: &str = "\ sage - simple age wrapper for named identities USAGE: sage [OPTIONS] [SUBCOMMAND] sage [--encrypt] (-r RECIPIENT | -R PATH)... [--armor] [-o OUTPUT] [INPUT] sage [--encrypt] --passphrase [--armor] [-o OUTPUT] [INPUT] sage --decrypt [-i PATH]... [-o OUTPUT] [INPUT] OPTIONS: -h, --help Prints help information -D, --database Set the database file (default {CONFIGFILE}) -v, --verbose Enable debug logging -e, --encrypt Encrypt the input to the output. Default if omitted. -d, --decrypt Decrypt the input to the output. -o, --output OUTPUT Write the result to the file at path OUTPUT. -a, --armor Encrypt to a PEM encoded format. -p, --passphrase Encrypt with a passphrase. -r, --recipient RECIPIENT Encrypt to the specified RECIPIENT. Can be repeated. -R, --recipients-file PATH Encrypt to the recipients listed at PATH. Can be repeated. -i, --identity IDENTITY Use the specified identity. Can be repeated. INPUT defaults to standard input, and OUTPUT defaults to standard output. If OUTPUT exists, it will be overwritten. RECIPIENT can be an age public key generate by age-keygen (\"age1...\") an SSH public key (\"ssh-ed25519 AAAA...\", \"ssh-rsa AAAA...\"), OR a fuzzy search term to use the database to locate a key. Recipient files contain one or more recipients, one per line. Empty lines and lines starting with \"#\" are ignored as comments. \"-\" may be uised to read recipients from standard input. An IDENTITY may either be a fuzzy search term to search the database, or an identity file. Identity files contain one or more secret keys (\"AGE-SECRET-KEY-1...\"), one per line, or an SSH key. Empty lines and lines starting with \"#\" are ignored as comments. Passphrase encrypted age files can be used as identity files. Multiple key files can be provided, and any unused ones will be ignored. \"-\" may be used to read identities from standard input. When --encrypt is specified explicitly, -i can also be used to encrypt to an identity file symmetrically, instead or in addition to normal recipients. If an identity is omitted and only one local identity exists in the database, it will be chosen automatically. SUBCOMMANDS: create-id Create a new local identity in the database. Name for the new identity Email of the new identity ls [OPTIONS] List keys in the database OPTIONS: -l, --local Show only local (your) keys -p, --peer Show only peer (other's) keys -f, --full List full public keys instead of key IDs show [OPTIONS] Search the database (fuzzy) and show a specific key OPTIONS: -e, --expose-secret Output the secret key, if it is a local key import [OPTIONS] Imports the provided key into the database. If the keyid already exists, it will do nothing. OPTIONS: -i, --insert-anyway Insert even if a matching identity is already present ";