1use std::{
2 collections::{BTreeMap, BTreeSet, btree_map::Entry, HashSet},
3 env,
4 fmt,
5 fs,
6 io::{self, Read, Write},
7 path::{Path, PathBuf},
8 time::SystemTime,
9};
10
11use git2::{
12 Repository,
13 Oid,
14};
15use serde::{Deserialize, Serialize};
16
17use sequoia_openpgp::{
18 self as openpgp,
19 Cert,
20 Fingerprint,
21 KeyHandle,
22 Packet,
23 cert::{
24 amalgamation::ValidAmalgamation,
25 prelude::{SubordinateKeyAmalgamation, UserIDAmalgamation},
26 raw::{RawCert, RawCertParser},
27 },
28 packet::{
29 Signature,
30 UserID,
31 key::PublicParts,
32 },
33 parse::Parse,
34 parse::{stream::*},
35 policy::StandardPolicy,
36 serialize::Serialize as _,
37 types::SignatureType,
38};
39
40use crate::{
41 Error,
42 Result,
43 utils::prune_cert,
44 utils::serialize_packet,
45 utils::serialize_signature,
46};
47
48const TRACE: bool = false;
50
51#[derive(Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
58pub struct Policy {
59 #[serde(default)]
65 version: usize,
66
67 #[serde(default)]
74 commit_goodlist: BTreeSet<String>,
75
76 #[serde(default)]
81 authorization: BTreeMap<String, Authorization>,
82}
83
84impl Policy {
85 fn working_dir_policy_file() -> Result<PathBuf> {
88 let git = git2::Repository::discover(env::current_dir()?)?;
89 if let Some(wd) = git.workdir() {
90 Ok(wd.join("openpgp-policy.toml"))
91 } else {
92 Err(Error::InvalidOperation("doesn't work on bare repos".into()))
93 }
94 }
95
96 pub fn parse_bytes<D: AsRef<[u8]>>(bytes: D) -> Result<Self> {
97 let bytes = bytes.as_ref();
98 let s = std::str::from_utf8(bytes)
99 .map_err(|e| Error::StorageError(e.to_string()))?;
100 let policy = toml::from_str(s)
101 .map_err(|e| Error::StorageError(e.to_string()))?;
102 Ok(policy)
103 }
104
105 pub fn read_file<P: AsRef<Path>>(path: P) -> Result<Policy> {
107 let path = path.as_ref();
108 let mut f = fs::File::open(path)?;
109
110 let mut s = String::new();
111 f.read_to_string(&mut s)?;
112 let p: Policy =
113 toml::from_str(&s).map_err(|e| Error::StorageError(e.to_string()))?;
114
115 Ok(p)
116 }
117
118 pub fn read_file_or_default<P: AsRef<Path>>(path: P) -> Result<Policy> {
120 let path = path.as_ref();
121 let mut f = match fs::File::open(path) {
122 Ok(f) => f,
123 Err(e) => if e.kind() == io::ErrorKind::NotFound {
124 return Ok(Policy::default());
125 } else {
126 return Err(e.into());
127 },
128 };
129
130 let mut s = String::new();
131 f.read_to_string(&mut s)?;
132 let p: Policy =
133 toml::from_str(&s).map_err(|e| Error::StorageError(e.to_string()))?;
134
135 Ok(p)
136 }
137
138 pub fn read_from_working_dir() -> Result<Policy> {
143 Self::read_file_or_default(&Self::working_dir_policy_file()?)
144 }
145
146 pub fn read_bytes_from_commit(git: &Repository, commit: &Oid)
148 -> Result<Vec<u8>>
149 {
150 tracer!(TRACE, "Policy::read_bytes_from_commit");
151 t!("(_, {})", commit);
152
153 let commit = git.find_commit(commit.clone())?;
154 let tree = commit.tree()?;
155 let result = if let Some(entry) = tree.get_name("openpgp-policy.toml") {
156 Ok(entry.to_object(&git)?.peel_to_blob()?.content().to_vec())
157 } else {
158 Err(Error::MissingPolicy(commit.id()))
159 };
160 result
161 }
162
163 pub fn read_from_commit(git: &Repository, commit: &Oid) -> Result<Self> {
165 Self::parse_bytes(Self::read_bytes_from_commit(git, commit)?)
166 }
167
168 pub fn write<P: AsRef<Path>>(&self, path: P) -> Result<()> {
170 let path = path.as_ref();
171 let mut new =
172 tempfile::NamedTempFile::new_in(path.parent().unwrap())?;
173
174 new.write_all(toml::to_string_pretty(&self)
175 .map_err(|e| Error::StorageError(e.to_string()))?
176 .as_bytes())?;
177
178 new.persist(path).map_err(|e| Error::StorageError(e.to_string()))?;
179
180 Ok(())
181 }
182
183 pub fn write_to_working_dir(&self) -> Result<()> {
185 self.write(&Self::working_dir_policy_file()?)
186 }
187
188 pub fn version(&self) -> usize {
190 self.version
191 }
192
193 pub fn commit_goodlist(&self) -> &BTreeSet<String> {
200 &self.commit_goodlist
201 }
202
203 pub fn commit_goodlist_mut(&mut self) -> &mut BTreeSet<String> {
210 &mut self.commit_goodlist
211 }
212
213 pub fn authorization(&self) -> &BTreeMap<String, Authorization> {
218 &self.authorization
219 }
220
221 pub fn authorization_mut(&mut self) -> &mut BTreeMap<String, Authorization> {
226 &mut self.authorization
227 }
228
229 pub fn diff<'f, 't>(&'f self, other: &'t Policy) -> Result<Diff<'f, 't>> {
231 let mut changes = Vec::new();
232
233 if self.version != other.version {
235 changes.push(Change::VersionChange {
236 from: self.version,
237 to: other.version,
238 });
239 }
240
241 for c in self.commit_goodlist.difference(&other.commit_goodlist) {
243 changes.push(Change::UngoodlistCommit(c.parse()?));
244 }
245 for c in other.commit_goodlist.difference(&self.commit_goodlist) {
246 changes.push(Change::GoodlistCommit(c.parse()?));
247 }
248
249 let null_auth = Authorization::default();
252
253 for (k, from) in self.authorization.iter()
255 .filter(|(k, _)| ! other.authorization.contains_key(k.as_str()))
256 {
257 from.diff(&null_auth, k.into(), &mut changes);
259
260 changes.push(Change::RetireUser(k.into()));
262 }
263
264 for (k, from, to) in self.authorization.iter()
266 .filter_map(|(k, from)| other.authorization.get(k)
267 .map(|to| (k, from, to)))
268 {
269 from.diff(to, k.into(), &mut changes);
270 }
271
272 for (k, to) in other.authorization.iter()
274 .filter(|(k, _)| ! self.authorization.contains_key(k.as_str()))
275 {
276 changes.push(Change::AddUser(k.into()));
278
279 null_auth.diff(to, k.into(), &mut changes);
281 }
282
283 Ok(Diff {
284 version: DIFF_JSON_VERSION,
285 from: self,
286 changes,
287 to: other,
288 })
289 }
290
291 pub fn verify(&self, git: &Repository, commit_id: &Oid,
301 commit_policy: &Policy,
302 signer_keys: &mut BTreeSet<Fingerprint>,
303 primary_uids: &mut BTreeSet<UserID>)
304 -> Result<Vec<Result<(String, Signature, Cert, Fingerprint)>>>
305 {
306 tracer!(TRACE, "Policy::verify");
307 t!("verify(_, {})", commit_id);
308
309 if self.commit_goodlist.contains(&commit_id.to_string()) {
310 Ok(vec![])
311 } else {
312 let Ok((sig, data)) = git.extract_signature(commit_id, None)
313 else {
314 return Ok(vec![Err(Error::MissingSignature(commit_id.clone()))]);
315 };
316 t!("{} bytes of signature", sig.len());
317
318 self.verify_(&sig[..], &data[..],
333 commit_policy,
334 None,
335 signer_keys,
336 primary_uids,
337 Error::MissingSignature(commit_id.clone()),
338 Right::SignCommit)
339 }
340 }
341
342 pub fn verify_archive<T, S>(&self,
343 signature: S,
344 archive: T)
345 -> Result<Vec<Result<(String, Signature, Cert,
346 Fingerprint)>>>
347 where
348 T: AsRef<[u8]>,
349 S: AsRef<[u8]>,
350 {
351 let mut signer_keys = Default::default();
352 let mut primary_uids = Default::default();
353 self.verify_(signature.as_ref(),
354 archive.as_ref(),
355 self,
356 None,
357 &mut signer_keys,
358 &mut primary_uids,
359 Error::MissingDataSignature("Tarball".into()),
360 Right::SignArchive)
361 }
362
363 fn verify_(&self,
364 signature: &[u8],
365 data: &[u8],
366 commit_policy: &Policy,
367 commit_time: Option<SystemTime>,
368 signer_keys: &mut BTreeSet<Fingerprint>,
369 primary_uids: &mut BTreeSet<UserID>,
370 missing_signature_error: Error,
371 require_right: Right)
372 -> Result<Vec<Result<(String, Signature, Cert, Fingerprint)>>>
373 {
374 tracer!(TRACE, "Policy::verify_");
375 t!("verify_({} bytes, {} bytes, _, {:?}, _, _, {}, {})",
376 signature.len(), data.len(), commit_time,
377 missing_signature_error, require_right);
378
379 let p = &StandardPolicy::new();
380 let h = Helper {
381 parent_policy: self,
382 child_policy: commit_policy,
383 signer_keys,
384 primary_uids,
385 results: Default::default(),
386 };
387
388 let mut v = DetachedVerifierBuilder::from_bytes(signature)?
389 .with_policy(p, commit_time, h)?;
390 v.verify_bytes(data)?;
391 let h = v.into_helper();
392 let signature_results = h.results;
393
394 if signature_results.is_empty() {
395 t!("no signatures found!");
396 return Ok(vec![Err(missing_signature_error)]);
397 }
398
399 if signature_results.iter().all(|r| r.is_err()) {
400 let e = signature_results.into_iter().find(|r| r.is_err())
401 .expect("not empty and not all were ok");
402 return Err(e.unwrap_err());
403 }
404
405 let diff = self.diff(commit_policy)?;
409
410 let mut results: Vec<Result<(String, Signature, Cert, Fingerprint)>>
411 = Vec::new();
412 for r in signature_results {
413 match r {
414 Ok((sig, cert, signer_fpr)) => {
415 let cert_fp = cert.fingerprint();
418 for (name, a) in self.authorization.iter()
419 .filter(|(_, a)| a.certs().into_iter()
420 .flat_map(|r| r.into_iter())
421 .flat_map(|r| r.into_iter())
422 .any(|c| c.fingerprint() == cert_fp))
423 {
424 t!("{}: valid signature", name);
425 let r = a.rights();
426 t!("{}: {:?}", name, r);
427
428 if let Err(e) = r.assert(require_right)
429 .and_then(|_| diff.assert(&r))
430 {
431 results.push(Err(e));
432 } else {
433 results.push(
434 Ok((name.into(), sig.clone(), cert.clone(),
435 signer_fpr.clone())));
436 }
437 }
438 },
439 Err(e) => results.push(Err(e)),
440 }
441 }
442
443 Ok(results)
444 }
445}
446
447struct Helper<'p> {
449 parent_policy: &'p Policy,
450 child_policy: &'p Policy,
451 signer_keys: &'p mut BTreeSet<openpgp::Fingerprint>,
453 primary_uids: &'p mut BTreeSet<UserID>,
454 results: Vec<Result<(Signature, Cert, Fingerprint)>>,
455}
456
457impl Helper<'_> {
458 fn handle_result(&mut self, r: VerificationResult) {
459 tracer!(TRACE, "VerificationHelper::handle_result");
460 match r {
461 Ok(sig) => {
462 self.signer_keys.insert(sig.ka.fingerprint());
463
464 if let Ok(userid) = sig.ka.cert().primary_userid() {
465 let u = userid.userid();
466 if ! self.primary_uids.contains(u) {
467 self.primary_uids.insert(u.clone());
468 }
469 }
470
471 self.results.push(
472 Ok((sig.sig.clone(), sig.ka.cert().cert().clone(),
473 sig.ka.fingerprint().clone())));
474 },
475 Err(e) => {
476 t!("Signature verification failed: {}", e);
477 use VerificationError::*;
478 self.results.push(Err(match e {
479 MalformedSignature { error, .. } =>
480 Error::BadSignature(error.to_string()),
481 MissingKey { sig } => {
482 let mut issuers = sig.get_issuers();
483 if issuers.is_empty() {
484 Error::BadSignature(
485 "No issuer information".into())
486 } else {
487 Error::MissingKey(issuers.remove(0))
488 }
489 },
490 UnboundKey { cert, error, .. } =>
491 Error::BadKey(cert.key_handle(),
492 error.to_string()),
493 BadKey { ka, error, .. } =>
494 Error::BadKey(ka.cert().key_handle(),
495 error.to_string()),
496 BadSignature { error, .. } =>
497 Error::BadSignature(error.to_string()),
498 }));
499 },
500 }
501 }
502}
503
504impl VerificationHelper for Helper<'_> {
505 fn get_certs(&mut self, ids: &[KeyHandle]) -> openpgp::Result<Vec<Cert>> {
506 tracer!(TRACE, "VerificationHelper::get_certs");
507 t!("get_certs({:?})", ids);
508
509 let mut matches: BTreeMap<Fingerprint, Cert> = BTreeMap::new();
510
511 let mut parent: BTreeMap<Fingerprint, Vec<RawCert>> = BTreeMap::new();
512
513 for (name, auth) in self.parent_policy.authorization.iter() {
514 for cert in auth.certs()? {
515 let cert = cert?;
516
517 let entry = parent.entry(cert.fingerprint());
519 match entry {
520 Entry::Occupied(mut oe) => {
521 oe.get_mut().push(cert.clone());
522 }
523 Entry::Vacant(ve) => {
524 ve.insert(vec![ cert.clone() ]);
525 }
526 }
527
528 if cert.keys().any(
529 |k| ids.iter().any(|i| i.aliases(&k.key_handle())))
530 {
531 t!("Signature could be from {}", name);
532
533 let cert = Cert::try_from(cert)?;
534
535 let entry = matches.entry(cert.fingerprint());
536 match entry {
537 Entry::Occupied(mut oe) => {
538 let c: &mut Cert = oe.get_mut();
539 *c = c.clone().merge_public(cert)?;
540 }
541 Entry::Vacant(ve) => {
542 ve.insert(cert);
543 }
544 }
545 }
546 }
547 }
548
549 if self.parent_policy != self.child_policy {
555 let merge = |parent: Cert, child: Cert| -> Result<Cert> {
558 let child = child.into_packets2().filter(|p| {
559 if let Packet::Signature(sig) = p {
560 ! matches!(sig.typ(),
561 SignatureType::KeyRevocation
562 | SignatureType::SubkeyRevocation
563 | SignatureType::CertificationRevocation)
564 } else {
565 true
566 }
567 });
568
569 Ok(parent.insert_packets2(child)?.0)
570 };
571
572 for (name, auth) in self.child_policy.authorization.iter() {
573 let child_certs = if let Ok(certs) = auth.certs() {
574 certs
575 } else {
576 continue;
578 };
579
580 for child_cert in child_certs {
581 let child_cert = if let Ok(cert) = child_cert {
582 cert
583 } else {
584 continue;
586 };
587
588 let fpr = child_cert.fingerprint();
589 if let Some(cert) = matches.get_mut(&fpr) {
590 t!("Updating {}", fpr);
591
592 let child_cert = if let Ok(cert)
593 = Cert::try_from(child_cert)
594 {
595 cert
596 } else {
597 continue;
599 };
600
601 if let Ok(merged) = merge(cert.clone(), child_cert) {
602 *cert = merged;
603 }
604 } else {
605 if child_cert.keys().any(
606 |k| ids.iter().any(|i| i.aliases(&k.key_handle())))
607 {
608 t!("Signature could be from {}", name);
609
610 if let Some(certs)
616 = parent.get(&child_cert.fingerprint())
617 {
618 if let Ok(child_cert) = Cert::try_from(child_cert) {
619 let mut parent: Option<Cert> = None;
620 for c in certs.into_iter() {
621 let c = if let Ok(c) = Cert::try_from(c) {
622 c
623 } else {
624 continue;
625 };
626 if let Some(parent) = parent.as_mut() {
627 if let Ok(merged) =
628 parent.clone().merge_public(c)
629 {
630 *parent = merged;
631 }
632 } else {
633 parent = Some(c);
634 }
635 }
636
637 let parent = if let Some(parent) = parent {
638 parent
639 } else {
640 continue;
641 };
642
643 if let Ok(merged) = merge(parent, child_cert) {
645 matches.insert(
646 merged.fingerprint(), merged);
647 }
648 }
649 }
650 }
651 }
652 }
653 }
654 }
655
656 Ok(matches.into_values().collect())
657 }
658 fn check(&mut self, structure: MessageStructure) -> openpgp::Result<()> {
659 tracer!(TRACE, "VerificationHelper::get_certs");
660 if false {
661 t!("check({:?})", structure);
662 }
663
664 for (i, layer) in structure.into_iter().enumerate() {
665 match layer {
666 MessageLayer::SignatureGroup { results } if i == 0 => {
667 for r in results {
668 self.handle_result(r);
669 }
670 },
671 _ => return Err(Error::BadSignature(
672 "Unexpected signature structure".into()).into()),
673 }
674 }
675 Ok(())
676 }
677}
678
679#[derive(Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
680pub struct Authorization {
681 #[serde(default, skip_serializing_if = "bool_is_false")]
682 pub sign_commit: bool,
683 #[serde(default, skip_serializing_if = "bool_is_false")]
684 pub sign_tag: bool,
685 #[serde(default, skip_serializing_if = "bool_is_false")]
686 pub sign_archive: bool,
687 #[serde(default, skip_serializing_if = "bool_is_false")]
688 pub add_user: bool,
689 #[serde(default, skip_serializing_if = "bool_is_false")]
690 pub retire_user: bool,
691 #[serde(default, skip_serializing_if = "bool_is_false")]
692 pub audit: bool,
693 pub keyring: String,
694}
695
696fn bool_is_false(b: &bool) -> bool {
697 *b == false
698}
699
700impl Authorization {
701 pub fn rights(&self) -> Rights {
702 use Right::*;
703
704 let mut r = BTreeSet::default();
705
706 if self.sign_commit {
707 r.insert(SignCommit);
708 }
709 if self.sign_tag {
710 r.insert(SignTag);
711 }
712 if self.sign_archive {
713 r.insert(SignArchive);
714 }
715 if self.add_user {
716 r.insert(AddUser);
717 }
718 if self.retire_user {
719 r.insert(RetireUser);
720 }
721 if self.audit {
722 r.insert(Audit);
723 }
724
725 Rights(r)
726 }
727
728 pub fn certs(&self) -> Result<impl Iterator<Item = openpgp::Result<RawCert>>> {
729 Ok(RawCertParser::from_bytes(self.keyring.as_bytes())?)
730 }
731
732 pub fn set_certs(&mut self, certs: Vec<openpgp::Cert>) -> Result<()> {
733 self.set_certs_filter(certs, |_| true, |_| true)
734 }
735
736 pub fn set_certs_filter<S, U>(&mut self, certs: Vec<openpgp::Cert>,
737 mut subkeys: S,
738 mut userids: U)
739 -> Result<()>
740 where
741 S: FnMut(&SubordinateKeyAmalgamation<PublicParts>) -> bool,
742 U: FnMut(&UserIDAmalgamation) -> bool,
743 {
744 let mut keyring = Vec::new();
745
746 for c in certs {
747 let c = prune_cert(c, &mut subkeys, &mut userids)?;
748 c.armored().export(&mut keyring)?;
749 }
750
751 self.keyring = String::from_utf8(keyring)
752 .map_err(|e| Error::StorageError(e.to_string()))?;
753 Ok(())
754 }
755
756 fn diff(&self, other: &Authorization, name: String,
759 changes: &mut Vec<Change>)
760 {
761 let (from, to) = (self, other);
762
763 if from.sign_commit && ! to.sign_commit {
765 changes.push(Change::RemoveRight(name.clone(), Right::SignCommit));
766 }
767 if from.sign_tag && ! to.sign_tag {
768 changes.push(Change::RemoveRight(name.clone(), Right::SignTag));
769 }
770 if from.sign_archive && ! to.sign_archive {
771 changes.push(Change::RemoveRight(name.clone(), Right::SignArchive));
772 }
773 if from.add_user && ! to.add_user {
774 changes.push(Change::RemoveRight(name.clone(), Right::AddUser));
775 }
776 if from.retire_user && ! to.retire_user {
777 changes.push(Change::RemoveRight(name.clone(), Right::RetireUser));
778 }
779 if from.audit && ! to.audit {
780 changes.push(Change::RemoveRight(name.clone(), Right::Audit));
781 }
782
783 if ! from.sign_commit && to.sign_commit {
785 changes.push(Change::AddRight(name.clone(), Right::SignCommit));
786 }
787 if ! from.sign_tag && to.sign_tag {
788 changes.push(Change::AddRight(name.clone(), Right::SignTag));
789 }
790 if ! from.sign_archive && to.sign_archive {
791 changes.push(Change::AddRight(name.clone(), Right::SignArchive));
792 }
793 if ! from.add_user && to.add_user {
794 changes.push(Change::AddRight(name.clone(), Right::AddUser));
795 }
796 if ! from.retire_user && to.retire_user {
797 changes.push(Change::AddRight(name.clone(), Right::RetireUser));
798 }
799 if ! from.audit && to.audit {
800 changes.push(Change::AddRight(name.clone(), Right::Audit));
801 }
802
803 if self.keyring != other.keyring {
805 fn parse_keyring<'a>(name: &str, keyring: &'a str)
811 -> BTreeMap<Fingerprint, Vec<RawCert<'a>>>
812 {
813 match RawCertParser::from_bytes(keyring) {
814 Err(err) => {
815 eprintln!("Parsing {}'s keyring: {}", name, err);
816 Default::default()
817 }
818 Ok(certs) => {
819 let certs = certs.into_iter()
820 .filter_map(|cert| {
821 match cert {
822 Err(err) => {
823 eprintln!("Parsing certificate from {}'s keyring: {}",
824 name, err);
825 None
826 }
827 Ok(cert) => Some(cert),
828 }
829 });
830
831 let mut map: BTreeMap<Fingerprint, Vec<RawCert>> = BTreeMap::new();
832 for cert in certs {
833 let entry = map.entry(cert.fingerprint());
834 match entry {
835 Entry::Occupied(mut oe) => {
836 let oe: &mut Vec<RawCert> = oe.get_mut();
837 oe.push(cert);
838 }
839 Entry::Vacant(ve) => {
840 ve.insert(vec![ cert ]);
841 }
842 }
843 }
844
845 map
846 }
847 }
848 }
849
850 let old = parse_keyring(&name, &self.keyring);
851 let new = parse_keyring(&name, &other.keyring);
852
853 let old_certs: BTreeSet<&Fingerprint> = old.keys().collect();
855 let new_certs: BTreeSet<&Fingerprint> = new.keys().collect();
856
857 for &removed in old_certs.difference(&new_certs) {
858 changes.push(Change::RemoveCert(name.clone(), removed.clone()));
859 }
860 for &added in new_certs.difference(&old_certs) {
861 changes.push(Change::AddCert(name.clone(), added.clone()));
862 }
863
864 for &fpr in old_certs.intersection(&new_certs) {
867 let old = old.get(fpr).expect("have it");
868 let new = new.get(fpr).expect("have it");
869
870 if old == new {
871 continue;
872 }
873
874 let into_packets = |certs: Vec<RawCert>| -> HashSet<(Packet, Signature)> {
877 let mut pairs: HashSet<(Packet, Signature)> = HashSet::new();
878
879 for cert in certs.into_iter() {
880 let mut packets = cert.packets();
881 let primary_key
882 = packets.next().expect("have a primary key");
883 let primary_key = match Packet::try_from(primary_key) {
884 Ok(p) => p,
885 Err(err) => {
886 eprintln!(
887 "Warning: {} has a corrupted primary key \
888 packet (skipped): {}",
889 cert.fingerprint(), err);
890 continue;
891 }
892 };
893
894 packets.fold(
895 primary_key,
896 |component, packet| {
897 let packet = match Packet::try_from(packet) {
898 Ok(p) => p,
899 Err(err) => {
900 eprintln!(
901 "Warning: {} has a corrupted packet \
902 (skipped): {}",
903 cert.fingerprint(), err);
904 return component;
905 }
906 };
907
908 match packet {
909 Packet::Signature(sig) => {
910 pairs.insert(
911 (component.clone(), sig.clone()));
912 component
913 }
914 Packet::Marker(_) => {
915 component
917 }
918 _ => {
919 packet.clone()
921 }
922 }
923 });
924 }
925
926 pairs
927 };
928
929 let old_packets = into_packets(old.clone());
930 let new_packets = into_packets(new.clone());
931
932 for (component, sig) in old_packets.difference(&new_packets) {
933 changes.push(Change::RemovePacket(name.clone(),
934 fpr.clone(),
935 component.clone(),
936 sig.clone()));
937 }
938 for (component, sig) in new_packets.difference(&old_packets) {
939 changes.push(Change::AddPacket(name.clone(),
940 fpr.clone(),
941 component.clone(),
942 sig.clone()));
943 }
944 }
945 }
946 }
947}
948
949static DIFF_JSON_VERSION: &'static str = "1.0.0";
952
953#[derive(Serialize)]
955pub struct Diff<'f, 't> {
956 version: &'static str,
957
958 pub from: &'f Policy,
959 pub changes: Vec<Change>,
960 pub to: &'t Policy,
961}
962
963impl Diff<'_, '_> {
964 fn assert(&self, r: &Rights) -> Result<()> {
965 for c in &self.changes {
966 c.assert(r)?;
967 }
968 Ok(())
969 }
970}
971
972use crate::utils::{serialize_fp, serialize_oid};
973
974#[derive(Clone, Serialize)]
975pub enum Change {
976 VersionChange {
977 from: usize,
978 to: usize,
979 },
980 GoodlistCommit(
981 #[serde(serialize_with = "serialize_oid")] Oid),
982 UngoodlistCommit(
983 #[serde(serialize_with = "serialize_oid")] Oid),
984
985 AddUser(String),
986 RetireUser(String),
987
988 AddRight(String, Right),
989 RemoveRight(String, Right),
990
991 AddCert(String,
992 #[serde(serialize_with = "serialize_fp")] Fingerprint),
993 RemoveCert(String,
994 #[serde(serialize_with = "serialize_fp")] Fingerprint),
995
996 AddPacket(String,
997 #[serde(serialize_with = "serialize_fp")] Fingerprint,
999 #[serde(serialize_with = "serialize_packet")] Packet,
1001 #[serde(serialize_with = "serialize_signature")] Signature),
1003 RemovePacket(String,
1004 #[serde(serialize_with = "serialize_fp")] Fingerprint,
1006 #[serde(serialize_with = "serialize_packet")] Packet,
1008 #[serde(serialize_with = "serialize_signature")] Signature),
1010}
1011
1012impl Change {
1013 fn assert(&self, r: &Rights) -> Result<()> {
1014 use Change::*;
1015 match self {
1016 VersionChange { .. } => r.assert(Right::Audit),
1017 GoodlistCommit(_) => r.assert(Right::Audit),
1018 UngoodlistCommit(_) => r.assert(Right::Audit),
1019
1020 AddUser(_) => r.assert(Right::AddUser),
1022 RetireUser(_) => r.assert(Right::RetireUser),
1023 AddRight(_, right) =>
1024 r.assert(Right::AddUser).and_then(|_| r.assert(*right)),
1025 RemoveRight(_, right) =>
1026 r.assert(Right::RetireUser).and_then(|_| r.assert(*right)),
1027
1028 AddCert(_, _) => r.assert(Right::AddUser),
1030 RemoveCert(_, _) => r.assert(Right::RetireUser),
1031
1032 AddPacket(_, _, _, _) => Ok(()),
1034
1035 RemovePacket(_, fpr, _component, sig) => {
1037 if sig.get_issuers().into_iter()
1038 .any(|kh| kh.aliases(KeyHandle::from(fpr)))
1039 {
1040 r.assert(Right::RetireUser)
1043 } else {
1044 Ok(())
1045 }
1046 }
1047 }
1048 }
1049}
1050
1051#[derive(Debug)]
1052pub struct Rights(BTreeSet<Right>);
1053
1054impl Rights {
1055 fn assert(&self, r: Right) -> Result<()> {
1056 if ! self.0.contains(&r) {
1057 Err(Error::Unauthorized(format!("Right {} is missing", r)))
1058 } else {
1059 Ok(())
1060 }
1061 }
1062}
1063
1064#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq, PartialOrd, Ord)]
1065pub enum Right {
1066 SignCommit,
1067 SignTag,
1068 SignArchive,
1069 AddUser,
1070 RetireUser,
1071 Audit,
1072}
1073
1074impl fmt::Display for Right {
1075 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1076 use Right::*;
1077 match self {
1078 SignCommit => f.write_str("sign-commit"),
1079 SignTag => f.write_str("sign-tag"),
1080 SignArchive => f.write_str("sign-archive"),
1081 AddUser => f.write_str("add-user"),
1082 RetireUser => f.write_str("retire-user"),
1083 Audit => f.write_str("audit"),
1084 }
1085 }
1086}