1use emv_tlv_parser::parse_tlv;
44use std::error;
45pub mod gui; #[derive(Debug)]
48pub struct LTV {
49 pub length: usize,
50 pub tag: u8,
51 pub value: String,
52}
53pub struct PrivateTlv {
54 pub tag: String,
55 pub length: usize,
56 pub value: String,
57}
58
59pub struct Mode {
60 pub enabled_private_tlv: bool,
61 pub enabled_private_ltv: bool,
62}
63
64pub fn positions_of_set_bits(n: u64) -> Vec<u32> {
66 (0..64).filter(|&bit| 1 & (n >> (63 - bit)) != 0).map(|bit| bit + 1).collect()
67}
68
69pub trait StringManipulation {
71 fn get_slice_until(&mut self, length: usize) -> String;
73
74 fn hex_to_ascii(&mut self) -> Result<String, hex::FromHexError>;
76
77 fn process_field(&mut self, field_number: u32, length: u32, name: &str, mode: &Mode) -> String;
79
80 fn parse_private_ltv(&mut self) -> Result<Vec<LTV>, Box<dyn error::Error>>;
82
83 fn parse_private_tlv(&mut self) -> Result<Vec<PrivateTlv>, Box<dyn error::Error>>;
85}
86
87impl StringManipulation for String {
88 fn get_slice_until(&mut self, length: usize) -> String {
90 self.drain(..length).collect::<String>()
91 }
92
93 fn hex_to_ascii(&mut self) -> Result<String, hex::FromHexError> {
95 let hex_bytes = hex::decode(self)?;
96 let ascii_chars: String = hex_bytes.iter().map(|&byte| byte as char).collect();
97 Ok(ascii_chars)
98 }
99
100 fn process_field(&mut self, field_number: u32, length: u32, name: &str, mode: &Mode) -> String {
102 if self.len() == 0 {
104 return format!(
105 "Field {:3} | Length: {:3}| {:25} | Error: No data available\n",
106 field_number,
107 length,
108 name
109 );
110 }
111
112 let padded_length = if length % 2 == 1 {
113 length + 1
114 } else {
115 length
116 };
117
118 if self.len() < padded_length as usize {
120 return format!(
121 "Field {:3} | Length: {:3}| {:25} | Error: Insufficient data (needed {} bytes, had {} bytes)\n",
122 field_number,
123 length,
124 name,
125 padded_length,
126 self.len()
127 );
128 }
129
130 let mut field_value = if field_number == 35 {
131 self.get_slice_until(38.min(self.len()))
132 } else {
133 self.get_slice_until(padded_length as usize)
134 };
135
136 let value_to_print = if matches!(field_number, 37 | 38 | 41 | 42 | 44 | 49 | 50 | 51 | 62 | 116 | 122) {
137 field_value.hex_to_ascii().unwrap()
138 } else {
139 field_value.to_string()
140 };
141
142 let mut result = format!(
143 "Field {:3} | Length: {:3}| {:25} | {}\n",
144 field_number,
145 length,
146 name,
147 value_to_print.chars().take(length as usize).collect::<String>()
148 );
149
150 if field_number == 55 {
151 match parse_tlv(value_to_print) {
152 Ok(tags) => {
153 for tag in tags {
154 result.push_str(&format!("{}\n", tag));
155 }
156 }
157 Err(e) => result.push_str(&format!("Error parsing TLV: {}\n", e)),
158 }
159 } else if field_number == 48 || field_number == 121 {
160 if mode.enabled_private_tlv {
161 let mut tlv_private_value = value_to_print;
162 match tlv_private_value.parse_private_tlv() {
163 Ok(tlvs_p) => {
164 for tlv_p in tlvs_p {
165 result.push_str(&format!("{}\n", tlv_p));
166 }
167 }
168 Err(e) => result.push_str(&format!("Error parsing private tlv: {:?}\n", e)),
169 }
170 } else if mode.enabled_private_ltv {
171 let mut ltv_value = value_to_print;
172 match ltv_value.parse_private_ltv() {
173 Ok(ltvs) => {
174 for ltv in ltvs {
175 result.push_str(&format!("{}\n", ltv));
176 }
177 }
178 Err(e) => result.push_str(&format!("Error parsing LTV: {:?}\n", e)),
179 }
180 }
181 }
182
183 result
184 }
185
186
187 fn parse_private_ltv(&mut self) -> Result<Vec<LTV>, Box<dyn error::Error>> {
188 let mut ltvs = Vec::new();
189 while self.len() > 0 {
190 let length = self.drain(..2).collect::<String>().parse::<usize>()?;
191 let tag = self.drain(..2).collect::<String>().parse::<u8>()?;
192 let byte_length = (length - 1) * 2;
193 let value = self.drain(..byte_length).collect::<String>();
194 let ltv = LTV { length, tag, value};
195 ltvs.push(ltv);
196 }
197 Ok(ltvs)
198 }
199
200 fn parse_private_tlv(&mut self) -> Result<Vec<PrivateTlv>, Box<dyn error::Error>> {
201 let mut private_tlvs = Vec::new();
202 while self.len() > 0 {
203 let tag = self.drain(..4).collect::<String>().hex_to_ascii().unwrap();
204 let length_hex_string = self.drain(..4).collect::<String>().hex_to_ascii().unwrap();
205 let length = usize::from_str_radix(length_hex_string.as_str(), 16)?;
206 let byte_length = length * 2;
207 let value = self.drain(..byte_length).collect::<String>().hex_to_ascii().unwrap();
208 let private_tlv = PrivateTlv { tag, length, value};
209 private_tlvs.push(private_tlv);
210 }
211 Ok(private_tlvs)
212 }
213
214}
215
216use std::fmt;
217impl fmt::Display for LTV {
218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219 let value_string = match self.value.clone().hex_to_ascii() {
220 Ok(ascii) => format!("-> {}", ascii),
221 Err(e) => e.to_string(), };
223 write!(
224 f,
225 "\tLen: {:3} | Tag: {:3} | Val: {} {}",
226 self.length,
227 self.tag,
228 self.value,
229 value_string,
230 )
231 }
232}
233
234impl fmt::Display for PrivateTlv {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 write!(
237 f,
238 "\tTag: {:3} | Len: {:3} | Val: {}",
239 self.tag,
240 self.length,
241 self.value,
242 )
243 }
244}
245
246#[derive(Debug)]
247pub struct ParserResult {
248 pub message_length: Option<u32>,
249 pub header: Option<String>,
250 pub mti: String,
251 pub bitmap: Vec<u32>,
252 pub fields: Vec<String>, pub unparsed: String,
254}
255
256pub fn parse_iso8583(message: &str, including_header_length: bool, tlv_private: bool, ltv_private: bool) -> Result<ParserResult, Box<dyn error::Error>> {
257 let mut result = ParserResult {
258 message_length: None,
259 header: None,
260 mti: String::new(),
261 bitmap: Vec::new(),
262 fields: Vec::new(),
263 unparsed: String::new(),
264 };
265
266 let mut s = message.replace("\"", "").replace(" ", "");
267
268 if including_header_length {
269 let message_len = u32::from_str_radix(&s.get_slice_until(4), 16)? * 2;
270 result.message_length = Some(message_len);
271
272 if s.len() != message_len as usize {
273 return Err(format!("Error: Incorrect message len. The expected length is {} but The actual is {}", message_len, s.len()).into());
274 }
275 result.header = Some(s.get_slice_until(10).to_string());
276 }
277
278 result.mti = s.get_slice_until(4).to_string();
279
280 let mut bitmap: Vec<u32> = positions_of_set_bits(u64::from_str_radix(&s.get_slice_until(16), 16)?);
281 if bitmap.contains(&1) {
282 let mut positions = positions_of_set_bits(u64::from_str_radix(&s.get_slice_until(16), 16)?);
283 positions.iter_mut().for_each(|num| *num += 64);
284 bitmap.append(&mut positions);
285 bitmap.retain(|&x| x != 1);
286 }
287 result.bitmap = bitmap;
288
289 let mode = Mode {
290 enabled_private_tlv: tlv_private,
291 enabled_private_ltv: ltv_private,
292 };
293
294 for &bit in &result.bitmap {
295 let field_info = match bit {
296 2 => {
297 let pan_len: u32 = s.get_slice_until(2).parse::<u32>().unwrap();
298 Some((bit, pan_len, "PAN"))
299 }
300 3 => Some((bit, 6, "Process Code")),
301 4 => Some((bit, 12, "Transaction Amount")),
302 5 => Some((bit, 12, "Settlement Amount")),
303 6 => Some((bit, 12, "Cardholder Billing Amount")),
304 7 => Some((bit, 10, "Transaction Date and Time")),
305 9 => Some((bit, 8, "Conversion rate, settlement")),
306 10 => Some((bit, 8, "Conversion rate, cardholder billing")),
307 11 => Some((bit, 6, "Trace")),
308 12 => Some((bit, 6, "Time")),
309 13 => Some((bit, 4, "Date")),
310 14 => Some((bit, 4, "Card EXpiration Date")),
311 15 => Some((bit, 4, "Settlement Date")),
312 18 => Some((bit, 4, "Merchant Category Code")),
313 19 => Some((bit, 3, "Acquirer Country Code")),
314 22 => Some((bit, 4, "POS Entry Mode")),
315 23 => Some((bit, 3, "Card Sequence Number")),
316 24 => Some((bit, 4, "")),
317 25 => Some((bit, 2, "")),
318 32 => {
319 let field32_len: u32 = s.get_slice_until(2).parse::<u32>().unwrap();
320 Some((bit, field32_len, "Institution Identification Code Acquiring"))
321 }
322 35 => {
323 let track2_len: u32 = s.get_slice_until(2).parse::<u32>().unwrap() * 2;
324 Some((bit, track2_len, "Track2"))
325 }
326 37 => Some((bit, 24, "Retrieval Ref #")),
327 38 => Some((bit, 12, "Authorization Code")),
328 39 => Some((bit, 4, "Response Code")),
329 41 => Some((bit, 16, "Terminal")),
330 42 => Some((bit, 30, "Acceptor")),
331 43 => Some((bit, 40, "Card Acceptor Name/Location")),
332 44 => {
333 let field44_len: u32 = s.get_slice_until(2).parse::<u32>().unwrap() * 2;
334 Some((bit, field44_len, "Additional response data"))
335 }
336 45 => {
337 let track1_len: u32 = s.get_slice_until(2).parse::<u32>().unwrap();
338 Some((bit, track1_len, "Track 1 Data"))
339 }
340 48 => {
341 let field48_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
342 Some((bit, field48_len, "Aditional Data"))
343 }
344 49 => Some((bit, 6, "Transaction Currency Code")),
345 50 => Some((bit, 6, "Settlement Currency Code")),
346 51 => Some((bit, 6, "Billing Currency Code")),
347 52 => Some((bit, 16, "PinBlock")),
348 54 => {
349 let field54_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
350 Some((bit, field54_len, "Amount"))
351 }
352 55 => {
353 let field55_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
354 Some((bit, field55_len, ""))
355 }
356 60 => {
357 let field60_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
358 Some((bit, field60_len, ""))
359 }
360 62 => {
361 let field62_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
362 Some((bit, field62_len, "Private"))
363 }
364 64 => Some((bit, 16, "MAC")),
365 70 => Some((bit, 4, "")),
366 116 => {
367 let field116_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
368 Some((bit, field116_len, ""))
369 }
370 121 => {
371 let field121_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
372 Some((bit, field121_len, "Additional Data"))
373 }
374 122 => {
375 let field122_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
376 Some((bit, field122_len, "Additional Data"))
377 }
378 128 => Some((bit, 16, "MAC")),
379 _ => return Err(format!("Field {} is not implemented", bit).into()),
380 };
381
382 if let Some((field_number, length, name)) = field_info {
383 let field_data = s.process_field(field_number, length, name, &mode);
384 result.fields.push(field_data);
385 }
386 }
387
388 result.unparsed = s;
389 Ok(result)
390}
391
392#[cfg(test)]
393mod tests {
394 use crate::StringManipulation;
395 #[test]
396 fn test_parse_ltv_single() {
397 let mut s = String::from("061148656C6C6F");
398 let mut ltvs = s.parse_private_ltv().unwrap();
399
400 assert_eq!(ltvs.len(), 1);
401
402 let ltv = &mut ltvs[0];
403 assert_eq!(ltv.length, 6);
404 assert_eq!(ltv.tag, 11);
405 assert_eq!(ltv.value.hex_to_ascii().unwrap(), "Hello");
406 }
407
408 #[test]
409 fn test_parse_ltv_multiple() {
410 let mut s = String::from("031148690622576F726C64");
411 let mut ltvs = s.parse_private_ltv().unwrap();
412
413 assert_eq!(ltvs.len(), 2);
414
415 let ltv1 = &mut ltvs[0];
416 assert_eq!(ltv1.length, 3);
417 assert_eq!(ltv1.tag, 11);
418 assert_eq!(ltv1.value.hex_to_ascii().unwrap(), "Hi");
419
420 let ltv2 = &mut ltvs[1];
421 assert_eq!(ltv2.length, 6);
422 assert_eq!(ltv2.tag, 22);
423 assert_eq!(ltv2.value.hex_to_ascii().unwrap(), "World");
424 }
425
426 #[test]
427 fn test_parse_ltv_empty() {
428 let mut s = String::new();
429 let ltvs = s.parse_private_ltv();
430
431 assert!(ltvs.is_ok());
432 assert!(ltvs.unwrap().is_empty());
433 }
434
435 #[test]
436 fn error_test() {
437 let mut s = String::from("T31148690622576F726C64");
438 let ltvs = s.parse_private_ltv();
439 assert!(ltvs.is_err());
440 assert_eq!(ltvs.err().unwrap().to_string().as_str(), "invalid digit found in string");
441 }
442
443}