package edu.fudan.weixin.actions;
import java.io.BufferedReader;
import java.io.IOException;
import java.security.GeneralSecurityException;
import javax.servlet.http.HttpServletResponse;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;
import edu.fudan.eservice.common.struts.GuestActionBase;
import edu.fudan.eservice.common.utils.CommonUtil;
import edu.fudan.eservice.common.utils.Config;
import edu.fudan.eservice.common.utils.EncodeHelper;
import edu.fudan.eservice.common.utils.MongoUtil;
import edu.fudan.weixin.model.TemplateMessage;
@ParentPackage("servicebase")
@Namespace("/")
public class MsgpushAction extends GuestActionBase {
/**
*
*/
private static final long serialVersionUID = -87130337020325361L;
private String clientid;
private String userenc;
private long timestamp;
private int msgid;
private String errormsg;
private Log log=LogFactory.getLog(MsgpushAction.class);
@Action("msgpush")
public String msgpush() throws Exception
{
BufferedReader r=ServletActionContext.getRequest().getReader();
String ret = null;
StringBuffer sb=new StringBuffer();
String s;
while((s=r.readLine())!=null)
{
sb.append(s);
}
DBObject req=(DBObject)JSON.parse(sb.toString());
DBObject head=(DBObject)req.get("head");
timestamp=(long)head.get("timestamp");
clientid=String.valueOf(head.get("clientid"));
userenc=String.valueOf(head.get("userenc"));
String touser=String.valueOf(head.get("touser"));
DB db=MongoUtil.getInstance().getDB();
if(checkTime(timestamp))
{
if(checkenc(db,timestamp,clientid,userenc))
{
if(checkmsgsum(req.get("data"),touser,userenc,String.valueOf(head.get("checksum"))))
{
Cache cache=CacheManager.getInstance().getCache("MsgCheck");
if(cache.get(head.get("checksum"))==null)
{
cache.put(new Element(head.get("checksum"),null));
DBObject user=db.getCollection("Bindings").findOne(new BasicDBObject("binds",new BasicDBObject("$elemMatch",new BasicDBObject("uisid",touser))));
if(!CommonUtil.isEmpty(user)&&!CommonUtil.isEmpty(user.get("openid")))
{
//template白名单
if(Config.getInstance().get("push.whitelist").indexOf(head.get("template").toString())>=0 || db.getCollection("Books").findOne(new BasicDBObject("openid",user.get("openid")).append("item", head.get("template")).append("book" , true))!=null)
{
String cret=TemplateMessage.send(String.valueOf(head.get("template")), String.valueOf(user.get("openid")), (DBObject)req.get("data"));
if(cret!=null && cret.startsWith("{")){
DBObject retobj=(DBObject)JSON.parse(cret);
retobj.put("touser", touser);
retobj.put("timestamp", timestamp);
retobj.put("clientid", clientid);
db.getCollection("Pushmsgs").save(retobj);
ret=cret;
}else
errormsg=cret;
}else
{
errormsg="Message not booked";
}
}else
{
errormsg="Touser not binded";
}
}else
{
errormsg="Same message is sent too frequently";
}
}else
{
errormsg="Message checksum error";
}
}else
{
errormsg="User not authorized";
}
}else
errormsg="Timestamp outof range";
HttpServletResponse resp=ServletActionContext.getResponse();
resp.setCharacterEncoding("utf-8");
resp.setContentType("application/json");
if(!CommonUtil.isEmpty(ret))
resp.getWriter().print(ret);
else
resp.getWriter().write("{\"errcode\":50000,\"errmsg\":\""+errormsg+"\"}");
return NONE;
}
@Action("pushresult")
public String pushresult() throws IOException
{
DB db=MongoUtil.getInstance().getDB();
BasicDBObject ret=null;
if(checkTime(timestamp))
{
if(checkenc(db,timestamp,clientid,userenc))
{
DBObject dbo=db.getCollection("Pushmsgs").findOne(new BasicDBObject("msgid",msgid));
if(!CommonUtil.isEmpty(dbo))
{
ret=new BasicDBObject().append("msgid", dbo.get("msgid")).append("status", dbo.get("status"));
}else
{
errormsg="Message not found";
}
}else
{
errormsg="User not authorized";
}
}else
errormsg="Timestamp outof range";
HttpServletResponse resp=ServletActionContext.getResponse();
resp.setCharacterEncoding("utf-8");
resp.setContentType("application/json");
if(!CommonUtil.isEmpty(ret))
resp.getWriter().print(JSON.serialize(ret));
else
resp.getWriter().write("{\"errcode\":50000,\"errmsg\":\""+errormsg+"\"}");
return NONE;
}
private boolean checkTime(long stamp)
{
long diff=System.currentTimeMillis()-stamp;
if(diff>900000||diff<-900000)
return false;
else
return true;
}
private DBObject getClientInfo(DB db,String clientid)
{
return db.getCollection("Clients").findOne(new BasicDBObject("clientid",clientid));
}
private boolean checkenc(DB db,long stamp,String clientid,String userenc)
{
DBObject clientinfo=getClientInfo(db,clientid);
if(clientinfo==null) return false;
String enckey=String.valueOf(clientinfo.get("enckey"));
try {
String userdec=new String(EncodeHelper.dencrypt("DESede", EncodeHelper.hex2bytes(userenc), EncodeHelper.hex2bytes(enckey), null));
if(CommonUtil.eq(userdec, String.valueOf(clientinfo.get("password"))+stamp))
return true;
else
return false;
} catch (GeneralSecurityException e) {
log.error(e);
errormsg=e.getMessage();
return false;
}
}
private boolean checkmsgsum(Object data,String touser,String userenc,String checksum)
{
String sdata=JSON.serialize(data);
sdata=sdata.replaceAll("[ \\n\\r\\t]", "");
log.info(sdata);
if(CommonUtil.eq(checksum, EncodeHelper.digest(sdata+touser+userenc, "SHA")))
return true;
else
return false;
}
public String getClientid() {
return clientid;
}
public void setClientid(String clientid) {
this.clientid = clientid;
}
public String getUserenc() {
return userenc;
}
public void setUserenc(String userenc) {
this.userenc = userenc;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public int getMsgid() {
return msgid;
}
public void setMsgid(int msgid) {
this.msgid = msgid;
}
public String getErrormsg() {
return errormsg;
}
}