use crate::{Result, SigningError};
use std::path::Path;
use typed_builder::TypedBuilder;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SignatureLevel {
#[default]
PadesB,
PadesT,
PadesLT,
PadesLTA,
}
impl SignatureLevel {
#[must_use]
pub const fn as_str(&self) -> &'static str {
match self {
Self::PadesB => "B",
Self::PadesT => "T",
Self::PadesLT => "LT",
Self::PadesLTA => "LTA",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum MdpPermissions {
NoChanges = 1,
#[default]
FormFillingAndSigning = 2,
FormFillingSigningAndAnnotations = 3,
}
impl MdpPermissions {
#[must_use]
pub const fn as_u32(&self) -> u32 {
*self as u32
}
#[must_use]
pub const fn as_str(&self) -> &'static str {
match self {
Self::NoChanges => "no-changes",
Self::FormFillingAndSigning => "form-filling",
Self::FormFillingSigningAndAnnotations => "annotations",
}
}
#[must_use]
pub fn parse_arg(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"1" | "no-changes" | "none" => Some(Self::NoChanges),
"2" | "form-filling" | "forms" => Some(Self::FormFillingAndSigning),
"3" | "annotations" | "annots" => Some(Self::FormFillingSigningAndAnnotations),
_ => None,
}
}
}
pub struct SigningCertificate {
_private: (),
}
impl SigningCertificate {
pub fn from_pkcs12(_data: &[u8], _password: &str) -> Result<Self> {
Err(SigningError::RequiresLicense.into())
}
pub fn from_pkcs12_file(_path: impl AsRef<Path>, _password: &str) -> Result<Self> {
Err(SigningError::RequiresLicense.into())
}
#[must_use]
pub const fn subject_common_name(&self) -> Option<String> {
None
}
#[must_use]
pub const fn subject_name(&self) -> String {
String::new()
}
#[must_use]
pub const fn issuer_name(&self) -> String {
String::new()
}
#[must_use]
pub const fn serial_number_hex(&self) -> String {
String::new()
}
}
#[derive(Debug, Clone, TypedBuilder)]
#[builder(field_defaults(default, setter(into)))]
pub struct SigningOptions {
#[builder(default)]
pub reason: Option<String>,
#[builder(default)]
pub location: Option<String>,
#[builder(default)]
pub contact_info: Option<String>,
#[builder(default)]
pub signature_level: SignatureLevel,
#[builder(default)]
pub timestamp_url: Option<String>,
#[builder(default = "Signature".to_string())]
pub field_name: String,
#[builder(default = true)]
pub include_chain: bool,
#[builder(default = false)]
pub certify: bool,
#[builder(default)]
pub mdp_permissions: MdpPermissions,
}
impl Default for SigningOptions {
fn default() -> Self {
Self::builder().build()
}
}
#[derive(Debug, Clone, TypedBuilder)]
#[builder(field_defaults(default, setter(into)))]
pub struct SignatureAppearance {
#[builder(default = 1)]
pub page: u32,
#[builder(default = 50.0)]
pub x: f64,
#[builder(default = 50.0)]
pub y: f64,
#[builder(default = 200.0)]
pub width: f64,
#[builder(default = 75.0)]
pub height: f64,
#[builder(default = true)]
pub show_name: bool,
#[builder(default = true)]
pub show_date: bool,
#[builder(default = true)]
pub show_reason: bool,
#[builder(default)]
pub background_image: Option<Vec<u8>>,
}
impl Default for SignatureAppearance {
fn default() -> Self {
Self::builder().build()
}
}
pub struct SignedPdf {
data: Vec<u8>,
}
impl SignedPdf {
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.data
}
#[must_use]
pub fn into_bytes(self) -> Vec<u8> {
self.data
}
pub fn write_to_file(&self, path: impl AsRef<Path>) -> Result<()> {
std::fs::write(path, &self.data)?;
Ok(())
}
}
pub fn sign_pdf(
_pdf_data: &[u8],
_certificate: &SigningCertificate,
_options: &SigningOptions,
) -> Result<SignedPdf> {
Err(SigningError::RequiresLicense.into())
}
pub fn sign_pdf_visible(
_pdf_data: &[u8],
_certificate: &SigningCertificate,
_options: &SigningOptions,
_appearance: &SignatureAppearance,
) -> Result<SignedPdf> {
Err(SigningError::RequiresLicense.into())
}
#[derive(Debug, Clone, Copy, Default)]
pub struct DocumentValidity {
pub is_valid: bool,
pub covers_whole_document: bool,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct CertificateValidity {
pub time_valid: bool,
pub usage_valid: bool,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct SignatureStatus {
pub document: DocumentValidity,
pub certificate: CertificateValidity,
}
#[derive(Debug)]
pub struct SignatureVerification {
pub signer_name: String,
pub signing_time: Option<String>,
pub reason: Option<String>,
pub location: Option<String>,
pub status: SignatureStatus,
pub cert_warnings: Vec<String>,
pub error: Option<String>,
}
impl From<printwell_sys::SignatureInfo> for SignatureVerification {
fn from(info: printwell_sys::SignatureInfo) -> Self {
Self {
signer_name: info.signer_name,
signing_time: if info.signing_time.is_empty() {
None
} else {
Some(info.signing_time)
},
reason: if info.reason.is_empty() {
None
} else {
Some(info.reason)
},
location: if info.location.is_empty() {
None
} else {
Some(info.location)
},
status: SignatureStatus {
document: DocumentValidity {
is_valid: info.is_valid,
covers_whole_document: info.covers_whole_document,
},
certificate: CertificateValidity {
time_valid: true,
usage_valid: true,
},
},
cert_warnings: Vec::new(),
error: None,
}
}
}
#[derive(Debug)]
pub struct ExtractedSignature {
pub contents: Vec<u8>,
pub byte_range: Vec<i64>,
pub sub_filter: String,
pub reason: Option<String>,
pub location: Option<String>,
pub signing_time: Option<String>,
pub signer_name: Option<String>,
}
pub fn extract_signatures(_pdf_data: &[u8]) -> Result<Vec<ExtractedSignature>> {
Err(SigningError::RequiresLicense.into())
}
pub fn verify_signatures(_pdf_data: &[u8]) -> Result<Vec<SignatureVerification>> {
Err(SigningError::RequiresLicense.into())
}
pub fn verify_signatures_with_trust(
_pdf_data: &[u8],
_trust_store: Option<&crate::crypto::TrustStore>,
) -> Result<Vec<SignatureVerification>> {
Err(SigningError::RequiresLicense.into())
}
#[derive(Debug, Clone)]
pub struct SignatureFieldInfo {
pub name: String,
pub page: u32,
pub x: f64,
pub y: f64,
pub width: f64,
pub height: f64,
pub is_signed: bool,
}
pub fn list_signature_fields(_pdf_data: &[u8]) -> Result<Vec<SignatureFieldInfo>> {
Err(SigningError::RequiresLicense.into())
}
pub fn sign_pdf_field(
_pdf_data: &[u8],
_field_name: &str,
_certificate: &SigningCertificate,
_options: &SigningOptions,
) -> Result<SignedPdf> {
Err(SigningError::RequiresLicense.into())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum MdpPermission {
NoChanges = 1,
#[default]
FormFillAndSign = 2,
AnnotationsAllowed = 3,
}
pub fn certify_pdf(
_pdf_data: &[u8],
_certificate: &SigningCertificate,
_options: &SigningOptions,
_permission: MdpPermission,
) -> Result<SignedPdf> {
Err(SigningError::RequiresLicense.into())
}