From 5a4e91cda201c8466a208d18c803fddfb06baa8e Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Wed, 14 Feb 2024 22:51:44 +0100 Subject: [PATCH 1/4] fix capi build --- biscuit-auth/src/lib.rs | 4 +- biscuit-auth/tests/macros.rs | 1 + biscuit-auth/tests/rights.rs | 1 + biscuit-capi/src/lib.rs | 1245 ++++++++++++++++++++++++++++++++++ 4 files changed, 1249 insertions(+), 2 deletions(-) create mode 100644 biscuit-capi/src/lib.rs diff --git a/biscuit-auth/src/lib.rs b/biscuit-auth/src/lib.rs index a3596cf4..8ddaab0d 100644 --- a/biscuit-auth/src/lib.rs +++ b/biscuit-auth/src/lib.rs @@ -235,10 +235,10 @@ pub use token::Biscuit; pub use token::RootKeyProvider; pub use token::{ThirdPartyBlock, ThirdPartyRequest}; -#[cfg(cargo_c)] +#[cfg(feature = "capi")] mod capi; -#[cfg(cargo_c)] +#[cfg(feature = "capi")] pub use capi::*; #[cfg(bwk)] diff --git a/biscuit-auth/tests/macros.rs b/biscuit-auth/tests/macros.rs index 49244655..ee38d08c 100644 --- a/biscuit-auth/tests/macros.rs +++ b/biscuit-auth/tests/macros.rs @@ -1,3 +1,4 @@ +#![cfg(not(feature = "capi"))] use biscuit_auth::builder; use biscuit_quote::{ authorizer, authorizer_merge, biscuit, biscuit_merge, block, block_merge, check, fact, policy, diff --git a/biscuit-auth/tests/rights.rs b/biscuit-auth/tests/rights.rs index 39950811..898a5ef2 100644 --- a/biscuit-auth/tests/rights.rs +++ b/biscuit-auth/tests/rights.rs @@ -1,4 +1,5 @@ #![allow(unused_must_use)] +#![cfg(not(feature = "capi"))] use biscuit::builder::*; use biscuit::datalog::SymbolTable; use biscuit::KeyPair; diff --git a/biscuit-capi/src/lib.rs b/biscuit-capi/src/lib.rs new file mode 100644 index 00000000..3a80cbba --- /dev/null +++ b/biscuit-capi/src/lib.rs @@ -0,0 +1,1245 @@ +use rand::prelude::*; +use std::{ + cell::RefCell, + ffi::{CStr, CString}, + fmt, + os::raw::c_char, +}; + +use crate::datalog::SymbolTable; + +enum Error { + Biscuit(crate::error::Token), + InvalidArgument, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::InvalidArgument => write!(f, "invalid argument"), + Error::Biscuit(e) => write!(f, "{}", e), + } + } +} + +impl From for Error { + fn from(error: crate::error::Token) -> Self { + Error::Biscuit(error) + } +} + +thread_local! { + static LAST_ERROR: RefCell> = RefCell::new(None); +} + +fn update_last_error(err: Error) { + LAST_ERROR.with(|prev| { + *prev.borrow_mut() = Some(err); + }); +} + +#[no_mangle] +pub extern "C" fn error_message() -> *const c_char { + thread_local! { + static LAST: RefCell> = RefCell::new(None); + } + LAST_ERROR.with(|prev| match *prev.borrow() { + Some(ref err) => { + let err = CString::new(err.to_string()).ok(); + LAST.with(|ret| { + *ret.borrow_mut() = err; + ret.borrow() + .as_ref() + .map(|x| x.as_ptr()) + .unwrap_or(std::ptr::null()) + }) + } + None => std::ptr::null(), + }) +} + +#[repr(C)] +pub enum ErrorKind { + None, + InvalidArgument, + InternalError, + FormatSignatureInvalidFormat, + FormatSignatureInvalidSignature, + FormatSealedSignature, + FormatEmptyKeys, + FormatUnknownPublicKey, + FormatDeserializationError, + FormatSerializationError, + FormatBlockDeserializationError, + FormatBlockSerializationError, + FormatVersion, + FormatInvalidBlockId, + FormatExistingPublicKey, + FormatSymbolTableOverlap, + FormatPublicKeyTableOverlap, + FormatUnknownExternalKey, + FormatUnknownSymbol, + AppendOnSealed, + LogicInvalidBlockRule, + LogicUnauthorized, + LogicAuthorizerNotEmpty, + LogicNoMatchingPolicy, + LanguageError, + TooManyFacts, + TooManyIterations, + Timeout, + ConversionError, + FormatInvalidKeySize, + FormatInvalidSignatureSize, + FormatInvalidKey, + FormatSignatureDeserializationError, + FormatBlockSignatureDeserializationError, + FormatSignatureInvalidSignatureGeneration, + AlreadySealed, + Execution, +} + +#[no_mangle] +pub extern "C" fn error_kind() -> ErrorKind { + LAST_ERROR.with(|prev| match *prev.borrow() { + Some(ref err) => match err { + Error::InvalidArgument => ErrorKind::InvalidArgument, + Error::Biscuit(e) => { + use crate::error::*; + match e { + Token::InternalError => ErrorKind::InternalError, + Token::Format(Format::Signature(Signature::InvalidFormat)) => { + ErrorKind::FormatSignatureInvalidFormat + } + Token::Format(Format::Signature(Signature::InvalidSignature(_))) => { + ErrorKind::FormatSignatureInvalidSignature + } + Token::Format(Format::Signature(Signature::InvalidSignatureGeneration(_))) => { + ErrorKind::FormatSignatureInvalidSignatureGeneration + } + Token::Format(Format::SealedSignature) => ErrorKind::FormatSealedSignature, + Token::Format(Format::EmptyKeys) => ErrorKind::FormatEmptyKeys, + Token::Format(Format::UnknownPublicKey) => ErrorKind::FormatUnknownPublicKey, + Token::Format(Format::DeserializationError(_)) => { + ErrorKind::FormatDeserializationError + } + Token::Format(Format::SerializationError(_)) => { + ErrorKind::FormatSerializationError + } + Token::Format(Format::BlockDeserializationError(_)) => { + ErrorKind::FormatBlockDeserializationError + } + Token::Format(Format::BlockSerializationError(_)) => { + ErrorKind::FormatBlockSerializationError + } + Token::Format(Format::Version { .. }) => ErrorKind::FormatVersion, + Token::Format(Format::InvalidKeySize(_)) => ErrorKind::FormatInvalidKeySize, + Token::Format(Format::InvalidSignatureSize(_)) => { + ErrorKind::FormatInvalidSignatureSize + } + Token::Format(Format::InvalidKey(_)) => ErrorKind::FormatInvalidKey, + Token::Format(Format::SignatureDeserializationError(_)) => { + ErrorKind::FormatSignatureDeserializationError + } + Token::Format(Format::BlockSignatureDeserializationError(_)) => { + ErrorKind::FormatBlockSignatureDeserializationError + } + Token::Format(Format::InvalidBlockId(_)) => ErrorKind::FormatInvalidBlockId, + Token::Format(Format::ExistingPublicKey(_)) => { + ErrorKind::FormatExistingPublicKey + } + Token::Format(Format::SymbolTableOverlap) => { + ErrorKind::FormatSymbolTableOverlap + } + Token::Format(Format::PublicKeyTableOverlap) => { + ErrorKind::FormatPublicKeyTableOverlap + } + Token::Format(Format::UnknownExternalKey) => { + ErrorKind::FormatUnknownExternalKey + } + Token::Format(Format::UnknownSymbol(_)) => ErrorKind::FormatUnknownSymbol, + Token::AppendOnSealed => ErrorKind::AppendOnSealed, + Token::AlreadySealed => ErrorKind::AlreadySealed, + Token::Language(_) => ErrorKind::LanguageError, + Token::FailedLogic(Logic::InvalidBlockRule(_, _)) => { + ErrorKind::LogicInvalidBlockRule + } + Token::FailedLogic(Logic::Unauthorized { .. }) => ErrorKind::LogicUnauthorized, + Token::FailedLogic(Logic::AuthorizerNotEmpty) => { + ErrorKind::LogicAuthorizerNotEmpty + } + Token::FailedLogic(Logic::NoMatchingPolicy { .. }) => { + ErrorKind::LogicNoMatchingPolicy + } + Token::RunLimit(RunLimit::TooManyFacts) => ErrorKind::TooManyFacts, + Token::RunLimit(RunLimit::TooManyIterations) => ErrorKind::TooManyIterations, + Token::RunLimit(RunLimit::Timeout) => ErrorKind::Timeout, + Token::ConversionError(_) => ErrorKind::ConversionError, + Token::Base64(_) => ErrorKind::FormatDeserializationError, + Token::Execution(_) => ErrorKind::Execution, + } + } + }, + None => ErrorKind::None, + }) +} + +#[no_mangle] +pub extern "C" fn error_check_count() -> u64 { + use crate::error::*; + LAST_ERROR.with(|prev| match *prev.borrow() { + Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) + | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { + checks.len() as u64 + } + _ => 0, + }) +} + +#[no_mangle] +pub extern "C" fn error_check_id(check_index: u64) -> u64 { + use crate::error::*; + LAST_ERROR.with(|prev| match *prev.borrow() { + Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) + | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { + if check_index >= checks.len() as u64 { + u64::MAX + } else { + match checks[check_index as usize] { + FailedCheck::Block(FailedBlockCheck { check_id, .. }) => check_id as u64, + FailedCheck::Authorizer(FailedAuthorizerCheck { check_id, .. }) => { + check_id as u64 + } + } + } + } + _ => u64::MAX, + }) +} + +#[no_mangle] +pub extern "C" fn error_check_block_id(check_index: u64) -> u64 { + use crate::error::*; + LAST_ERROR.with(|prev| match *prev.borrow() { + Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) + | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { + if check_index >= checks.len() as u64 { + u64::MAX + } else { + match checks[check_index as usize] { + FailedCheck::Block(FailedBlockCheck { block_id, .. }) => block_id as u64, + _ => u64::MAX, + } + } + } + _ => u64::MAX, + }) +} + +/// deallocation is handled by Biscuit +/// the string is overwritten on each call +#[no_mangle] +pub extern "C" fn error_check_rule(check_index: u64) -> *const c_char { + use crate::error::*; + thread_local! { + static CAVEAT_RULE: RefCell> = RefCell::new(None); + } + + LAST_ERROR.with(|prev| match *prev.borrow() { + Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) + | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { + if check_index >= checks.len() as u64 { + std::ptr::null() + } else { + let rule = match &checks[check_index as usize] { + FailedCheck::Block(FailedBlockCheck { rule, .. }) => rule, + FailedCheck::Authorizer(FailedAuthorizerCheck { rule, .. }) => rule, + }; + let err = CString::new(rule.clone()).ok(); + CAVEAT_RULE.with(|ret| { + *ret.borrow_mut() = err; + ret.borrow() + .as_ref() + .map(|x| x.as_ptr()) + .unwrap_or(std::ptr::null()) + }) + } + } + _ => std::ptr::null(), + }) +} + +#[no_mangle] +pub extern "C" fn error_check_is_authorizer(check_index: u64) -> bool { + use crate::error::*; + LAST_ERROR.with(|prev| match *prev.borrow() { + Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) + | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { + if check_index >= checks.len() as u64 { + false + } else { + match checks[check_index as usize] { + FailedCheck::Block(FailedBlockCheck { .. }) => false, + FailedCheck::Authorizer(FailedAuthorizerCheck { .. }) => true, + } + } + } + _ => false, + }) +} + +pub struct Biscuit(crate::token::Biscuit); +pub struct KeyPair(crate::crypto::KeyPair); +pub struct PublicKey(crate::crypto::PublicKey); +pub struct BiscuitBuilder(crate::token::builder::BiscuitBuilder); +pub struct BlockBuilder(crate::token::builder::BlockBuilder); +pub struct Authorizer(crate::token::authorizer::Authorizer); + +#[no_mangle] +pub unsafe extern "C" fn key_pair_new<'a>( + seed_ptr: *const u8, + seed_len: usize, +) -> Option> { + let slice = std::slice::from_raw_parts(seed_ptr, seed_len); + if slice.len() != 32 { + update_last_error(Error::InvalidArgument); + return None; + } + + let mut seed = [0u8; 32]; + seed.copy_from_slice(slice); + + let mut rng: StdRng = SeedableRng::from_seed(seed); + + Some(Box::new(KeyPair(crate::crypto::KeyPair::new_with_rng( + &mut rng, + )))) +} + +#[no_mangle] +pub unsafe extern "C" fn key_pair_public(kp: Option<&KeyPair>) -> Option> { + if kp.is_none() { + update_last_error(Error::InvalidArgument); + } + let kp = kp?; + + Some(Box::new(PublicKey((*kp).0.public()))) +} + +/// expects a 32 byte buffer +#[no_mangle] +pub unsafe extern "C" fn key_pair_serialize(kp: Option<&KeyPair>, buffer_ptr: *mut u8) -> usize { + if kp.is_none() { + update_last_error(Error::InvalidArgument); + return 0; + } + let kp = kp.unwrap(); + + let output_slice = std::slice::from_raw_parts_mut(buffer_ptr, 32); + + output_slice.copy_from_slice(&kp.0.private().to_bytes()[..]); + 32 +} + +/// expects a 32 byte buffer +#[no_mangle] +pub unsafe extern "C" fn key_pair_deserialize(buffer_ptr: *mut u8) -> Option> { + let input_slice = std::slice::from_raw_parts_mut(buffer_ptr, 32); + + match crate::crypto::PrivateKey::from_bytes(input_slice).ok() { + None => { + update_last_error(Error::InvalidArgument); + None + } + Some(privkey) => Some(Box::new(KeyPair(crate::crypto::KeyPair::from(&privkey)))), + } +} + +#[no_mangle] +pub unsafe extern "C" fn key_pair_free(_kp: Option>) {} + +/// expects a 32 byte buffer +#[no_mangle] +pub unsafe extern "C" fn public_key_serialize( + kp: Option<&PublicKey>, + buffer_ptr: *mut u8, +) -> usize { + if kp.is_none() { + update_last_error(Error::InvalidArgument); + return 0; + } + let kp = kp.unwrap(); + + let output_slice = std::slice::from_raw_parts_mut(buffer_ptr, 32); + + output_slice.copy_from_slice(&kp.0.to_bytes()[..]); + 32 +} + +/// expects a 32 byte buffer +#[no_mangle] +pub unsafe extern "C" fn public_key_deserialize(buffer_ptr: *mut u8) -> Option> { + let input_slice = std::slice::from_raw_parts_mut(buffer_ptr, 32); + + match crate::crypto::PublicKey::from_bytes(input_slice).ok() { + None => { + update_last_error(Error::InvalidArgument); + None + } + Some(pubkey) => Some(Box::new(PublicKey(pubkey))), + } +} + +#[no_mangle] +pub unsafe extern "C" fn public_key_free(_kp: Option>) {} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_builder() -> Option> { + Some(Box::new(BiscuitBuilder(crate::token::Biscuit::builder()))) +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_builder_set_context( + builder: Option<&mut BiscuitBuilder>, + context: *const c_char, +) -> bool { + if builder.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let builder = builder.unwrap(); + + let context = CStr::from_ptr(context); + let s = context.to_str(); + match s { + Err(_) => { + update_last_error(Error::InvalidArgument); + false + } + Ok(context) => { + builder.0.set_context(context.to_string()); + true + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_builder_set_root_key_id( + builder: Option<&mut BiscuitBuilder>, + root_key_id: u32, +) -> bool { + if builder.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let builder = builder.unwrap(); + + builder.0.set_root_key_id(root_key_id); + true +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_builder_add_fact( + builder: Option<&mut BiscuitBuilder>, + fact: *const c_char, +) -> bool { + if builder.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let builder = builder.unwrap(); + + let fact = CStr::from_ptr(fact); + let s = fact.to_str(); + if s.is_err() { + update_last_error(Error::InvalidArgument); + return false; + } + + builder + .0 + .add_fact(s.unwrap()) + .map_err(|e| { + update_last_error(Error::Biscuit(e)); + }) + .is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_builder_add_rule( + builder: Option<&mut BiscuitBuilder>, + rule: *const c_char, +) -> bool { + if builder.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let builder = builder.unwrap(); + + let rule = CStr::from_ptr(rule); + let s = rule.to_str(); + if s.is_err() { + update_last_error(Error::InvalidArgument); + return false; + } + + builder + .0 + .add_rule(s.unwrap()) + .map_err(|e| { + update_last_error(Error::Biscuit(e)); + }) + .is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_builder_add_check( + builder: Option<&mut BiscuitBuilder>, + check: *const c_char, +) -> bool { + if builder.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let builder = builder.unwrap(); + + let check = CStr::from_ptr(check); + let s = check.to_str(); + if s.is_err() { + update_last_error(Error::InvalidArgument); + return false; + } + + builder + .0 + .add_check(s.unwrap()) + .map_err(|e| { + update_last_error(Error::Biscuit(e)); + }) + .is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_builder_build( + builder: Option<&BiscuitBuilder>, + key_pair: Option<&KeyPair>, + seed_ptr: *const u8, + seed_len: usize, +) -> Option> { + if builder.is_none() { + update_last_error(Error::InvalidArgument); + } + let builder = builder?; + + if key_pair.is_none() { + update_last_error(Error::InvalidArgument); + } + let key_pair = key_pair?; + + let slice = std::slice::from_raw_parts(seed_ptr, seed_len); + if slice.len() != 32 { + return None; + } + + let mut seed = [0u8; 32]; + seed.copy_from_slice(slice); + + let mut rng: StdRng = SeedableRng::from_seed(seed); + (*builder) + .0 + .clone() + .build_with_rng(&key_pair.0, SymbolTable::default(), &mut rng) + .map(Biscuit) + .map(Box::new) + .ok() +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_builder_free<'a>(_builder: Option>) {} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_from<'a>( + biscuit_ptr: *const u8, + biscuit_len: usize, + root: Option<&'a PublicKey>, +) -> Option> { + let biscuit = std::slice::from_raw_parts(biscuit_ptr, biscuit_len); + if root.is_none() { + update_last_error(Error::InvalidArgument); + } + let root = root?; + + crate::token::Biscuit::from(biscuit, root.0) + .map(Biscuit) + .map(Box::new) + .ok() +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_serialized_size(biscuit: Option<&Biscuit>) -> usize { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return 0; + } + + let biscuit = biscuit.unwrap(); + + match biscuit.0.serialized_size() { + Ok(sz) => sz, + Err(e) => { + update_last_error(Error::Biscuit(e)); + return 0; + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_sealed_size(biscuit: Option<&Biscuit>) -> usize { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return 0; + } + + let biscuit = biscuit.unwrap(); + + match biscuit.0.serialized_size() { + Ok(sz) => sz, + Err(e) => { + update_last_error(Error::Biscuit(e)); + return 0; + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_serialize( + biscuit: Option<&Biscuit>, + buffer_ptr: *mut u8, +) -> usize { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return 0; + } + + let biscuit = biscuit.unwrap(); + + match (*biscuit).0.to_vec() { + Ok(v) => { + let size = match biscuit.0.serialized_size() { + Ok(sz) => sz, + Err(e) => { + update_last_error(Error::Biscuit(e)); + return 0; + } + }; + + let output_slice = std::slice::from_raw_parts_mut(buffer_ptr, size); + + output_slice.copy_from_slice(&v[..]); + v.len() + } + Err(e) => { + update_last_error(Error::Biscuit(e)); + 0 + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_serialize_sealed( + biscuit: Option<&Biscuit>, + buffer_ptr: *mut u8, +) -> usize { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return 0; + } + + let biscuit = biscuit.unwrap(); + + match (*biscuit).0.seal() { + Ok(b) => match b.to_vec() { + Ok(v) => { + let size = match biscuit.0.serialized_size() { + Ok(sz) => sz, + Err(e) => { + update_last_error(Error::Biscuit(e)); + return 0; + } + }; + + let output_slice = std::slice::from_raw_parts_mut(buffer_ptr, size); + + output_slice.copy_from_slice(&v[..]); + v.len() + } + Err(e) => { + update_last_error(Error::Biscuit(e)); + 0 + } + }, + + Err(e) => { + update_last_error(Error::Biscuit(e)); + 0 + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_block_count(biscuit: Option<&Biscuit>) -> usize { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return 0; + } + + let biscuit = biscuit.unwrap(); + + biscuit.0.blocks.len() + 1 +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_block_fact_count( + biscuit: Option<&Biscuit>, + block_index: u32, +) -> usize { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return 0; + } + + let biscuit = biscuit.unwrap(); + + let block = match biscuit.0.block(block_index as usize) { + Ok(block) => block, + Err(e) => { + update_last_error(e.into()); + return 0; + } + }; + + block.facts.len() +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_block_rule_count( + biscuit: Option<&Biscuit>, + block_index: u32, +) -> usize { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return 0; + } + + let biscuit = biscuit.unwrap(); + + let block = match biscuit.0.block(block_index as usize) { + Ok(block) => block, + Err(e) => { + update_last_error(e.into()); + return 0; + } + }; + + block.rules.len() +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_block_check_count( + biscuit: Option<&Biscuit>, + block_index: u32, +) -> usize { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return 0; + } + + let biscuit = biscuit.unwrap(); + + let block = match biscuit.0.block(block_index as usize) { + Ok(block) => block, + Err(e) => { + update_last_error(e.into()); + return 0; + } + }; + + block.checks.len() +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_block_fact( + biscuit: Option<&Biscuit>, + block_index: u32, + fact_index: u32, +) -> *mut c_char { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + + let biscuit = biscuit.unwrap(); + + let block = match biscuit.0.block(block_index as usize) { + Ok(block) => block, + Err(e) => { + update_last_error(e.into()); + return std::ptr::null_mut(); + } + }; + + match block.facts.get(fact_index as usize) { + None => { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + Some(fact) => match CString::new(biscuit.0.symbols.print_fact(fact)) { + Ok(s) => s.into_raw(), + Err(_) => { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + }, + } +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_block_rule( + biscuit: Option<&Biscuit>, + block_index: u32, + rule_index: u32, +) -> *mut c_char { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + + let biscuit = biscuit.unwrap(); + + let block = match biscuit.0.block(block_index as usize) { + Ok(block) => block, + Err(e) => { + update_last_error(e.into()); + return std::ptr::null_mut(); + } + }; + + match block.rules.get(rule_index as usize) { + None => { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + Some(rule) => match CString::new(biscuit.0.symbols.print_rule(rule)) { + Ok(s) => s.into_raw(), + Err(_) => { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + }, + } +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_block_check( + biscuit: Option<&Biscuit>, + block_index: u32, + check_index: u32, +) -> *mut c_char { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + + let biscuit = biscuit.unwrap(); + + let block = match biscuit.0.block(block_index as usize) { + Ok(block) => block, + Err(e) => { + update_last_error(e.into()); + return std::ptr::null_mut(); + } + }; + + match block.checks.get(check_index as usize) { + None => { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + Some(check) => match CString::new(biscuit.0.symbols.print_check(check)) { + Ok(s) => s.into_raw(), + Err(_) => { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + }, + } +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_block_context( + biscuit: Option<&Biscuit>, + block_index: u32, +) -> *mut c_char { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + + let biscuit = biscuit.unwrap(); + + let block = if block_index == 0 { + &biscuit.0.authority + } else { + match biscuit.0.blocks.get(block_index as usize - 1) { + Some(b) => b, + None => { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + } + }; + + match &block.context { + None => { + return std::ptr::null_mut(); + } + Some(context) => match CString::new(context.clone()) { + Ok(s) => s.into_raw(), + Err(_) => { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + }, + } +} + +#[no_mangle] +pub unsafe extern "C" fn create_block() -> Box { + Box::new(BlockBuilder(crate::token::builder::BlockBuilder::new())) +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_append_block( + biscuit: Option<&Biscuit>, + block_builder: Option<&BlockBuilder>, + key_pair: Option<&KeyPair>, +) -> Option> { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + } + let biscuit = biscuit?; + + if block_builder.is_none() { + update_last_error(Error::InvalidArgument); + } + let builder = block_builder?; + + if key_pair.is_none() { + update_last_error(Error::InvalidArgument); + } + let key_pair = key_pair?; + + match biscuit + .0 + .append_with_keypair(&key_pair.0, builder.0.clone()) + { + Ok(token) => Some(Box::new(Biscuit(token))), + Err(e) => { + update_last_error(Error::Biscuit(e)); + None + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_authorizer<'a>( + biscuit: Option<&'a Biscuit>, +) -> Option> { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + } + let biscuit = biscuit?; + + (*biscuit).0.authorizer().map(Authorizer).map(Box::new).ok() +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_free(_biscuit: Option>) {} + +#[no_mangle] +pub unsafe extern "C" fn block_builder_set_context( + builder: Option<&mut BlockBuilder>, + context: *const c_char, +) -> bool { + if builder.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let builder = builder.unwrap(); + + let context = CStr::from_ptr(context); + let s = context.to_str(); + match s { + Err(_) => { + update_last_error(Error::InvalidArgument); + false + } + Ok(context) => { + builder.0.set_context(context.to_string()); + true + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn block_builder_add_fact( + builder: Option<&mut BlockBuilder>, + fact: *const c_char, +) -> bool { + if builder.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let builder = builder.unwrap(); + + let fact = CStr::from_ptr(fact); + let s = fact.to_str(); + if s.is_err() { + update_last_error(Error::InvalidArgument); + return false; + } + + builder + .0 + .add_fact(s.unwrap()) + .map_err(|e| { + update_last_error(Error::Biscuit(e)); + }) + .is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn block_builder_add_rule( + builder: Option<&mut BlockBuilder>, + rule: *const c_char, +) -> bool { + if builder.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let builder = builder.unwrap(); + + let rule = CStr::from_ptr(rule); + let s = rule.to_str(); + if s.is_err() { + update_last_error(Error::InvalidArgument); + return false; + } + + builder + .0 + .add_rule(s.unwrap()) + .map_err(|e| { + update_last_error(Error::Biscuit(e)); + }) + .is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn block_builder_add_check( + builder: Option<&mut BlockBuilder>, + check: *const c_char, +) -> bool { + if builder.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let builder = builder.unwrap(); + + let check = CStr::from_ptr(check); + let s = check.to_str(); + if s.is_err() { + update_last_error(Error::InvalidArgument); + return false; + } + + builder + .0 + .add_check(s.unwrap()) + .map_err(|e| { + update_last_error(Error::Biscuit(e)); + }) + .is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn block_builder_free(_builder: Option>) {} + +#[no_mangle] +pub unsafe extern "C" fn authorizer_add_fact( + authorizer: Option<&mut Authorizer>, + fact: *const c_char, +) -> bool { + if authorizer.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let authorizer = authorizer.unwrap(); + + let fact = CStr::from_ptr(fact); + let s = fact.to_str(); + if s.is_err() { + update_last_error(Error::InvalidArgument); + return false; + } + + authorizer + .0 + .add_fact(s.unwrap()) + .map_err(|e| { + update_last_error(Error::Biscuit(e)); + }) + .is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn authorizer_add_rule( + authorizer: Option<&mut Authorizer>, + rule: *const c_char, +) -> bool { + if authorizer.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let authorizer = authorizer.unwrap(); + + let rule = CStr::from_ptr(rule); + let s = rule.to_str(); + if s.is_err() { + update_last_error(Error::InvalidArgument); + return false; + } + + authorizer + .0 + .add_rule(s.unwrap()) + .map_err(|e| { + update_last_error(Error::Biscuit(e)); + }) + .is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn authorizer_add_check( + authorizer: Option<&mut Authorizer>, + check: *const c_char, +) -> bool { + if authorizer.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let authorizer = authorizer.unwrap(); + + let check = CStr::from_ptr(check); + let s = check.to_str(); + if s.is_err() { + update_last_error(Error::InvalidArgument); + return false; + } + + authorizer + .0 + .add_check(s.unwrap()) + .map_err(|e| { + update_last_error(Error::Biscuit(e)); + }) + .is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn authorizer_add_policy( + authorizer: Option<&mut Authorizer>, + policy: *const c_char, +) -> bool { + if authorizer.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let authorizer = authorizer.unwrap(); + + let policy = CStr::from_ptr(policy); + let s = policy.to_str(); + if s.is_err() { + update_last_error(Error::InvalidArgument); + return false; + } + + authorizer + .0 + .add_policy(s.unwrap()) + .map_err(|e| { + update_last_error(Error::Biscuit(e)); + }) + .is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn authorizer_authorize(authorizer: Option<&mut Authorizer>) -> bool { + if authorizer.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let authorizer = authorizer.unwrap(); + + match authorizer.0.authorize() { + Ok(_index) => true, + Err(e) => { + update_last_error(Error::Biscuit(e)); + false + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn authorizer_print(authorizer: Option<&mut Authorizer>) -> *mut c_char { + if authorizer.is_none() { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + let authorizer = authorizer.unwrap(); + + match CString::new(authorizer.0.print_world()) { + Ok(s) => s.into_raw(), + Err(_) => { + update_last_error(Error::InvalidArgument); + return std::ptr::null_mut(); + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn authorizer_free(_authorizer: Option>) {} + +#[no_mangle] +pub unsafe extern "C" fn string_free(ptr: *mut c_char) { + if ptr != std::ptr::null_mut() { + drop(CString::from_raw(ptr)); + } +} + +#[no_mangle] +pub unsafe extern "C" fn biscuit_print(biscuit: Option<&Biscuit>) -> *const c_char { + if biscuit.is_none() { + update_last_error(Error::InvalidArgument); + return std::ptr::null(); + } + let biscuit = biscuit.unwrap(); + + match CString::new(biscuit.0.print()) { + Ok(s) => s.into_raw(), + Err(_) => { + update_last_error(Error::InvalidArgument); + return std::ptr::null(); + } + } +} From 49fef7ff9541167847764b002d52b1762922c003 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Tue, 26 Mar 2024 20:54:35 +0100 Subject: [PATCH 2/4] missing file --- biscuit-auth/src/capi.rs | 1245 -------------------------------------- biscuit-auth/src/lib.rs | 6 - biscuit-capi/Cargo.toml | 9 + 3 files changed, 9 insertions(+), 1251 deletions(-) delete mode 100644 biscuit-auth/src/capi.rs create mode 100644 biscuit-capi/Cargo.toml diff --git a/biscuit-auth/src/capi.rs b/biscuit-auth/src/capi.rs deleted file mode 100644 index 3a80cbba..00000000 --- a/biscuit-auth/src/capi.rs +++ /dev/null @@ -1,1245 +0,0 @@ -use rand::prelude::*; -use std::{ - cell::RefCell, - ffi::{CStr, CString}, - fmt, - os::raw::c_char, -}; - -use crate::datalog::SymbolTable; - -enum Error { - Biscuit(crate::error::Token), - InvalidArgument, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Error::InvalidArgument => write!(f, "invalid argument"), - Error::Biscuit(e) => write!(f, "{}", e), - } - } -} - -impl From for Error { - fn from(error: crate::error::Token) -> Self { - Error::Biscuit(error) - } -} - -thread_local! { - static LAST_ERROR: RefCell> = RefCell::new(None); -} - -fn update_last_error(err: Error) { - LAST_ERROR.with(|prev| { - *prev.borrow_mut() = Some(err); - }); -} - -#[no_mangle] -pub extern "C" fn error_message() -> *const c_char { - thread_local! { - static LAST: RefCell> = RefCell::new(None); - } - LAST_ERROR.with(|prev| match *prev.borrow() { - Some(ref err) => { - let err = CString::new(err.to_string()).ok(); - LAST.with(|ret| { - *ret.borrow_mut() = err; - ret.borrow() - .as_ref() - .map(|x| x.as_ptr()) - .unwrap_or(std::ptr::null()) - }) - } - None => std::ptr::null(), - }) -} - -#[repr(C)] -pub enum ErrorKind { - None, - InvalidArgument, - InternalError, - FormatSignatureInvalidFormat, - FormatSignatureInvalidSignature, - FormatSealedSignature, - FormatEmptyKeys, - FormatUnknownPublicKey, - FormatDeserializationError, - FormatSerializationError, - FormatBlockDeserializationError, - FormatBlockSerializationError, - FormatVersion, - FormatInvalidBlockId, - FormatExistingPublicKey, - FormatSymbolTableOverlap, - FormatPublicKeyTableOverlap, - FormatUnknownExternalKey, - FormatUnknownSymbol, - AppendOnSealed, - LogicInvalidBlockRule, - LogicUnauthorized, - LogicAuthorizerNotEmpty, - LogicNoMatchingPolicy, - LanguageError, - TooManyFacts, - TooManyIterations, - Timeout, - ConversionError, - FormatInvalidKeySize, - FormatInvalidSignatureSize, - FormatInvalidKey, - FormatSignatureDeserializationError, - FormatBlockSignatureDeserializationError, - FormatSignatureInvalidSignatureGeneration, - AlreadySealed, - Execution, -} - -#[no_mangle] -pub extern "C" fn error_kind() -> ErrorKind { - LAST_ERROR.with(|prev| match *prev.borrow() { - Some(ref err) => match err { - Error::InvalidArgument => ErrorKind::InvalidArgument, - Error::Biscuit(e) => { - use crate::error::*; - match e { - Token::InternalError => ErrorKind::InternalError, - Token::Format(Format::Signature(Signature::InvalidFormat)) => { - ErrorKind::FormatSignatureInvalidFormat - } - Token::Format(Format::Signature(Signature::InvalidSignature(_))) => { - ErrorKind::FormatSignatureInvalidSignature - } - Token::Format(Format::Signature(Signature::InvalidSignatureGeneration(_))) => { - ErrorKind::FormatSignatureInvalidSignatureGeneration - } - Token::Format(Format::SealedSignature) => ErrorKind::FormatSealedSignature, - Token::Format(Format::EmptyKeys) => ErrorKind::FormatEmptyKeys, - Token::Format(Format::UnknownPublicKey) => ErrorKind::FormatUnknownPublicKey, - Token::Format(Format::DeserializationError(_)) => { - ErrorKind::FormatDeserializationError - } - Token::Format(Format::SerializationError(_)) => { - ErrorKind::FormatSerializationError - } - Token::Format(Format::BlockDeserializationError(_)) => { - ErrorKind::FormatBlockDeserializationError - } - Token::Format(Format::BlockSerializationError(_)) => { - ErrorKind::FormatBlockSerializationError - } - Token::Format(Format::Version { .. }) => ErrorKind::FormatVersion, - Token::Format(Format::InvalidKeySize(_)) => ErrorKind::FormatInvalidKeySize, - Token::Format(Format::InvalidSignatureSize(_)) => { - ErrorKind::FormatInvalidSignatureSize - } - Token::Format(Format::InvalidKey(_)) => ErrorKind::FormatInvalidKey, - Token::Format(Format::SignatureDeserializationError(_)) => { - ErrorKind::FormatSignatureDeserializationError - } - Token::Format(Format::BlockSignatureDeserializationError(_)) => { - ErrorKind::FormatBlockSignatureDeserializationError - } - Token::Format(Format::InvalidBlockId(_)) => ErrorKind::FormatInvalidBlockId, - Token::Format(Format::ExistingPublicKey(_)) => { - ErrorKind::FormatExistingPublicKey - } - Token::Format(Format::SymbolTableOverlap) => { - ErrorKind::FormatSymbolTableOverlap - } - Token::Format(Format::PublicKeyTableOverlap) => { - ErrorKind::FormatPublicKeyTableOverlap - } - Token::Format(Format::UnknownExternalKey) => { - ErrorKind::FormatUnknownExternalKey - } - Token::Format(Format::UnknownSymbol(_)) => ErrorKind::FormatUnknownSymbol, - Token::AppendOnSealed => ErrorKind::AppendOnSealed, - Token::AlreadySealed => ErrorKind::AlreadySealed, - Token::Language(_) => ErrorKind::LanguageError, - Token::FailedLogic(Logic::InvalidBlockRule(_, _)) => { - ErrorKind::LogicInvalidBlockRule - } - Token::FailedLogic(Logic::Unauthorized { .. }) => ErrorKind::LogicUnauthorized, - Token::FailedLogic(Logic::AuthorizerNotEmpty) => { - ErrorKind::LogicAuthorizerNotEmpty - } - Token::FailedLogic(Logic::NoMatchingPolicy { .. }) => { - ErrorKind::LogicNoMatchingPolicy - } - Token::RunLimit(RunLimit::TooManyFacts) => ErrorKind::TooManyFacts, - Token::RunLimit(RunLimit::TooManyIterations) => ErrorKind::TooManyIterations, - Token::RunLimit(RunLimit::Timeout) => ErrorKind::Timeout, - Token::ConversionError(_) => ErrorKind::ConversionError, - Token::Base64(_) => ErrorKind::FormatDeserializationError, - Token::Execution(_) => ErrorKind::Execution, - } - } - }, - None => ErrorKind::None, - }) -} - -#[no_mangle] -pub extern "C" fn error_check_count() -> u64 { - use crate::error::*; - LAST_ERROR.with(|prev| match *prev.borrow() { - Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) - | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { - checks.len() as u64 - } - _ => 0, - }) -} - -#[no_mangle] -pub extern "C" fn error_check_id(check_index: u64) -> u64 { - use crate::error::*; - LAST_ERROR.with(|prev| match *prev.borrow() { - Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) - | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { - if check_index >= checks.len() as u64 { - u64::MAX - } else { - match checks[check_index as usize] { - FailedCheck::Block(FailedBlockCheck { check_id, .. }) => check_id as u64, - FailedCheck::Authorizer(FailedAuthorizerCheck { check_id, .. }) => { - check_id as u64 - } - } - } - } - _ => u64::MAX, - }) -} - -#[no_mangle] -pub extern "C" fn error_check_block_id(check_index: u64) -> u64 { - use crate::error::*; - LAST_ERROR.with(|prev| match *prev.borrow() { - Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) - | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { - if check_index >= checks.len() as u64 { - u64::MAX - } else { - match checks[check_index as usize] { - FailedCheck::Block(FailedBlockCheck { block_id, .. }) => block_id as u64, - _ => u64::MAX, - } - } - } - _ => u64::MAX, - }) -} - -/// deallocation is handled by Biscuit -/// the string is overwritten on each call -#[no_mangle] -pub extern "C" fn error_check_rule(check_index: u64) -> *const c_char { - use crate::error::*; - thread_local! { - static CAVEAT_RULE: RefCell> = RefCell::new(None); - } - - LAST_ERROR.with(|prev| match *prev.borrow() { - Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) - | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { - if check_index >= checks.len() as u64 { - std::ptr::null() - } else { - let rule = match &checks[check_index as usize] { - FailedCheck::Block(FailedBlockCheck { rule, .. }) => rule, - FailedCheck::Authorizer(FailedAuthorizerCheck { rule, .. }) => rule, - }; - let err = CString::new(rule.clone()).ok(); - CAVEAT_RULE.with(|ret| { - *ret.borrow_mut() = err; - ret.borrow() - .as_ref() - .map(|x| x.as_ptr()) - .unwrap_or(std::ptr::null()) - }) - } - } - _ => std::ptr::null(), - }) -} - -#[no_mangle] -pub extern "C" fn error_check_is_authorizer(check_index: u64) -> bool { - use crate::error::*; - LAST_ERROR.with(|prev| match *prev.borrow() { - Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) - | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { - if check_index >= checks.len() as u64 { - false - } else { - match checks[check_index as usize] { - FailedCheck::Block(FailedBlockCheck { .. }) => false, - FailedCheck::Authorizer(FailedAuthorizerCheck { .. }) => true, - } - } - } - _ => false, - }) -} - -pub struct Biscuit(crate::token::Biscuit); -pub struct KeyPair(crate::crypto::KeyPair); -pub struct PublicKey(crate::crypto::PublicKey); -pub struct BiscuitBuilder(crate::token::builder::BiscuitBuilder); -pub struct BlockBuilder(crate::token::builder::BlockBuilder); -pub struct Authorizer(crate::token::authorizer::Authorizer); - -#[no_mangle] -pub unsafe extern "C" fn key_pair_new<'a>( - seed_ptr: *const u8, - seed_len: usize, -) -> Option> { - let slice = std::slice::from_raw_parts(seed_ptr, seed_len); - if slice.len() != 32 { - update_last_error(Error::InvalidArgument); - return None; - } - - let mut seed = [0u8; 32]; - seed.copy_from_slice(slice); - - let mut rng: StdRng = SeedableRng::from_seed(seed); - - Some(Box::new(KeyPair(crate::crypto::KeyPair::new_with_rng( - &mut rng, - )))) -} - -#[no_mangle] -pub unsafe extern "C" fn key_pair_public(kp: Option<&KeyPair>) -> Option> { - if kp.is_none() { - update_last_error(Error::InvalidArgument); - } - let kp = kp?; - - Some(Box::new(PublicKey((*kp).0.public()))) -} - -/// expects a 32 byte buffer -#[no_mangle] -pub unsafe extern "C" fn key_pair_serialize(kp: Option<&KeyPair>, buffer_ptr: *mut u8) -> usize { - if kp.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - let kp = kp.unwrap(); - - let output_slice = std::slice::from_raw_parts_mut(buffer_ptr, 32); - - output_slice.copy_from_slice(&kp.0.private().to_bytes()[..]); - 32 -} - -/// expects a 32 byte buffer -#[no_mangle] -pub unsafe extern "C" fn key_pair_deserialize(buffer_ptr: *mut u8) -> Option> { - let input_slice = std::slice::from_raw_parts_mut(buffer_ptr, 32); - - match crate::crypto::PrivateKey::from_bytes(input_slice).ok() { - None => { - update_last_error(Error::InvalidArgument); - None - } - Some(privkey) => Some(Box::new(KeyPair(crate::crypto::KeyPair::from(&privkey)))), - } -} - -#[no_mangle] -pub unsafe extern "C" fn key_pair_free(_kp: Option>) {} - -/// expects a 32 byte buffer -#[no_mangle] -pub unsafe extern "C" fn public_key_serialize( - kp: Option<&PublicKey>, - buffer_ptr: *mut u8, -) -> usize { - if kp.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - let kp = kp.unwrap(); - - let output_slice = std::slice::from_raw_parts_mut(buffer_ptr, 32); - - output_slice.copy_from_slice(&kp.0.to_bytes()[..]); - 32 -} - -/// expects a 32 byte buffer -#[no_mangle] -pub unsafe extern "C" fn public_key_deserialize(buffer_ptr: *mut u8) -> Option> { - let input_slice = std::slice::from_raw_parts_mut(buffer_ptr, 32); - - match crate::crypto::PublicKey::from_bytes(input_slice).ok() { - None => { - update_last_error(Error::InvalidArgument); - None - } - Some(pubkey) => Some(Box::new(PublicKey(pubkey))), - } -} - -#[no_mangle] -pub unsafe extern "C" fn public_key_free(_kp: Option>) {} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_builder() -> Option> { - Some(Box::new(BiscuitBuilder(crate::token::Biscuit::builder()))) -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_builder_set_context( - builder: Option<&mut BiscuitBuilder>, - context: *const c_char, -) -> bool { - if builder.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let builder = builder.unwrap(); - - let context = CStr::from_ptr(context); - let s = context.to_str(); - match s { - Err(_) => { - update_last_error(Error::InvalidArgument); - false - } - Ok(context) => { - builder.0.set_context(context.to_string()); - true - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_builder_set_root_key_id( - builder: Option<&mut BiscuitBuilder>, - root_key_id: u32, -) -> bool { - if builder.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let builder = builder.unwrap(); - - builder.0.set_root_key_id(root_key_id); - true -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_builder_add_fact( - builder: Option<&mut BiscuitBuilder>, - fact: *const c_char, -) -> bool { - if builder.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let builder = builder.unwrap(); - - let fact = CStr::from_ptr(fact); - let s = fact.to_str(); - if s.is_err() { - update_last_error(Error::InvalidArgument); - return false; - } - - builder - .0 - .add_fact(s.unwrap()) - .map_err(|e| { - update_last_error(Error::Biscuit(e)); - }) - .is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_builder_add_rule( - builder: Option<&mut BiscuitBuilder>, - rule: *const c_char, -) -> bool { - if builder.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let builder = builder.unwrap(); - - let rule = CStr::from_ptr(rule); - let s = rule.to_str(); - if s.is_err() { - update_last_error(Error::InvalidArgument); - return false; - } - - builder - .0 - .add_rule(s.unwrap()) - .map_err(|e| { - update_last_error(Error::Biscuit(e)); - }) - .is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_builder_add_check( - builder: Option<&mut BiscuitBuilder>, - check: *const c_char, -) -> bool { - if builder.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let builder = builder.unwrap(); - - let check = CStr::from_ptr(check); - let s = check.to_str(); - if s.is_err() { - update_last_error(Error::InvalidArgument); - return false; - } - - builder - .0 - .add_check(s.unwrap()) - .map_err(|e| { - update_last_error(Error::Biscuit(e)); - }) - .is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_builder_build( - builder: Option<&BiscuitBuilder>, - key_pair: Option<&KeyPair>, - seed_ptr: *const u8, - seed_len: usize, -) -> Option> { - if builder.is_none() { - update_last_error(Error::InvalidArgument); - } - let builder = builder?; - - if key_pair.is_none() { - update_last_error(Error::InvalidArgument); - } - let key_pair = key_pair?; - - let slice = std::slice::from_raw_parts(seed_ptr, seed_len); - if slice.len() != 32 { - return None; - } - - let mut seed = [0u8; 32]; - seed.copy_from_slice(slice); - - let mut rng: StdRng = SeedableRng::from_seed(seed); - (*builder) - .0 - .clone() - .build_with_rng(&key_pair.0, SymbolTable::default(), &mut rng) - .map(Biscuit) - .map(Box::new) - .ok() -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_builder_free<'a>(_builder: Option>) {} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_from<'a>( - biscuit_ptr: *const u8, - biscuit_len: usize, - root: Option<&'a PublicKey>, -) -> Option> { - let biscuit = std::slice::from_raw_parts(biscuit_ptr, biscuit_len); - if root.is_none() { - update_last_error(Error::InvalidArgument); - } - let root = root?; - - crate::token::Biscuit::from(biscuit, root.0) - .map(Biscuit) - .map(Box::new) - .ok() -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_serialized_size(biscuit: Option<&Biscuit>) -> usize { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - - let biscuit = biscuit.unwrap(); - - match biscuit.0.serialized_size() { - Ok(sz) => sz, - Err(e) => { - update_last_error(Error::Biscuit(e)); - return 0; - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_sealed_size(biscuit: Option<&Biscuit>) -> usize { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - - let biscuit = biscuit.unwrap(); - - match biscuit.0.serialized_size() { - Ok(sz) => sz, - Err(e) => { - update_last_error(Error::Biscuit(e)); - return 0; - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_serialize( - biscuit: Option<&Biscuit>, - buffer_ptr: *mut u8, -) -> usize { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - - let biscuit = biscuit.unwrap(); - - match (*biscuit).0.to_vec() { - Ok(v) => { - let size = match biscuit.0.serialized_size() { - Ok(sz) => sz, - Err(e) => { - update_last_error(Error::Biscuit(e)); - return 0; - } - }; - - let output_slice = std::slice::from_raw_parts_mut(buffer_ptr, size); - - output_slice.copy_from_slice(&v[..]); - v.len() - } - Err(e) => { - update_last_error(Error::Biscuit(e)); - 0 - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_serialize_sealed( - biscuit: Option<&Biscuit>, - buffer_ptr: *mut u8, -) -> usize { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - - let biscuit = biscuit.unwrap(); - - match (*biscuit).0.seal() { - Ok(b) => match b.to_vec() { - Ok(v) => { - let size = match biscuit.0.serialized_size() { - Ok(sz) => sz, - Err(e) => { - update_last_error(Error::Biscuit(e)); - return 0; - } - }; - - let output_slice = std::slice::from_raw_parts_mut(buffer_ptr, size); - - output_slice.copy_from_slice(&v[..]); - v.len() - } - Err(e) => { - update_last_error(Error::Biscuit(e)); - 0 - } - }, - - Err(e) => { - update_last_error(Error::Biscuit(e)); - 0 - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_count(biscuit: Option<&Biscuit>) -> usize { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - - let biscuit = biscuit.unwrap(); - - biscuit.0.blocks.len() + 1 -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_fact_count( - biscuit: Option<&Biscuit>, - block_index: u32, -) -> usize { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - - let biscuit = biscuit.unwrap(); - - let block = match biscuit.0.block(block_index as usize) { - Ok(block) => block, - Err(e) => { - update_last_error(e.into()); - return 0; - } - }; - - block.facts.len() -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_rule_count( - biscuit: Option<&Biscuit>, - block_index: u32, -) -> usize { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - - let biscuit = biscuit.unwrap(); - - let block = match biscuit.0.block(block_index as usize) { - Ok(block) => block, - Err(e) => { - update_last_error(e.into()); - return 0; - } - }; - - block.rules.len() -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_check_count( - biscuit: Option<&Biscuit>, - block_index: u32, -) -> usize { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - - let biscuit = biscuit.unwrap(); - - let block = match biscuit.0.block(block_index as usize) { - Ok(block) => block, - Err(e) => { - update_last_error(e.into()); - return 0; - } - }; - - block.checks.len() -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_fact( - biscuit: Option<&Biscuit>, - block_index: u32, - fact_index: u32, -) -> *mut c_char { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - - let biscuit = biscuit.unwrap(); - - let block = match biscuit.0.block(block_index as usize) { - Ok(block) => block, - Err(e) => { - update_last_error(e.into()); - return std::ptr::null_mut(); - } - }; - - match block.facts.get(fact_index as usize) { - None => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - Some(fact) => match CString::new(biscuit.0.symbols.print_fact(fact)) { - Ok(s) => s.into_raw(), - Err(_) => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - }, - } -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_rule( - biscuit: Option<&Biscuit>, - block_index: u32, - rule_index: u32, -) -> *mut c_char { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - - let biscuit = biscuit.unwrap(); - - let block = match biscuit.0.block(block_index as usize) { - Ok(block) => block, - Err(e) => { - update_last_error(e.into()); - return std::ptr::null_mut(); - } - }; - - match block.rules.get(rule_index as usize) { - None => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - Some(rule) => match CString::new(biscuit.0.symbols.print_rule(rule)) { - Ok(s) => s.into_raw(), - Err(_) => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - }, - } -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_check( - biscuit: Option<&Biscuit>, - block_index: u32, - check_index: u32, -) -> *mut c_char { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - - let biscuit = biscuit.unwrap(); - - let block = match biscuit.0.block(block_index as usize) { - Ok(block) => block, - Err(e) => { - update_last_error(e.into()); - return std::ptr::null_mut(); - } - }; - - match block.checks.get(check_index as usize) { - None => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - Some(check) => match CString::new(biscuit.0.symbols.print_check(check)) { - Ok(s) => s.into_raw(), - Err(_) => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - }, - } -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_context( - biscuit: Option<&Biscuit>, - block_index: u32, -) -> *mut c_char { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - - let biscuit = biscuit.unwrap(); - - let block = if block_index == 0 { - &biscuit.0.authority - } else { - match biscuit.0.blocks.get(block_index as usize - 1) { - Some(b) => b, - None => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - } - }; - - match &block.context { - None => { - return std::ptr::null_mut(); - } - Some(context) => match CString::new(context.clone()) { - Ok(s) => s.into_raw(), - Err(_) => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - }, - } -} - -#[no_mangle] -pub unsafe extern "C" fn create_block() -> Box { - Box::new(BlockBuilder(crate::token::builder::BlockBuilder::new())) -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_append_block( - biscuit: Option<&Biscuit>, - block_builder: Option<&BlockBuilder>, - key_pair: Option<&KeyPair>, -) -> Option> { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - } - let biscuit = biscuit?; - - if block_builder.is_none() { - update_last_error(Error::InvalidArgument); - } - let builder = block_builder?; - - if key_pair.is_none() { - update_last_error(Error::InvalidArgument); - } - let key_pair = key_pair?; - - match biscuit - .0 - .append_with_keypair(&key_pair.0, builder.0.clone()) - { - Ok(token) => Some(Box::new(Biscuit(token))), - Err(e) => { - update_last_error(Error::Biscuit(e)); - None - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_authorizer<'a>( - biscuit: Option<&'a Biscuit>, -) -> Option> { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - } - let biscuit = biscuit?; - - (*biscuit).0.authorizer().map(Authorizer).map(Box::new).ok() -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_free(_biscuit: Option>) {} - -#[no_mangle] -pub unsafe extern "C" fn block_builder_set_context( - builder: Option<&mut BlockBuilder>, - context: *const c_char, -) -> bool { - if builder.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let builder = builder.unwrap(); - - let context = CStr::from_ptr(context); - let s = context.to_str(); - match s { - Err(_) => { - update_last_error(Error::InvalidArgument); - false - } - Ok(context) => { - builder.0.set_context(context.to_string()); - true - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn block_builder_add_fact( - builder: Option<&mut BlockBuilder>, - fact: *const c_char, -) -> bool { - if builder.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let builder = builder.unwrap(); - - let fact = CStr::from_ptr(fact); - let s = fact.to_str(); - if s.is_err() { - update_last_error(Error::InvalidArgument); - return false; - } - - builder - .0 - .add_fact(s.unwrap()) - .map_err(|e| { - update_last_error(Error::Biscuit(e)); - }) - .is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn block_builder_add_rule( - builder: Option<&mut BlockBuilder>, - rule: *const c_char, -) -> bool { - if builder.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let builder = builder.unwrap(); - - let rule = CStr::from_ptr(rule); - let s = rule.to_str(); - if s.is_err() { - update_last_error(Error::InvalidArgument); - return false; - } - - builder - .0 - .add_rule(s.unwrap()) - .map_err(|e| { - update_last_error(Error::Biscuit(e)); - }) - .is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn block_builder_add_check( - builder: Option<&mut BlockBuilder>, - check: *const c_char, -) -> bool { - if builder.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let builder = builder.unwrap(); - - let check = CStr::from_ptr(check); - let s = check.to_str(); - if s.is_err() { - update_last_error(Error::InvalidArgument); - return false; - } - - builder - .0 - .add_check(s.unwrap()) - .map_err(|e| { - update_last_error(Error::Biscuit(e)); - }) - .is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn block_builder_free(_builder: Option>) {} - -#[no_mangle] -pub unsafe extern "C" fn authorizer_add_fact( - authorizer: Option<&mut Authorizer>, - fact: *const c_char, -) -> bool { - if authorizer.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let authorizer = authorizer.unwrap(); - - let fact = CStr::from_ptr(fact); - let s = fact.to_str(); - if s.is_err() { - update_last_error(Error::InvalidArgument); - return false; - } - - authorizer - .0 - .add_fact(s.unwrap()) - .map_err(|e| { - update_last_error(Error::Biscuit(e)); - }) - .is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn authorizer_add_rule( - authorizer: Option<&mut Authorizer>, - rule: *const c_char, -) -> bool { - if authorizer.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let authorizer = authorizer.unwrap(); - - let rule = CStr::from_ptr(rule); - let s = rule.to_str(); - if s.is_err() { - update_last_error(Error::InvalidArgument); - return false; - } - - authorizer - .0 - .add_rule(s.unwrap()) - .map_err(|e| { - update_last_error(Error::Biscuit(e)); - }) - .is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn authorizer_add_check( - authorizer: Option<&mut Authorizer>, - check: *const c_char, -) -> bool { - if authorizer.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let authorizer = authorizer.unwrap(); - - let check = CStr::from_ptr(check); - let s = check.to_str(); - if s.is_err() { - update_last_error(Error::InvalidArgument); - return false; - } - - authorizer - .0 - .add_check(s.unwrap()) - .map_err(|e| { - update_last_error(Error::Biscuit(e)); - }) - .is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn authorizer_add_policy( - authorizer: Option<&mut Authorizer>, - policy: *const c_char, -) -> bool { - if authorizer.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let authorizer = authorizer.unwrap(); - - let policy = CStr::from_ptr(policy); - let s = policy.to_str(); - if s.is_err() { - update_last_error(Error::InvalidArgument); - return false; - } - - authorizer - .0 - .add_policy(s.unwrap()) - .map_err(|e| { - update_last_error(Error::Biscuit(e)); - }) - .is_ok() -} - -#[no_mangle] -pub unsafe extern "C" fn authorizer_authorize(authorizer: Option<&mut Authorizer>) -> bool { - if authorizer.is_none() { - update_last_error(Error::InvalidArgument); - return false; - } - let authorizer = authorizer.unwrap(); - - match authorizer.0.authorize() { - Ok(_index) => true, - Err(e) => { - update_last_error(Error::Biscuit(e)); - false - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn authorizer_print(authorizer: Option<&mut Authorizer>) -> *mut c_char { - if authorizer.is_none() { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - let authorizer = authorizer.unwrap(); - - match CString::new(authorizer.0.print_world()) { - Ok(s) => s.into_raw(), - Err(_) => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn authorizer_free(_authorizer: Option>) {} - -#[no_mangle] -pub unsafe extern "C" fn string_free(ptr: *mut c_char) { - if ptr != std::ptr::null_mut() { - drop(CString::from_raw(ptr)); - } -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_print(biscuit: Option<&Biscuit>) -> *const c_char { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return std::ptr::null(); - } - let biscuit = biscuit.unwrap(); - - match CString::new(biscuit.0.print()) { - Ok(s) => s.into_raw(), - Err(_) => { - update_last_error(Error::InvalidArgument); - return std::ptr::null(); - } - } -} diff --git a/biscuit-auth/src/lib.rs b/biscuit-auth/src/lib.rs index 8ddaab0d..635b6078 100644 --- a/biscuit-auth/src/lib.rs +++ b/biscuit-auth/src/lib.rs @@ -235,12 +235,6 @@ pub use token::Biscuit; pub use token::RootKeyProvider; pub use token::{ThirdPartyBlock, ThirdPartyRequest}; -#[cfg(feature = "capi")] -mod capi; - -#[cfg(feature = "capi")] -pub use capi::*; - #[cfg(bwk)] mod bwk; #[cfg(bwk)] diff --git a/biscuit-capi/Cargo.toml b/biscuit-capi/Cargo.toml new file mode 100644 index 00000000..c67317a0 --- /dev/null +++ b/biscuit-capi/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "biscuit-capi" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +biscuit-auth = { version = "4.1.1", path = "../biscuit-auth" } From 5202d949f9da1650d70ae2fc0dd99ca6a3ad558b Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Tue, 26 Mar 2024 21:06:18 +0100 Subject: [PATCH 3/4] update imports --- Cargo.toml | 2 +- biscuit-auth/Cargo.toml | 3 -- biscuit-capi/Cargo.toml | 7 ++- biscuit-capi/src/lib.rs | 48 ++++++++++---------- {biscuit-auth => biscuit-capi}/tests/capi.rs | 0 5 files changed, 31 insertions(+), 29 deletions(-) rename {biscuit-auth => biscuit-capi}/tests/capi.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 28254783..9dcf7dc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["biscuit-auth", "biscuit-quote", "biscuit-parser"] +members = ["biscuit-auth", "biscuit-quote", "biscuit-parser", "biscuit-capi"] diff --git a/biscuit-auth/Cargo.toml b/biscuit-auth/Cargo.toml index 8e6b0148..ee0383fb 100644 --- a/biscuit-auth/Cargo.toml +++ b/biscuit-auth/Cargo.toml @@ -13,8 +13,6 @@ repository = "https://github.com/biscuit-auth/biscuit-rust" [features] default = ["regex-full", "datalog-macro"] regex-full = [ "regex/perf", "regex/unicode"] -# used by cargo-c to signal the compilation of C bindings -capi = ["inline-c"] wasm = ["wasm-bindgen", "getrandom/wasm-bindgen"] # used by biscuit-wasm to serialize errors to JSON serde-error = ["serde", "biscuit-parser/serde-error"] @@ -38,7 +36,6 @@ hex = "0.4" zeroize = { version = "1", default-features = false } thiserror = "1" rand = { version = "0.8" } -inline-c = { version = "0.1", optional = true } wasm-bindgen = { version = "0.2", optional = true } base64 = "0.13.0" ed25519-dalek = { version = "2.0.0", features = ["rand_core", "zeroize"] } diff --git a/biscuit-capi/Cargo.toml b/biscuit-capi/Cargo.toml index c67317a0..f5affae5 100644 --- a/biscuit-capi/Cargo.toml +++ b/biscuit-capi/Cargo.toml @@ -3,7 +3,12 @@ name = "biscuit-capi" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +# used by cargo-c to signal the compilation of C bindings +capi = ["inline-c"] [dependencies] biscuit-auth = { version = "4.1.1", path = "../biscuit-auth" } +inline-c = { version = "0.1", optional = true } +rand = { version = "0.8" } + diff --git a/biscuit-capi/src/lib.rs b/biscuit-capi/src/lib.rs index 3a80cbba..a8a9f643 100644 --- a/biscuit-capi/src/lib.rs +++ b/biscuit-capi/src/lib.rs @@ -6,10 +6,10 @@ use std::{ os::raw::c_char, }; -use crate::datalog::SymbolTable; +use biscuit_auth::datalog::SymbolTable; enum Error { - Biscuit(crate::error::Token), + Biscuit(biscuit_auth::error::Token), InvalidArgument, } @@ -22,8 +22,8 @@ impl fmt::Display for Error { } } -impl From for Error { - fn from(error: crate::error::Token) -> Self { +impl From for Error { + fn from(error: biscuit_auth::error::Token) -> Self { Error::Biscuit(error) } } @@ -105,7 +105,7 @@ pub extern "C" fn error_kind() -> ErrorKind { Some(ref err) => match err { Error::InvalidArgument => ErrorKind::InvalidArgument, Error::Biscuit(e) => { - use crate::error::*; + use biscuit_auth::error::*; match e { Token::InternalError => ErrorKind::InternalError, Token::Format(Format::Signature(Signature::InvalidFormat)) => { @@ -186,7 +186,7 @@ pub extern "C" fn error_kind() -> ErrorKind { #[no_mangle] pub extern "C" fn error_check_count() -> u64 { - use crate::error::*; + use biscuit_auth::error::*; LAST_ERROR.with(|prev| match *prev.borrow() { Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { @@ -198,7 +198,7 @@ pub extern "C" fn error_check_count() -> u64 { #[no_mangle] pub extern "C" fn error_check_id(check_index: u64) -> u64 { - use crate::error::*; + use biscuit_auth::error::*; LAST_ERROR.with(|prev| match *prev.borrow() { Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { @@ -219,7 +219,7 @@ pub extern "C" fn error_check_id(check_index: u64) -> u64 { #[no_mangle] pub extern "C" fn error_check_block_id(check_index: u64) -> u64 { - use crate::error::*; + use biscuit_auth::error::*; LAST_ERROR.with(|prev| match *prev.borrow() { Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { @@ -240,7 +240,7 @@ pub extern "C" fn error_check_block_id(check_index: u64) -> u64 { /// the string is overwritten on each call #[no_mangle] pub extern "C" fn error_check_rule(check_index: u64) -> *const c_char { - use crate::error::*; + use biscuit_auth::error::*; thread_local! { static CAVEAT_RULE: RefCell> = RefCell::new(None); } @@ -271,7 +271,7 @@ pub extern "C" fn error_check_rule(check_index: u64) -> *const c_char { #[no_mangle] pub extern "C" fn error_check_is_authorizer(check_index: u64) -> bool { - use crate::error::*; + use biscuit_auth::error::*; LAST_ERROR.with(|prev| match *prev.borrow() { Some(Error::Biscuit(Token::FailedLogic(Logic::Unauthorized { ref checks, .. }))) | Some(Error::Biscuit(Token::FailedLogic(Logic::NoMatchingPolicy { ref checks }))) => { @@ -288,12 +288,12 @@ pub extern "C" fn error_check_is_authorizer(check_index: u64) -> bool { }) } -pub struct Biscuit(crate::token::Biscuit); -pub struct KeyPair(crate::crypto::KeyPair); -pub struct PublicKey(crate::crypto::PublicKey); -pub struct BiscuitBuilder(crate::token::builder::BiscuitBuilder); -pub struct BlockBuilder(crate::token::builder::BlockBuilder); -pub struct Authorizer(crate::token::authorizer::Authorizer); +pub struct Biscuit(biscuit_auth::Biscuit); +pub struct KeyPair(biscuit_auth::KeyPair); +pub struct PublicKey(biscuit_auth::PublicKey); +pub struct BiscuitBuilder(biscuit_auth::builder::BiscuitBuilder); +pub struct BlockBuilder(biscuit_auth::builder::BlockBuilder); +pub struct Authorizer(biscuit_auth::Authorizer); #[no_mangle] pub unsafe extern "C" fn key_pair_new<'a>( @@ -311,7 +311,7 @@ pub unsafe extern "C" fn key_pair_new<'a>( let mut rng: StdRng = SeedableRng::from_seed(seed); - Some(Box::new(KeyPair(crate::crypto::KeyPair::new_with_rng( + Some(Box::new(KeyPair(biscuit_auth::KeyPair::new_with_rng( &mut rng, )))) } @@ -346,12 +346,12 @@ pub unsafe extern "C" fn key_pair_serialize(kp: Option<&KeyPair>, buffer_ptr: *m pub unsafe extern "C" fn key_pair_deserialize(buffer_ptr: *mut u8) -> Option> { let input_slice = std::slice::from_raw_parts_mut(buffer_ptr, 32); - match crate::crypto::PrivateKey::from_bytes(input_slice).ok() { + match biscuit_auth::PrivateKey::from_bytes(input_slice).ok() { None => { update_last_error(Error::InvalidArgument); None } - Some(privkey) => Some(Box::new(KeyPair(crate::crypto::KeyPair::from(&privkey)))), + Some(privkey) => Some(Box::new(KeyPair(biscuit_auth::KeyPair::from(&privkey)))), } } @@ -381,7 +381,7 @@ pub unsafe extern "C" fn public_key_serialize( pub unsafe extern "C" fn public_key_deserialize(buffer_ptr: *mut u8) -> Option> { let input_slice = std::slice::from_raw_parts_mut(buffer_ptr, 32); - match crate::crypto::PublicKey::from_bytes(input_slice).ok() { + match biscuit_auth::PublicKey::from_bytes(input_slice).ok() { None => { update_last_error(Error::InvalidArgument); None @@ -395,7 +395,7 @@ pub unsafe extern "C" fn public_key_free(_kp: Option>) {} #[no_mangle] pub unsafe extern "C" fn biscuit_builder() -> Option> { - Some(Box::new(BiscuitBuilder(crate::token::Biscuit::builder()))) + Some(Box::new(BiscuitBuilder(biscuit_auth::Biscuit::builder()))) } #[no_mangle] @@ -569,7 +569,7 @@ pub unsafe extern "C" fn biscuit_from<'a>( } let root = root?; - crate::token::Biscuit::from(biscuit, root.0) + biscuit_auth::Biscuit::from(biscuit, root.0) .map(Biscuit) .map(Box::new) .ok() @@ -695,7 +695,7 @@ pub unsafe extern "C" fn biscuit_block_count(biscuit: Option<&Biscuit>) -> usize let biscuit = biscuit.unwrap(); - biscuit.0.blocks.len() + 1 + biscuit.0.block_count() } #[no_mangle] @@ -915,7 +915,7 @@ pub unsafe extern "C" fn biscuit_block_context( #[no_mangle] pub unsafe extern "C" fn create_block() -> Box { - Box::new(BlockBuilder(crate::token::builder::BlockBuilder::new())) + Box::new(BlockBuilder(biscuit_auth::builder::BlockBuilder::new())) } #[no_mangle] diff --git a/biscuit-auth/tests/capi.rs b/biscuit-capi/tests/capi.rs similarity index 100% rename from biscuit-auth/tests/capi.rs rename to biscuit-capi/tests/capi.rs From d33a93f8823538c9c5d30749f1674a8936848cee Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Sat, 25 May 2024 16:10:37 +0200 Subject: [PATCH 4/4] fixes --- biscuit-auth/Cargo.toml | 30 +++--- biscuit-capi/Cargo.toml | 5 + biscuit-capi/src/lib.rs | 194 +------------------------------------ biscuit-capi/tests/capi.rs | 4 +- 4 files changed, 22 insertions(+), 211 deletions(-) diff --git a/biscuit-auth/Cargo.toml b/biscuit-auth/Cargo.toml index ee0383fb..0dcd71cd 100644 --- a/biscuit-auth/Cargo.toml +++ b/biscuit-auth/Cargo.toml @@ -10,6 +10,18 @@ documentation = "https://docs.rs/biscuit-auth" homepage = "https://github.com/biscuit-auth/biscuit" repository = "https://github.com/biscuit-auth/biscuit-rust" +include = [ + "Cargo.toml", + "cbindgen.toml", + "build.rs", + "examples/*.rs", + "LICENSE", + "README.md", + "src/*.rs", + "src/*/*.rs", + "tests/*.rs" +] + [features] default = ["regex-full", "datalog-macro"] regex-full = [ "regex/perf", "regex/unicode"] @@ -47,7 +59,6 @@ biscuit-parser = { version = "0.1.2", path = "../biscuit-parser" } biscuit-quote = { version = "0.2.2", optional = true, path = "../biscuit-quote" } chrono = { version = "0.4.26", optional = true, default-features = false, features = ["serde"] } - [dev-dependencies] bencher = "0.1.5" rand = "0.8" @@ -60,23 +71,6 @@ serde_json = "1.0.67" #[build-dependencies] #prost-build = "0.10" -[package.metadata.capi.library] -# Used as the library name and defaults to the crate name. This might get -# prefixed with `lib` depending on the target platform. -name = "biscuit_auth" - -include = [ - "Cargo.toml", - "cbindgen.toml", - "build.rs", - "examples/*.rs", - "LICENSE", - "README.md", - "src/*.rs", - "src/*/*.rs", - "tests/*.rs" -] - [[example]] name = "testcases" required-features = ["serde-error"] diff --git a/biscuit-capi/Cargo.toml b/biscuit-capi/Cargo.toml index f5affae5..bafb6148 100644 --- a/biscuit-capi/Cargo.toml +++ b/biscuit-capi/Cargo.toml @@ -7,6 +7,11 @@ edition = "2021" # used by cargo-c to signal the compilation of C bindings capi = ["inline-c"] +[package.metadata.capi.library] +# Used as the library name and defaults to the crate name. This might get +# prefixed with `lib` depending on the target platform. +name = "biscuit_auth" + [dependencies] biscuit-auth = { version = "4.1.1", path = "../biscuit-auth" } inline-c = { version = "0.1", optional = true } diff --git a/biscuit-capi/src/lib.rs b/biscuit-capi/src/lib.rs index a8a9f643..05b07290 100644 --- a/biscuit-capi/src/lib.rs +++ b/biscuit-capi/src/lib.rs @@ -698,183 +698,6 @@ pub unsafe extern "C" fn biscuit_block_count(biscuit: Option<&Biscuit>) -> usize biscuit.0.block_count() } -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_fact_count( - biscuit: Option<&Biscuit>, - block_index: u32, -) -> usize { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - - let biscuit = biscuit.unwrap(); - - let block = match biscuit.0.block(block_index as usize) { - Ok(block) => block, - Err(e) => { - update_last_error(e.into()); - return 0; - } - }; - - block.facts.len() -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_rule_count( - biscuit: Option<&Biscuit>, - block_index: u32, -) -> usize { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - - let biscuit = biscuit.unwrap(); - - let block = match biscuit.0.block(block_index as usize) { - Ok(block) => block, - Err(e) => { - update_last_error(e.into()); - return 0; - } - }; - - block.rules.len() -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_check_count( - biscuit: Option<&Biscuit>, - block_index: u32, -) -> usize { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return 0; - } - - let biscuit = biscuit.unwrap(); - - let block = match biscuit.0.block(block_index as usize) { - Ok(block) => block, - Err(e) => { - update_last_error(e.into()); - return 0; - } - }; - - block.checks.len() -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_fact( - biscuit: Option<&Biscuit>, - block_index: u32, - fact_index: u32, -) -> *mut c_char { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - - let biscuit = biscuit.unwrap(); - - let block = match biscuit.0.block(block_index as usize) { - Ok(block) => block, - Err(e) => { - update_last_error(e.into()); - return std::ptr::null_mut(); - } - }; - - match block.facts.get(fact_index as usize) { - None => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - Some(fact) => match CString::new(biscuit.0.symbols.print_fact(fact)) { - Ok(s) => s.into_raw(), - Err(_) => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - }, - } -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_rule( - biscuit: Option<&Biscuit>, - block_index: u32, - rule_index: u32, -) -> *mut c_char { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - - let biscuit = biscuit.unwrap(); - - let block = match biscuit.0.block(block_index as usize) { - Ok(block) => block, - Err(e) => { - update_last_error(e.into()); - return std::ptr::null_mut(); - } - }; - - match block.rules.get(rule_index as usize) { - None => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - Some(rule) => match CString::new(biscuit.0.symbols.print_rule(rule)) { - Ok(s) => s.into_raw(), - Err(_) => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - }, - } -} - -#[no_mangle] -pub unsafe extern "C" fn biscuit_block_check( - biscuit: Option<&Biscuit>, - block_index: u32, - check_index: u32, -) -> *mut c_char { - if biscuit.is_none() { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - - let biscuit = biscuit.unwrap(); - - let block = match biscuit.0.block(block_index as usize) { - Ok(block) => block, - Err(e) => { - update_last_error(e.into()); - return std::ptr::null_mut(); - } - }; - - match block.checks.get(check_index as usize) { - None => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - Some(check) => match CString::new(biscuit.0.symbols.print_check(check)) { - Ok(s) => s.into_raw(), - Err(_) => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - }, - } -} - #[no_mangle] pub unsafe extern "C" fn biscuit_block_context( biscuit: Option<&Biscuit>, @@ -886,24 +709,13 @@ pub unsafe extern "C" fn biscuit_block_context( } let biscuit = biscuit.unwrap(); + let context = biscuit.0.context().remove(block_index as usize); - let block = if block_index == 0 { - &biscuit.0.authority - } else { - match biscuit.0.blocks.get(block_index as usize - 1) { - Some(b) => b, - None => { - update_last_error(Error::InvalidArgument); - return std::ptr::null_mut(); - } - } - }; - - match &block.context { + match context { None => { return std::ptr::null_mut(); } - Some(context) => match CString::new(context.clone()) { + Some(context) => match CString::new(context) { Ok(s) => s.into_raw(), Err(_) => { update_last_error(Error::InvalidArgument); diff --git a/biscuit-capi/tests/capi.rs b/biscuit-capi/tests/capi.rs index 9d0a1c61..67d0f4ae 100644 --- a/biscuit-capi/tests/capi.rs +++ b/biscuit-capi/tests/capi.rs @@ -8,7 +8,7 @@ mod capi { (assert_c! { #include #include - #include "biscuit_auth.h" + #include "biscuit_capi.h" int main() { char *seed = "abcdefghabcdefghabcdefghabcdefgh"; @@ -135,7 +135,7 @@ wrote 322 bytes (assert_c! { #include #include - #include "biscuit_auth.h" + #include "biscuit_capi.h" int main() { char *seed = "abcdefghabcdefghabcdefghabcdefgh";