From 762eabad6d83ac8d85f270afd33c1440e26347f2 Mon Sep 17 00:00:00 2001 From: misomosi Date: Mon, 3 Aug 2026 13:38:33 -0400 Subject: [PATCH] Add magstripe serialization program for MSR605X --- MSR605X/mxser.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 MSR605X/mxser.py diff --git a/MSR605X/mxser.py b/MSR605X/mxser.py new file mode 100644 index 0000000..b99a7da --- /dev/null +++ b/MSR605X/mxser.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +import argparse +import datetime +import getpass +import sys + +def main(argv): + parser = argparse.ArgumentParser(prog=argv[0]) + parser.add_argument('-n', '--name', default='', help='Name of card holder') + parser.add_argument('-e', '--expires', default='9912', help='Date of expiration on card (Format: YYMM)') + parser.add_argument('-s', '--service', default='121', help='Service code of card (TODO: help for service code)') + parser.add_argument('-p', '--pan', default='', help='Primary account number of card (CAUTION: COMMAND LINE SAVED IN SHELL HISTORIES)') + parser.add_argument('FILE') + args = parser.parse_args(args=argv[1:]) + + exitcode = 0 + NAME = args.name + if len(NAME) != 0 and not NAME.isalnum(): + print(f'Name ({NAME}) is not alphanumeric!') + exitcode |= 2 + if len(NAME) > 26: + print(f'Name ({NAME}) is longer than 26 characters!') + exitcode |= 2 + + SVC = args.service + if len(SVC) != 0 and not SVC.isdigit(): + print(f'Service code ({SVC}) is not numeric, not 3 characters, or is not a known service code!') + exitcode |= 4 + if len(SVC) != 3: + print(f'Service code ({SVC}) is not 3 characters, or is not a known service code!') + exitcode |= 4 + if SVC[0] not in '125679' or SVC[1] not in '024' or SVC[2] not in '01234567': + print(f'Service code ({SVC}) is not a known service code!') + exitcode |= 4 + + EXP = args.expires + if len(EXP) != 0 and not EXP.isdigit(): + print(f'Expiration date ({EXP}) is not numeric, not 4 characters, not a valid date, or is already expired!') + exitcode |= 8 + if len(EXP) != 4: + print(f'Expiration date ({EXP}) is not 4 characters') + exitcode |= 8 + if not (1 <= int(EXP[2:4]) <= 12): + print(f'Expiration date ({EXP}) is not a valid date, or is already expired!') + exitcode |= 8 + + TODAY = datetime.datetime.now() + if datetime.datetime(2000 + int(EXP[0:2]), int(EXP[2:4]), 1) <= TODAY: + print(f'Expiration date ({EXP}) is not a valid date, or is already expired!') + exitcode |= 8 + + PAN = args.pan + if not PAN and exitcode == 0: + PAN = getpass.getpass("Enter PAN here: ") + if not PAN.isdigit() or len(PAN) >= 20: + print(f'Primary account number is not numeric or is longer than 19 characters!') + exitcode |= 16 + + if exitcode != 0: + return exitcode + + # Write file and add a couple of newlines normally emitted by the + # MSR605X reader/writer program when reading magstripe cards + T1 = f'%B{PAN}^{NAME}^{EXP}{SVC}^^^?' + T2 = f';{PAN}={EXP}{SVC}===?' + T3 = '+?' + with open(args.FILE, 'w') as fp: + datestr = TODAY.strftime('%Y.%m.%d %H:%M:%S') + fp.write('\n'.join([datestr, T1, T2, T3, '', ''])) + + return 0 + +if __name__ == '__main__': + sys.exit(main(sys.argv)) -- 2.49.1