(&self)
| 81 | |
| 82 | impl Renew { |
| 83 | async fn execute(&self) -> CliResult<()> { |
| 84 | let store = IdentityStore::open_default().map_err(|e| { |
| 85 | CliError::Internal(anyhow::anyhow!("Failed to open identity store: {e}")) |
| 86 | })?; |
| 87 | |
| 88 | let agent = store |
| 89 | .load_by_name(&self.name) |
| 90 | .map_err(|_| CliError::IdentityNotFound(self.name.clone()))?; |
| 91 | |
| 92 | // Renew from the newest certificate even when it is expired or revoked |
| 93 | // — its scope is the record of what was intended, and expiry is the |
| 94 | // very thing being fixed. |
| 95 | let previous = load_for_delegate(&store, &agent)? |
| 96 | .into_iter() |
| 97 | .next() |
| 98 | .ok_or_else(|| CliError::DelegationError { |
| 99 | message: format!( |
| 100 | "'{}' has no certificate to renew.\n Issue one with: atomic identity delegate {}", |
| 101 | self.name, self.name |
| 102 | ), |
| 103 | })?; |
| 104 | |
| 105 | let delegator = store |
| 106 | .load_by_name(&previous.delegation.delegator_name) |
| 107 | .map_err(|_| CliError::DelegationError { |
| 108 | message: format!( |
| 109 | "The delegating identity '{}' is not on this machine, so a renewal cannot \ |
| 110 | be signed here.\n Renew from the machine holding that key.", |
| 111 | previous.delegation.delegator_name |
| 112 | ), |
| 113 | })?; |
| 114 | |
| 115 | // Guard against a name collision resolving to a different key than the |
| 116 | // one that signed the original. |
| 117 | if delegator.id.to_did() != previous.delegation.delegator { |
| 118 | return Err(CliError::DelegationError { |
| 119 | message: format!( |
| 120 | "Identity '{}' on this machine is not the key that issued the current \ |
| 121 | certificate.\n Renew from the machine holding {}.", |
| 122 | previous.delegation.delegator_name, previous.delegation.delegator |
| 123 | ), |
| 124 | }); |
| 125 | } |
| 126 | |
| 127 | let scope = self.next_scope(&previous.delegation.scope)?; |
| 128 | let expires = self |
| 129 | .expires |
| 130 | .as_deref() |
| 131 | .map(parse_duration) |
| 132 | .transpose()? |
| 133 | .unwrap_or_else(|| Duration::days(DEFAULT_EXPIRY_DAYS)); |
| 134 | |
| 135 | let mut terms = Delegation::new(&delegator, &agent, scope).expires_in(expires); |
| 136 | if let Some(agent_urn) = &previous.delegation.software_agent { |
| 137 | terms = terms.with_software_agent(agent_urn.clone()); |
| 138 | } |
| 139 | |
| 140 | let keypair = store.load_keypair(&delegator.id, None).map_err(|e| { |
no test coverage detected