forked from OKEAMAH/didkit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcredential.rs
More file actions
133 lines (124 loc) · 4.16 KB
/
credential.rs
File metadata and controls
133 lines (124 loc) · 4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::io::{stdin, stdout, BufReader, BufWriter, Read};
use anyhow::Result;
use clap::{Args, Subcommand};
use didkit::{
generate_proof, ContextLoader, LinkedDataProofOptions, ProofFormat, VerifiableCredential, JWK,
};
use tracing::warn;
use crate::{get_ssh_agent_sock, opts::ResolverOptions, KeyArg, ProofOptions};
#[derive(Subcommand)]
pub enum CredentialCmd {
/// Issue Credential
Issue(Box<CredentialIssueArgs>),
/// Verify Credential
Verify(CredentialVerifyArgs),
}
#[derive(Args)]
pub struct CredentialIssueArgs {
#[clap(flatten)]
key: KeyArg,
#[clap(flatten)]
proof_options: ProofOptions,
#[clap(flatten)]
resolver_options: ResolverOptions,
}
#[derive(Args)]
pub struct CredentialVerifyArgs {
#[clap(flatten)]
proof_options: ProofOptions,
#[clap(flatten)]
resolver_options: ResolverOptions,
}
pub async fn cli(cmd: CredentialCmd) -> Result<()> {
match cmd {
CredentialCmd::Issue(cmd_issue) => issue(*cmd_issue).await?,
CredentialCmd::Verify(cmd_verify) => verify(cmd_verify).await?,
};
Ok(())
}
pub async fn issue(args: CredentialIssueArgs) -> Result<()> {
let resolver = args.resolver_options.to_resolver();
let mut context_loader = ContextLoader::default();
let credential_reader = BufReader::new(stdin());
let mut credential: VerifiableCredential = serde_json::from_reader(credential_reader).unwrap();
let proof_format = args.proof_options.proof_format.clone();
let jwk_opt: Option<JWK> = args.key.get_jwk_opt();
let ssh_agent_sock_opt = if args.key.ssh_agent {
Some(get_ssh_agent_sock())
} else {
None
};
let options = LinkedDataProofOptions::from(args.proof_options);
match proof_format {
ProofFormat::JWT => {
if ssh_agent_sock_opt.is_some() {
todo!("ssh-agent for JWT not implemented");
}
let jwt = credential
.generate_jwt(jwk_opt.as_ref(), &options, &resolver)
.await
.unwrap();
print!("{jwt}");
}
ProofFormat::LDP => {
let proof = generate_proof(
&credential,
jwk_opt.as_ref(),
options,
&resolver,
&mut context_loader,
ssh_agent_sock_opt.as_deref(),
)
.await
.unwrap();
credential.add_proof(proof);
let stdout_writer = BufWriter::new(stdout());
serde_json::to_writer(stdout_writer, &credential).unwrap();
}
_ => {
panic!("Unknown proof format: {:?}", proof_format);
}
}
Ok(())
}
pub async fn verify(args: CredentialVerifyArgs) -> Result<()> {
let resolver = args.resolver_options.to_resolver();
let mut context_loader = ContextLoader::default();
let mut credential_reader = BufReader::new(stdin());
let proof_format = args.proof_options.proof_format.clone();
let options = LinkedDataProofOptions::from(args.proof_options);
let result = match proof_format {
ProofFormat::JWT => {
let mut jwt = String::new();
credential_reader.read_to_string(&mut jwt).unwrap();
let trimmed_jwt = jwt.trim();
if jwt != trimmed_jwt {
warn!("JWT was trimmed for extraneous whitespaces and new lines.");
}
VerifiableCredential::verify_jwt(
trimmed_jwt,
Some(options),
&resolver,
&mut context_loader,
)
.await
}
ProofFormat::LDP => {
let credential: VerifiableCredential =
serde_json::from_reader(credential_reader).unwrap();
credential.validate_unsigned().unwrap();
credential
.verify(Some(options), &resolver, &mut context_loader)
.await
}
_ => {
panic!("Unknown proof format: {:?}", proof_format);
}
};
let stdout_writer = BufWriter::new(stdout());
serde_json::to_writer(stdout_writer, &result).unwrap();
if !result.errors.is_empty() {
std::process::exit(2);
}
Ok(())
}