348 lines
12 KiB
JavaScript
348 lines
12 KiB
JavaScript
|
|
/* eslint-disable no-eval */
|
|
import axios from 'axios';
|
|
import { observable, action } from 'mobx';
|
|
|
|
import helper from 'utils/helper';
|
|
import storage from 'utils/storage';
|
|
import { normalize } from 'utils/emoji';
|
|
import chat from './chat';
|
|
import contacts from './contacts';
|
|
|
|
const CancelToken = axios.CancelToken;
|
|
const headers = {
|
|
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36',
|
|
'client-version': '2.0.0',
|
|
extspam: 'Go8FCIkFEokFCggwMDAwMDAwMRAGGvAESySibk50w5Wb3uTl2c2h64jVVrV7gNs06GFlWplHQbY/5FfiO++1yH4ykCyNPWKXmco+wfQzK5R98D3so7rJ5LmGFvBLjGceleySrc3SOf2Pc1gVehzJgODeS0lDL3/I/0S2SSE98YgKleq6Uqx6ndTy9yaL9qFxJL7eiA/R3SEfTaW1SBoSITIu+EEkXff+Pv8NHOk7N57rcGk1w0ZzRrQDkXTOXFN2iHYIzAAZPIOY45Lsh+A4slpgnDiaOvRtlQYCt97nmPLuTipOJ8Qc5pM7ZsOsAPPrCQL7nK0I7aPrFDF0q4ziUUKettzW8MrAaiVfmbD1/VkmLNVqqZVvBCtRblXb5FHmtS8FxnqCzYP4WFvz3T0TcrOqwLX1M/DQvcHaGGw0B0y4bZMs7lVScGBFxMj3vbFi2SRKbKhaitxHfYHAOAa0X7/MSS0RNAjdwoyGHeOepXOKY+h3iHeqCvgOH6LOifdHf/1aaZNwSkGotYnYScW8Yx63LnSwba7+hESrtPa/huRmB9KWvMCKbDThL/nne14hnL277EDCSocPu3rOSYjuB9gKSOdVmWsj9Dxb/iZIe+S6AiG29Esm+/eUacSba0k8wn5HhHg9d4tIcixrxveflc8vi2/wNQGVFNsGO6tB5WF0xf/plngOvQ1/ivGV/C1Qpdhzznh0ExAVJ6dwzNg7qIEBaw+BzTJTUuRcPk92Sn6QDn2Pu3mpONaEumacjW4w6ipPnPw+g2TfywJjeEcpSZaP4Q3YV5HG8D6UjWA4GSkBKculWpdCMadx0usMomsSS/74QgpYqcPkmamB4nVv1JxczYITIqItIKjD35IGKAUwAA==',
|
|
referer: 'https://wx.qq.com/?&lang=zh_CN&target=t',
|
|
};
|
|
|
|
class Session {
|
|
@observable loading = true;
|
|
@observable auth;
|
|
@observable code;
|
|
@observable avatar;
|
|
@observable user;
|
|
|
|
syncKey;
|
|
|
|
genSyncKey(list) {
|
|
return (self.syncKey = list.map(e => `${e.Key}_${e.Val}`).join('|'));
|
|
}
|
|
|
|
@action async getCode() {
|
|
var response = await axios.get('https://login.wx.qq.com/jslogin', {
|
|
params: {
|
|
appid: 'wx782c26e4c19acffb',
|
|
fun: 'new',
|
|
redirect_uri: 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?mod=desktop',
|
|
lang: 'zh_CN'
|
|
},
|
|
headers: headers,
|
|
});
|
|
// var response = await axios.get('https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=en_US&_=' + +new Date());
|
|
var code = response.data.match(/[A-Za-z_\-\d]{10}==/)[0];
|
|
|
|
self.code = code;
|
|
self.check();
|
|
return code;
|
|
}
|
|
@action async check() {
|
|
// Already logined
|
|
if (self.auth) return;
|
|
|
|
var response = await axios.get('https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login', {
|
|
params: {
|
|
loginicon: true,
|
|
uuid: self.code,
|
|
tip: 1,
|
|
r: ~new Date(),
|
|
_: +new Date(),
|
|
},
|
|
headers: headers
|
|
});
|
|
eval(response.data);
|
|
|
|
switch (window.code) {
|
|
case 200:
|
|
let authAddress = window.redirect_uri;
|
|
|
|
// Set your weChat network route, otherwise you will got a code '1102'
|
|
axios.defaults.baseURL = authAddress.match(/^https:\/\/(.*?)\//)[0];
|
|
|
|
delete window.redirect_uri;
|
|
delete window.code;
|
|
delete window.userAvatar;
|
|
|
|
// Login success, create session
|
|
let response = await axios.get(authAddress, {
|
|
params: {
|
|
fun: 'new',
|
|
version: 'v2',
|
|
},
|
|
headers: headers
|
|
});
|
|
let auth = {};
|
|
|
|
try {
|
|
auth = {
|
|
baseURL: axios.defaults.baseURL,
|
|
skey: response.data.match(/<skey>(.*?)<\/skey>/)[1],
|
|
passTicket: response.data.match(/<pass_ticket>(.*?)<\/pass_ticket>/)[1],
|
|
wxsid: response.data.match(/<wxsid>(.*?)<\/wxsid>/)[1],
|
|
wxuin: response.data.match(/<wxuin>(.*?)<\/wxuin>/)[1],
|
|
};
|
|
} catch (ex) {
|
|
window.alert('Your login may be compromised. For account security, you cannot log in to Web WeChat. You can try mobile WeChat or Windows WeChat.');
|
|
window.location.reload();
|
|
}
|
|
|
|
self.auth = auth;
|
|
await storage.set('auth', auth);
|
|
await self.initUser();
|
|
self.keepalive().catch(ex => self.logout());
|
|
break;
|
|
|
|
case 201:
|
|
// Confirm to login
|
|
self.avatar = window.userAvatar;
|
|
self.check();
|
|
break;
|
|
|
|
case 400:
|
|
// QR Code has expired
|
|
window.location.reload();
|
|
return;
|
|
|
|
default:
|
|
// Continue call server and waite
|
|
self.check();
|
|
}
|
|
}
|
|
|
|
@action async initUser() {
|
|
var response = await axios.post(`/cgi-bin/mmwebwx-bin/webwxinit?r=${-new Date()}&pass_ticket=${self.auth.passTicket}`, {
|
|
BaseRequest: {
|
|
Sid: self.auth.wxsid,
|
|
Uin: self.auth.wxuin,
|
|
Skey: self.auth.skey,
|
|
}
|
|
});
|
|
|
|
await axios.post(`/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=en_US&pass_ticket=${self.auth.passTicket}`, {
|
|
BaseRequest: {
|
|
Sid: self.auth.wxsid,
|
|
Uin: self.auth.wxuin,
|
|
Skey: self.auth.skey,
|
|
},
|
|
ClientMsgId: +new Date(),
|
|
Code: 3,
|
|
FromUserName: response.data.User.UserName,
|
|
ToUserName: response.data.User.UserName,
|
|
});
|
|
|
|
self.user = response.data;
|
|
self.user.ContactList.map(e => {
|
|
e.HeadImgUrl = `${axios.defaults.baseURL}${e.HeadImgUrl.substr(1)}`;
|
|
});
|
|
await contacts.getContats();
|
|
await chat.loadChats(self.user.ChatSet);
|
|
|
|
return self.user;
|
|
}
|
|
|
|
async getNewMessage() {
|
|
var auth = self.auth;
|
|
var response = await axios.post(`/cgi-bin/mmwebwx-bin/webwxsync?sid=${auth.wxsid}&skey=${auth.skey}&lang=en_US&pass_ticket=${auth.passTicket}`, {
|
|
BaseRequest: {
|
|
Sid: auth.wxsid,
|
|
Uin: auth.wxuin,
|
|
Skey: auth.skey,
|
|
},
|
|
SyncKey: self.user.SyncKey,
|
|
rr: ~new Date(),
|
|
});
|
|
var mods = [];
|
|
|
|
// Refresh the sync keys
|
|
self.user.SyncKey = response.data.SyncCheckKey;
|
|
self.genSyncKey(response.data.SyncCheckKey.List);
|
|
|
|
// Get the new friend, or chat room has change
|
|
response.data.ModContactList.map(e => {
|
|
var hasUser = contacts.memberList.find(user => user.UserName === e.UserName);
|
|
|
|
if (hasUser) {
|
|
// Just update the user
|
|
contacts.updateUser(e);
|
|
} else {
|
|
// If user not exists put it in batch list
|
|
mods.push(e.UserName);
|
|
}
|
|
});
|
|
|
|
// Delete user
|
|
response.data.DelContactList.map((e) => {
|
|
contacts.deleteUser(e.UserName);
|
|
chat.removeChat(e);
|
|
});
|
|
|
|
if (mods.length) {
|
|
await contacts.batch(mods, true);
|
|
}
|
|
|
|
response.data.AddMsgList.map(e => {
|
|
var from = e.FromUserName;
|
|
var to = e.ToUserName;
|
|
var fromYourPhone = from === self.user.User.UserName && from !== to;
|
|
|
|
// When message has been readed on your phone, will receive this message
|
|
if (e.MsgType === 51) {
|
|
return chat.markedRead(fromYourPhone ? from : to);
|
|
}
|
|
|
|
e.Content = normalize(e.Content);
|
|
|
|
// Sync message from your phone
|
|
if (fromYourPhone) {
|
|
// Message is sync from your phone
|
|
chat.addMessage(e, true);
|
|
return;
|
|
}
|
|
|
|
if (from.startsWith('@')) {
|
|
chat.addMessage(e);
|
|
}
|
|
});
|
|
|
|
return response.data;
|
|
}
|
|
|
|
// A callback for cancel the sync request
|
|
cancelCheck = window.Function;
|
|
|
|
checkTimeout(weakup) {
|
|
// Kill the zombie request or duplicate request
|
|
self.cancelCheck();
|
|
clearTimeout(self.checkTimeout.timer);
|
|
|
|
if (helper.isSuspend() || weakup) {
|
|
return;
|
|
}
|
|
|
|
self.checkTimeout.timer = setTimeout(() => {
|
|
self.cancelCheck();
|
|
}, 30 * 1000);
|
|
}
|
|
|
|
async keepalive() {
|
|
var auth = self.auth;
|
|
var response = await axios.post(`/cgi-bin/mmwebwx-bin/webwxsync?sid=${auth.wxsid}&skey=${auth.skey}&lang=en_US&pass_ticket=${auth.passTicket}`, {
|
|
BaseRequest: {
|
|
Sid: auth.wxsid,
|
|
Uin: auth.wxuin,
|
|
Skey: auth.skey,
|
|
},
|
|
SyncKey: self.user.SyncKey,
|
|
rr: ~new Date(),
|
|
});
|
|
var host = axios.defaults.baseURL.replace('//', '//webpush.');
|
|
var loop = async() => {
|
|
// Start detect timeout
|
|
self.checkTimeout();
|
|
|
|
var response = await axios.get(`${host}cgi-bin/mmwebwx-bin/synccheck`, {
|
|
cancelToken: new CancelToken(exe => {
|
|
// An executor function receives a cancel function as a parameter
|
|
this.cancelCheck = exe;
|
|
}),
|
|
params: {
|
|
r: +new Date(),
|
|
sid: auth.wxsid,
|
|
uin: auth.wxuin,
|
|
skey: auth.skey,
|
|
synckey: self.syncKey,
|
|
}
|
|
}).catch(ex => {
|
|
if (axios.isCancel(ex)) {
|
|
loop();
|
|
} else {
|
|
self.logout();
|
|
}
|
|
});
|
|
|
|
if (!response) {
|
|
// Request has been canceled
|
|
return;
|
|
}
|
|
|
|
eval(response.data);
|
|
|
|
if (+window.synccheck.retcode === 0) {
|
|
// 2, Has new message
|
|
// 6, New friend
|
|
// 4, Conversation refresh ?
|
|
// 7, Exit or enter
|
|
let selector = +window.synccheck.selector;
|
|
|
|
if (selector !== 0) {
|
|
await self.getNewMessage();
|
|
}
|
|
|
|
// Do next sync keep your wechat alive
|
|
return loop();
|
|
} else {
|
|
self.logout();
|
|
}
|
|
};
|
|
|
|
// Load the rencets chats
|
|
response.data.AddMsgList.map(
|
|
async e => {
|
|
await chat.loadChats(e.StatusNotifyUserName);
|
|
}
|
|
);
|
|
|
|
self.loading = false;
|
|
self.genSyncKey(response.data.SyncCheckKey.List);
|
|
|
|
return loop();
|
|
}
|
|
|
|
@action async hasLogin() {
|
|
var auth = await storage.get('auth');
|
|
|
|
axios.defaults.baseURL = auth.baseURL;
|
|
|
|
self.auth = auth && Object.keys(auth).length ? auth : void 0;
|
|
|
|
if (self.auth) {
|
|
await self.initUser().catch(ex => self.logout());
|
|
self.keepalive().catch(ex => self.logout());
|
|
}
|
|
|
|
return auth;
|
|
}
|
|
|
|
@action async logout() {
|
|
var auth = self.auth;
|
|
|
|
try {
|
|
await axios.post(`/cgi-bin/mmwebwx-bin/webwxlogout?skey=${auth.skey}&redirect=0&type=1`, {
|
|
sid: auth.sid,
|
|
uin: auth.uid,
|
|
});
|
|
} finally {
|
|
self.exit();
|
|
}
|
|
}
|
|
|
|
async exit() {
|
|
await storage.remove('auth');
|
|
window.location.reload();
|
|
}
|
|
}
|
|
|
|
const self = new Session();
|
|
export default self;
|