|
@@ -32,14 +32,14 @@ class WXBot:
|
|
|
self.skey = ''
|
|
|
self.pass_ticket = ''
|
|
|
self.deviceId = 'e' + repr(random.random())[2:17]
|
|
|
- self.BaseRequest = {}
|
|
|
- self.synckey = ''
|
|
|
- self.SyncKey = []
|
|
|
- self.User = []
|
|
|
- self.MemberList = []
|
|
|
- self.ContactList = []
|
|
|
- self.GroupList = []
|
|
|
- self.syncHost = ''
|
|
|
+ self.base_request = {}
|
|
|
+ self.sync_key_str = ''
|
|
|
+ self.sync_key = []
|
|
|
+ self.user = []
|
|
|
+ self.member_list = []
|
|
|
+ self.contact_list = []
|
|
|
+ self.group_list = []
|
|
|
+ self.sync_host = ''
|
|
|
self.session = requests.Session()
|
|
|
self.session.headers.update({'User-Agent': 'Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5'})
|
|
|
|
|
@@ -89,9 +89,9 @@ class WXBot:
|
|
|
self.base_uri = redirect_uri[:redirect_uri.rfind('/')]
|
|
|
return True
|
|
|
elif code == '408':
|
|
|
- print '[login timeout]'
|
|
|
+ print '[ERROR] WeChat login timeout .'
|
|
|
else:
|
|
|
- print '[login exception]'
|
|
|
+ print '[ERROR] WeChat login exception .'
|
|
|
return False
|
|
|
|
|
|
def login(self):
|
|
@@ -114,7 +114,7 @@ class WXBot:
|
|
|
if '' in (self.skey, self.sid, self.uin, self.pass_ticket):
|
|
|
return False
|
|
|
|
|
|
- self.BaseRequest = {
|
|
|
+ self.base_request = {
|
|
|
'Uin': self.uin,
|
|
|
'Sid': self.sid,
|
|
|
'Skey': self.skey,
|
|
@@ -125,24 +125,24 @@ class WXBot:
|
|
|
def init(self):
|
|
|
url = self.base_uri + '/webwxinit?r=%i&lang=en_US&pass_ticket=%s' % (int(time.time()), self.pass_ticket)
|
|
|
params = {
|
|
|
- 'BaseRequest': self.BaseRequest
|
|
|
+ 'BaseRequest': self.base_request
|
|
|
}
|
|
|
r = self.session.post(url, json=params)
|
|
|
r.encoding = 'utf-8'
|
|
|
dic = json.loads(r.text)
|
|
|
- self.SyncKey = dic['SyncKey']
|
|
|
- self.User = dic['User']
|
|
|
- self.synckey = '|'.join([ str(keyVal['Key']) + '_' + str(keyVal['Val']) for keyVal in self.SyncKey['List'] ])
|
|
|
+ self.sync_key = dic['SyncKey']
|
|
|
+ self.user = dic['User']
|
|
|
+ self.sync_key_str = '|'.join([ str(keyVal['Key']) + '_' + str(keyVal['Val']) for keyVal in self.sync_key['List'] ])
|
|
|
return dic['BaseResponse']['Ret'] == 0
|
|
|
|
|
|
def status_notify(self):
|
|
|
url = self.base_uri + '/webwxstatusnotify?lang=zh_CN&pass_ticket=%s' % (self.pass_ticket)
|
|
|
- self.BaseRequest['Uin'] = int(self.BaseRequest['Uin'])
|
|
|
+ self.base_request['Uin'] = int(self.base_request['Uin'])
|
|
|
params = {
|
|
|
- 'BaseRequest': self.BaseRequest,
|
|
|
+ 'BaseRequest': self.base_request,
|
|
|
"Code": 3,
|
|
|
- "FromUserName": self.User['UserName'],
|
|
|
- "ToUserName": self.User['UserName'],
|
|
|
+ "FromUserName": self.user['UserName'],
|
|
|
+ "ToUserName": self.user['UserName'],
|
|
|
"ClientMsgId": int(time.time())
|
|
|
}
|
|
|
r = self.session.post(url, json=params)
|
|
@@ -158,32 +158,36 @@ class WXBot:
|
|
|
with open('contacts.json', 'w') as f:
|
|
|
f.write(r.text.encode('utf-8'))
|
|
|
dic = json.loads(r.text)
|
|
|
- self.MemberList = dic['MemberList']
|
|
|
+ self.member_list = dic['MemberList']
|
|
|
|
|
|
- ContactList = self.MemberList[:]
|
|
|
+ contact_list = self.member_list[:]
|
|
|
SpecialUsers = ['newsapp','fmessage','filehelper','weibo','qqmail','fmessage','tmessage','qmessage','qqsync','floatbottle','lbsapp','shakeapp','medianote',
|
|
|
'qqfriend','readerapp','blogapp','facebookapp','masssendapp','meishiapp','feedsapp','voip','blogappweixin','weixin','brandsessionholder','weixinreminder','wxid_novlwrv3lqwv11',
|
|
|
'gh_22b87fa7cb3c','officialaccounts','notification_messages','wxid_novlwrv3lqwv11','gh_22b87fa7cb3c','wxitil','userexperience_alarm','notification_messages']
|
|
|
- for contact in ContactList:
|
|
|
+ for contact in contact_list:
|
|
|
if contact['VerifyFlag'] & 8 != 0: # public account
|
|
|
- ContactList.remove(contact)
|
|
|
+ contact_list.remove(contact)
|
|
|
elif contact['UserName'] in SpecialUsers: # special account
|
|
|
- ContactList.remove(contact)
|
|
|
+ contact_list.remove(contact)
|
|
|
elif contact['UserName'].find('@@') != -1: # group
|
|
|
- self.GroupList.append(contact)
|
|
|
- ContactList.remove(contact)
|
|
|
- elif contact['UserName'] == self.User['UserName']: # self
|
|
|
- ContactList.remove(contact)
|
|
|
- self.ContactList = ContactList
|
|
|
+ self.group_list.append(contact)
|
|
|
+ contact_list.remove(contact)
|
|
|
+ elif contact['UserName'] == self.user['UserName']: # self
|
|
|
+ contact_list.remove(contact)
|
|
|
+ self.contact_list = contact_list
|
|
|
+
|
|
|
+ if self.DEBUG:
|
|
|
+ with open('contactlist.json', 'w') as f:
|
|
|
+ f.write(json.dumps(self.contact_list))
|
|
|
|
|
|
return True
|
|
|
|
|
|
def batch_get_contact(self):
|
|
|
url = self.base_uri + '/webwxbatchgetcontact?type=ex&r=%s&pass_ticket=%s' % (int(time.time()), self.pass_ticket)
|
|
|
params = {
|
|
|
- 'BaseRequest': self.BaseRequest,
|
|
|
- "Count": len(self.GroupList),
|
|
|
- "List": [ {"UserName": g['UserName'], "EncryChatRoomId":""} for g in self.GroupList ]
|
|
|
+ 'BaseRequest': self.base_request,
|
|
|
+ "Count": len(self.group_list),
|
|
|
+ "List": [ {"UserName": g['UserName'], "EncryChatRoomId":""} for g in self.group_list ]
|
|
|
}
|
|
|
r = self.session.post(url, data=params)
|
|
|
r.encoding = 'utf-8'
|
|
@@ -192,7 +196,7 @@ class WXBot:
|
|
|
|
|
|
def test_sync_check(self):
|
|
|
for host in ['webpush', 'webpush2']:
|
|
|
- self.syncHost = host
|
|
|
+ self.sync_host = host
|
|
|
[retcode, selector] = self.sync_check()
|
|
|
if retcode == '0':
|
|
|
return True
|
|
@@ -205,10 +209,10 @@ class WXBot:
|
|
|
'uin': self.uin,
|
|
|
'skey': self.skey,
|
|
|
'deviceid': self.deviceId,
|
|
|
- 'synckey': self.synckey,
|
|
|
+ 'synckey': self.sync_key_str,
|
|
|
'_': int(time.time()),
|
|
|
}
|
|
|
- url = 'https://' + self.syncHost + '.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck?' + urllib.urlencode(params)
|
|
|
+ url = 'https://' + self.sync_host + '.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck?' + urllib.urlencode(params)
|
|
|
r = self.session.get(url)
|
|
|
r.encoding = 'utf-8'
|
|
|
data = r.text
|
|
@@ -220,18 +224,16 @@ class WXBot:
|
|
|
def sync(self):
|
|
|
url = self.base_uri + '/webwxsync?sid=%s&skey=%s&lang=en_US&pass_ticket=%s' % (self.sid, self.skey, self.pass_ticket)
|
|
|
params = {
|
|
|
- 'BaseRequest': self.BaseRequest,
|
|
|
- 'SyncKey': self.SyncKey,
|
|
|
+ 'BaseRequest': self.base_request,
|
|
|
+ 'SyncKey': self.sync_key,
|
|
|
'rr': ~int(time.time())
|
|
|
}
|
|
|
r = self.session.post(url, json=params)
|
|
|
r.encoding = 'utf-8'
|
|
|
dic = json.loads(r.text)
|
|
|
- if self.DEBUG:
|
|
|
- print json.dumps(dic, indent=4)
|
|
|
if dic['BaseResponse']['Ret'] == 0:
|
|
|
- self.SyncKey = dic['SyncKey']
|
|
|
- self.synckey = '|'.join([ str(keyVal['Key']) + '_' + str(keyVal['Val']) for keyVal in self.SyncKey['List'] ])
|
|
|
+ self.sync_key = dic['SyncKey']
|
|
|
+ self.sync_key_str = '|'.join([ str(keyVal['Key']) + '_' + str(keyVal['Val']) for keyVal in self.sync_key['List'] ])
|
|
|
return dic
|
|
|
|
|
|
def get_icon(self, id):
|
|
@@ -264,16 +266,6 @@ class WXBot:
|
|
|
f.write(data)
|
|
|
return fn
|
|
|
|
|
|
- # Not work now for weixin haven't support this API
|
|
|
- def get_video(self, msgid):
|
|
|
- url = self.base_uri + '/webwxgetvideo?msgid=%s&skey=%s' % (msgid, self.skey)
|
|
|
- r = self.session.get(url)
|
|
|
- data = r.content
|
|
|
- fn = 'video_'+msgid+'.mp4'
|
|
|
- with open(fn, 'wb') as f:
|
|
|
- f.write(data)
|
|
|
- return fn
|
|
|
-
|
|
|
def get_voice_url(self, msgid):
|
|
|
return self.base_uri + '/webwxgetvoice?msgid=%s&skey=%s' % (msgid, self.skey)
|
|
|
|
|
@@ -289,14 +281,14 @@ class WXBot:
|
|
|
#Get the NickName or RemarkName of an user by user id
|
|
|
def get_user_remark_name(self, uid):
|
|
|
name = 'unknown group' if uid[:2] == '@@' else 'stranger'
|
|
|
- for member in self.MemberList:
|
|
|
+ for member in self.member_list:
|
|
|
if member['UserName'] == uid:
|
|
|
name = member['RemarkName'] if member['RemarkName'] else member['NickName']
|
|
|
return name
|
|
|
|
|
|
#Get user id of an user
|
|
|
def get_user_id(self, name):
|
|
|
- for member in self.MemberList:
|
|
|
+ for member in self.member_list:
|
|
|
if name == member['RemarkName'] or name == member['NickName'] or name == member['UserName']:
|
|
|
return member['UserName']
|
|
|
return None
|
|
@@ -359,7 +351,7 @@ class WXBot:
|
|
|
if self.DEBUG:
|
|
|
print '[File] %s : %s' % (name, )
|
|
|
|
|
|
- elif msg['FromUserName'] == self.User['UserName']: #self
|
|
|
+ elif msg['FromUserName'] == self.user['UserName']: #self
|
|
|
msg_type_id = 3
|
|
|
|
|
|
elif msg['FromUserName'][:2] == '@@':
|
|
@@ -452,19 +444,17 @@ class WXBot:
|
|
|
self.handle_msg_all(message)
|
|
|
|
|
|
def proc_msg(self):
|
|
|
- print 'proc start'
|
|
|
self.test_sync_check()
|
|
|
while True:
|
|
|
[retcode, selector] = self.sync_check()
|
|
|
- if retcode == '1100':
|
|
|
+ if retcode == '1100': # User have login on mobile
|
|
|
pass
|
|
|
- #print '[*] you have login on mobile'
|
|
|
elif retcode == '0':
|
|
|
if selector == '2':
|
|
|
r = self.sync()
|
|
|
if r is not None:
|
|
|
self.handle_msg(r)
|
|
|
- elif selector == '7': # play WeChat on mobile
|
|
|
+ elif selector == '7': # Play WeChat on mobile
|
|
|
r = self.sync()
|
|
|
if r is not None:
|
|
|
self.handle_msg(r)
|
|
@@ -475,11 +465,11 @@ class WXBot:
|
|
|
url = self.base_uri + '/webwxsendmsg?pass_ticket=%s' % (self.pass_ticket)
|
|
|
msg_id = str(int(time.time()*1000)) + str(random.random())[:5].replace('.','')
|
|
|
params = {
|
|
|
- 'BaseRequest': self.BaseRequest,
|
|
|
+ 'BaseRequest': self.base_request,
|
|
|
'Msg': {
|
|
|
"Type": 1,
|
|
|
"Content": make_unicode(word),
|
|
|
- "FromUserName": self.User['UserName'],
|
|
|
+ "FromUserName": self.user['UserName'],
|
|
|
"ToUserName": dst,
|
|
|
"LocalID": msg_id,
|
|
|
"ClientMsgId": msg_id
|
|
@@ -512,8 +502,10 @@ class WXBot:
|
|
|
else:
|
|
|
return False
|
|
|
else:
|
|
|
- print '[*] this user does not exist'
|
|
|
+ if self.DEBUG:
|
|
|
+ print '[ERROR] This user does not exist .'
|
|
|
return False
|
|
|
+
|
|
|
def search_content(self, key, content, fmat = 'attr'):
|
|
|
if fmat == 'attr':
|
|
|
pm = re.search(key+'\s?=\s?"([^"<]+)"', content)
|
|
@@ -525,27 +517,23 @@ class WXBot:
|
|
|
|
|
|
def run(self):
|
|
|
self.get_uuid()
|
|
|
- print 'get uuid end'
|
|
|
self.gen_qr_code('qr.jpg')
|
|
|
- print 'gen qr code end'
|
|
|
+ print '[INFO] Please use WeCaht to scan QR code in qr.jpg .'
|
|
|
self.wait4login(1)
|
|
|
- print 'wait4login end'
|
|
|
+ print '[INFO] Please confirm to login .'
|
|
|
self.wait4login(0)
|
|
|
- print 'wait4login end'
|
|
|
if self.login():
|
|
|
- print 'login succeed'
|
|
|
+ print '[INFO] Web WeChat login succeed .'
|
|
|
else:
|
|
|
- print 'login failed'
|
|
|
+ print '[ERROR] Web WeChat login failed .'
|
|
|
return
|
|
|
if self.init():
|
|
|
- print 'init succeed'
|
|
|
+ print '[INFO] Web WeChat init succeed .'
|
|
|
else:
|
|
|
- print 'init failed'
|
|
|
+ print '[INFO] Web WeChat init failed'
|
|
|
return
|
|
|
- print 'init end'
|
|
|
self.status_notify()
|
|
|
- print 'status notify end'
|
|
|
self.get_contact()
|
|
|
- print 'get %d contacts' % len(self.ContactList)
|
|
|
-
|
|
|
+ print '[INFO] Get %d contacts' % len(self.contact_list)
|
|
|
+ print '[INFO] Start to process messages .'
|
|
|
self.proc_msg()
|