1 use std::{collections::BTreeMap, fmt, str::FromStr}; 2 3 use chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc}; 4 5 use rpki::repository::{crypto::KeyIdentifier, x509::Time}; 6 7 use crate::{ 8 commons::{ 9 api::{ 10 ArgKey, ArgVal, AspaCustomer, AspaProvidersUpdate, ChildHandle, Handle, Label, Message, ParentHandle, 11 PublisherHandle, RequestResourceLimit, ResourceClassName, ResourceSet, RevocationRequest, 12 RoaDefinitionUpdates, RtaName, StorableParentContact, 13 }, 14 eventsourcing::{CommandKey, CommandKeyError, StoredCommand, WithStorableDetails}, 15 remote::rfc8183::ServiceUri, 16 }, 17 daemon::ca::{self, DropReason}, 18 }; 19 20 use super::AspaDefinitionUpdates; 21 22 //------------ CaCommandDetails ---------------------------------------------- 23 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 24 pub struct CaCommandDetails { 25 command: StoredCommand<StorableCaCommand>, 26 result: CaCommandResult, 27 } 28 29 impl CaCommandDetails { new(command: StoredCommand<StorableCaCommand>, result: CaCommandResult) -> Self30 pub fn new(command: StoredCommand<StorableCaCommand>, result: CaCommandResult) -> Self { 31 CaCommandDetails { command, result } 32 } 33 command(&self) -> &StoredCommand<StorableCaCommand>34 pub fn command(&self) -> &StoredCommand<StorableCaCommand> { 35 &self.command 36 } 37 effect(&self) -> &CaCommandResult38 pub fn effect(&self) -> &CaCommandResult { 39 &self.result 40 } 41 } 42 43 impl fmt::Display for CaCommandDetails { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 45 let command = self.command(); 46 writeln!( 47 f, 48 "Time: {}", 49 command.time().to_rfc3339_opts(SecondsFormat::Secs, true) 50 )?; 51 writeln!(f, "Action: {}", command.details().summary().msg)?; 52 53 match self.effect() { 54 CaCommandResult::Error(msg) => writeln!(f, "Error: {}", msg)?, 55 CaCommandResult::Events(events) => { 56 writeln!(f, "Changes:")?; 57 for evt in events { 58 writeln!(f, " {}", evt.details().to_string())?; 59 } 60 } 61 } 62 63 Ok(()) 64 } 65 } 66 67 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 68 pub enum CaCommandResult { 69 Error(String), 70 Events(Vec<ca::CaEvt>), 71 } 72 73 impl CaCommandResult { error(msg: String) -> Self74 pub fn error(msg: String) -> Self { 75 CaCommandResult::Error(msg) 76 } events(events: Vec<ca::CaEvt>) -> Self77 pub fn events(events: Vec<ca::CaEvt>) -> Self { 78 CaCommandResult::Events(events) 79 } 80 } 81 82 //------------ CommandHistory ------------------------------------------------ 83 84 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 85 pub struct CommandHistory { 86 offset: usize, 87 total: usize, 88 commands: Vec<CommandHistoryRecord>, 89 } 90 91 impl CommandHistory { new(offset: usize, total: usize, commands: Vec<CommandHistoryRecord>) -> Self92 pub fn new(offset: usize, total: usize, commands: Vec<CommandHistoryRecord>) -> Self { 93 CommandHistory { 94 offset, 95 total, 96 commands, 97 } 98 } 99 offset(&self) -> usize100 pub fn offset(&self) -> usize { 101 self.offset 102 } 103 total(&self) -> usize104 pub fn total(&self) -> usize { 105 self.total 106 } 107 commands(&self) -> &Vec<CommandHistoryRecord>108 pub fn commands(&self) -> &Vec<CommandHistoryRecord> { 109 &self.commands 110 } 111 } 112 113 impl fmt::Display for CommandHistory { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 115 writeln!(f, "time::command::key::success")?; 116 117 for command in self.commands() { 118 let success_string = match &command.effect { 119 StoredEffect::Error { msg } => format!("ERROR -> {}", msg), 120 StoredEffect::Success { .. } => "OK".to_string(), 121 }; 122 writeln!( 123 f, 124 "{}::{} ::{}::{}", 125 command.time().to_rfc3339_opts(SecondsFormat::Secs, true), 126 command.summary.msg, 127 command.key, 128 success_string 129 )?; 130 } 131 132 Ok(()) 133 } 134 } 135 136 //------------ CommandHistoryRecord ------------------------------------------ 137 138 /// A description of a command that was processed, and the events / or error 139 /// that followed. Does not include the full stored command details, but only 140 /// the summary which is shown in the history response. 141 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 142 pub struct CommandHistoryRecord { 143 pub key: String, 144 pub actor: String, 145 pub timestamp: i64, 146 pub handle: Handle, 147 pub version: u64, 148 pub sequence: u64, 149 pub summary: CommandSummary, 150 pub effect: StoredEffect, 151 } 152 153 impl CommandHistoryRecord { time(&self) -> Time154 pub fn time(&self) -> Time { 155 let seconds = self.timestamp / 1000; 156 let time = NaiveDateTime::from_timestamp(seconds, 0); 157 Time::from(DateTime::from_utc(time, Utc)) 158 } 159 resulting_version(&self) -> u64160 pub fn resulting_version(&self) -> u64 { 161 if let Some(versions) = self.effect.events() { 162 if let Some(last) = versions.last() { 163 *last 164 } else { 165 self.version 166 } 167 } else { 168 self.version 169 } 170 } 171 command_key(&self) -> Result<CommandKey, CommandKeyError>172 pub fn command_key(&self) -> Result<CommandKey, CommandKeyError> { 173 CommandKey::from_str(&self.key) 174 } 175 } 176 177 //------------ StoredEffect -------------------------------------------------- 178 179 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 180 #[serde(rename_all = "snake_case", tag = "result")] 181 pub enum StoredEffect { 182 Error { msg: String }, 183 Success { events: Vec<u64> }, 184 } 185 186 impl StoredEffect { successful(&self) -> bool187 pub fn successful(&self) -> bool { 188 match self { 189 StoredEffect::Error { .. } => false, 190 StoredEffect::Success { .. } => true, 191 } 192 } 193 events(&self) -> Option<&Vec<u64>>194 pub fn events(&self) -> Option<&Vec<u64>> { 195 match self { 196 StoredEffect::Error { .. } => None, 197 StoredEffect::Success { events } => Some(events), 198 } 199 } 200 } 201 202 //------------ CommandSummary ------------------------------------------------ 203 204 /// Generic command summary used to show command details in history in a way 205 /// that support internationalization. 206 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 207 pub struct CommandSummary { 208 pub msg: Message, 209 pub label: Label, 210 pub args: BTreeMap<ArgKey, ArgVal>, 211 } 212 213 impl CommandSummary { new(label: &str, msg: impl fmt::Display) -> Self214 pub fn new(label: &str, msg: impl fmt::Display) -> Self { 215 CommandSummary { 216 msg: msg.to_string(), 217 label: label.to_string(), 218 args: BTreeMap::new(), 219 } 220 } 221 with_arg(mut self, key: &str, val: impl fmt::Display) -> Self222 pub fn with_arg(mut self, key: &str, val: impl fmt::Display) -> Self { 223 self.args.insert(key.to_string(), val.to_string()); 224 self 225 } 226 with_child(self, child: &ChildHandle) -> Self227 pub fn with_child(self, child: &ChildHandle) -> Self { 228 self.with_arg("child", child) 229 } 230 with_parent(self, parent: &ParentHandle) -> Self231 pub fn with_parent(self, parent: &ParentHandle) -> Self { 232 self.with_arg("parent", parent) 233 } 234 with_publisher(self, publisher: &PublisherHandle) -> Self235 pub fn with_publisher(self, publisher: &PublisherHandle) -> Self { 236 self.with_arg("publisher", publisher) 237 } 238 with_id_ski(self, id: &str) -> Self239 pub fn with_id_ski(self, id: &str) -> Self { 240 self.with_arg("id_key", id) 241 } 242 with_resources(self, resources: &ResourceSet) -> Self243 pub fn with_resources(self, resources: &ResourceSet) -> Self { 244 let summary = resources.summary(); 245 self.with_arg("resources", resources) 246 .with_arg("asn_blocks", summary.asn_blocks()) 247 .with_arg("ipv4_blocks", summary.ipv4_blocks()) 248 .with_arg("ipv6_blocks", summary.ipv6_blocks()) 249 } 250 with_rcn(self, rcn: &ResourceClassName) -> Self251 pub fn with_rcn(self, rcn: &ResourceClassName) -> Self { 252 self.with_arg("class_name", rcn) 253 } 254 with_key(self, ki: &KeyIdentifier) -> Self255 pub fn with_key(self, ki: &KeyIdentifier) -> Self { 256 self.with_arg("key", ki) 257 } 258 with_parent_contact(self, contact: &StorableParentContact) -> Self259 pub fn with_parent_contact(self, contact: &StorableParentContact) -> Self { 260 self.with_arg("parent_contact", contact) 261 } 262 with_seconds(self, seconds: i64) -> Self263 pub fn with_seconds(self, seconds: i64) -> Self { 264 self.with_arg("seconds", seconds) 265 } 266 with_added(self, nr: usize) -> Self267 pub fn with_added(self, nr: usize) -> Self { 268 self.with_arg("added", nr) 269 } 270 with_removed(self, nr: usize) -> Self271 pub fn with_removed(self, nr: usize) -> Self { 272 self.with_arg("removed", nr) 273 } 274 with_service_uri(self, service_uri: &ServiceUri) -> Self275 pub fn with_service_uri(self, service_uri: &ServiceUri) -> Self { 276 self.with_arg("service_uri", service_uri) 277 } 278 with_rta_name(self, name: &str) -> Self279 pub fn with_rta_name(self, name: &str) -> Self { 280 self.with_arg("rta_name", name) 281 } 282 } 283 284 //------------ CommandHistoryCriteria ---------------------------------------- 285 286 /// Used to limit the scope when finding commands to show in the history. 287 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 288 pub struct CommandHistoryCriteria { 289 #[serde(skip_serializing_if = "Option::is_none")] 290 before: Option<i64>, 291 #[serde(skip_serializing_if = "Option::is_none")] 292 after: Option<i64>, 293 #[serde(skip_serializing_if = "Option::is_none")] 294 after_sequence: Option<u64>, 295 #[serde(skip_serializing_if = "Option::is_none")] 296 label_includes: Option<Vec<String>>, 297 #[serde(skip_serializing_if = "Option::is_none")] 298 label_excludes: Option<Vec<String>>, 299 300 offset: usize, 301 #[serde(skip_serializing_if = "Option::is_none")] 302 rows_limit: Option<usize>, 303 } 304 305 impl CommandHistoryCriteria { set_excludes(&mut self, labels: &[&str])306 pub fn set_excludes(&mut self, labels: &[&str]) { 307 self.label_excludes = Some(labels.iter().map(|s| (*s).to_string()).collect()); 308 } 309 set_includes(&mut self, labels: &[&str])310 pub fn set_includes(&mut self, labels: &[&str]) { 311 self.label_includes = Some(labels.iter().map(|s| (*s).to_string()).collect()); 312 } 313 set_after(&mut self, timestamp: i64)314 pub fn set_after(&mut self, timestamp: i64) { 315 self.after = Some(timestamp); 316 } 317 set_before(&mut self, timestamp: i64)318 pub fn set_before(&mut self, timestamp: i64) { 319 self.before = Some(timestamp); 320 } 321 set_after_sequence(&mut self, sequence: u64)322 pub fn set_after_sequence(&mut self, sequence: u64) { 323 self.after_sequence = Some(sequence) 324 } 325 set_rows(&mut self, rows: usize)326 pub fn set_rows(&mut self, rows: usize) { 327 self.rows_limit = Some(rows); 328 } 329 set_unlimited_rows(&mut self)330 pub fn set_unlimited_rows(&mut self) { 331 self.rows_limit = None 332 } 333 set_offset(&mut self, offset: usize)334 pub fn set_offset(&mut self, offset: usize) { 335 self.offset = offset; 336 } 337 matches_timestamp_secs(&self, stamp: i64) -> bool338 pub fn matches_timestamp_secs(&self, stamp: i64) -> bool { 339 if let Some(before) = self.before { 340 if stamp > before { 341 return false; 342 } 343 } 344 if let Some(after) = self.after { 345 if stamp < after { 346 return false; 347 } 348 } 349 true 350 } 351 matches_sequence(&self, sequence: u64) -> bool352 pub fn matches_sequence(&self, sequence: u64) -> bool { 353 match self.after_sequence { 354 None => true, 355 Some(seq_crit) => sequence > seq_crit, 356 } 357 } 358 359 #[allow(clippy::ptr_arg)] matches_label(&self, label: &Label) -> bool360 pub fn matches_label(&self, label: &Label) -> bool { 361 if let Some(includes) = &self.label_includes { 362 if !includes.contains(label) { 363 return false; 364 } 365 } 366 if let Some(excludes) = &self.label_excludes { 367 if excludes.contains(label) { 368 return false; 369 } 370 } 371 372 true 373 } 374 offset(&self) -> usize375 pub fn offset(&self) -> usize { 376 self.offset 377 } 378 rows_limit(&self) -> Option<usize>379 pub fn rows_limit(&self) -> Option<usize> { 380 self.rows_limit 381 } 382 } 383 384 impl Default for CommandHistoryCriteria { default() -> Self385 fn default() -> Self { 386 CommandHistoryCriteria { 387 before: None, 388 after: None, 389 after_sequence: None, 390 label_includes: None, 391 label_excludes: None, 392 offset: 0, 393 rows_limit: Some(100), 394 } 395 } 396 } 397 398 //------------ StorableCaCommand ------------------------------------------- 399 400 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 401 #[allow(clippy::large_enum_variant)] 402 #[serde(rename_all = "snake_case")] 403 #[serde(tag = "type")] 404 pub enum StorableCaCommand { 405 MakeTrustAnchor, 406 ChildAdd { 407 child: ChildHandle, 408 ski: String, 409 resources: ResourceSet, 410 }, 411 ChildUpdateResources { 412 child: ChildHandle, 413 resources: ResourceSet, 414 }, 415 ChildUpdateId { 416 child: ChildHandle, 417 ski: String, 418 }, 419 ChildCertify { 420 child: ChildHandle, 421 resource_class_name: ResourceClassName, 422 limit: RequestResourceLimit, 423 ki: KeyIdentifier, 424 }, 425 ChildRevokeKey { 426 child: ChildHandle, 427 revoke_req: RevocationRequest, 428 }, 429 ChildRemove { 430 child: ChildHandle, 431 }, 432 ChildSuspendInactive { 433 child: ChildHandle, 434 }, 435 ChildUnsuspend { 436 child: ChildHandle, 437 }, 438 GenerateNewIdKey, 439 AddParent { 440 parent: ParentHandle, 441 contact: StorableParentContact, 442 }, 443 UpdateParentContact { 444 parent: ParentHandle, 445 contact: StorableParentContact, 446 }, 447 RemoveParent { 448 parent: ParentHandle, 449 }, 450 UpdateResourceEntitlements { 451 parent: ParentHandle, 452 entitlements: Vec<StorableRcEntitlement>, 453 }, 454 UpdateRcvdCert { 455 resource_class_name: ResourceClassName, 456 resources: ResourceSet, 457 }, 458 DropResourceClass { 459 resource_class_name: ResourceClassName, 460 reason: DropReason, 461 }, 462 KeyRollInitiate { 463 older_than_seconds: i64, 464 }, 465 KeyRollActivate { 466 staged_for_seconds: i64, 467 }, 468 KeyRollFinish { 469 resource_class_name: ResourceClassName, 470 }, 471 RoaDefinitionUpdates { 472 updates: RoaDefinitionUpdates, 473 }, 474 ReissueBeforeExpiring, 475 ForceReissue, 476 AspasUpdate { 477 updates: AspaDefinitionUpdates, 478 }, 479 AspasUpdateExisting { 480 customer: AspaCustomer, 481 update: AspaProvidersUpdate, 482 }, 483 AspaRemove { 484 customer: AspaCustomer, 485 }, 486 RepoUpdate { 487 service_uri: ServiceUri, 488 }, 489 RtaPrepare { 490 name: RtaName, 491 }, 492 RtaSign { 493 name: RtaName, 494 }, 495 RtaCoSign { 496 name: RtaName, 497 }, 498 Deactivate, 499 } 500 501 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 502 pub struct StorableRcEntitlement { 503 pub resource_class_name: ResourceClassName, 504 pub resources: ResourceSet, 505 } 506 507 impl WithStorableDetails for StorableCaCommand { summary(&self) -> CommandSummary508 fn summary(&self) -> CommandSummary { 509 match self { 510 StorableCaCommand::MakeTrustAnchor => CommandSummary::new("cmd-ca-make-ta", &self), 511 StorableCaCommand::ChildAdd { child, ski, resources } => CommandSummary::new("cmd-ca-child-add", &self) 512 .with_child(child) 513 .with_id_ski(ski.as_ref()) 514 .with_resources(resources), 515 StorableCaCommand::ChildUpdateResources { child, resources } => { 516 CommandSummary::new("cmd-ca-child-update-res", &self) 517 .with_child(child) 518 .with_resources(resources) 519 } 520 StorableCaCommand::ChildUpdateId { child, ski } => CommandSummary::new("cmd-ca-child-update-id", &self) 521 .with_child(child) 522 .with_id_ski(ski), 523 StorableCaCommand::ChildCertify { 524 child, 525 resource_class_name, 526 ki, 527 .. 528 } => CommandSummary::new("cmd-ca-child-certify", &self) 529 .with_child(child) 530 .with_rcn(resource_class_name) 531 .with_key(ki), 532 StorableCaCommand::ChildRemove { child } => { 533 CommandSummary::new("cmd-ca-child-remove", &self).with_child(child) 534 } 535 StorableCaCommand::ChildSuspendInactive { child } => { 536 CommandSummary::new("cmd-ca-child-suspend-inactive", &self).with_child(child) 537 } 538 StorableCaCommand::ChildUnsuspend { child } => { 539 CommandSummary::new("cmd-ca-child-unsuspend", &self).with_child(child) 540 } 541 StorableCaCommand::ChildRevokeKey { child, revoke_req } => { 542 CommandSummary::new("cmd-ca-child-revoke", &self) 543 .with_child(child) 544 .with_rcn(revoke_req.class_name()) 545 .with_key(revoke_req.key()) 546 } 547 StorableCaCommand::GenerateNewIdKey => CommandSummary::new("cmd-ca-generate-new-id", &self), 548 StorableCaCommand::AddParent { parent, contact } => CommandSummary::new("cmd-ca-parent-add", &self) 549 .with_parent(parent) 550 .with_parent_contact(contact), 551 StorableCaCommand::UpdateParentContact { parent, contact } => { 552 CommandSummary::new("cmd-ca-parent-update", &self) 553 .with_parent(parent) 554 .with_parent_contact(contact) 555 } 556 StorableCaCommand::RemoveParent { parent } => { 557 CommandSummary::new("cmd-ca-parent-remove", &self).with_parent(parent) 558 } 559 StorableCaCommand::UpdateResourceEntitlements { parent, .. } => { 560 CommandSummary::new("cmd-ca-parent-entitlements", &self).with_parent(parent) 561 } 562 StorableCaCommand::UpdateRcvdCert { 563 resource_class_name, 564 resources, 565 } => CommandSummary::new("cmd-ca-rcn-receive", &self) 566 .with_rcn(resource_class_name) 567 .with_resources(resources), 568 StorableCaCommand::DropResourceClass { 569 resource_class_name, 570 reason, 571 } => CommandSummary::new("cmd-ca-rc-drop", &self) 572 .with_rcn(resource_class_name) 573 .with_arg("reason", reason), 574 575 // Key rolls 576 StorableCaCommand::KeyRollInitiate { older_than_seconds } => { 577 CommandSummary::new("cmd-ca-keyroll-init", &self).with_seconds(*older_than_seconds) 578 } 579 StorableCaCommand::KeyRollActivate { staged_for_seconds } => { 580 CommandSummary::new("cmd-ca-keyroll-activate", &self).with_seconds(*staged_for_seconds) 581 } 582 StorableCaCommand::KeyRollFinish { resource_class_name } => { 583 CommandSummary::new("cmd-ca-keyroll-finish", &self).with_rcn(resource_class_name) 584 } 585 586 // ROA 587 StorableCaCommand::RoaDefinitionUpdates { updates } => CommandSummary::new("cmd-ca-roas-updated", &self) 588 .with_added(updates.added().len()) 589 .with_removed(updates.removed().len()), 590 591 // ASPA 592 StorableCaCommand::AspasUpdate { .. } => CommandSummary::new("cmd-ca-aspas-update", &self), 593 StorableCaCommand::AspasUpdateExisting { .. } => CommandSummary::new("cmd-ca-aspas-update-existing", &self), 594 StorableCaCommand::AspaRemove { .. } => CommandSummary::new("cmd-ca-aspas-remove", &self), 595 596 // REPO 597 StorableCaCommand::RepoUpdate { service_uri } => { 598 CommandSummary::new("cmd-ca-repo-update", &self).with_service_uri(service_uri) 599 } 600 601 StorableCaCommand::ReissueBeforeExpiring => CommandSummary::new("cmd-ca-reissue-before-expiring", &self), 602 StorableCaCommand::ForceReissue => CommandSummary::new("cmd-ca-force-reissue", &self), 603 604 // RTA 605 StorableCaCommand::RtaPrepare { name } => { 606 CommandSummary::new("cmd-ca-rta-prepare", &self).with_rta_name(name) 607 } 608 StorableCaCommand::RtaSign { name } => CommandSummary::new("cmd-ca-rta-sign", &self).with_rta_name(name), 609 StorableCaCommand::RtaCoSign { name } => { 610 CommandSummary::new("cmd-ca-rta-cosign", &self).with_rta_name(name) 611 } 612 613 // Deactivation 614 StorableCaCommand::Deactivate => CommandSummary::new("cmd-ca-deactivate", &self), 615 } 616 } 617 } 618 619 impl fmt::Display for StorableCaCommand { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result620 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 621 match self { 622 // ------------------------------------------------------------ 623 // Becoming a trust anchor 624 // ------------------------------------------------------------ 625 StorableCaCommand::MakeTrustAnchor => write!(f, "Turn into Trust Anchor"), 626 627 // ------------------------------------------------------------ 628 // Being a parent 629 // ------------------------------------------------------------ 630 StorableCaCommand::ChildAdd { child, ski, resources } => write!( 631 f, 632 "Add child '{}' with RFC8183 key '{}' and resources '{}'", 633 child, 634 ski, 635 resources.summary() 636 ), 637 StorableCaCommand::ChildUpdateResources { child, resources } => { 638 write!(f, "Update resources for child '{}' to: {}", child, resources.summary()) 639 } 640 StorableCaCommand::ChildUpdateId { child, ski } => { 641 write!(f, "Update child '{}' RFC 8183 key '{}'", child, ski) 642 } 643 StorableCaCommand::ChildCertify { child, ki, .. } => { 644 write!(f, "Issue certificate to child '{}' for key '{}'", child, ki) 645 } 646 StorableCaCommand::ChildRevokeKey { child, revoke_req } => write!( 647 f, 648 "Revoke certificates for child '{}' for key '{}' in RC {}", 649 child, 650 revoke_req.key(), 651 revoke_req.class_name() 652 ), 653 StorableCaCommand::ChildRemove { child } => { 654 write!(f, "Remove child '{}' and revoke & remove its certs", child) 655 } 656 StorableCaCommand::ChildSuspendInactive { child } => { 657 write!(f, "Suspend inactive child '{}': stop publishing its certs", child) 658 } 659 StorableCaCommand::ChildUnsuspend { child } => { 660 write!(f, "Unsuspend child '{}': publish its unexpired certs", child) 661 } 662 663 // ------------------------------------------------------------ 664 // Being a child (only allowed if this CA is not self-signed) 665 // ------------------------------------------------------------ 666 StorableCaCommand::GenerateNewIdKey => write!(f, "Generate a new RFC8183 ID."), 667 StorableCaCommand::AddParent { parent, contact } => write!(f, "Add parent '{}' as '{}'", parent, contact), 668 StorableCaCommand::UpdateParentContact { parent, contact } => { 669 write!(f, "Update contact for parent '{}' to '{}'", parent, contact) 670 } 671 StorableCaCommand::RemoveParent { parent } => write!(f, "Remove parent '{}'", parent), 672 673 StorableCaCommand::UpdateResourceEntitlements { parent, entitlements } => { 674 let mut summary = format!("Update entitlements under parent '{}': ", parent); 675 676 for entitlement in entitlements.iter() { 677 summary.push_str(&format!( 678 "{} => {} ", 679 entitlement.resource_class_name, entitlement.resources 680 )) 681 } 682 683 write!(f, "{}", summary) 684 } 685 // Process a new certificate received from a parent. 686 StorableCaCommand::UpdateRcvdCert { 687 resource_class_name, 688 resources, 689 } => write!( 690 f, 691 "Update received cert in RC '{}', with resources '{}'", 692 resource_class_name, 693 resources.summary() 694 ), 695 StorableCaCommand::DropResourceClass { 696 resource_class_name, 697 reason, 698 } => write!( 699 f, 700 "Removing resource class '{}' because of reason: {}", 701 resource_class_name, reason 702 ), 703 704 // ------------------------------------------------------------ 705 // Key rolls 706 // ------------------------------------------------------------ 707 StorableCaCommand::KeyRollInitiate { older_than_seconds } => { 708 write!( 709 f, 710 "Initiate key roll for keys older than '{}' seconds", 711 older_than_seconds 712 ) 713 } 714 StorableCaCommand::KeyRollActivate { staged_for_seconds } => { 715 write!( 716 f, 717 "Activate new keys staging longer than '{}' seconds", 718 staged_for_seconds 719 ) 720 } 721 722 StorableCaCommand::KeyRollFinish { resource_class_name } => { 723 write!(f, "Retire old revoked key in RC '{}'", resource_class_name) 724 } 725 726 // ------------------------------------------------------------ 727 // ROA Support 728 // ------------------------------------------------------------ 729 StorableCaCommand::RoaDefinitionUpdates { updates } => { 730 write!(f, "Update ROAs",)?; 731 if !updates.added().is_empty() { 732 write!(f, " ADD:",)?; 733 for addition in updates.added() { 734 write!(f, " {}", addition)?; 735 } 736 } 737 if !updates.removed().is_empty() { 738 write!(f, " REMOVE:",)?; 739 for rem in updates.removed() { 740 write!(f, " {}", rem)?; 741 } 742 } 743 Ok(()) 744 } 745 StorableCaCommand::ReissueBeforeExpiring => { 746 write!(f, "Automatically re-issue objects before they would expire") 747 } 748 StorableCaCommand::ForceReissue => { 749 write!(f, "Force re-issuance of objects") 750 } 751 752 // ------------------------------------------------------------ 753 // ASPA Support 754 // ------------------------------------------------------------ 755 StorableCaCommand::AspasUpdate { updates } => { 756 write!(f, "{}", updates) 757 } 758 StorableCaCommand::AspasUpdateExisting { customer, update } => { 759 write!(f, "update ASPA for customer AS: {} {}", customer, update) 760 } 761 StorableCaCommand::AspaRemove { customer } => { 762 write!(f, "Remove ASPA for customer AS: {}", customer) 763 } 764 765 // ------------------------------------------------------------ 766 // Publishing 767 // ------------------------------------------------------------ 768 StorableCaCommand::RepoUpdate { service_uri } => write!(f, "Update repo to server at: {}", service_uri), 769 770 // ------------------------------------------------------------ 771 // RTA 772 // ------------------------------------------------------------ 773 StorableCaCommand::RtaPrepare { name } => write!(f, "RTA Prepare {}", name), 774 StorableCaCommand::RtaSign { name } => write!(f, "RTA Sign {}", name), 775 StorableCaCommand::RtaCoSign { name } => write!(f, "RTA Co-Sign {}", name), 776 777 // ------------------------------------------------------------ 778 // Deactivate 779 // ------------------------------------------------------------ 780 StorableCaCommand::Deactivate => write!(f, "Deactivate CA"), 781 } 782 } 783 } 784 785 //------------ StorableRepositoryCommand ----------------------------------- 786 787 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 788 #[allow(clippy::large_enum_variant)] 789 #[serde(rename_all = "snake_case", tag = "type")] 790 pub enum StorableRepositoryCommand { 791 AddPublisher { name: PublisherHandle }, 792 RemovePublisher { name: PublisherHandle }, 793 } 794 795 impl WithStorableDetails for StorableRepositoryCommand { summary(&self) -> CommandSummary796 fn summary(&self) -> CommandSummary { 797 match self { 798 StorableRepositoryCommand::AddPublisher { name } => { 799 CommandSummary::new("pubd-publisher-add", &self).with_publisher(name) 800 } 801 StorableRepositoryCommand::RemovePublisher { name } => { 802 CommandSummary::new("pubd-publisher-remove", &self).with_publisher(name) 803 } 804 } 805 } 806 } 807 808 impl fmt::Display for StorableRepositoryCommand { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result809 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 810 match self { 811 StorableRepositoryCommand::AddPublisher { name } => { 812 write!(f, "Added publisher '{}'", name) 813 } 814 StorableRepositoryCommand::RemovePublisher { name } => write!(f, "Removed publisher '{}'", name), 815 } 816 } 817 } 818