def parse_oem_options(api_key): """ 解析oem帐号选项 :param api_key: """ if not isinstance(api_key, str): return None if not OEM_KEY_PATTERN.search(api_key): #正则已修改 return None if api_key.startswith('a685'): #兼容山西旧key api_key = '9006' head = int(api_key[:4], 16) #版本 ver = span_bits(head, 15, 12) if not (ver >> 3): return None ver &= 0b111 #todo: 检查版本号 #短信相关选项。批量推送,凌拓帐号,短信,手机号码,密码 return span_bits(head, 5, 0, 0)
def extract_ref_l(ref): """ 解析ref:长字符串 :param ref: :return: """ logger.debug('extract ref begin') if not ref or not isinstance(ref, str) or ref == '': return None ref = rc4_decrypt(ref, ref_pwd, a2b_hex) logger.debug(u'ref = %r', ref) if len(ref) <= 3: #至少要求3字节 return None head, acc_len, key_cipher_len = struct.unpack('>BBB', ref[:3]) logger.debug(u'head = %r, acc_len = %r, key_cipher_len = %r', head, acc_len, key_cipher_len) if len(ref) != 3 + acc_len + key_cipher_len + MAX_FILENAME_LEN: return None acc = ref[3:acc_len + 3] key_cipher = ref[acc_len + 3:acc_len + 3 + key_cipher_len] logger.debug(u'acc = %r, key_cipher = %r', acc, key_cipher) logger.debug(u'rc4 decrypt result = %r', rc4_decrypt(key_cipher, ref_pwd, None)) if acc != rc4_decrypt(key_cipher, ref_pwd, None): return None share, by_app = span_bits(head, 7, 6, 0) logger.debug('extract ref end') return share, by_app, acc, unpad(ref[-MAX_FILENAME_LEN:])
def extract_ref_s(ref): """ 解析ref:短字符串 :param ref: :return: """ b64str = base64.b64decode(str(ref)) head, acc_len = struct.unpack('>BB', b64str[:2]) share, by_app = span_bits(head, 7, 6, 0) return share, by_app, b64str[2:acc_len + 2], b64str[acc_len + 2:]
def parse_io_options(bits, split=True): """ io选项在绑定设备和用户关系时需要提取,其他时候用不到 id格式的转换需要把io选项排除在外 :param split: io选项拆分 """ assert isinstance(bits, int) and bits <= 0b111 if not split: return bits # 数据,短信,蓝牙 return span_bits(bits, 2, 0, 0)
def extract_tk_s(tk, ul): """ :param ul: 上传:短字符串 """ b64str = base64.b64decode(str(tk)) head, acc_len = struct.unpack('>BB', b64str[:2]) share, by_app, is_ul = span_bits(head, 7, 5, 0) #10分钟有效 ts_offset = 2 + acc_len t = struct.unpack('>I', b64str[ts_offset:ts_offset + 4])[0] if time.time() - t >= 600: return None return share, by_app, b64str[2:acc_len + 2], b64str[ts_offset + 4:]
def extract_tk_l(tk, ul): """ :param ul: 上传:长字符串 """ logger.debug('extract tk begin') if not tk or not isinstance(tk, str) or len(tk) <= 2: logger.info('tk too short') return None tk = rc4_decrypt(tk, tk_pwd, a2b_hex) logger.debug(u'tk = %r', tk) rnd, val = tk[-2:] val = rc4_decrypt(val, tk_pwd, None) logger.debug('rnd = %r, val = %r', rnd, val) rnd = struct.unpack('>B', rnd)[0] val = struct.unpack('>B', val)[0] logger.debug('rnd = %r, val = %r', rnd, val) if rnd + 1 != val: logger.warn('rnd={0} & val={1} unmatch'.format(rnd, val)) return None head, acc_len = struct.unpack('>BB', tk[:2]) logger.debug('head = %r, acc_len = %r', head, acc_len) if len(tk) != 2 + acc_len + 4 + MAX_FILENAME_LEN + 2: logger.warn('tk len not ok') return None #10分钟有效 ts_offset = 2 + acc_len t = struct.unpack('>I', tk[ts_offset:ts_offset + 4])[0] now = time.time() logger.debug('now = %r, t = %r', now, t) if now - struct.unpack('>I', tk[ts_offset:ts_offset + 4])[0] >= 600: logger.warn('tk timeout') logger.debug('now = %r, t = %r', now, t) return None share, by_app, is_ul = span_bits(head, 7, 5, 0) logger.debug('share = %r, by_app = %r, is_ul = %r, ul=%r', share, by_app, is_ul, ul) if is_ul != ul: logger.warn('ul param invalid') return None logger.debug('extract tk end') return share, by_app, tk[2:acc_len + 2], unpad(tk[ts_offset + 4:ts_offset + 4 + MAX_FILENAME_LEN])