1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5use std::ffi::{CStr, CString};
6use std::os::raw::c_char;
7use std::ptr;
8
9use thiserror::Error;
10
11include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
12
13#[derive(Debug, Default)]
14pub struct ZSignOptions {
15 pub input_path: String,
16
17 pub cert_file: Option<String>,
18 pub pkey_file: Option<String>,
19 pub prov_file: Option<String>,
20 pub password: Option<String>,
21 pub adhoc: bool,
22 pub sha256_only: bool,
23
24 pub bundle_id: Option<String>,
25 pub bundle_name: Option<String>,
26 pub bundle_version: Option<String>,
27 pub entitlements_file: Option<String>,
28
29 pub dylib_files: Vec<String>,
30 pub weak_inject: bool,
31
32 pub force: bool,
33 pub check_signature: bool,
34 pub temp_folder: Option<String>,
35
36 pub debug: bool,
37 pub quiet: bool,
38 pub enable_cache: bool,
39}
40
41#[derive(Debug, Clone, Error)]
42pub enum ZSignError {
43 #[error("Invalid input parameters")]
44 InvalidInput,
45 #[error("Signing operation failed")]
46 SigningFailed,
47 #[error("File is not signed")]
48 NotSigned,
49 #[error("Unknown error, code {0}")]
50 Unknown(i32),
51}
52
53impl ZSignOptions {
54 pub fn new<S: Into<String>>(input_path: S) -> Self {
55 Self {
56 input_path: input_path.into(),
57 enable_cache: true,
58 ..Default::default()
59 }
60 }
61
62 pub fn with_adhoc_signing(mut self) -> Self {
63 self.adhoc = true;
64 self
65 }
66
67 pub fn with_cert_file<S: Into<String>>(mut self, cert_file: S) -> Self {
68 self.cert_file = Some(cert_file.into());
69 self
70 }
71
72 pub fn with_pkey_file<S: Into<String>>(mut self, pkey_file: S) -> Self {
73 self.pkey_file = Some(pkey_file.into());
74 self
75 }
76
77 pub fn with_prov_file<S: Into<String>>(mut self, prov_file: S) -> Self {
78 self.prov_file = Some(prov_file.into());
79 self
80 }
81
82 pub fn with_password<S: Into<String>>(mut self, password: S) -> Self {
83 self.password = Some(password.into());
84 self
85 }
86
87 pub fn with_bundle_id<S: Into<String>>(mut self, bundle_id: S) -> Self {
88 self.bundle_id = Some(bundle_id.into());
89 self
90 }
91
92 pub fn with_bundle_name<S: Into<String>>(mut self, bundle_name: S) -> Self {
93 self.bundle_name = Some(bundle_name.into());
94 self
95 }
96
97 pub fn with_bundle_version<S: Into<String>>(mut self, bundle_version: S) -> Self {
98 self.bundle_version = Some(bundle_version.into());
99 self
100 }
101
102 pub fn with_entitlements_file<S: Into<String>>(mut self, entitlements_file: S) -> Self {
103 self.entitlements_file = Some(entitlements_file.into());
104 self
105 }
106
107 pub fn with_temp_folder<S: Into<String>>(mut self, temp_folder: S) -> Self {
108 self.temp_folder = Some(temp_folder.into());
109 self
110 }
111
112 pub fn with_weak_inject(mut self) -> Self {
113 self.weak_inject = true;
114 self
115 }
116
117 pub fn with_force(mut self) -> Self {
118 self.force = true;
119 self
120 }
121
122 pub fn with_check_signature(mut self) -> Self {
123 self.check_signature = true;
124 self
125 }
126
127 pub fn with_quiet(mut self) -> Self {
128 self.quiet = true;
129 self
130 }
131
132 pub fn with_debug(mut self) -> Self {
133 self.debug = true;
134 self
135 }
136
137 pub fn with_disable_cache(mut self) -> Self {
138 self.enable_cache = false;
139 self
140 }
141
142 pub fn add_dylib<S: Into<String>>(mut self, dylib_path: S) -> Self {
143 self.dylib_files.push(dylib_path.into());
144 self
145 }
146
147 pub fn sign(&self) -> Result<(), ZSignError> {
148 let input_path = CString::new(self.input_path.clone()).unwrap();
149 let cert_file = self
150 .cert_file
151 .as_ref()
152 .map(|s| CString::new(s.clone()).unwrap());
153 let pkey_file = self
154 .pkey_file
155 .as_ref()
156 .map(|s| CString::new(s.clone()).unwrap());
157 let prov_file = self
158 .prov_file
159 .as_ref()
160 .map(|s| CString::new(s.clone()).unwrap());
161 let password = self
162 .password
163 .as_ref()
164 .map(|s| CString::new(s.clone()).unwrap());
165 let bundle_id = self
166 .bundle_id
167 .as_ref()
168 .map(|s| CString::new(s.clone()).unwrap());
169 let bundle_name = self
170 .bundle_name
171 .as_ref()
172 .map(|s| CString::new(s.clone()).unwrap());
173 let bundle_version = self
174 .bundle_version
175 .as_ref()
176 .map(|s| CString::new(s.clone()).unwrap());
177 let entitlements_file = self
178 .entitlements_file
179 .as_ref()
180 .map(|s| CString::new(s.clone()).unwrap());
181 let temp_folder = self
182 .temp_folder
183 .as_ref()
184 .map(|s| CString::new(s.clone()).unwrap());
185
186 let dylib_cstrings: Vec<CString> = self
187 .dylib_files
188 .iter()
189 .map(|s| CString::new(s.clone()).unwrap())
190 .collect();
191 let mut dylib_ptrs: Vec<*const c_char> =
192 dylib_cstrings.iter().map(|cs| cs.as_ptr()).collect();
193
194 unsafe {
195 let result = sign_ipa(
196 input_path.as_ptr(),
197 cert_file.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
198 pkey_file.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
199 prov_file.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
200 password.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
201 if self.adhoc { 1 } else { 0 },
202 if self.sha256_only { 1 } else { 0 },
203 bundle_id.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
204 bundle_name.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
205 bundle_version.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
206 entitlements_file
207 .as_ref()
208 .map_or(ptr::null(), |s| s.as_ptr()),
209 if dylib_ptrs.is_empty() {
210 ptr::null_mut()
211 } else {
212 dylib_ptrs.as_mut_ptr()
213 },
214 dylib_ptrs.len() as i32,
215 if self.weak_inject { 1 } else { 0 },
216 if self.force { 1 } else { 0 },
217 if self.check_signature { 1 } else { 0 },
218 temp_folder.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
219 if self.debug { 1 } else { 0 },
220 if self.quiet { 1 } else { 0 },
221 if self.enable_cache { 1 } else { 0 },
222 );
223
224 match result {
225 0 => Ok(()),
226 -1 => Err(ZSignError::SigningFailed),
227 -2 => Err(ZSignError::NotSigned),
228 code => Err(ZSignError::Unknown(code)),
229 }
230 }
231 }
232}
233
234pub fn get_version() -> String {
235 unsafe {
236 let version_ptr = get_zsign_version();
237 let version_cstr = CStr::from_ptr(version_ptr);
238 version_cstr.to_str().unwrap().to_string()
239 }
240}