Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ jobs:

steps:
- name: "Checkout code"
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false

- name: "Run analysis"
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
with:
results_file: results.sarif
results_format: sarif
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ serde_json = "1.0"
url = { version = "2.5.4", features = ["serde"] }
uuid = { version = "1.10.1", features = ["v4"] }
time = { version = "0.3.36", features = ["serde"] }
serde_with = { version = "2", features = ["time_0_3"] }
serde_with = { version = "3", features = ["time_0_3"] }
reqwest = { version = "0.12.5", features = ["blocking"] }
openssl = "0.10.72"
openssl-sys = "0.9.103"
ring = "0.17.12"
coset = "^0.3.5"
hex = "0.4"
base64 = "0.13"
base64 = "0.22"
chrono = { version = "0.4", features = ["serde"] }

[dev-dependencies]
mockito = "0.31.0"
mockito = "1.7.0"
9 changes: 6 additions & 3 deletions src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ use crate::claim::{validate_claim_v2, ClaimV2};
pub use crate::cross_reference::CrossReference;
use crate::datetime_wrapper::OffsetDateTimeWrapper;
use crate::ingredient::{validate_ingredient, Ingredient};
use base64::{engine::general_purpose, Engine as _};
use openssl::pkey::PKey;
use openssl::sign::Verifier;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -265,7 +266,8 @@ fn extract_signature_from_manifest(manifest_bytes: &[u8]) -> Result<Vec<u8>, Str
// Check if claim_v2 is present
if let Some(claim_v2) = manifest.claim_v2 {
if let Some(signature) = claim_v2.signature {
let signature_bytes = base64::decode(signature)
let signature_bytes = general_purpose::STANDARD
.decode(signature)
.map_err(|e| format!("Failed to decode signature: {e}"))?;
return Ok(signature_bytes);
} else {
Expand All @@ -274,8 +276,9 @@ fn extract_signature_from_manifest(manifest_bytes: &[u8]) -> Result<Vec<u8>, Str
}

if let Some(signature) = manifest.claim.signature {
let signature_bytes =
base64::decode(signature).map_err(|e| format!("Failed to decode signature: {e}"))?;
let signature_bytes = general_purpose::STANDARD
.decode(signature)
.map_err(|e| format!("Failed to decode signature: {e}"))?;
Ok(signature_bytes)
} else {
Err("Signature field is missing in claim.".to_string())
Expand Down
13 changes: 9 additions & 4 deletions tests/test_dataset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ use atlas_c2pa_lib::assertion::{
Action, ActionAssertion, Assertion, Author, CreativeWorkAssertion,
};
use atlas_c2pa_lib::asset_type::AssetType;
use atlas_c2pa_lib::claim::ClaimV2; // Using ClaimV2
use atlas_c2pa_lib::claim::ClaimV2;
use atlas_c2pa_lib::datetime_wrapper::OffsetDateTimeWrapper;
use atlas_c2pa_lib::ingredient::{Ingredient, IngredientData};
use atlas_c2pa_lib::manifest::Manifest;
use mockito::mock;
use mockito::Server;
use openssl::sha::sha256;
use std::fs;
use time::OffsetDateTime;

#[test]
fn test_dataset_manifest_creation_v2() {
let mut server = Server::new();
let claim_generator = "c2pa-ml/0.1.0".to_string();

let file_paths = [
Expand All @@ -21,18 +23,20 @@ fn test_dataset_manifest_creation_v2() {
];

let mut ingredients = vec![];
let mut mocks = vec![]; // Store mocks to keep them alive

for (i, file_path) in file_paths.iter().enumerate() {
let file_content = fs::read(file_path).expect("Failed to read test file");

let mock = mock("GET", format!("/dataset_file_{i}").as_str())
let mock = server
.mock("GET", format!("/dataset_file_{i}").as_str())
.with_status(200)
.with_header("content-type", "application/octet-stream")
.with_body(file_content.clone())
.create();

let ingredient_data = IngredientData {
url: mockito::server_url() + &format!("/dataset_file_{i}"),
url: server.url() + &format!("/dataset_file_{i}"),
alg: "sha256".to_string(),
hash: "".to_string(),
data_types: vec![AssetType::Dataset],
Expand Down Expand Up @@ -76,6 +80,7 @@ fn test_dataset_manifest_creation_v2() {
};

ingredients.push(ingredient);
mocks.push(mock); // Keep mock alive
}

let creative_work_assertion = Assertion::CreativeWork(CreativeWorkAssertion {
Expand Down
13 changes: 8 additions & 5 deletions tests/test_linking_ingredients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ use atlas_c2pa_lib::claim::ClaimV2;
use atlas_c2pa_lib::datetime_wrapper::OffsetDateTimeWrapper;
use atlas_c2pa_lib::ingredient::{Ingredient, IngredientData, LinkedIngredient};
use atlas_c2pa_lib::manifest::Manifest;
use mockito::mock;
use mockito::Server;
use openssl::sha::sha256;
use time::OffsetDateTime;

#[test]
fn test_ingredient_linking_with_verification() {
let mut server = Server::new(); // Create a new mock server
let claim_generator = "c2pa-ml/0.1.0".to_string();

// Fixed timestamp for consistent hashing
Expand All @@ -22,14 +23,14 @@ fn test_ingredient_linking_with_verification() {

// Linked ingredient (that itself is a reference to another dataset or model)
let linked_ingredient = LinkedIngredient {
url: mockito::server_url() + "/linked_ingredient.json",
url: server.url() + "/linked_ingredient.json",
hash: "ab82708c91050a674c1b12e2d48f4b2dced1dd25b1132d3f59460ec39ecce664".to_string(), // We'll verify this later
media_type: "application/json".to_string(),
};

// Main ingredient with a link to another ingredient
let ingredient_data = IngredientData {
url: mockito::server_url() + "/ingredient.json",
url: server.url() + "/ingredient.json",
alg: "sha256".to_string(),
hash: "ingredient_hash".to_string(),
data_types: vec![AssetType::ModelOpenVino],
Expand Down Expand Up @@ -78,14 +79,16 @@ fn test_ingredient_linking_with_verification() {
let _manifest_hash = hex::encode(sha256(manifest_json.as_bytes()));

// Mock the HTTP server to return the linked ingredient
let linked_ingredient_mock = mock("GET", "/linked_ingredient.json")
let linked_ingredient_mock = server
.mock("GET", "/linked_ingredient.json")
.with_status(200)
.with_header("content-type", "application/json")
.with_body("{ \"ingredient\": \"linked\" }") // Simulated linked ingredient
.create();

// Mock the HTTP server to return the ingredient
let ingredient_mock = mock("GET", "/ingredient.json")
let ingredient_mock = server
.mock("GET", "/ingredient.json")
.with_status(200)
.with_header("content-type", "application/json")
.with_body(manifest_json.clone()) // Return the serialized manifest
Expand Down
10 changes: 6 additions & 4 deletions tests/test_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,33 @@ use atlas_c2pa_lib::assertion::{
Action, ActionAssertion, Assertion, Author, CreativeWorkAssertion,
};
use atlas_c2pa_lib::asset_type::AssetType;
use atlas_c2pa_lib::claim::ClaimV2; // Updated to use ClaimV2
use atlas_c2pa_lib::claim::ClaimV2;
use atlas_c2pa_lib::datetime_wrapper::OffsetDateTimeWrapper;
use atlas_c2pa_lib::ingredient::{Ingredient, IngredientData};
use atlas_c2pa_lib::manifest::Manifest;
use mockito::mock;
use mockito::Server;
use openssl::sha::sha256;
use std::fs;
use time::OffsetDateTime;

#[test]
fn test_manifest_creation_v2() {
let mut server = Server::new(); // Create a new mock server
let claim_generator = "c2pa-ml/0.1.0".to_string();

let file_path = "tests/test_data/model.bin";
let file_content = fs::read(file_path).expect("Failed to read test file");

// Mock the server to expect a GET request to /model.file
let mock = mock("GET", "/model.file")
let mock = server
.mock("GET", "/model.file")
.with_status(200)
.with_header("content-type", "application/octet-stream")
.with_body(file_content.clone())
.create();

let ingredient_data = IngredientData {
url: mockito::server_url() + "/model.file",
url: server.url() + "/model.file",
alg: "sha256".to_string(),
hash: "".to_string(),
data_types: vec![AssetType::ModelOpenVino],
Expand Down
10 changes: 6 additions & 4 deletions tests/test_manifest_cross_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ use atlas_c2pa_lib::claim::ClaimV2;
use atlas_c2pa_lib::datetime_wrapper::OffsetDateTimeWrapper;
use atlas_c2pa_lib::ingredient::{Ingredient, IngredientData};
use atlas_c2pa_lib::manifest::{CrossReference, Manifest};
use mockito::mock;
use mockito::Server;
use openssl::sha::sha256;
use time::OffsetDateTime;

#[test]
fn test_cross_manifest_linking() {
let mut server = Server::new(); // Create a new mock server
let claim_generator = "c2pa-ml/0.1.0".to_string();

let fixed_timestamp = OffsetDateTimeWrapper(
Expand Down Expand Up @@ -45,14 +46,15 @@ fn test_cross_manifest_linking() {

let linked_manifest_hash = hex::encode(sha256(linked_manifest_json.as_bytes()));

let linked_manifest_mock = mock("GET", "/linked_manifest.json")
let linked_manifest_mock = server
.mock("GET", "/linked_manifest.json")
.with_status(200)
.with_header("content-type", "application/json")
.with_body(linked_manifest_json.clone()) // Fixed linked manifest
.create();

let ingredient_data = IngredientData {
url: mockito::server_url() + "/model.file",
url: server.url() + "/model.file",
alg: "sha256".to_string(),
hash: "4e4fc7c4587ee5d5fa73f0b679e2d3549b5b0101fc556df783445a6db8b4161f".to_string(),
data_types: vec![AssetType::ModelOpenVino],
Expand Down Expand Up @@ -118,7 +120,7 @@ fn test_cross_manifest_linking() {
}),
created_at: fixed_timestamp.clone(),
cross_references: vec![CrossReference {
manifest_url: mockito::server_url() + "/linked_manifest.json",
manifest_url: server.url() + "/linked_manifest.json",
manifest_hash: linked_manifest_hash.clone(),
media_type: Some("application/json".to_string()),
}],
Expand Down