whitespace fixed

This commit is contained in:
Dionysus 2024-05-11 22:21:49 -04:00
parent 3495efc8be
commit db50027ea8
Signed by: acidvegas
GPG Key ID: EF4B922DB85DC9DE
1 changed files with 126 additions and 126 deletions

242
msr90.py
View File

@ -7,162 +7,162 @@ import sys
def format_pan(pan: str) -> str: def format_pan(pan: str) -> str:
''' '''
Format the Primary Account Number (PAN) by grouping the digits in sets of 4 Format the Primary Account Number (PAN) by grouping the digits in sets of 4
:param pan: The Primary Account Number (PAN) to format :param pan: The Primary Account Number (PAN) to format
''' '''
return ' '.join(pan[i:i+4] for i in range(0, len(pan), 4)) return ' '.join(pan[i:i+4] for i in range(0, len(pan), 4))
def format_exp_date(exp_date: str) -> str: def format_exp_date(exp_date: str) -> str:
''' '''
Format the expiration date by to be MM/YY Format the expiration date by to be MM/YY
:param exp_date: The expiration date to format''' :param exp_date: The expiration date to format'''
return exp_date[2:4] + '/' + exp_date[0:2] return exp_date[2:4] + '/' + exp_date[0:2]
def service_code_descriptions(digit, code): def service_code_descriptions(digit, code):
''' '''
Get the description for the service code digit Get the description for the service code digit
:param digit: The digit number (1, 2, or 3) :param digit: The digit number (1, 2, or 3)
:param code: The code value for the digit :param code: The code value for the digit
''' '''
descriptions = { descriptions = {
'1': { '1': {
'1': 'International interchange OK', '1': 'International interchange OK',
'2': 'International interchange, use IC (chip) where feasible', '2': 'International interchange, use IC (chip) where feasible',
'5': 'National interchange only except under bilateral agreement', '5': 'National interchange only except under bilateral agreement',
'6': 'National interchange only, use IC (chip) where feasible', '6': 'National interchange only, use IC (chip) where feasible',
'7': 'No interchange except under bilateral agreement (closed loop)', '7': 'No interchange except under bilateral agreement (closed loop)',
'9': 'Test' '9': 'Test'
}, },
'2': { '2': {
'0': 'Normal', '0': 'Normal',
'2': 'Contact issuer via online means', '2': 'Contact issuer via online means',
'4': 'Contact issuer via online means except under bilateral agreement' '4': 'Contact issuer via online means except under bilateral agreement'
}, },
'3': { '3': {
'0': 'No restrictions, PIN required', '0': 'No restrictions, PIN required',
'1': 'No restrictions', '1': 'No restrictions',
'2': 'Goods and services only (no cash)', '2': 'Goods and services only (no cash)',
'3': 'ATM only, PIN required', '3': 'ATM only, PIN required',
'4': 'Cash only', '4': 'Cash only',
'5': 'Goods and services only (no cash), PIN required', '5': 'Goods and services only (no cash), PIN required',
'6': 'No restrictions, use PIN where feasible', '6': 'No restrictions, use PIN where feasible',
'7': 'Goods and services only (no cash), use PIN where feasible' '7': 'Goods and services only (no cash), use PIN where feasible'
} }
} }
return descriptions[str(digit)].get(code, 'Unknown') return descriptions[str(digit)].get(code, 'Unknown')
def parse_magnetic_stripe(data: str): def parse_magnetic_stripe(data: str):
''' '''
Parse the magnetic stripe data and print the results Parse the magnetic stripe data and print the results
:param data: The raw magnetic stripe data to parse :param data: The raw magnetic stripe data to parse
''' '''
# Patterns for specific track data parsing # Patterns for specific track data parsing
track1_pattern = r'^%([AB])(\d{1,19})\^([^\^]{2,26})\^(\d{4})(\d{3})([^\?]*?)\?(\w?)' track1_pattern = r'^%([AB])(\d{1,19})\^([^\^]{2,26})\^(\d{4})(\d{3})([^\?]*?)\?(\w?)'
track2_pattern = r';(\d{1,19})=(\d{4})(\d{3})(.*?)\?$' track2_pattern = r';(\d{1,19})=(\d{4})(\d{3})(.*?)\?$'
# Generic patterns to capture raw data if specific parsing fails # Generic patterns to capture raw data if specific parsing fails
generic_track1_pattern = r'(%[AB][^\?]+\?)' generic_track1_pattern = r'(%[AB][^\?]+\?)'
generic_track2_pattern = r'(;[^\?]+\?)' generic_track2_pattern = r'(;[^\?]+\?)'
generic_track3_pattern = r'(\+[^\?]+\?)' generic_track3_pattern = r'(\+[^\?]+\?)'
# Attempt to match the track data # Attempt to match the track data
track1_match = re.search(track1_pattern, data) track1_match = re.search(track1_pattern, data)
track2_match = re.search(track2_pattern, data) track2_match = re.search(track2_pattern, data)
track3_match = re.search(generic_track3_pattern, data) track3_match = re.search(generic_track3_pattern, data)
# Track 1 specific parsing # Track 1 specific parsing
if track1_match: if track1_match:
format_code, pan, name, exp_date, service_code, discretionary_data, lrc = track1_match.groups() format_code, pan, name, exp_date, service_code, discretionary_data, lrc = track1_match.groups()
if format_code == 'A': if format_code == 'A':
print('Error: Unsupported format code \'A\'. Exiting.') print('Error: Unsupported format code \'A\'. Exiting.')
sys.exit(1) sys.exit(1)
formatted_pan = format_pan(pan) formatted_pan = format_pan(pan)
formatted_exp_date = format_exp_date(exp_date) formatted_exp_date = format_exp_date(exp_date)
desc1 = service_code_descriptions(1, service_code[0]) desc1 = service_code_descriptions(1, service_code[0])
desc2 = service_code_descriptions(2, service_code[1]) desc2 = service_code_descriptions(2, service_code[1])
desc3 = service_code_descriptions(3, service_code[2]) desc3 = service_code_descriptions(3, service_code[2])
print_fields('Track 1 Data', [ print_fields('Track 1 Data', [
('Format Code', f'{format_code} - Financial cards (ISO/IEC 7813)'), ('Format Code', f'{format_code} - Financial cards (ISO/IEC 7813)'),
('Primary Account Number (PAN)', formatted_pan), ('Primary Account Number (PAN)', formatted_pan),
('Cardholder Name', name), ('Cardholder Name', name),
('Expiration Date', formatted_exp_date), ('Expiration Date', formatted_exp_date),
('Service Code Digit 1', f'{service_code[0]}: {desc1}'), ('Service Code Digit 1', f'{service_code[0]}: {desc1}'),
('Service Code Digit 2', f'{service_code[1]}: {desc2}'), ('Service Code Digit 2', f'{service_code[1]}: {desc2}'),
('Service Code Digit 3', f'{service_code[2]}: {desc3}'), ('Service Code Digit 3', f'{service_code[2]}: {desc3}'),
('Discretionary Data', discretionary_data), ('Discretionary Data', discretionary_data),
('LRC (optional)', lrc), ('LRC (optional)', lrc),
('Raw Track Data', track1_match.group(0)) ('Raw Track Data', track1_match.group(0))
], '\033[93m') ], '\033[93m')
# Fallback generic track 1 # Fallback generic track 1
elif re.search(generic_track1_pattern, data): elif re.search(generic_track1_pattern, data):
print('Track 1 Data:') print('Track 1 Data:')
print('Raw: ' + re.search(generic_track1_pattern, data).group(1)) print('Raw: ' + re.search(generic_track1_pattern, data).group(1))
print('\n') print('\n')
# Track 2 specific parsing # Track 2 specific parsing
if track2_match: if track2_match:
pan, exp_date, service_code, discretionary_data = track2_match.groups() pan, exp_date, service_code, discretionary_data = track2_match.groups()
formatted_pan = format_pan(pan) formatted_pan = format_pan(pan)
formatted_exp_date = format_exp_date(exp_date) formatted_exp_date = format_exp_date(exp_date)
print_fields('Track 2 Data', [ print_fields('Track 2 Data', [
('Primary Account Number (PAN)', formatted_pan), ('Primary Account Number (PAN)', formatted_pan),
('Expiration Date', formatted_exp_date), ('Expiration Date', formatted_exp_date),
('Service Code', service_code), ('Service Code', service_code),
('Discretionary Data', discretionary_data), ('Discretionary Data', discretionary_data),
('Raw Track Data', track2_match.group(0)) ('Raw Track Data', track2_match.group(0))
], '\033[96m') ], '\033[96m')
# Fallback generic track 2 # Fallback generic track 2
elif re.search(generic_track2_pattern, data): elif re.search(generic_track2_pattern, data):
print('Track 2 Data:') print('Track 2 Data:')
print('Raw: ' + re.search(generic_track2_pattern, data).group(1)) print('Raw: ' + re.search(generic_track2_pattern, data).group(1))
print('\n') print('\n')
# Track 3 generic data if found # Track 3 generic data if found
if track3_match: if track3_match:
print('Track 3 Data:') print('Track 3 Data:')
print('Raw: ' + track3_match.group(1)) print('Raw: ' + track3_match.group(1))
else: else:
print('Track 3 Data: No data found.') print('Track 3 Data: No data found.')
def print_fields(title: str, fields: list, color_code: str): def print_fields(title: str, fields: list, color_code: str):
''' '''
Print the fields in a formatted table Print the fields in a formatted table
:param title: The title of the table :param title: The title of the table
:param fields: The fields to print :param fields: The fields to print
:param color_code: The color code to use for the table :param color_code: The color code to use for the table
''' '''
max_len = max(len(name) for name, _ in fields) max_len = max(len(name) for name, _ in fields)
print(title) print(title)
for name, value in fields: for name, value in fields:
print(color_code + name.ljust(max_len) + '\033[90m | \033[0m' + value) print(color_code + name.ljust(max_len) + '\033[90m | \033[0m' + value)
if __name__ == '__main__': if __name__ == '__main__':
try: try:
swipe_data = getpass.getpass(prompt='Please swipe the card: ') swipe_data = getpass.getpass(prompt='Please swipe the card: ')
parse_magnetic_stripe(swipe_data) parse_magnetic_stripe(swipe_data)
except Exception as e: except Exception as e:
print('Error:', e) print('Error:', e)