2022-10-18 12:05:06 +00:00
|
|
|
use std::io;
|
2022-10-26 11:44:31 +00:00
|
|
|
use std::str::FromStr;
|
2022-10-18 12:05:06 +00:00
|
|
|
|
|
|
|
use clap::ArgGroup;
|
2022-10-26 11:44:31 +00:00
|
|
|
use clap::CommandFactory;
|
|
|
|
use clap::Parser;
|
|
|
|
use clap::Subcommand;
|
|
|
|
use clap::arg;
|
2022-10-18 12:05:06 +00:00
|
|
|
use clap_complete::{generate, Shell};
|
2023-09-29 12:56:35 +00:00
|
|
|
use noise_protocol::DH;
|
|
|
|
use noise_protocol::Hash;
|
|
|
|
use noise_rust_crypto::Blake2s;
|
|
|
|
use noise_rust_crypto::X25519;
|
2022-10-18 12:05:06 +00:00
|
|
|
use preserves::hex::HexParser;
|
2022-10-26 11:44:31 +00:00
|
|
|
use preserves::value::BytesBinarySource;
|
|
|
|
use preserves::value::NestedValue;
|
2022-10-18 12:05:06 +00:00
|
|
|
use preserves::value::NoEmbeddedDomainCodec;
|
2022-10-26 11:44:31 +00:00
|
|
|
use preserves::value::Reader;
|
|
|
|
use preserves::value::TextReader;
|
2022-10-18 12:05:06 +00:00
|
|
|
use preserves::value::ViaCodec;
|
|
|
|
use preserves::value::TextWriter;
|
|
|
|
use syndicate::language;
|
|
|
|
use syndicate::preserves_schema::Codec;
|
2022-10-26 11:44:31 +00:00
|
|
|
use syndicate::preserves_schema::ParseError;
|
2023-09-29 12:56:35 +00:00
|
|
|
use syndicate::schemas::noise;
|
2022-10-26 11:44:31 +00:00
|
|
|
use syndicate::sturdy::_Any;
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
struct Preserves<N: NestedValue>(N);
|
|
|
|
|
|
|
|
#[derive(Subcommand, Debug)]
|
|
|
|
enum Action {
|
|
|
|
#[command(group(ArgGroup::new("key").required(true)))]
|
|
|
|
/// Generate a fresh SturdyRef from an OID value and a key
|
|
|
|
Mint {
|
|
|
|
#[arg(long, value_name="VALUE")]
|
|
|
|
/// Preserves value to use as SturdyRef OID
|
|
|
|
oid: Preserves<_Any>,
|
2022-10-18 12:05:06 +00:00
|
|
|
|
2022-10-26 11:44:31 +00:00
|
|
|
#[arg(long, group="key")]
|
|
|
|
/// Key phrase
|
|
|
|
phrase: Option<String>,
|
|
|
|
|
|
|
|
#[arg(long, group="key")]
|
|
|
|
/// Key bytes, encoded as hex
|
|
|
|
hex: Option<String>,
|
|
|
|
},
|
|
|
|
|
2023-09-29 12:56:35 +00:00
|
|
|
#[command(group(ArgGroup::new("key").required(true)))]
|
|
|
|
/// Generate a fresh NoiseServiceSpec from a service selector and a key
|
|
|
|
Noise {
|
|
|
|
#[arg(long, value_name="VALUE")]
|
|
|
|
/// Preserves value to use as the service selector
|
|
|
|
service: Preserves<_Any>,
|
|
|
|
|
|
|
|
#[arg(long, value_name="PROTOCOL")]
|
|
|
|
/// Noise handshake protocol name
|
|
|
|
protocol: Option<String>,
|
|
|
|
|
|
|
|
#[arg(long, group="key")]
|
|
|
|
/// Key phrase
|
|
|
|
phrase: Option<String>,
|
|
|
|
|
|
|
|
#[arg(long, group="key")]
|
|
|
|
/// Key bytes, encoded as hex
|
|
|
|
hex: Option<String>,
|
|
|
|
|
|
|
|
#[arg(long, group="key")]
|
|
|
|
/// Generate a random key
|
|
|
|
random: bool,
|
|
|
|
},
|
|
|
|
|
2022-10-26 11:44:31 +00:00
|
|
|
/// Emit shell completion code
|
|
|
|
Completions {
|
|
|
|
/// Shell dialect to generate
|
|
|
|
shell: Shell,
|
|
|
|
}
|
2022-10-18 12:05:06 +00:00
|
|
|
}
|
|
|
|
|
2022-10-26 11:44:31 +00:00
|
|
|
#[derive(Parser, Debug)]
|
|
|
|
#[command(version)]
|
|
|
|
struct Cli {
|
|
|
|
#[command(subcommand)]
|
|
|
|
action: Action,
|
|
|
|
}
|
2022-10-18 12:05:06 +00:00
|
|
|
|
2022-10-26 11:44:31 +00:00
|
|
|
impl<N: NestedValue> FromStr for Preserves<N> {
|
|
|
|
type Err = ParseError;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
Ok(Preserves(TextReader::new(&mut BytesBinarySource::new(s.as_bytes()),
|
|
|
|
ViaCodec::new(NoEmbeddedDomainCodec)).demand_next(false)?))
|
2022-10-18 12:05:06 +00:00
|
|
|
}
|
2022-10-26 11:44:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() -> io::Result<()> {
|
|
|
|
let args = <Cli as Parser>::parse();
|
|
|
|
|
|
|
|
match args.action {
|
|
|
|
Action::Completions { shell } => {
|
|
|
|
let mut cmd = <Cli as CommandFactory>::command();
|
|
|
|
let name = cmd.get_name().to_string();
|
|
|
|
generate(shell, &mut cmd, name, &mut io::stdout());
|
|
|
|
}
|
2022-10-18 12:05:06 +00:00
|
|
|
|
2023-09-29 12:56:35 +00:00
|
|
|
Action::Noise { service, protocol, phrase, hex, random } => {
|
|
|
|
let key =
|
|
|
|
if random {
|
|
|
|
X25519::genkey()
|
|
|
|
} else if let Some(hex) = hex {
|
|
|
|
let mut hash = Blake2s::default();
|
|
|
|
hash.input(hex.as_bytes());
|
|
|
|
hash.result()
|
|
|
|
} else if let Some(phrase) = phrase {
|
|
|
|
let mut hash = Blake2s::default();
|
|
|
|
hash.input(phrase.as_bytes());
|
|
|
|
hash.result()
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
|
|
|
let n = noise::NoiseServiceSpec {
|
|
|
|
base: noise::NoiseSpec {
|
|
|
|
key: X25519::pubkey(&key).to_vec(),
|
|
|
|
service: noise::ServiceSelector(service.0),
|
|
|
|
pre_shared_keys: noise::NoisePreSharedKeys::Absent,
|
|
|
|
protocol: if let Some(p) = protocol {
|
|
|
|
noise::NoiseProtocol::Present { protocol: p }
|
|
|
|
} else {
|
|
|
|
noise::NoiseProtocol::Absent
|
|
|
|
},
|
|
|
|
},
|
|
|
|
secret_key: noise::SecretKeyField::Present {
|
|
|
|
secret_key: key.to_vec(),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
println!("{}", TextWriter::encode(&mut NoEmbeddedDomainCodec,
|
|
|
|
&language().unparse(&n))?);
|
|
|
|
}
|
|
|
|
|
2022-10-26 11:44:31 +00:00
|
|
|
Action::Mint { oid, phrase, hex } => {
|
|
|
|
let key =
|
|
|
|
if let Some(hex) = hex {
|
|
|
|
HexParser::Liberal.decode(&hex).expect("hex encoded sturdyref")
|
|
|
|
} else if let Some(phrase) = phrase {
|
|
|
|
phrase.as_bytes().to_owned()
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
|
|
|
let m = syndicate::sturdy::SturdyRef::mint(oid.0, &key);
|
|
|
|
println!("{}", TextWriter::encode(&mut NoEmbeddedDomainCodec,
|
|
|
|
&language().unparse(&m))?);
|
|
|
|
}
|
2022-10-18 12:05:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|