Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add key generation subcommands #259

Merged
merged 9 commits into from
Feb 16, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
didkit = { version = "0.3", path = "../lib", features = ["http-did"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
structopt = "0.3"
clap = { version = "3.0", features = ["derive", "env"] }
did-method-key = { version = "0.1", path = "../../ssi/did-key" }
ssi = { version = "0.3", path = "../../ssi", default-features = false }
thiserror = "1.0"
Expand Down
128 changes: 85 additions & 43 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use std::path::PathBuf;
use std::str::FromStr;

use chrono::prelude::*;
use clap::{AppSettings, ArgGroup, Parser, StructOpt};
use serde::Serialize;
use serde_json::Value;
use sshkeys::PublicKey;
use structopt::{clap::AppSettings, clap::ArgGroup, StructOpt};

use did_method_key::DIDKey;
use didkit::generate_proof;
Expand All @@ -22,11 +22,14 @@ use didkit_cli::opts::ResolverOptions;
#[derive(StructOpt, Debug)]
pub enum DIDKit {
/// Generate and output a Ed25519 keypair in JWK format
#[clap(setting(clap::AppSettings::Hidden))]
GenerateEd25519Key,
#[clap(subcommand)]
Key(KeyCmd),
clehner marked this conversation as resolved.
Show resolved Hide resolved
/// Output a did:key DID for a JWK. Deprecated in favor of key-to-did.
#[structopt(setting = AppSettings::Hidden)]
#[clap(setting = AppSettings::Hidden)]
KeyToDIDKey {
#[structopt(flatten)]
#[clap(flatten)]
key: KeyArg,
},
/// Output a DID for a given JWK according to the provided DID method name or pattern
Expand All @@ -42,21 +45,21 @@ pub enum DIDKit {
/// begins with `did:pkh:tz`.
KeyToDID {
/// DID method name or pattern. e.g. `key`, `tz`, or `pkh:tz`
#[structopt(default_value = "key")]
#[clap(default_value = "key")]
method_pattern: String,
#[structopt(flatten)]
#[clap(flatten)]
key: KeyArg,
},
/// Output a verificationMethod DID URL for a JWK and DID method name/pattern
KeyToVerificationMethod {
/// DID method id or pattern. e.g. `key`, `tz`, or `pkh:tz`
method_pattern: Option<String>,
#[structopt(flatten)]
#[clap(flatten)]
key: KeyArg,
},
/// Convert a SSH public key to a JWK
SshPkToJwk {
#[structopt(parse(try_from_str=PublicKey::from_string))]
#[clap(parse(try_from_str=PublicKey::from_string))]
/// SSH Public Key
ssh_pk: PublicKey,
},
Expand All @@ -69,36 +72,36 @@ pub enum DIDKit {
/// Resolve a DID to a DID Document.
DIDResolve {
did: String,
#[structopt(short = "m", long)]
#[clap(short = 'm', long)]
/// Return resolution result with metadata
with_metadata: bool,
#[structopt(short = "i", name = "name=value")]
#[clap(short = 'i', name = "name=value")]
/// DID resolution input metadata
input_metadata: Vec<MetadataProperty>,
#[structopt(flatten)]
#[clap(flatten)]
resolver_options: ResolverOptions,
},
/// Dereference a DID URL to a resource.
DIDDereference {
did_url: String,
#[structopt(short = "m", long)]
#[clap(short = 'm', long)]
/// Return resolution result with metadata
with_metadata: bool,
#[structopt(short = "i", name = "name=value")]
#[clap(short = 'i', name = "name=value")]
/// DID dereferencing input metadata
input_metadata: Vec<MetadataProperty>,
#[structopt(flatten)]
#[clap(flatten)]
resolver_options: ResolverOptions,
},
/// Authenticate with a DID.
DIDAuth {
#[structopt(flatten)]
#[clap(flatten)]
key: KeyArg,
#[structopt(short = "h", long)]
#[clap(long)]
clehner marked this conversation as resolved.
Show resolved Hide resolved
holder: String,
#[structopt(flatten)]
#[clap(flatten)]
proof_options: ProofOptions,
#[structopt(flatten)]
#[clap(flatten)]
resolver_options: ResolverOptions,
},
/*
Expand All @@ -114,46 +117,46 @@ pub enum DIDKit {
// VC Functionality
/// Issue Credential
VCIssueCredential {
#[structopt(flatten)]
#[clap(flatten)]
key: KeyArg,
#[structopt(flatten)]
#[clap(flatten)]
proof_options: ProofOptions,
#[structopt(flatten)]
#[clap(flatten)]
resolver_options: ResolverOptions,
},
/// Verify Credential
VCVerifyCredential {
#[structopt(flatten)]
#[clap(flatten)]
proof_options: ProofOptions,
#[structopt(flatten)]
#[clap(flatten)]
resolver_options: ResolverOptions,
},
/// Issue Presentation
VCIssuePresentation {
#[structopt(flatten)]
#[clap(flatten)]
key: KeyArg,
#[structopt(flatten)]
#[clap(flatten)]
proof_options: ProofOptions,
#[structopt(flatten)]
#[clap(flatten)]
resolver_options: ResolverOptions,
},
/// Verify Presentation
VCVerifyPresentation {
#[structopt(flatten)]
#[clap(flatten)]
resolver_options: ResolverOptions,
#[structopt(flatten)]
#[clap(flatten)]
proof_options: ProofOptions,
},
/// Convert JSON-LD to URDNA2015-canonicalized RDF N-Quads
ToRdfURDNA2015 {
/// Base IRI
#[structopt(short = "b", long)]
#[clap(short = 'b', long)]
base: Option<String>,
/// IRI for expandContext option
#[structopt(short = "c", long)]
#[clap(short = 'c', long)]
expand_context: Option<String>,
/// Additional values for JSON-LD @context property.
#[structopt(short = "C", long)]
#[clap(short = 'C', long)]
more_context_json: Option<String>,
},
/*
Expand All @@ -176,42 +179,42 @@ pub enum DIDKit {
#[non_exhaustive]
pub struct ProofOptions {
// Options as in vc-api (vc-http-api)
#[structopt(env, short, long)]
#[clap(env, short, long)]
pub type_: Option<String>,
#[structopt(env, short, long)]
#[clap(env, short, long)]
pub verification_method: Option<URI>,
#[structopt(env, short, long)]
#[clap(env, short, long)]
pub proof_purpose: Option<ProofPurpose>,
#[structopt(env, short, long)]
#[clap(env, short, long)]
pub created: Option<DateTime<Utc>>,
#[structopt(env, short = "C", long)]
#[clap(env, short = 'C', long)]
pub challenge: Option<String>,
#[structopt(env, short, long)]
#[clap(env, short, long)]
pub domain: Option<String>,

// Non-standard options
#[structopt(env, default_value, short = "f", long)]
#[clap(env, default_value_t, short = 'f', long)]
pub proof_format: ProofFormat,
}

#[derive(StructOpt, Debug)]
#[structopt(group = ArgGroup::with_name("key_group").multiple(true).required(true))]
#[clap(group = ArgGroup::new("key_group").multiple(true).required(true))]
pub struct KeyArg {
#[structopt(env, short, long, parse(from_os_str), group = "key_group")]
#[clap(env, short, long, parse(from_os_str), group = "key_group")]
key_path: Option<PathBuf>,
#[structopt(
#[clap(
env,
short,
long,
parse(try_from_str = serde_json::from_str),
hide_env_values = true,
conflicts_with = "key_path",
conflicts_with = "key-path",
group = "key_group",
help = "WARNING: you should not use this through the CLI in a production environment, prefer its environment variable."
)]
jwk: Option<JWK>,
/// Request signature using SSH Agent
#[structopt(short = "S", long, group = "key_group")]
#[clap(short = 'S', long, group = "key_group")]
ssh_agent: bool,
}

Expand Down Expand Up @@ -247,6 +250,19 @@ impl From<ProofOptions> for LinkedDataProofOptions {
}
}

#[derive(StructOpt, Debug)]
pub enum KeyCmd {
#[clap(subcommand)]
Generate(KeyGenerateCmd),
}

#[derive(StructOpt, Debug)]
pub enum KeyGenerateCmd {
clehner marked this conversation as resolved.
Show resolved Hide resolved
Ed25519,
Secp256k1,
Secp256r1,
}

#[derive(Debug, Serialize)]
/// Subset of [DID Metadata Structure][metadata] that is just a string property name and string value.
/// [metadata]: https://w3c.github.io/did-core/#metadata-structure
Expand Down Expand Up @@ -328,6 +344,12 @@ mod tests {
let meta = metadata_properties_to_value(props).unwrap();
assert_eq!(meta, json!({"name": ["value1", "value2"]}));
}

#[test]
fn verify_app() {
use clap::IntoApp;
DIDKit::into_app().debug_assert()
}
}

fn get_ssh_agent_sock() -> String {
Expand All @@ -349,7 +371,7 @@ set. For more info, see the manual for ssh-agent(1) and ssh-add(1).

fn main() {
let rt = runtime::get().unwrap();
let opt = DIDKit::from_args();
let opt = DIDKit::parse();
let ssh_agent_sock;

match opt {
Expand All @@ -359,6 +381,26 @@ fn main() {
println!("{}", jwk_str);
}

DIDKit::Key(cmd) => match cmd {
KeyCmd::Generate(cmd_generate) => {
let jwk_str = match cmd_generate {
KeyGenerateCmd::Ed25519 => {
let jwk = JWK::generate_ed25519().unwrap();
serde_json::to_string(&jwk).unwrap()
}
KeyGenerateCmd::Secp256k1 => {
let jwk = JWK::generate_secp256k1().unwrap();
serde_json::to_string(&jwk).unwrap()
}
KeyGenerateCmd::Secp256r1 => {
let jwk = JWK::generate_p256().unwrap();
serde_json::to_string(&jwk).unwrap()
}
};
println!("{}", jwk_str);
}
},

DIDKit::KeyToDIDKey { key } => {
// Deprecated in favor of KeyToDID
eprintln!("didkit: use key-to-did instead of key-to-did-key");
Expand Down
6 changes: 3 additions & 3 deletions cli/src/opts.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use structopt::StructOpt;
use clap::StructOpt;

use didkit::{HTTPDIDResolver, SeriesResolver, DID_METHODS};

#[derive(StructOpt, Debug, Clone, Default)]
pub struct ResolverOptions {
#[structopt(env, short = "r", long, parse(from_str = HTTPDIDResolver::new))]
#[clap(env, short = 'r', long, parse(from_str = HTTPDIDResolver::new))]
/// Fallback DID Resolver HTTP(S) endpoint, for non-built-in DID methods.
pub did_resolver: Option<HTTPDIDResolver>,
#[structopt(env, short = "R", long, parse(from_str = HTTPDIDResolver::new))]
#[clap(env, short = 'R', long, parse(from_str = HTTPDIDResolver::new))]
/// Override DID Resolver HTTP(S) endpoint, for all DID methods.
pub did_resolver_override: Option<HTTPDIDResolver>,
}
Expand Down
2 changes: 1 addition & 1 deletion cli/tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ fn didkit_cli() {
"did-auth",
"-k",
"tests/ed25519-key.jwk",
"-h",
"--holder",
&did.to_string(),
"-v",
&verification_method.trim(),
Expand Down
2 changes: 1 addition & 1 deletion cli/tests/example.sh
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ then
fi
if ! didkit did-auth \
-k key.jwk \
-h "$did" \
--holder "$did" \
-p authentication \
-C "$challenge" \
-v "$verification_method" \
Expand Down
2 changes: 1 addition & 1 deletion http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ ring = ["ssi/ring"]
didkit = { version = "0.3", path = "../lib", features = ["http-did"] }
didkit-cli = { version = "^0.1.1", path = "../cli" }
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
structopt = "0.3"
clap = { version = "3.0", features = ["derive", "env"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_urlencoded = "0.7"
Expand Down
16 changes: 8 additions & 8 deletions http/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;

use clap::{AppSettings, ArgGroup, Parser, StructOpt};
use hyper::Server;
use structopt::StructOpt;

use didkit::JWK;
use didkit_cli::opts::ResolverOptions;
Expand All @@ -13,28 +13,28 @@ use didkit_http::Error;
#[derive(StructOpt, Debug)]
pub struct DIDKitHttpOpts {
/// Port to listen on
#[structopt(env, short, long)]
#[clap(env, short, long)]
port: Option<u16>,
/// Hostname to listen on
#[structopt(env, short = "s", long)]
#[clap(env, short = 's', long)]
host: Option<std::net::IpAddr>,
/// JWK to use for issuing
#[structopt(flatten)]
#[clap(flatten)]
key: KeyArg,
#[structopt(flatten)]
#[clap(flatten)]
resolver_options: ResolverOptions,
}

#[derive(StructOpt, Debug)]
pub struct KeyArg {
#[structopt(env, short, long, parse(from_os_str), group = "key_group")]
#[clap(env, short, long, parse(from_os_str), group = "key_group")]
key_path: Option<Vec<PathBuf>>,
#[structopt(
#[clap(
env,
short,
long,
parse(try_from_str = serde_json::from_str),
conflicts_with = "key_path",
conflicts_with = "key-path",
group = "key_group",
help = "WARNING: you should not use this through the CLI in a production environment, prefer its environment variable."
)]
Expand Down