pub mod manifest;
pub mod package;
pub mod sign;
use crate::config::AppleConfig;
use crate::images;
use crate::subject::WalletSubject;
use crate::WalletError;
pub struct ApplePassBuilder {
pub(crate) pass_type_id: String,
pub(crate) team_id: String,
pub(crate) app_name: String,
pub(crate) signing: sign::SigningMaterial,
}
impl ApplePassBuilder {
pub fn new(cfg: AppleConfig, app_name: String) -> Result<Self, WalletError> {
let signing = sign::SigningMaterial::parse(
&cfg.cert_pem,
&cfg.key_pem,
cfg.key_password.as_deref(),
&cfg.wwdr_pem,
)?;
Ok(Self {
pass_type_id: cfg.pass_type_id,
team_id: cfg.team_id,
app_name,
signing,
})
}
pub fn build<S: WalletSubject>(&self, s: &S) -> Result<Vec<u8>, WalletError> {
let pass_json_bytes = manifest::build_pass_json(self, s)?;
let branding = s.branding();
let mut image_entries: Vec<(String, Vec<u8>)> = Vec::new();
let icon_source: Vec<u8> = match (
branding.icon_png_bytes.as_deref(),
branding.logo_png_bytes.as_deref(),
) {
(Some(_), _) => Vec::new(), (None, Some(logo)) => logo.to_vec(), (None, None) => images::transparent_1x1_png()?, };
if let Some(logo) = branding.logo_png_bytes.as_deref() {
image_entries.extend(images::apple_logo_set(logo)?);
}
let icon_entries =
images::apple_icon_set(branding.icon_png_bytes.as_deref(), &icon_source)?;
image_entries.extend(icon_entries);
if let Some(hero) = branding.hero_png_bytes.as_deref() {
let strip_entries = images::apple_strip_set(hero)?;
image_entries.extend(strip_entries);
}
let mut manifest_inputs: Vec<(String, Vec<u8>)> =
vec![("pass.json".to_string(), pass_json_bytes.clone())];
manifest_inputs.extend(image_entries.iter().cloned());
let manifest_bytes = manifest::build_manifest(&manifest_inputs)?;
let signature_bytes = self.signing.sign_detached(&manifest_bytes)?;
let mut zip_entries: Vec<(String, Vec<u8>)> = Vec::with_capacity(9);
zip_entries.push(("pass.json".to_string(), pass_json_bytes));
zip_entries.push(("manifest.json".to_string(), manifest_bytes));
zip_entries.push(("signature".to_string(), signature_bytes));
zip_entries.extend(image_entries);
package::zip_pkpass(&zip_entries)
}
}