1 use std::{ 2 collections::HashMap, 3 convert::{TryFrom, TryInto}, 4 fmt, 5 path::PathBuf, 6 }; 7 8 use rpki::{ 9 repository::{ 10 crypto::KeyIdentifier, 11 roa::Roa, 12 x509::{Serial, Time}, 13 }, 14 uri, 15 }; 16 17 use crate::{ 18 commons::{ 19 api::{ 20 rrdp::{CurrentObjects, DeltaElements, PublishElement, RrdpSession}, 21 Base64, ChildHandle, Handle, HexEncodedHash, IssuanceRequest, IssuedCert, ObjectName, ParentCaContact, 22 ParentHandle, PublisherHandle, RcvdCert, RepoInfo, RepositoryContact, ResourceClassName, ResourceSet, 23 RevocationRequest, RevocationsDelta, RevokedObject, RoaAggregateKey, RtaName, TaCertDetails, 24 }, 25 crypto::IdCert, 26 eventsourcing::StoredEvent, 27 remote::rfc8183, 28 }, 29 daemon::ca::{self, CaEvt, CaEvtDet, PreparedRta, RouteAuthorization, SignedRta}, 30 pubd::{ 31 Publisher, RepositoryAccessEvent, RepositoryAccessEventDetails, RepositoryAccessInitDetails, RepositoryManager, 32 RrdpSessionReset, RrdpUpdate, 33 }, 34 upgrades::UpgradeError, 35 }; 36 37 use super::*; 38 39 pub type OldPubdEvt = StoredEvent<OldPubdEvtDet>; 40 pub type OldPubdInit = StoredEvent<OldPubdIniDet>; 41 pub type OldCaEvt = StoredEvent<OldCaEvtDet>; 42 43 impl OldPubdEvt { into_stored_pubd_event(self, version: u64) -> Result<RepositoryAccessEvent, UpgradeError>44 pub fn into_stored_pubd_event(self, version: u64) -> Result<RepositoryAccessEvent, UpgradeError> { 45 let (id, _, details) = self.unpack(); 46 Ok(RepositoryAccessEvent::new(&id, version, details.into())) 47 } 48 needs_migration(&self) -> bool49 pub fn needs_migration(&self) -> bool { 50 matches!(self.details(), OldPubdEvtDet::PublisherAdded(_, _)) 51 || matches!(self.details(), OldPubdEvtDet::PublisherRemoved(_, _)) 52 } 53 } 54 55 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 56 pub struct OldPubdIniDet { 57 id_cert: IdCert, 58 session: RrdpSession, 59 rrdp_base_uri: uri::Https, 60 rsync_jail: uri::Rsync, 61 repo_base_dir: PathBuf, 62 } 63 64 impl OldPubdIniDet { unpack(self) -> (IdCert, RrdpSession, uri::Https, uri::Rsync, PathBuf)65 pub fn unpack(self) -> (IdCert, RrdpSession, uri::Https, uri::Rsync, PathBuf) { 66 ( 67 self.id_cert, 68 self.session, 69 self.rrdp_base_uri, 70 self.rsync_jail, 71 self.repo_base_dir, 72 ) 73 } 74 } 75 76 impl fmt::Display for OldPubdIniDet { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 78 write!(f, "old init") 79 } 80 } 81 82 impl From<OldPubdIniDet> for RepositoryAccessInitDetails { from(old: OldPubdIniDet) -> Self83 fn from(old: OldPubdIniDet) -> Self { 84 RepositoryAccessInitDetails::new(old.id_cert, old.rrdp_base_uri, old.rsync_jail) 85 } 86 } 87 88 pub struct DerivedEmbeddedCaMigrationInfo { 89 pub child_request: rfc8183::ChildRequest, 90 pub parent_responses: HashMap<ChildHandle, rfc8183::ParentResponse>, 91 } 92 93 impl OldCaEvt { into_stored_ca_event( self, version: u64, repo_manager: &RepositoryManager, derived_embedded_ca_info_map: &HashMap<Handle, DerivedEmbeddedCaMigrationInfo>, ) -> Result<CaEvt, UpgradeError>94 pub fn into_stored_ca_event( 95 self, 96 version: u64, 97 repo_manager: &RepositoryManager, 98 derived_embedded_ca_info_map: &HashMap<Handle, DerivedEmbeddedCaMigrationInfo>, 99 ) -> Result<CaEvt, UpgradeError> { 100 let (id, _, details) = self.unpack(); 101 102 let event = match details { 103 OldCaEvtDet::RepoUpdated(contact) => { 104 let contact = match contact { 105 OldRepositoryContact::Rfc8181(res) => RepositoryContact::new(res), 106 OldRepositoryContact::Embedded(_) => { 107 let res = repo_manager.repository_response(&id)?; 108 RepositoryContact::new(res) 109 } 110 }; 111 CaEvtDet::RepoUpdated { contact } 112 } 113 OldCaEvtDet::ParentAdded(parent, old_contact) => { 114 let contact = match old_contact { 115 OldParentCaContact::Rfc6492(res) => ParentCaContact::for_rfc6492(res), 116 OldParentCaContact::Ta(details) => ParentCaContact::Ta(details), 117 OldParentCaContact::Embedded => match derived_embedded_ca_info_map.get(&parent) { 118 Some(info) => { 119 let res = info.parent_responses.get(&id).ok_or_else(|| UpgradeError::Custom( 120 format!("Cannot upgrade CA '{}' using embedded parent '{}' which no longer has this CA as a child", id, parent)))?; 121 ParentCaContact::for_rfc6492(res.clone()) 122 } 123 None => { 124 return Err(UpgradeError::Custom(format!( 125 "Cannot upgrade CA '{}' using embedded parent '{}' which is no longer present", 126 id, parent 127 ))) 128 } 129 }, 130 }; 131 CaEvtDet::ParentAdded { parent, contact } 132 } 133 OldCaEvtDet::ChildAdded(child, old_details) => { 134 let (resources, id_cert_opt) = (old_details.resources, old_details.id_cert); 135 136 let id_cert = match id_cert_opt { 137 Some(id_cert) => id_cert, 138 None => { 139 let child_info = derived_embedded_ca_info_map.get(&child).ok_or_else(|| { 140 UpgradeError::Custom(format!( 141 "Cannot upgrade CA {}, embedded child {} is no longer present", 142 id, child 143 )) 144 })?; 145 146 child_info.child_request.id_cert().clone() 147 } 148 }; 149 150 CaEvtDet::ChildAdded { 151 child, 152 id_cert, 153 resources, 154 } 155 } 156 _ => details.try_into()?, 157 }; 158 159 Ok(CaEvt::new(&id, version, event)) 160 } 161 needs_migration(&self) -> bool162 pub fn needs_migration(&self) -> bool { 163 !matches!(self.details(), OldCaEvtDet::ObjectSetUpdated(_, _)) 164 && !matches!(self.details(), OldCaEvtDet::RepoCleaned(_)) 165 } 166 } 167 168 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 169 #[allow(clippy::large_enum_variant)] 170 #[serde(rename_all = "snake_case")] 171 pub enum OldCaEvtDet { 172 // Being a Trust Anchor 173 TrustAnchorMade(TaCertDetails), 174 175 // Being a parent Events 176 ChildAdded(ChildHandle, OldChildDetails), 177 ChildCertificateIssued(ChildHandle, ResourceClassName, KeyIdentifier), 178 ChildKeyRevoked(ChildHandle, ResourceClassName, KeyIdentifier), 179 ChildCertificatesUpdated(ResourceClassName, ChildCertificateUpdates), 180 ChildUpdatedIdCert(ChildHandle, IdCert), 181 ChildUpdatedResources(ChildHandle, ResourceSet), 182 ChildRemoved(ChildHandle), 183 184 // Being a child Events 185 IdUpdated(Rfc8183Id), 186 ParentAdded(ParentHandle, OldParentCaContact), 187 ParentUpdated(ParentHandle, OldParentCaContact), 188 ParentRemoved(ParentHandle, Vec<ObjectsDelta>), 189 190 ResourceClassAdded(ResourceClassName, OldResourceClass), 191 ResourceClassRemoved(ResourceClassName, ObjectsDelta, ParentHandle, Vec<RevocationRequest>), 192 CertificateRequested(ResourceClassName, IssuanceRequest, KeyIdentifier), 193 CertificateReceived(ResourceClassName, KeyIdentifier, RcvdCert), 194 195 // Key life cycle 196 KeyRollPendingKeyAdded(ResourceClassName, KeyIdentifier), 197 KeyPendingToNew(ResourceClassName, OldCertifiedKey, ObjectsDelta), 198 KeyPendingToActive(ResourceClassName, OldCertifiedKey, ObjectsDelta), 199 KeyRollActivated(ResourceClassName, RevocationRequest), 200 KeyRollFinished(ResourceClassName, ObjectsDelta), 201 UnexpectedKeyFound(ResourceClassName, RevocationRequest), 202 203 // Route Authorizations 204 RouteAuthorizationAdded(RouteAuthorization), 205 RouteAuthorizationRemoved(RouteAuthorization), 206 RoasUpdated(ResourceClassName, RoaUpdates), 207 208 // Publishing 209 ObjectSetUpdated(ResourceClassName, HashMap<KeyIdentifier, CurrentObjectSetDelta>), 210 RepoUpdated(OldRepositoryContact), 211 RepoCleaned(OldRepositoryContact), 212 213 // Rta 214 RtaPrepared(RtaName, PreparedRta), 215 RtaSigned(RtaName, SignedRta), 216 } 217 218 impl TryFrom<OldCaEvtDet> for CaEvtDet { 219 type Error = UpgradeError; 220 try_from(old: OldCaEvtDet) -> Result<Self, Self::Error>221 fn try_from(old: OldCaEvtDet) -> Result<Self, Self::Error> { 222 let evt = match old { 223 OldCaEvtDet::TrustAnchorMade(ta_cert_details) => CaEvtDet::TrustAnchorMade { ta_cert_details }, 224 OldCaEvtDet::ChildAdded(_child, _details) => { 225 unreachable!("Add child must be converted with embedded children in mind") 226 } 227 OldCaEvtDet::ChildCertificateIssued(child, resource_class_name, ki) => CaEvtDet::ChildCertificateIssued { 228 child, 229 resource_class_name, 230 ki, 231 }, 232 OldCaEvtDet::ChildKeyRevoked(child, resource_class_name, ki) => CaEvtDet::ChildKeyRevoked { 233 child, 234 resource_class_name, 235 ki, 236 }, 237 OldCaEvtDet::ChildCertificatesUpdated(resource_class_name, cert_updates) => { 238 CaEvtDet::ChildCertificatesUpdated { 239 resource_class_name, 240 updates: cert_updates.into(), 241 } 242 } 243 OldCaEvtDet::ChildUpdatedIdCert(child, id_cert) => CaEvtDet::ChildUpdatedIdCert { child, id_cert }, 244 OldCaEvtDet::ChildUpdatedResources(child, resources) => { 245 CaEvtDet::ChildUpdatedResources { child, resources } 246 } 247 OldCaEvtDet::ChildRemoved(child) => CaEvtDet::ChildRemoved { child }, 248 249 OldCaEvtDet::IdUpdated(id) => CaEvtDet::IdUpdated { id: id.into() }, 250 OldCaEvtDet::ParentAdded(_parent, _contact) => { 251 unreachable!("Parent Added event is migrated differently") 252 } 253 OldCaEvtDet::ParentUpdated(_parent, _contact) => { 254 unreachable!("Parent Updated event is migrated differently") 255 } 256 OldCaEvtDet::ParentRemoved(parent, _delta) => CaEvtDet::ParentRemoved { parent }, 257 258 OldCaEvtDet::ResourceClassAdded(_rcn, rc) => rc.into_added_event()?, 259 OldCaEvtDet::ResourceClassRemoved(resource_class_name, _delta, parent, revoke_requests) => { 260 CaEvtDet::ResourceClassRemoved { 261 resource_class_name, 262 parent, 263 revoke_requests, 264 } 265 } 266 OldCaEvtDet::CertificateRequested(resource_class_name, req, ki) => CaEvtDet::CertificateRequested { 267 resource_class_name, 268 req, 269 ki, 270 }, 271 OldCaEvtDet::CertificateReceived(resource_class_name, ki, rcvd_cert) => CaEvtDet::CertificateReceived { 272 resource_class_name, 273 ki, 274 rcvd_cert, 275 }, 276 277 OldCaEvtDet::KeyRollPendingKeyAdded(resource_class_name, pending_key_id) => { 278 CaEvtDet::KeyRollPendingKeyAdded { 279 resource_class_name, 280 pending_key_id, 281 } 282 } 283 OldCaEvtDet::KeyPendingToNew(resource_class_name, new_key, _delta) => CaEvtDet::KeyPendingToNew { 284 resource_class_name, 285 new_key: new_key.into(), 286 }, 287 OldCaEvtDet::KeyPendingToActive(resource_class_name, current_key, _delta) => CaEvtDet::KeyPendingToActive { 288 resource_class_name, 289 current_key: current_key.into(), 290 }, 291 OldCaEvtDet::KeyRollActivated(resource_class_name, revoke_req) => CaEvtDet::KeyRollActivated { 292 resource_class_name, 293 revoke_req, 294 }, 295 OldCaEvtDet::KeyRollFinished(resource_class_name, _delta) => { 296 CaEvtDet::KeyRollFinished { resource_class_name } 297 } 298 OldCaEvtDet::UnexpectedKeyFound(resource_class_name, revoke_req) => CaEvtDet::UnexpectedKeyFound { 299 resource_class_name, 300 revoke_req, 301 }, 302 303 OldCaEvtDet::RouteAuthorizationAdded(auth) => CaEvtDet::RouteAuthorizationAdded { auth }, 304 OldCaEvtDet::RouteAuthorizationRemoved(auth) => CaEvtDet::RouteAuthorizationRemoved { auth }, 305 OldCaEvtDet::RoasUpdated(resource_class_name, updates) => CaEvtDet::RoasUpdated { 306 resource_class_name, 307 updates: updates.try_into()?, 308 }, 309 310 OldCaEvtDet::ObjectSetUpdated(_, _) => unreachable!("This event must not be migrated"), 311 312 OldCaEvtDet::RepoUpdated(_contact) => { 313 unreachable!("Repo Updated is migrated with the embedded repo context") 314 } 315 OldCaEvtDet::RepoCleaned(_contact) => unreachable!("This event must not be migrated"), 316 317 OldCaEvtDet::RtaPrepared(name, prepared) => CaEvtDet::RtaPrepared { name, prepared }, 318 OldCaEvtDet::RtaSigned(name, rta) => CaEvtDet::RtaSigned { name, rta }, 319 }; 320 Ok(evt) 321 } 322 } 323 324 impl fmt::Display for OldCaEvtDet { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result325 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 326 write!(f, "pre 0.9.0 event") 327 } 328 } 329 330 /// Describes an update to the set of ROAs under a ResourceClass. 331 #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] 332 pub struct ChildCertificateUpdates { 333 issued: Vec<IssuedCert>, 334 removed: Vec<KeyIdentifier>, 335 } 336 337 impl From<ChildCertificateUpdates> for ca::ChildCertificateUpdates { from(old: ChildCertificateUpdates) -> Self338 fn from(old: ChildCertificateUpdates) -> Self { 339 ca::ChildCertificateUpdates::new(old.issued, old.removed, vec![], vec![]) 340 } 341 } 342 343 impl ChildCertificateUpdates { unpack(self) -> (Vec<IssuedCert>, Vec<KeyIdentifier>)344 pub fn unpack(self) -> (Vec<IssuedCert>, Vec<KeyIdentifier>) { 345 (self.issued, self.removed) 346 } 347 } 348 349 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 350 pub struct ObjectsDelta { 351 ca_repo: uri::Rsync, 352 added: Vec<AddedObject>, 353 updated: Vec<UpdatedObject>, 354 withdrawn: Vec<WithdrawnObject>, 355 } 356 357 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 358 pub struct AddedObject { 359 name: ObjectName, 360 object: CurrentObject, 361 } 362 363 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 364 pub struct UpdatedObject { 365 name: ObjectName, 366 object: CurrentObject, 367 old: HexEncodedHash, 368 } 369 370 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 371 pub struct WithdrawnObject { 372 name: ObjectName, 373 hash: HexEncodedHash, 374 } 375 376 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 377 pub struct CurrentObjectSetDelta { 378 pub number: u64, 379 pub revocations_delta: RevocationsDelta, 380 pub manifest_info: OldManifestInfo, 381 pub crl_info: OldCrlInfo, 382 pub objects_delta: ObjectsDelta, 383 } 384 385 // Describes an update to the set of ROAs under a ResourceClass. 386 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 387 pub struct RoaUpdates { 388 #[serde(skip_serializing_if = "HashMap::is_empty", default = "HashMap::new")] 389 updated: HashMap<RouteAuthorization, RoaInfo>, 390 391 #[serde(skip_serializing_if = "HashMap::is_empty", default = "HashMap::new")] 392 removed: HashMap<RouteAuthorization, RevokedObject>, 393 394 #[serde(skip_serializing_if = "HashMap::is_empty", default = "HashMap::new")] 395 aggregate_updated: HashMap<RoaAggregateKey, AggregateRoaInfo>, 396 397 #[serde(skip_serializing_if = "HashMap::is_empty", default = "HashMap::new")] 398 aggregate_removed: HashMap<RoaAggregateKey, RevokedObject>, 399 } 400 401 impl TryFrom<RoaUpdates> for ca::RoaUpdates { 402 type Error = UpgradeError; 403 try_from(old: RoaUpdates) -> Result<Self, UpgradeError>404 fn try_from(old: RoaUpdates) -> Result<Self, UpgradeError> { 405 let mut updates = ca::RoaUpdates::default(); 406 for (auth, info) in old.updated { 407 let roa = info.roa()?; 408 let roa_info = ca::RoaInfo::new(roa, info.since); 409 updates.update(auth, roa_info); 410 } 411 412 for (auth, revoke) in old.removed { 413 updates.remove(auth, revoke) 414 } 415 416 for (agg_key, agg_info) in old.aggregate_updated { 417 let roa = agg_info.roa.roa()?; 418 let roa_info = ca::RoaInfo::new(roa, agg_info.roa.since); 419 let authorizations = agg_info.authorizations; 420 let agg = ca::AggregateRoaInfo::new(authorizations, roa_info); 421 updates.update_aggregate(agg_key, agg); 422 } 423 424 for (agg_key, revoke) in old.aggregate_removed { 425 updates.remove_aggregate(agg_key, revoke); 426 } 427 428 Ok(updates) 429 } 430 } 431 432 impl RoaUpdates { 433 #[allow(clippy::type_complexity)] unpack( self, ) -> ( HashMap<RouteAuthorization, RoaInfo>, HashMap<RouteAuthorization, RevokedObject>, HashMap<RoaAggregateKey, AggregateRoaInfo>, HashMap<RoaAggregateKey, RevokedObject>, )434 pub fn unpack( 435 self, 436 ) -> ( 437 HashMap<RouteAuthorization, RoaInfo>, 438 HashMap<RouteAuthorization, RevokedObject>, 439 HashMap<RoaAggregateKey, AggregateRoaInfo>, 440 HashMap<RoaAggregateKey, RevokedObject>, 441 ) { 442 ( 443 self.updated, 444 self.removed, 445 self.aggregate_updated, 446 self.aggregate_removed, 447 ) 448 } 449 } 450 451 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 452 pub struct RoaInfo { 453 pub object: CurrentObject, // actual ROA 454 name: ObjectName, // Name for object in repo 455 since: Time, // first ROA in RC created 456 replaces: Option<OldReplacedObject>, // for revoking when renewing 457 } 458 459 impl RoaInfo { roa(&self) -> Result<Roa, UpgradeError>460 pub fn roa(&self) -> Result<Roa, UpgradeError> { 461 Roa::decode(self.object.content.to_bytes(), true).map_err(|_| UpgradeError::custom("Cannot parse existing ROA")) 462 } 463 } 464 465 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 466 pub struct AggregateRoaInfo { 467 pub authorizations: Vec<RouteAuthorization>, 468 469 #[serde(flatten)] 470 pub roa: RoaInfo, 471 } 472 473 pub type OldCaIni = StoredEvent<OldCaIniDet>; 474 475 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 476 pub struct OldCaIniDet { 477 id: Rfc8183Id, 478 479 // The following two fields need to be kept to maintain data compatibility 480 // with Krill 0.4.2 installations. 481 // 482 // Newer versions of krill will no longer include these fields. I.e. there 483 // will be no default embedded repository, and trust anchors will be created 484 // through an explicit command and events. 485 #[serde(skip_serializing_if = "Option::is_none")] 486 info: Option<RepoInfo>, 487 #[serde(skip_serializing_if = "Option::is_none")] 488 ta_details: Option<TaCertDetails>, 489 } 490 491 impl OldCaIniDet { unpack(self) -> (Rfc8183Id, Option<RepoInfo>, Option<TaCertDetails>)492 pub fn unpack(self) -> (Rfc8183Id, Option<RepoInfo>, Option<TaCertDetails>) { 493 (self.id, self.info, self.ta_details) 494 } 495 } 496 497 impl fmt::Display for OldCaIniDet { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result498 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 499 write!(f, "Pre 0.9.0 CA init") 500 } 501 } 502 503 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 504 pub struct CurrentObject { 505 content: Base64, 506 serial: Serial, 507 expires: Time, 508 } 509 510 impl CurrentObject { content(&self) -> &Base64511 pub fn content(&self) -> &Base64 { 512 &self.content 513 } 514 } 515 516 //================ Pubd 517 518 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 519 #[allow(clippy::large_enum_variant)] 520 #[serde(rename_all = "snake_case")] 521 pub enum OldPubdEvtDet { 522 PublisherAdded(PublisherHandle, OldPublisher), 523 PublisherRemoved(PublisherHandle, RrdpUpdate), 524 Published(PublisherHandle, RrdpUpdate), 525 RrdpSessionReset(RrdpSessionReset), 526 } 527 528 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 529 pub struct OldPublisher { 530 /// Used by remote RFC8181 publishers 531 pub id_cert: IdCert, 532 533 /// Publication jail for this publisher 534 pub base_uri: uri::Rsync, 535 536 /// All objects currently published by this publisher, by hash 537 pub current_objects: OldCurrentObjects, 538 } 539 540 impl OldPublisher { apply_delta(&mut self, delta: DeltaElements)541 pub fn apply_delta(&mut self, delta: DeltaElements) { 542 self.current_objects.apply_delta(delta); 543 } 544 } 545 546 impl fmt::Display for OldPubdEvtDet { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result547 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 548 write!(f, "pre 0.9.0 event") 549 } 550 } 551 552 impl From<OldPublisher> for Publisher { from(old: OldPublisher) -> Self553 fn from(old: OldPublisher) -> Self { 554 Publisher::new(old.id_cert, old.base_uri) 555 } 556 } 557 558 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 559 pub struct OldCurrentObjects(HashMap<HexEncodedHash, PublishElement>); 560 561 impl OldCurrentObjects { new(map: HashMap<HexEncodedHash, PublishElement>) -> Self562 pub fn new(map: HashMap<HexEncodedHash, PublishElement>) -> Self { 563 OldCurrentObjects(map) 564 } apply_delta(&mut self, delta: DeltaElements)565 pub fn apply_delta(&mut self, delta: DeltaElements) { 566 let (publishes, updates, withdraws) = delta.unpack(); 567 568 for p in publishes { 569 let hash = p.base64().to_encoded_hash(); 570 self.0.insert(hash, p); 571 } 572 573 for u in updates { 574 self.0.remove(u.hash()); 575 let p: PublishElement = u.into(); 576 let hash = p.base64().to_encoded_hash(); 577 self.0.insert(hash, p); 578 } 579 580 for w in withdraws { 581 self.0.remove(w.hash()); 582 } 583 } 584 } 585 586 impl From<OldCurrentObjects> for CurrentObjects { from(old: OldCurrentObjects) -> Self587 fn from(old: OldCurrentObjects) -> Self { 588 CurrentObjects::new(old.0) 589 } 590 } 591 592 impl From<OldPubdEvtDet> for RepositoryAccessEventDetails { from(old: OldPubdEvtDet) -> Self593 fn from(old: OldPubdEvtDet) -> Self { 594 match old { 595 OldPubdEvtDet::PublisherAdded(name, publisher) => RepositoryAccessEventDetails::PublisherAdded { 596 name, 597 publisher: publisher.into(), 598 }, 599 OldPubdEvtDet::PublisherRemoved(name, _) => RepositoryAccessEventDetails::PublisherRemoved { name }, 600 _ => unreachable!("no need to migrate these old events"), 601 } 602 } 603 } 604