acme_lib_load_order/acc/
mod.rs1use std::sync::Arc;
3
4use crate::api::{ApiAccount, ApiDirectory, ApiIdentifier, ApiOrder, ApiRevocation};
5use crate::cert::Certificate;
6use crate::order::{NewOrder, Order};
7use crate::persist::{Persist, PersistKey, PersistKind};
8use crate::req::req_expect_header;
9use crate::trans::Transport;
10use crate::util::{base64url, read_json};
11use crate::Result;
12
13mod akey;
14
15pub(crate) use self::akey::AcmeKey;
16
17#[derive(Clone, Debug)]
18pub(crate) struct AccountInner<P: Persist> {
19 pub persist: P,
20 pub transport: Transport,
21 pub realm: String,
22 pub api_account: ApiAccount,
23 pub api_directory: ApiDirectory,
24}
25
26#[derive(Clone)]
41pub struct Account<P: Persist> {
42 inner: Arc<AccountInner<P>>,
43}
44
45impl<P: Persist> Account<P> {
46 pub(crate) fn new(
47 persist: P,
48 transport: Transport,
49 realm: &str,
50 api_account: ApiAccount,
51 api_directory: ApiDirectory,
52 ) -> Self {
53 Account {
54 inner: Arc::new(AccountInner {
55 persist,
56 transport,
57 realm: realm.to_string(),
58 api_account,
59 api_directory,
60 }),
61 }
62 }
63
64 pub fn acme_private_key_pem(&self) -> String {
68 String::from_utf8(self.inner.transport.acme_key().to_pem()).expect("from_utf8")
69 }
70
71 pub fn certificate(&self, primary_name: &str) -> Result<Option<Certificate>> {
83 let realm = &self.inner.realm;
85 let persist = &self.inner.persist;
86
87 let pk_key = PersistKey::new(realm, PersistKind::PrivateKey, primary_name);
89 debug!("Read private key: {}", pk_key);
90 let private_key = persist
91 .get(&pk_key)?
92 .and_then(|s| String::from_utf8(s).ok());
93
94 let pk_crt = PersistKey::new(realm, PersistKind::Certificate, primary_name);
96 debug!("Read certificate: {}", pk_crt);
97 let certificate = persist
98 .get(&pk_crt)?
99 .and_then(|s| String::from_utf8(s).ok());
100
101 Ok(match (private_key, certificate) {
102 (Some(k), Some(c)) => Some(Certificate::new(k, c)),
103 _ => None,
104 })
105 }
106
107 pub fn new_order(&self, primary_name: &str, alt_names: &[&str]) -> Result<NewOrder<P>> {
120 let prim_arr = [primary_name];
122 let domains = prim_arr.iter().chain(alt_names);
123 let order = ApiOrder {
124 identifiers: domains
125 .map(|s| ApiIdentifier {
126 _type: "dns".into(),
127 value: s.to_string(),
128 })
129 .collect(),
130 ..Default::default()
131 };
132
133 let new_order_url = &self.inner.api_directory.newOrder;
134
135 let res = self.inner.transport.call(new_order_url, &order)?;
136 let order_url = req_expect_header(&res, "location")?;
137 let api_order: ApiOrder = read_json(res)?;
138
139 let order = Order::new(&self.inner, api_order, order_url);
140 Ok(NewOrder { order })
141 }
142
143
144 pub fn load_order(&self, order_url: &str) -> Result<NewOrder<P>> {
149 let res = self.inner.transport.call(order_url, "")?;
150 let api_order: ApiOrder = read_json(res)?;
151 let order = Order::new(&self.inner, api_order, order_url.to_string());
152 Ok(NewOrder { order })
153 }
154
155 pub fn revoke_certificate(&self, cert: &Certificate, reason: RevocationReason) -> Result<()> {
162 let certificate = base64url(&cert.certificate_der());
164
165 let revoc = ApiRevocation {
166 certificate,
167 reason: reason as usize,
168 };
169
170 let url = &self.inner.api_directory.revokeCert;
171 self.inner.transport.call(url, &revoc)?;
172
173 Ok(())
174 }
175
176 pub fn api_account(&self) -> &ApiAccount {
178 &self.inner.api_account
179 }
180}
181
182pub enum RevocationReason {
186 Unspecified = 0,
187 KeyCompromise = 1,
188 CACompromise = 2,
189 AffiliationChanged = 3,
190 Superseded = 4,
191 CessationOfOperation = 5,
192 CertificateHold = 6,
193 RemoveFromCRL = 8,
195 PrivilegeWithdrawn = 9,
196 AACompromise = 10,
197}
198
199#[cfg(test)]
200mod test {
201 use crate::persist::*;
202 use crate::*;
203
204 #[test]
205 fn test_create_order() -> Result<()> {
206 let server = crate::test::with_directory_server();
207 let url = DirectoryUrl::Other(&server.dir_url);
208 let persist = MemoryPersist::new();
209 let dir = Directory::from_url(persist, url)?;
210 let acc = dir.account("foo@bar.com")?;
211 let _ = acc.new_order("acmetest.example.com", &[])?;
212 Ok(())
213 }
214}