def parse_key_pack(data): def get_pack_dict(pack): tag_dict = dict() tag_info = pack.split(b'\xdf') if tag_info[0][1] == len(pack[2:]): tag_info.pop(0) for tag in tag_info: if tag[1] == len(tag[2:]): tag_dict.update( {f'DF{hex(tag[0]).replace("0x", "")}': tag[2:]}) else: resp_gen.set_logging() logging.error( f'ERROR: missing data in tag: DF{hex(tag[0]).replace("0x", "")}\nPack:{pack}' ) else: resp_gen.set_logging() logging.error( f'ERROR: missing data in package №{tag_info[0][0]}\nPack:{pack}' ) return tag_dict res_dict = dict() packs = data.split(b'\xff')[1:] for p in packs: tmp_dict = get_pack_dict(p) try: res_dict.update({tmp_dict['DF24']: tmp_dict}) except KeyError: resp_gen.set_logging() logging.error( f'ERROR: missing tag DF24 in package №{p[0]}\nPack:{p}') return res_dict
def clear_resource(res): try: if res in INPUT_DATA: INPUT_DATA.remove(res) if res in OUTPUT_DATA: OUTPUT_DATA.remove(res) print(f'Connection closed:{str(res.getpeername())}\n') resp_gen.set_logging(); logging.info(f'Connection closed:{str(res)}') res.close() except Exception as e: resp_gen.set_logging() logging.error(f'ERROR:\n{e}')
def handle_writables(writs): for resource in writs: try: if PROTOCOL == 'TPTP': req = LAST_REQUEST[resource.getpeername()].decode('utf-8') resp = resp_gen.form_answer(req, RC_DICT, status_ready(resource.getpeername(), req)) elif PROTOCOL == 'OWN': req = LAST_REQUEST[resource.getpeername()] resp = open_way.form_answer(req, OWN_RC_DICT, status_ready(resource.getpeername(), req)) else: resp = None if resp and ready_to_answer(resource.getpeername(), resp): if PROTOCOL == 'TPTP': print(f'RESPONSE TO {resource.getpeername()}:\n{resp_gen.print_req_res(resp)}\n') resp_gen.set_logging() logging.info(f'RESPONSE TO {resource.getpeername()}:{str(resp)}') if PRINT_HEX: print(resp_gen.print_hex_dump(resp)) if PARSE: values = resp_gen.parse_data(resp) if values: resp_gen.print_result(values) resource.send(resp) OUTPUT_DATA.remove(resource) if resp.decode('utf-8').find('SUCCESS') != -1 or resp.decode('utf-8').find('FAILED') != -1: for peer in STATUS_TIMER_LIST: if resource.getpeername() in peer: STATUS_TIMER_LIST.pop(STATUS_TIMER_LIST.index(peer)) elif PROTOCOL == 'OWN': print(f'RESPONSE TO {resource.getpeername()}:\n{resp}\n') resp_gen.set_logging() logging.info(f'RESPONSE TO {resource.getpeername()}:{str(resp)}') if PRINT_HEX: print(resp_gen.print_hex_dump(resp[2:])) if PARSE: values = open_way.get_values(resp) if values: open_way.print_result(values) resource.send(resp) OUTPUT_DATA.remove(resource) if resp[2:4] == b'\x06\x30' and resp[43:45] != b'09': for peer in STATUS_TIMER_LIST: if resource.getpeername() in peer: STATUS_TIMER_LIST.pop(STATUS_TIMER_LIST.index(peer)) except OSError: clear_resource(resource)
def handle_readables(reads, server): for resource in reads: if resource is server: conn, addr = resource.accept() conn.setblocking(False) INPUT_DATA.append(conn) print(f'New connection:{addr}\n') resp_gen.set_logging(); logging.info(f'New connection:{str(conn)}') if PROTOCOL == 'TPTP': conn.send(b'\x05') else: data = b'' try: data = resource.recv(1024) except ConnectionResetError: pass if data: if PROTOCOL == 'TPTP': print(f'REQUEST FROM {resource.getpeername()}:\n{resp_gen.print_req_res(data)}\n') elif PROTOCOL == 'OWN': print(f'REQUEST FROM {resource.getpeername()}:\n{data}\n') resp_gen.set_logging() logging.info(f'REQUEST FROM {resource.getpeername()}:{str(data)}') if PRINT_HEX: if PROTOCOL == 'TPTP': print(resp_gen.print_hex_dump(data)) elif PROTOCOL == 'OWN': print(resp_gen.print_hex_dump(data[2:])) if PARSE: if PROTOCOL == 'OWN': values = open_way.get_values(data) if values: open_way.print_result(values) elif PROTOCOL == 'TPTP': values = resp_gen.parse_data(data) if values: resp_gen.print_result(values) if resource.getpeername() not in LAST_REQUEST: LAST_REQUEST.update({resource.getpeername(): data}) else: LAST_REQUEST[resource.getpeername()] = data if resource not in OUTPUT_DATA: OUTPUT_DATA.append(resource) else: clear_resource(resource)
def get_pack_dict(pack): tag_dict = dict() tag_info = pack.split(b'\xdf') if tag_info[0][1] == len(pack[2:]): tag_info.pop(0) for tag in tag_info: if tag[1] == len(tag[2:]): tag_dict.update( {f'DF{hex(tag[0]).replace("0x", "")}': tag[2:]}) else: resp_gen.set_logging() logging.error( f'ERROR: missing data in tag: DF{hex(tag[0]).replace("0x", "")}\nPack:{pack}' ) else: resp_gen.set_logging() logging.error( f'ERROR: missing data in package №{tag_info[0][0]}\nPack:{pack}' ) return tag_dict
def ready_to_answer(addr, resp=None): for conn in TIMER_CONN_LIST: if addr in conn: if time.perf_counter() > conn[1]: TIMER_CONN_LIST.pop(TIMER_CONN_LIST.index(conn)) return True else: return False else: cur_time = time.perf_counter() if len(resp) >= 10: try: if resp[41:43] == b'00' or resp[2:4] == b'\x94\x30': TIMER_CONN_LIST.append([addr, cur_time + DELAY['VOID']]) elif resp[41:43] == b'01' or resp[2:4] == b'\x97\x10': TIMER_CONN_LIST.append([addr, cur_time + DELAY['QR_CODE']]) elif resp[41:43] == b'02' or resp[2:4] == b'\x02\x30': TIMER_CONN_LIST.append([addr, cur_time + DELAY['FINAL']]) elif resp[41:43] == b'04' or resp[2:4] == b'\x02\x10': TIMER_CONN_LIST.append([addr, cur_time + DELAY['REFUND']]) elif resp[41:43] == b'36' or resp[2:4] == b'\x06\x30': TIMER_CONN_LIST.append([addr, cur_time + DELAY['STATUS']]) else: TIMER_CONN_LIST.append([addr, cur_time + DELAY['DEFAULT']]) for connect in TIMER_CONN_LIST: if addr in connect: if TIMER_CONN_LIST[TIMER_CONN_LIST.index(connect)][1] == cur_time: return True else: return False except TypeError as e: resp_gen.set_logging(); logging.error(f'ERROR:\n{e}') return False else: if resp: TIMER_CONN_LIST.append([addr, cur_time + DELAY['CLOSE_OP']]) return False
def print_result(raw_dict): bytes_list = [2, 3, 4, 7, 11, 12, 13, 14, 22, 24, 25, 48, 49, 64] string_list = [37, 38, 39, 41, 42, 60, 63] try: for field in raw_dict: if int(field) in bytes_list: res = list() for value in raw_dict[field]: tmp = hex(value).replace('0x', '') if len(tmp) < 2: tmp = ''.join(['0', tmp]) res.append(tmp) raw_dict[field] = ''.join(res) elif int(field) in string_list: raw_dict[field] = raw_dict[field].decode('utf-8') elif int(field) == 61: raw_dict[field] = raw_dict[field][10:].decode('utf-8') except Exception as e: resp_gen.set_logging() logging.error(f'ERROR:\n{e}') for f in raw_dict: print('{:3}: {}'.format(f, raw_dict[f])) print('\n', end='')
def go_to_key_files(): global INI_KEYS INI_KEYS = dict() if os.path.exists('keys'): file = None for term_file in os.listdir('keys'): if '.ini' in term_file: if ''.join([TERMINAL, '.ini']) == term_file: file = os.path.join('keys', term_file) elif ''.join(['NEW_', TERMINAL, '.ini']) == term_file: try: new_conf = Config(os.path.join('keys', term_file)).as_args() comp_1 = new_conf[new_conf.index('--KLK-Component-1') + 1].zfill(32).upper() comp_2 = new_conf[new_conf.index('--KLK-Component-2') + 1].zfill(32).upper() if (not re.match(r'[\dABCDEF]{32}', comp_1) or not re.match(r'[\dABCDEF]{32}', comp_2) or comp_1 == '0' * 32 and comp_2 == '0' * 32): raise ValueError new_klk = DES3.new( unhexlify(klk_compile(comp_1, comp_2)), DES3.MODE_ECB) klk_cv = new_klk.encrypt(unhexlify( '0' * 32)).hex().upper()[:6] os.remove(os.path.join(os.getcwd(), 'keys', term_file)) INI_KEYS.update({ 'KLK': { 'BODY': klk_compile(comp_1, comp_2), 'CV': klk_cv, 'INDEX': '0' } }) return True except ValueError: print( f'Wrong values in {term_file}, please try again.\n' ) else: try: os.remove(os.path.join(os.getcwd(), 'keys', term_file)) except PermissionError: shutil.rmtree(os.path.join(os.getcwd(), 'keys', term_file), ignore_errors=True) if file: try: conf_vals = Config(file).as_args() for i in range(len(conf_vals) // 2): key_vals = conf_vals[i * 2 + 1].split('|') if ((not re.match(r'[\dABCDEF]{32}', key_vals[0]) or len(key_vals[0]) != 32) or (not re.match(r'[\dABCDEF]{6}', key_vals[1]) or len(key_vals[1]) != 6) or not re.match(r'\d+', key_vals[2])): raise IndexError INI_KEYS.update({ conf_vals[i * 2].split('-')[-1]: { 'BODY': key_vals[0], 'CV': key_vals[1], 'INDEX': key_vals[2] } }) if INI_KEYS: return True return False except IndexError: resp_gen.set_logging() logging.error(f'Error while parsing file {file}') return False else: gen_new_ini_file() return False else: os.mkdir('keys') return go_to_key_files()
def form_answer(request, rc_dict, status_ready): def qr_code_resp(): fields_list = [3, 4, 7, 11, 12, 13, 37, 38, 39, 41, 49, 61] datetime_dict = get_date_time() massage_type = b'\x97\x10' bitmap = get_bitmap(fields_list) processing_code = b'\x38\x00\x00' # 3 amount = parsed_req['4'] # 4 trans_date_time = b''.join([datetime_dict['date'], datetime_dict['time']]) # 7 audit_number = parsed_req['11'] # 11 trans_time = datetime_dict['time'] # 12 trans_date = datetime_dict['date'] # 13 retrieval_ref = str(datetime.datetime.now().time()).replace('.', '').replace(':', '').encode('utf-8') # 37 auth_code = ''.join([str(randint(0, 9)) for i in range(6)]).encode('utf-8') # 38 resp_code = b'00' # 39 acceptor_terminal = parsed_req['41'] # 41 currency = parsed_req['49'] # 49 qr_code = b'\x00\x00\x26\xeb\x18\xf2\x16\xc2\x14\x54https://example.com' # 61 resp_no_len = b''.join([massage_type, bitmap, processing_code, amount, trans_date_time, audit_number, trans_time, trans_date, retrieval_ref, auth_code, resp_code, acceptor_terminal, currency, qr_code]) response = b''.join([convert_len_to_bytes(len(resp_no_len)), resp_no_len]) return response def status_resp(): fields_list = [4, 7, 11, 12, 13, 37, 39, 41, 49] datetime_dict = get_date_time() massage_type = b'\x06\x30' bitmap = get_bitmap(fields_list) amount = parsed_req['4'] # 4 trans_date_time = b''.join([datetime_dict['date'], datetime_dict['time']]) # 7 audit_number = parsed_req['11'] # 11 trans_time = datetime_dict['time'] # 12 trans_date = datetime_dict['date'] # 13 retrieval_ref = parsed_req['37'] # 37 if status_ready: # - if b'SBPAY' in parsed_req['63']: # - resp_code = rc_dict['sale_rc'] # 39 else: # - resp_code = b'00' # 39 else: # - resp_code = b'09' # 39 acceptor_terminal = parsed_req['41'] # 41 currency = parsed_req['49'] # 49 resp_no_len = b''.join([massage_type, bitmap, amount, trans_date_time, audit_number, trans_time, trans_date, retrieval_ref, resp_code, acceptor_terminal, currency]) response = b''.join([convert_len_to_bytes(len(resp_no_len)), resp_no_len]) return response def final_sale_resp(): fields_list = [3, 7, 11, 12, 13, 37, 38, 39, 41, 49] datetime_dict = get_date_time() massage_type = b'\x02\x30' bitmap = get_bitmap(fields_list) processing_code = b'\x00\x00\x00' # 3 trans_date_time = b''.join([datetime_dict['date'], datetime_dict['time']]) # 7 audit_number = parsed_req['11'] # 11 trans_time = datetime_dict['time'] # 12 trans_date = datetime_dict['date'] # 13 retrieval_ref = parsed_req['37'] # 37 auth_code = ''.join([str(randint(0, 9)) for i in range(6)]).encode('utf-8') # 38 resp_code = rc_dict['sale_rc'] # 39 acceptor_terminal = parsed_req['41'] # 41 currency = parsed_req['49'] # 49 resp_no_len = b''.join([massage_type, bitmap, processing_code, trans_date_time, audit_number, trans_time, trans_date, retrieval_ref, auth_code, resp_code, acceptor_terminal, currency]) response = b''.join([convert_len_to_bytes(len(resp_no_len)), resp_no_len]) return response def refund_resp(): fields_list = [2, 3, 7, 11, 12, 13, 37, 38, 39, 41, 49] datetime_dict = get_date_time() massage_type = b'\x02\x10' bitmap = get_bitmap(fields_list) pan = b''.join([get_bytes(str(len(parsed_req['2']) * 2)), parsed_req['2']]) # 2 processing_code = b'\x25\x00\x00' # 3 trans_date_time = b''.join([datetime_dict['date'], datetime_dict['time']]) # 7 audit_number = parsed_req['11'] # 11 trans_time = datetime_dict['time'] # 12 trans_date = datetime_dict['date'] # 13 retrieval_ref = ''.join([str(randint(0, 9)) for i in range(12)]).encode('utf-8') # 37 auth_code = ''.join([str(randint(0, 9)) for i in range(6)]).encode('utf-8') # 38 resp_code = rc_dict['refund_rc'] # 39 acceptor_terminal = parsed_req['41'] # 41 currency = parsed_req['49'] # 49 resp_no_len = b''.join([massage_type, bitmap, pan, processing_code, trans_date_time, audit_number, trans_time, trans_date, retrieval_ref, auth_code, resp_code, acceptor_terminal, currency]) response = b''.join([convert_len_to_bytes(len(resp_no_len)), resp_no_len]) return response def qr_rev_resp(): fields_list = [3, 7, 11, 12, 13, 37, 38, 39, 41, 49] datetime_dict = get_date_time() massage_type = b'\x94\x30' bitmap = get_bitmap(fields_list) processing_code = b'\x38\x00\x00' # 3 trans_date_time = b''.join([datetime_dict['date'], datetime_dict['time']]) # 7 audit_number = parsed_req['11'] # 11 trans_time = datetime_dict['time'] # 12 trans_date = datetime_dict['date'] # 13 try: # - retrieval_ref = parsed_req['37'] # 37 except KeyError: # - retrieval_ref = ''.join([str(randint(0, 9)) for i in range(12)]).encode('utf-8') # 37 auth_code = ''.join([str(randint(0, 9)) for i in range(6)]).encode('utf-8') # 38 resp_code = b'00' # 39 acceptor_terminal = parsed_req['41'] # 41 currency = parsed_req['49'] # 49 resp_no_len = b''.join([massage_type, bitmap, processing_code, trans_date_time, audit_number, trans_time, trans_date, retrieval_ref, auth_code, resp_code, acceptor_terminal, currency]) response = b''.join([convert_len_to_bytes(len(resp_no_len)), resp_no_len]) return response def close_batch_resp(): fields_list = [3, 7, 11, 12, 13, 37, 39, 41, 60] datetime_dict = get_date_time() massage_type = b'\x05\x10' bitmap = get_bitmap(fields_list) processing_code = b'\x92\x00\x00' # 3 trans_date_time = b''.join([datetime_dict['date'], datetime_dict['time']]) # 7 audit_number = parsed_req['11'] # 11 trans_time = datetime_dict['time'] # 12 trans_date = datetime_dict['date'] # 13 retrieval_ref = ''.join([str(randint(0, 9)) for i in range(12)]).encode('utf-8') # 37 if rc_dict['cl_batch']: # - resp_code = b'00' # 39 else: # - resp_code = b'01' # 39 acceptor_terminal = parsed_req['41'] # 41 original_element = b''.join([b'\x00\x06', parsed_req['60']]) # 60 resp_no_len = b''.join([massage_type, bitmap, processing_code, trans_date_time, audit_number, trans_time, trans_date, retrieval_ref, resp_code, acceptor_terminal, original_element]) response = b''.join([convert_len_to_bytes(len(resp_no_len)), resp_no_len]) return response def reversal_resp(): fields_list = [2, 3, 4, 7, 11, 12, 13, 24, 37, 39, 41, 49] datetime_dict = get_date_time() massage_type = b'\x05\x10' bitmap = get_bitmap(fields_list) pan = b''.join([get_bytes(str(len(parsed_req['2']) * 2)), parsed_req['2']]) # 2 processing_code = parsed_req['3'] # 3 amount = parsed_req['4'] # 4 trans_date_time = b''.join([datetime_dict['date'], datetime_dict['time']]) # 7 audit_number = parsed_req['11'] # 11 trans_time = datetime_dict['time'] # 12 trans_date = datetime_dict['date'] # 13 func_code = parsed_req['24'] # 24 retrieval_ref = ''.join([str(randint(0, 9)) for i in range(12)]).encode('utf-8') # 37 resp_code = b'00' # 39 acceptor_terminal = parsed_req['41'] # 41 currency = parsed_req['49'] # 49 resp_no_len = b''.join([massage_type, bitmap, pan, processing_code, amount, trans_date_time, audit_number, trans_time, trans_date, func_code, retrieval_ref, resp_code, acceptor_terminal, currency]) response = b''.join([convert_len_to_bytes(len(resp_no_len)), resp_no_len]) return response def key_export_resp(): fields_list = [3, 7, 11, 12, 13, 39, 41] datetime_dict = get_date_time() massage_type = b'\x08\x10' processing_code = parsed_req['3'] # 3 trans_date_time = b''.join([datetime_dict['date'], datetime_dict['time']]) # 7 audit_number = parsed_req['11'] # 11 trans_time = datetime_dict['time'] # 12 trans_date = datetime_dict['date'] # 13 resp_code = rc_dict['key_decline_rc'] # 39 acceptor_terminal = parsed_req['41'] # 41 additional_data = key_manager.gen_key_field(parsed_req['48'], parsed_req['41']) # 48 if additional_data: resp_code = b'00' fields_list.append(48) additional_data = b''.join([get_bytes(str(len(additional_data))), additional_data]) bitmap = get_bitmap(fields_list) resp_no_len = b''.join([massage_type, bitmap, processing_code, trans_date_time, audit_number, trans_time, trans_date, resp_code, acceptor_terminal, additional_data]) response = b''.join([convert_len_to_bytes(len(resp_no_len)), resp_no_len]) return response try: parsed_req = get_values(request) if request[2:4] == b'\x97\x00': return qr_code_resp() elif request[2:4] == b'\x06\x20': return status_resp() elif request[2:4] == b'\x02\x20': return final_sale_resp() elif request[2:4] == b'\x02\x00': return refund_resp() elif request[2:4] == b'\x94\x20': return qr_rev_resp() elif request[2:4] == b'\x05\x00' or request[2:4] == b'\x05\x01': return close_batch_resp() elif request[2:4] == b'\x04\x20' or request[2:4] == b'\x04\x21': return reversal_resp() elif request[2:4] == b'\x08\x00': return key_export_resp() else: return None except Exception as e: resp_gen.set_logging() logging.error(f'ERROR:\n{e}') return None
if __name__ == '__main__': os.system('cls') setup_vars() # initiates variables time.perf_counter() # initiates timer resp_gen.check_log_files() # controls maximal log files try: srv_socket = get_server_socket() except OSError: print('Program is already running or address/port is wrong!') input('Press ENTER to exit.') sys.exit() INPUT_DATA.append(srv_socket) length = shutil.get_terminal_size()[0] fin_length = length - ((length - 25) // 2) - 25 header = f'{"-" * ((length - 25) // 2)}Alipay test server v{version.get_version()}{"-" * fin_length}' resp_gen.set_logging(); logging.info(f'Server started {srv_socket}') print(header) try: while INPUT_DATA: readables, writables, exceptional = select(INPUT_DATA, OUTPUT_DATA, INPUT_DATA) handle_readables(readables, srv_socket) handle_writables(writables) except KeyboardInterrupt: clear_resource(srv_socket) print('Server stopped!') resp_gen.set_logging(); logging.info('Server stopped!')