Skip to main content

cdx_core/document/
security.rs

1#[cfg(feature = "encryption")]
2use crate::security::EncryptionMetadata;
3
4#[cfg(feature = "signatures")]
5use crate::archive::SIGNATURES_PATH;
6#[cfg(feature = "signatures")]
7use crate::manifest::SecurityRef;
8#[cfg(feature = "signatures")]
9use crate::security::{Signature, SignatureFile};
10
11use crate::Result;
12
13use super::Document;
14use super::MutableResource;
15
16impl Document {
17    /// Get a reference to the signature file, if present.
18    #[cfg(feature = "signatures")]
19    #[must_use]
20    pub fn signature_file(&self) -> Option<&SignatureFile> {
21        self.signature_file.as_ref()
22    }
23
24    /// Get the signatures from the document.
25    #[cfg(feature = "signatures")]
26    #[must_use]
27    pub fn signatures(&self) -> &[Signature] {
28        self.signature_file
29            .as_ref()
30            .map_or(&[], |sf| sf.signatures.as_slice())
31    }
32
33    /// Add a signature to the document.
34    ///
35    /// This adds the signature to the document's signature file. If no signature file
36    /// exists, one will be created. The document ID in the signature file will be
37    /// updated to match the current computed document ID.
38    ///
39    /// # Errors
40    ///
41    /// Returns an error if the document ID cannot be computed.
42    #[cfg(feature = "signatures")]
43    pub fn add_signature(&mut self, signature: Signature) -> Result<()> {
44        let doc_id = self.compute_id()?;
45
46        if let Some(sig_file) = self.signature_file.as_mut() {
47            // Update document ID if it changed
48            sig_file.document_id = doc_id;
49            sig_file.add_signature(signature);
50        } else {
51            let mut sig_file = SignatureFile::new(doc_id);
52            sig_file.add_signature(signature);
53            self.signature_file = Some(sig_file);
54        }
55
56        // Update manifest to reference the security section
57        self.manifest.security = Some(SecurityRef {
58            signatures: Some(SIGNATURES_PATH.to_string()),
59            encryption: self
60                .manifest
61                .security
62                .as_ref()
63                .and_then(|s| s.encryption.clone()),
64        });
65
66        Ok(())
67    }
68
69    /// Check if the document has any signatures.
70    #[cfg(feature = "signatures")]
71    #[must_use]
72    pub fn has_signatures(&self) -> bool {
73        self.signature_file
74            .as_ref()
75            .is_some_and(|sf| !sf.is_empty())
76    }
77
78    /// Check if the document has any signatures.
79    ///
80    /// Always returns false when the signatures feature is disabled.
81    #[cfg(not(feature = "signatures"))]
82    #[must_use]
83    pub fn has_signatures(&self) -> bool {
84        false
85    }
86
87    /// Get a reference to the encryption metadata, if present.
88    #[cfg(feature = "encryption")]
89    #[must_use]
90    pub fn encryption_metadata(&self) -> Option<&EncryptionMetadata> {
91        self.encryption_metadata.as_ref()
92    }
93
94    /// Check if the document has encryption metadata.
95    #[cfg(feature = "encryption")]
96    #[must_use]
97    pub fn is_encrypted(&self) -> bool {
98        self.encryption_metadata.is_some()
99    }
100
101    /// Check if the document has encryption metadata.
102    ///
103    /// Always returns false when the encryption feature is disabled.
104    #[cfg(not(feature = "encryption"))]
105    #[must_use]
106    pub fn is_encrypted(&self) -> bool {
107        false
108    }
109
110    /// Set encryption metadata for this document.
111    ///
112    /// # Errors
113    ///
114    /// Returns an error if the document is in an immutable state.
115    #[cfg(feature = "encryption")]
116    pub fn set_encryption(&mut self, metadata: EncryptionMetadata) -> Result<()> {
117        self.require_mutable("set encryption")?;
118        self.encryption_metadata = Some(metadata);
119        Ok(())
120    }
121
122    /// Remove encryption metadata from this document.
123    ///
124    /// # Errors
125    ///
126    /// Returns an error if the document is in an immutable state.
127    #[cfg(feature = "encryption")]
128    pub fn clear_encryption(&mut self) -> Result<()> {
129        self.require_mutable("remove encryption")?;
130        self.encryption_metadata = None;
131        Ok(())
132    }
133}