Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix blob import, improve blob hash #18

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "pubky-app-specs",
"type": "module",
"description": "Pubky.app Data Model Specifications",
"version": "0.3.0-rc6",
"version": "0.3.0-rc7",
"license": "MIT",
"collaborators": [
"SHAcollision"
Expand Down
44 changes: 26 additions & 18 deletions src/models/blob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use crate::{
traits::{HasPath, HashId, Validatable},
APP_PATH, PUBLIC_PATH,
};
use base32::{encode, Alphabet};
use blake3::Hasher;
use serde::{Deserialize, Serialize};

#[cfg(target_arch = "wasm32")]
Expand All @@ -12,8 +14,6 @@ use wasm_bindgen::prelude::*;
#[cfg(feature = "openapi")]
use utoipa::ToSchema;

const SAMPLE_SIZE: usize = 2 * 1024;

/// Represents a file uploaded by the user.
/// URI: /pub/pubky.app/files/:file_id
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
Expand Down Expand Up @@ -53,20 +53,22 @@ impl Json for PubkyAppBlob {}

impl HashId for PubkyAppBlob {
fn get_id_data(&self) -> String {
// Get the start and end samples
let start = &self.0[..SAMPLE_SIZE.min(self.0.len())];
let end = if self.0.len() > SAMPLE_SIZE {
&self.0[self.0.len() - SAMPLE_SIZE..]
} else {
&[]
};
// data string id hashing is not needed for PubkyAppBlob as we hash the entire blob
"".to_string()
}

// Combine the samples
let mut combined = Vec::with_capacity(start.len() + end.len());
combined.extend_from_slice(start);
combined.extend_from_slice(end);
fn create_id(&self) -> String {
// Create a Blake3 hash of the blob data
let mut hasher = Hasher::new();
hasher.update(&self.0);
let blake3_hash = hasher.finalize();

base32::encode(base32::Alphabet::Crockford, &combined)
// Get the first half of the hash bytes
let half_hash_length = blake3_hash.as_bytes().len() / 2;
let half_hash = &blake3_hash.as_bytes()[..half_hash_length];

// Encode the first half of the hash in Base32 using the Z-base32 alphabet
encode(Alphabet::Crockford, half_hash)
}
}

Expand All @@ -79,6 +81,12 @@ impl HasPath for PubkyAppBlob {
}

impl Validatable for PubkyAppBlob {
fn try_from(blob: &[u8], id: &str) -> Result<Self, String> {
let instance = Self(blob.to_vec());
instance.validate(Some(id))?;
Ok(instance)
}

fn validate(&self, id: Option<&str>) -> Result<(), String> {
// Validate the blob ID
if let Some(id) = id {
Expand All @@ -95,9 +103,9 @@ mod tests {
use crate::traits::HashId;

#[test]
fn test_get_id_data_size_is_smaller_than_sample() {
let blob = PubkyAppBlob(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
let id = blob.get_id_data();
assert_eq!(id, "041061050R3GG28A");
fn test_create_id_from_small_blob() {
let blob = PubkyAppBlob(vec![1, 2]);
let id = blob.create_id();
assert_eq!(id, "PZBQ010FF079VVZPQG1RNFN6DR");
}
}
6 changes: 3 additions & 3 deletions src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,10 @@ mod tests {

#[test]
fn test_import_blob() {
let uri = "pubky://operrr8wsbpr3ue9d4qj41ge1kcc6r7fdiy6o3ugjrrhi4y77rdo/pub/pubky.app/blobs/8FACA7A6XMYH0GD9KBXMQ373PR";
let uri = "pubky://operrr8wsbpr3ue9d4qj41ge1kcc6r7fdiy6o3ugjrrhi4y77rdo/pub/pubky.app/blobs/CDW1T5RM4PHP64QT0P6RE4PNT0";
// For a blob, assume the JSON is an array of numbers representing the data.
let blob_json = r#"[1,2,3,4]"#;
let result = PubkyAppObject::from_uri(uri, blob_json.as_bytes());
let blob: Vec<u8> = vec![1, 2, 3, 4];
let result = PubkyAppObject::from_uri(uri, &blob);
assert!(
result.is_ok(),
"Expected a successful import for blob, got error: {:?}",
Expand Down