use crate::ffi::converter::{to_cstr, to_hotp, to_str};
use crate::ffi::{
error_bool_result, error_hotp_config_result, error_string_result, success_bool_result, success_hotp_config_result,
success_string_result, BoolResult, HotpConfig, HotpConfigResult, StringResult,
};
use crate::{AlgorithmTrait, HOTP};
use std::ffi::{c_ulonglong, c_ushort};
use std::os::raw::c_char;
#[no_mangle]
pub extern "C" fn hotp_generate(config: HotpConfig, counter: c_ulonglong) -> StringResult {
match to_hotp(config).generate(counter) {
Ok(c) => success_string_result(c.as_str()),
Err(e) => error_string_result(e.to_string().as_str()),
}
}
#[no_mangle]
pub extern "C" fn hotp_verify(
config: HotpConfig,
otp: *const c_char,
counter: c_ulonglong,
retries: c_ulonglong,
) -> BoolResult {
if otp.is_null() {
error_bool_result("OTP is null")
} else {
match to_hotp(config).verify(to_str(otp), counter, retries) {
Ok(verified) => success_bool_result(verified.is_some()),
Err(e) => error_bool_result(e.to_string().as_str()),
}
}
}
#[no_mangle]
pub extern "C" fn hotp_provisioning_uri(
config: HotpConfig,
issuer: *const c_char,
user: *const c_char,
counter: c_ulonglong,
) -> StringResult {
if user.is_null() {
error_string_result("Name is null")
} else {
match to_hotp(config).provisioning_uri(to_str(issuer), to_str(user), counter) {
Ok(uri) => success_string_result(uri.as_str()),
Err(e) => error_string_result(e.to_string().as_str()),
}
}
}
#[no_mangle]
pub extern "C" fn hotp_from_uri(uri: *const c_char) -> HotpConfigResult {
if uri.is_null() {
error_hotp_config_result("URI is null")
} else {
match HOTP::from_uri(to_str(uri)) {
Ok(hotp) => success_hotp_config_result(HotpConfig {
algorithm: to_cstr(hotp.algorithm.to_string().as_str()),
secret: to_cstr(hotp.secret.string().as_str()),
length: hotp.length.get() as c_ushort,
radix: hotp.radix.get() as c_ushort,
}),
Err(e) => error_hotp_config_result(e.to_string().as_str()),
}
}
}
#[cfg(test)]
mod hotp_c_bind_tests;