commit 3dde9494824bd75214b7a830375c849d9b64a7d8
parent 526fba3b6631caf3cf1a37e29ec5744fabe6ace0
Author: lash <dev@holbrook.no>
Date:   Mon, 25 Jul 2022 14:02:27 +0000
Allow import from known digest types
Diffstat:
4 files changed, 171 insertions(+), 13 deletions(-)
diff --git a/src/digest.rs b/src/digest.rs
@@ -0,0 +1,127 @@
+use crate::error::ParseError;
+
+use sha2::{
+    Sha512,
+    Sha256,
+    Digest,
+};
+
+use log::error;
+
+pub enum RecordDigest {
+    Sha512(Vec<u8>),
+    Sha256(Vec<u8>),
+    SwarmHash(Vec<u8>),
+    Empty,
+}
+
+
+
+pub fn from_vec(v: Vec<u8>) -> Result<RecordDigest, ParseError> {
+    let sz = Sha512::output_size();
+    if v.len() != sz {
+        return Err(ParseError);
+    }
+    Ok(RecordDigest::Sha512(v))
+}
+
+pub fn from_urn(urn: &str) -> Result<RecordDigest, ParseError> {
+    let mut v = urn.split(":");
+    let r = match v.next() {
+        Some("sha512") => {
+            let digest_hex = v.next().unwrap();
+            let digest = hex::decode(digest_hex).unwrap();
+            match from_vec(digest) {
+                Ok(vv) => {
+                    vv
+                },
+                Err(e) => {
+                    return Err(ParseError);
+                },
+            }
+        },
+        Some("sha256") => {
+            let digest_hex = v.next().unwrap();
+            let digest = hex::decode(digest_hex).unwrap();
+
+            let sz = Sha256::output_size();
+            if digest.len() != sz {
+                return Err(ParseError);
+            }
+
+            RecordDigest::Sha256(digest)
+        },
+        Some("bzz") => {
+            let digest_hex = v.next().unwrap();
+            let digest = hex::decode(digest_hex).unwrap();
+
+            if digest.len() != 32 {
+                return Err(ParseError);
+            }
+            
+            RecordDigest::SwarmHash(digest)
+        },
+        Some("") => {
+            RecordDigest::Empty
+        },
+        Some(_) => {
+            return Err(ParseError);
+        },
+        None => {
+            RecordDigest::Empty
+        },
+    };
+    Ok(r)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::from_urn;
+    use super::ParseError;
+
+    #[test]
+    fn test_digest_urn_parse() {
+        match from_urn("sha512:deadbeef") {
+            Ok(v) => {
+                panic!("expected fail");
+            },
+            _ => {},
+        };
+        match from_urn("sha512:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") {
+            Ok(v) => {},
+            _ => {
+                panic!("expected pass");
+            },
+        };
+        match from_urn("sha256:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") {
+            Ok(v) => {},
+            _ => {
+                panic!("expected pass");
+            },
+        };
+        match from_urn("bzz:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") {
+            Ok(v) => {},
+            _ => {
+                panic!("expected pass");
+            },
+        };
+        match from_urn("foo:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") {
+            Ok(v) => {
+                panic!("expected fail");
+            },
+            _ => {},
+        };
+        match from_urn("foo:deadbeef") {
+            Ok(v) => {
+                panic!("expected fail");
+            },
+            _ => {},
+        };
+        match from_urn("") {
+            Ok(v) => {},
+            _ => {
+                panic!("expected pass");
+            },
+        };
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
@@ -12,6 +12,8 @@ pub mod biblatex;
 
 pub mod error;
 
+pub mod digest;
+
 #[cfg(test)]
 mod tests {
     use env_logger;
diff --git a/src/meta.rs b/src/meta.rs
@@ -37,6 +37,8 @@ use crate::dc::{
     DC_XATTR_MEDIATYPE,
 };
 
+use crate::digest;
+
 use log::{
     debug,
 };
@@ -49,7 +51,7 @@ pub type FilePath = String;
 
 pub struct MetaData {
     dc: DCMetaData,
-    digest: Vec<u8>,
+    digest: digest::RecordDigest,
     local_name: Option<FileName>,
     comment: String,
     publish_date: PublishDate,
@@ -81,7 +83,7 @@ impl MetaData {
 
         let mut m = MetaData{
                 dc: dc,
-                digest: vec!(),
+                digest: digest::RecordDigest::Empty,
                 comment: String::new(),
                 local_name: filename,
                 publish_date: (0, 0, 0),
@@ -96,7 +98,7 @@ impl MetaData {
         let dc = DCMetaData::new("", "", EntryType::Unknown(String::new()));
         MetaData{
                 dc: dc,
-                digest: vec!(),
+                digest: digest::RecordDigest::Empty,
                 comment: String::new(),
                 //local_name: filepath.to_str().unwrap().to_string(),
                 local_name: None,
@@ -114,11 +116,11 @@ impl MetaData {
     }
 
     pub fn set_fingerprint(&mut self, fingerprint: Vec<u8>) {
-        let sz = Sha512::output_size();
-        if fingerprint.len() != sz {
-            panic!("wrong digest size, must be {}", sz);
-        }
-        self.digest = fingerprint;
+        self.digest = digest::from_vec(fingerprint).unwrap();
+    }
+
+    pub fn set_fingerprint_urn(&mut self, urn: &str) {
+        self.digest = digest::from_urn(urn).unwrap();
     }
 
     pub fn title(&self) -> String {
@@ -174,7 +176,20 @@ impl MetaData {
     }
 
     pub fn fingerprint(&self) -> String {
-        hex::encode(&self.digest)
+        match &self.digest {
+            digest::RecordDigest::Empty => {
+                return String::new();
+            },
+            digest::RecordDigest::Sha512(v) => {
+                return hex::encode(&v);
+            },
+            digest::RecordDigest::Sha256(v) => {
+                return hex::encode(&v);
+            },
+            digest::RecordDigest::SwarmHash(v) => {
+                return hex::encode(&v);
+            },
+        }
     }
 
     pub fn from_xattr(filepath: &path::Path) -> MetaData {
diff --git a/src/rdf.rs b/src/rdf.rs
@@ -32,6 +32,7 @@ use log::{
     error,
 };
 
+use crate::digest;
 use crate::meta::MetaData;
 use crate::error::ParseError;
 use crate::dc::{
@@ -118,17 +119,30 @@ pub fn write(entry: &MetaData, w: impl Write) -> Result<usize, std::io::Error> {
 fn handle_parse_match(metadata: &mut MetaData, triple: Triple) -> Result<(), RdfError> {
     let subject_iri = triple.subject.to_string();
     let l = subject_iri.len()-1;
+    //let subject = &subject_iri[1..l];
     let subject = &subject_iri[1..l];
+    match &subject[0..4] {
+        "urn:"  => {},
+        _ => {
+            return Err(RdfError::UrnError(UrnError::InvalidNid));
+        },
+    };
+    let digest_urn = match digest::from_urn(&subject[4..]) {
+        Err(e) => {
+            error!("error {:?}", &subject);
+            return Err(RdfError::UrnError(UrnError::InvalidNid));
+        },
+        Ok(v) => {
+            &subject[4..]
+        },
+    };
     let subject_urn = Urn::from_str(subject).unwrap();
-    if subject_urn.nid() != "sha512" {
-        return Err(RdfError::UrnError(UrnError::InvalidNid));
-    }
 
     let v = subject_urn.nss();
     let b = hex::decode(&v).unwrap();
     if metadata.fingerprint().len() == 0 {
         debug!("setting fingerprint {}", v);
-        metadata.set_fingerprint(b);
+        metadata.set_fingerprint_urn(digest_urn);
     } else if metadata.fingerprint() != v {
         return Err(RdfError::HashMismatchError);
     }