--- /dev/null
+#!/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))