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
5 changes: 5 additions & 0 deletions .changeset/stupid-bats-join.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@contentauth/c2pa-node": minor
---

Integrate postCawgValidate into Reader.
3 changes: 1 addition & 2 deletions js-src/IdentityAssertion.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,9 @@ describe("IdentityAssertionBuilder", () => {
await builder.signAsync(iaSigner, source, dest);

// Verify the manifest
const reader = await Reader.fromAsset({
await Reader.fromAsset({
buffer: dest.buffer! as Buffer,
mimeType: "image/jpeg",
});
await reader.postValidateCawg();
});
});
5 changes: 0 additions & 5 deletions js-src/Reader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import path from "path";
import * as fs from "fs-extra";

import { Reader } from "./Reader.js";
import { patchVerifyConfig } from "./Settings.js";

const tempDir = path.join(__dirname, "tmp");

Expand Down Expand Up @@ -109,7 +108,6 @@ describe("Reader", () => {
}`);

beforeAll(async () => {
patchVerifyConfig({ verifyTrust: false });
await fs.ensureDir(tempDir);
});

Expand Down Expand Up @@ -206,9 +204,6 @@ describe("Reader", () => {
path: "./tests/fixtures/C_with_CAWG_data.jpg",
});

// Call postValidateCawg to decode CAWG assertions
await reader.postValidateCawg();

const activeManifest = reader.getActive();

// Find the cawg.identity assertion
Expand Down
4 changes: 0 additions & 4 deletions js-src/Reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,4 @@ export class Reader implements ReaderInterface {

return manifestStore.manifests[activeManifest];
}

async postValidateCawg(): Promise<void> {
return getNeonBinary().readerPostValidateCawg.call(this.reader);
}
}
18 changes: 12 additions & 6 deletions js-src/Settings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@

import type { TrustConfig, VerifyConfig } from "./types.d.ts";
import {
loadC2paSettings,
loadTrustConfig,
loadCawgTrustConfig,
getCawgTrustConfig,
getSettingsJson,
getTrustConfig,
getCawgTrustConfig,
loadVerifyConfig,
getVerifyConfig,
loadC2paSettings,
loadCawgTrustConfig,
loadTrustConfig,
loadVerifyConfig,
patchVerifyConfig,
resetSettings,
} from "./Settings.js";

describe("Settings", () => {
afterAll(() => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Do it in beforeAll too? So if something else would run on the same thread before, only the settings from the tests would be set, no doubts?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could do it beforeAll in all of the test suites or none of them. It's been a real headache in c2pa-rs finding all of the tests that modify and don't reset the settings. I like the idea of detecting when tests don't put things back as they should.

resetSettings();
});

it("loads a trustlist-shaped JSON and returns JSON via getSettingsJson", () => {
// Matches c2pa-rs settings structure: trust + verify
// trust.allowed_list accepts base64 lines or PEMs; provide a simple base64 line
Expand All @@ -37,6 +42,7 @@ describe("Settings", () => {
expect(obj.trust?.allowed_list).toBe("Zm9v\n");
expect(obj.verify?.verify_trust).toBe(true);
});

describe("loadTrustConfig", () => {
it("preserves other settings when loading trust config", () => {
// First, load basic settings that work with c2pa-rs
Expand Down Expand Up @@ -128,7 +134,7 @@ describe("Settings", () => {

// Verify settings are still intact
const currentSettings = JSON.parse(getSettingsJson());
expect(currentSettings.core.merkle_tree_max_proofs).toBe(5);
expect(currentSettings.core.decode_identity_assertions).toBe(true);
expect(currentSettings.verify.verify_trust).toBe(true);
expect(currentSettings.trust.verify_trust_list).toBe(true);
});
Expand Down
8 changes: 8 additions & 0 deletions js-src/Settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,11 @@ export function getVerifyConfig(): VerifyConfig {
strictV1Validation: parsed.strict_v1_validation,
};
}

/**
* Reset settings to their default values.
* This clears any custom settings and restores the default configuration.
*/
export function resetSettings(): void {
getNeonBinary().resetSettings();
}
3 changes: 3 additions & 0 deletions js-src/index.node.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,7 @@ declare module "index.node" {
export function loadCawgTrustConfig(trustConfigJson: string): void;
export function getTrustConfig(): string;
export function getCawgTrustConfig(): string;
export function loadVerifyConfig(verifyConfigJson: string): void;
export function getVerifyConfig(): string;
export function resetSettings(): void;
}
5 changes: 0 additions & 5 deletions js-src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,11 +309,6 @@ export interface ReaderInterface {
* @param filePath The path to the file
*/
resourceToAsset(uri: string, output: DestinationAsset): Promise<number>;

/**
* Run CAWG validation
*/
postValidateCawg(): Promise<void>;
}

export interface IdentityAssertionSignerInterface {
Expand Down
7 changes: 3 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,6 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> {
"readerResourceToAsset",
neon_reader::NeonReader::resource_to_asset,
)?;
cx.export_function(
"readerPostValidateCawg",
neon_reader::NeonReader::post_validate_cawg,
)?;

// Signers
cx.export_function("localSignerNew", neon_signer::NeonLocalSigner::new)?;
Expand Down Expand Up @@ -186,5 +182,8 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> {
cx.export_function("loadVerifyConfig", settings::load_verify_config)?;
cx.export_function("getVerifyConfig", settings::get_verify_config)?;

// Reset Settings
cx.export_function("resetSettings", settings::reset_settings)?;

Ok(())
}
86 changes: 42 additions & 44 deletions src/neon_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,30 +123,28 @@ impl NeonBuilder {
}

pub fn add_resource(mut cx: FunctionContext) -> JsResult<JsPromise> {
let rt = runtime();
let this = cx.this::<JsBox<Self>>()?;
let uri = cx.argument::<JsString>(0)?.value(&mut cx);
let resource = cx
.argument::<JsObject>(1)
.and_then(|obj| parse_asset(&mut cx, obj))?;
let builder = Arc::clone(&this.builder);

let channel = cx.channel();
let (deferred, promise) = cx.promise();

rt.spawn(async move {
let mut builder = builder.lock().await;

let result = resource.into_read_stream().and_then(|mut resource_stream| {
builder.add_resource(&uri, &mut resource_stream)?;
Ok(())
});
let promise = cx
.task(move || {
// Block on acquiring the async mutex lock
let rt = runtime();
let mut builder = rt.block_on(async { builder.lock().await });

deferred.settle_with(&channel, |mut cx| match result {
resource.into_read_stream().and_then(|mut resource_stream| {
builder.add_resource(&uri, &mut resource_stream)?;
Ok(())
})
})
.promise(move |mut cx, result: Result<(), Error>| match result {
Ok(_) => Ok(cx.undefined()),
Err(err) => as_js_error(&mut cx, err).and_then(|err| cx.throw(err)),
});
});

Ok(promise)
}
Expand All @@ -167,18 +165,24 @@ impl NeonBuilder {
rt.spawn(async move {
let mut builder = builder.lock().await;

let result = ingredient
.mime_type()
.ok_or_else(|| Error::Signing("Ingredient asset must have a mime type".to_string()))
.and_then(|format| {
let mut ingredient_stream = ingredient.into_read_stream()?;
builder.add_ingredient_from_stream(
let result = async {
let format = ingredient
.mime_type()
.ok_or_else(|| {
Error::Signing("Ingredient asset must have a mime type".to_string())
})?
.to_owned();
let mut ingredient_stream = ingredient.into_read_stream()?;
builder
.add_ingredient_from_stream_async(
&ingredient_json,
&format,
&mut ingredient_stream,
)?;
Ok(())
});
)
.await?;
Ok(())
}
.await;

deferred.settle_with(&channel, move |mut cx| match result {
Ok(_) => Ok(cx.undefined()),
Expand All @@ -190,53 +194,47 @@ impl NeonBuilder {
}

pub fn to_archive(mut cx: FunctionContext) -> JsResult<JsPromise> {
let rt = runtime();
let this = cx.this::<JsBox<Self>>()?;
let dest = cx
.argument::<JsObject>(0)
.and_then(|obj| parse_asset(&mut cx, obj))?;
let builder = Arc::clone(&this.builder);

let channel = cx.channel();
let (deferred, promise) = cx.promise();

rt.spawn(async move {
let mut builder = builder.lock().await;
let result = dest.write_stream().and_then(|dest_stream| {
builder.to_archive(dest_stream)?;
Ok(())
});
let promise = cx
.task(move || {
// Block on acquiring the async mutex lock
let rt = runtime();
let mut builder = rt.block_on(async { builder.lock().await });

deferred.settle_with(&channel, move |mut cx| match result {
dest.write_stream().and_then(|dest_stream| {
builder.to_archive(dest_stream)?;
Ok(())
})
})
.promise(move |mut cx, result: Result<(), Error>| match result {
Ok(_) => Ok(cx.undefined()),
Err(err) => as_js_error(&mut cx, err).and_then(|err| cx.throw(err)),
});
});
Ok(promise)
}

pub fn from_archive(mut cx: FunctionContext) -> JsResult<JsPromise> {
let rt = runtime();
let source = cx
.argument::<JsObject>(0)
.and_then(|obj| parse_asset(&mut cx, obj))?;

let channel = cx.channel();
let (deferred, promise) = cx.promise();

rt.spawn(async move {
let result = source.into_read_stream().and_then(|source_stream| {
let promise = cx
.task(move || {
let source_stream = source.into_read_stream()?;
let builder = Builder::from_archive(source_stream)?;
Ok(builder)
});

deferred.settle_with(&channel, move |mut cx| match result {
})
.promise(move |mut cx, result: Result<Builder, Error>| match result {
Ok(builder) => Ok(cx.boxed(Self {
builder: Arc::new(Mutex::new(builder)),
})),
Err(err) => as_js_error(&mut cx, err).and_then(|err| cx.throw(err)),
});
});
Ok(promise)
}

Expand Down
Loading