Skip to content

Commit 3ebb416

Browse files
committed
update to c2pa-rs main API
1 parent 74afb3f commit 3ebb416

File tree

12 files changed

+253
-312
lines changed

12 files changed

+253
-312
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ crate-type = ["cdylib"]
1313
v1 = ["c2pa/file_io"]
1414

1515
[dependencies]
16-
c2pa = {git = "https://github.com/contentauth/c2pa-rs.git", branch = "gpeacock/manifest_store_builder", features = ["openssl", "openssl_sign"]}
16+
c2pa = {git = "https://github.com/contentauth/c2pa-rs.git", branch = "main", features = ["unstable_api", "openssl", "openssl_sign"]}
1717
pem = "3.0.3"
1818
serde = { version = "1.0.197", features = ["derive"] }
1919
serde_derive = "1.0"

src/c2pa.udl

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ namespace c2pa {
33
string version();
44
string sdk_version();
55
/// [Throws=Error]
6+
/// CallbackSigner create_signer(SignerCallback callback, SigningAlg alg, bytes certs, string? ta_url);
7+
/// [Throws=Error]
68
/// string read_file([ByRef] string path, string? data_dir);
79
/// [Throws=Error]
810
/// string read_ingredient_file([ByRef] string path, [ByRef] string data_dir);
@@ -22,7 +24,6 @@ interface Error {
2224
Manifest(string reason);
2325
ManifestNotFound(string reason);
2426
NotSupported(string reason);
25-
FileNotFound(string reason);
2627
Other(string reason);
2728
RemoteManifest(string reason);
2829
ResourceNotFound(string reason);
@@ -62,27 +63,13 @@ interface Reader {
6263
constructor();
6364

6465
[Throws=Error]
65-
string read([ByRef] string format, [ByRef] Stream reader);
66+
string from_stream([ByRef] string format, [ByRef] Stream reader);
6667

6768
[Throws=Error]
6869
string json();
6970

7071
[Throws=Error]
71-
u64 resource([ByRef] string uri, [ByRef] Stream stream);
72-
};
73-
74-
///dictionary SignerInfo {
75-
/// string alg;
76-
/// sequence<u8> sign_cert;
77-
/// sequence<u8> private_key;
78-
/// string? ta_url;
79-
///};
80-
81-
dictionary SignerConfig {
82-
SigningAlg alg;
83-
bytes certs;
84-
string? time_authority_url = null;
85-
boolean use_ocsp = false;
72+
u64 resource_to_stream([ByRef] string uri, [ByRef] Stream stream);
8673
};
8774

8875
callback interface SignerCallback {
@@ -91,7 +78,7 @@ callback interface SignerCallback {
9178
};
9279

9380
interface CallbackSigner {
94-
constructor(SignerCallback callback, SignerConfig config);
81+
constructor(SignerCallback callback, SigningAlg alg, bytes certs, string? ta_url);
9582
};
9683

9784
interface Builder {
@@ -106,6 +93,12 @@ interface Builder {
10693
[Throws=Error]
10794
void add_ingredient([ByRef] string ingredient_json, [ByRef] string format, [ByRef] Stream stream );
10895

96+
[Throws=Error]
97+
void to_archive([ByRef] Stream stream );
98+
99+
[Throws=Error]
100+
void from_archive([ByRef] Stream stream );
101+
109102
[Throws=Error]
110103
bytes sign([ByRef] string format, [ByRef] Stream input, [ByRef] Stream output ,[ByRef] CallbackSigner signer);
111104
};

src/callback_signer.rs

Lines changed: 24 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -10,80 +10,47 @@
1010
// specific language governing permissions and limitations under
1111
// each license.
1212

13-
use c2pa::{Signer, SigningAlg};
13+
use c2pa::SigningAlg;
1414

1515
use crate::Result;
1616

17-
1817
/// Defines the callback interface for a signer
1918
pub trait SignerCallback: Send + Sync {
20-
/// Read a stream of bytes from the stream
19+
/// Sign the given bytes and return the signature
2120
fn sign(&self, bytes: Vec<u8>) -> Result<Vec<u8>>;
2221
}
2322

24-
/// Configuration for a Signer
25-
#[repr(C)]
26-
pub struct SignerConfig {
27-
/// Returns the algorithm of the Signer.
28-
pub alg: c2pa::SigningAlg,
29-
30-
/// Returns the certificates as a Vec containing a Vec of DER bytes for each certificate.
31-
pub certs: Vec<u8>,
32-
33-
/// URL for time authority to time stamp the signature
34-
pub time_authority_url: Option<String>,
35-
36-
/// Try to fetch OCSP response for the signing cert if available
37-
pub use_ocsp: bool,
38-
}
39-
40-
/// Callback signer that uses a callback to sign data
23+
/// This is a wrapper around the CallbackSigner for Python
24+
///
25+
/// Uniffi callbacks are only supported as a method in a structure, so this is a workaround
4126
pub struct CallbackSigner {
42-
callback: Box<dyn SignerCallback>,
43-
alg: SigningAlg,
44-
sign_certs: Vec<u8>,
45-
ta_url: Option<String>,
27+
signer: c2pa::CallbackSigner,
4628
}
4729

4830
impl CallbackSigner {
4931
pub fn new(
5032
callback: Box<dyn SignerCallback>,
51-
config: SignerConfig,
52-
// alg: SigningAlg,
53-
// sign_certs: Vec<u8>,
54-
// ta_url: Option<String>,
33+
alg: SigningAlg,
34+
certs: Vec<u8>,
35+
ta_url: Option<String>,
5536
) -> Self {
56-
Self {
57-
callback,
58-
alg: config.alg,
59-
sign_certs: config.certs,
60-
ta_url: config.time_authority_url,
37+
38+
// When this closure is called it will call the sign method on the python callback
39+
let python_signer = move |_context: *const (), data: &[u8]| {
40+
callback
41+
.sign(data.to_vec())
42+
.map_err(|e| c2pa::Error::BadParam(e.to_string()))
43+
};
44+
45+
let mut signer = c2pa::CallbackSigner::new(python_signer, alg, certs);
46+
if let Some(url) = ta_url {
47+
signer = signer.set_tsa_url(url);
6148
}
62-
}
63-
}
64-
65-
impl Signer for CallbackSigner {
66-
fn sign(&self, data: &[u8]) -> c2pa::Result<Vec<u8>> {
67-
self.callback
68-
.sign(data.to_vec())
69-
.map_err(|e| c2pa::Error::BadParam(e.to_string()))
70-
}
71-
72-
fn alg(&self) -> SigningAlg {
73-
self.alg
74-
}
75-
76-
fn certs(&self) -> c2pa::Result<Vec<Vec<u8>>> {
77-
let mut pems =
78-
pem::parse_many(&self.sign_certs).map_err(|e| c2pa::Error::OtherError(Box::new(e)))?;
79-
Ok(pems.drain(..).map(|p| p.into_contents()).collect())
80-
}
81-
82-
fn reserve_size(&self) -> usize {
83-
20000
49+
Self { signer }
8450
}
8551

86-
fn time_authority_url(&self) -> Option<String> {
87-
self.ta_url.clone()
52+
/// The python Builder wrapper sign function calls this
53+
pub fn signer(&self) -> &c2pa::CallbackSigner {
54+
&self.signer
8855
}
8956
}

src/error.rs

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub enum Error {
99
#[error("AssertionNotFound {reason}")]
1010
AssertionNotFound { reason: String },
1111
#[error("Decoding {reason}")]
12-
Decoding{ reason: String },
12+
Decoding { reason: String },
1313
#[error("Encoding {reason}")]
1414
Encoding { reason: String },
1515
#[error("FileNotFound{reason}")]
@@ -45,10 +45,12 @@ impl Error {
4545
use c2pa::Error::*;
4646
let err_str = err.to_string();
4747
match err {
48-
c2pa::Error::AssertionMissing { url } => Self::AssertionNotFound{ reason: "".to_string()},
48+
c2pa::Error::AssertionMissing { url } => Self::AssertionNotFound {
49+
reason: "".to_string(),
50+
},
4951
AssertionInvalidRedaction
5052
| AssertionRedactionNotFound
51-
| AssertionUnsupportedVersion => Self::Assertion{ reason: err_str},
53+
| AssertionUnsupportedVersion => Self::Assertion { reason: err_str },
5254
ClaimAlreadySigned
5355
| ClaimUnsigned
5456
| ClaimMissingSignatureBox
@@ -59,11 +61,11 @@ impl Error {
5961
| ClaimSelfRedact
6062
| ClaimDisallowedRedaction
6163
| UpdateManifestInvalid
62-
| TooManyManifestStores => Self::Manifest{ reason: err_str},
63-
ClaimMissing { label } => Self::ManifestNotFound{ reason: err_str},
64-
AssertionDecoding(_) | ClaimDecoding => Self::Decoding{ reason: err_str},
65-
AssertionEncoding | XmlWriteError | ClaimEncoding => Self::Encoding{ reason: err_str},
66-
InvalidCoseSignature { coset_error } => Self::Signature{ reason: err_str},
64+
| TooManyManifestStores => Self::Manifest { reason: err_str },
65+
ClaimMissing { label } => Self::ManifestNotFound { reason: err_str },
66+
AssertionDecoding(_) | ClaimDecoding => Self::Decoding { reason: err_str },
67+
AssertionEncoding | XmlWriteError | ClaimEncoding => Self::Encoding { reason: err_str },
68+
InvalidCoseSignature { coset_error } => Self::Signature { reason: err_str },
6769
CoseSignatureAlgorithmNotSupported
6870
| CoseMissingKey
6971
| CoseX5ChainMissing
@@ -78,19 +80,25 @@ impl Error {
7880
| CoseTimeStampGeneration
7981
| CoseTimeStampAuthority
8082
| CoseSigboxTooSmall
81-
| InvalidEcdsaSignature => Self::Signature{ reason: err_str},
82-
RemoteManifestFetch(_) | RemoteManifestUrl(_) => Self::RemoteManifest{ reason: err_str},
83-
JumbfNotFound => Self::ManifestNotFound{ reason: err_str},
84-
BadParam(_) | MissingFeature(_) => Self::Other{ reason: err_str},
85-
IoError(_) => Self::Io{ reason: err_str},
86-
JsonError(e) => Self::Json{ reason: err_str},
87-
NotFound | ResourceNotFound(_) | MissingDataBox => Self::ResourceNotFound{ reason: err_str},
88-
FileNotFound(_) => Self::FileNotFound{ reason: err_str},
89-
UnsupportedType => Self::NotSupported{ reason: err_str},
90-
ClaimVerification(_) | InvalidClaim(_) | JumbfParseError(_) => Self::Verify{ reason: err_str},
83+
| InvalidEcdsaSignature => Self::Signature { reason: err_str },
84+
RemoteManifestFetch(_) | RemoteManifestUrl(_) => {
85+
Self::RemoteManifest { reason: err_str }
86+
}
87+
JumbfNotFound => Self::ManifestNotFound { reason: err_str },
88+
BadParam(_) | MissingFeature(_) => Self::Other { reason: err_str },
89+
IoError(_) => Self::Io { reason: err_str },
90+
JsonError(e) => Self::Json { reason: err_str },
91+
NotFound | ResourceNotFound(_) | MissingDataBox => {
92+
Self::ResourceNotFound { reason: err_str }
93+
}
94+
FileNotFound(_) => Self::FileNotFound { reason: err_str },
95+
UnsupportedType => Self::NotSupported { reason: err_str },
96+
ClaimVerification(_) | InvalidClaim(_) | JumbfParseError(_) => {
97+
Self::Verify { reason: err_str }
98+
}
9199
#[cfg(feature = "add_thumbnails")]
92100
ImageError => Self::ImageError(err_str),
93-
_ => Self::Other{ reason: err_str},
101+
_ => Self::Other { reason: err_str },
94102
}
95103
}
96104
}
@@ -111,7 +119,8 @@ impl From<c2pa::Error> for Error {
111119

112120
impl From<std::io::Error> for Error {
113121
fn from(err: std::io::Error) -> Self {
114-
Self::Io { reason: err.to_string()}
122+
Self::Io {
123+
reason: err.to_string(),
124+
}
115125
}
116126
}
117-

0 commit comments

Comments
 (0)