Example #1
0
// 验证 code
func AuthCode(email string, code []byte) (bool, error) {
	item, err := mc.Client().Get(key(email))
	if err != nil && err != memcache.ErrCacheMiss { // 出错, 直接返回错误
		return false, err
	}
	if err == memcache.ErrCacheMiss {
		if !security.SecureCompare(compareByteSlice, compareByteSlice) {
			return false, nil
		}
		return false, nil
	}
	if !security.SecureCompare(code, item.Value) {
		return false, nil
	}
	return true, nil
}
Example #2
0
func authPhonePassword(ctx *gin.Context, querylValues url.Values) {
	phone := querylValues.Get("phone")
	if phone == "" {
		ctx.JSON(200, errors.ErrBadRequest)
		return
	}
	if !check.IsChinaMobileString(phone) {
		ctx.JSON(200, errors.ErrBadRequest)
		return
	}
	password := querylValues.Get("password")
	if password == "" {
		ctx.JSON(200, errors.ErrBadRequest)
		return
	}

	user, err := model.GetByPhone(phone)
	switch err {
	case nil:
		cipherPassword := model.EncryptPassword([]byte(password), user.Salt)
		if !security.SecureCompare(cipherPassword, user.Password) {
			ctx.JSON(200, errors.ErrAuthFailed)
			return
		}
		authSuccess(ctx, AuthTypePhonePassword, user)
		return
	case model.ErrNotFound:
		cipherPassword := model.EncryptPassword([]byte(password), model.PasswordSalt)
		if !security.SecureCompare(cipherPassword, cipherPassword) {
			ctx.JSON(200, errors.ErrAuthFailed)
			return
		}
		ctx.JSON(200, errors.ErrAuthFailed)
		return
	default:
		glog.Errorln(err)
		ctx.JSON(200, errors.ErrInternalServerError)
		return
	}
}
Example #3
0
// ServeHTTP 处理 http 消息请求
//  NOTE: 调用者保证所有参数有效
func ServeHTTP(w http.ResponseWriter, r *http.Request, queryValues url.Values, srv AgentServer, errHandler ErrorHandler) {
	LogInfoln("[WECHAT_DEBUG] request uri:", r.RequestURI)
	LogInfoln("[WECHAT_DEBUG] request remote-addr:", r.RemoteAddr)
	LogInfoln("[WECHAT_DEBUG] request user-agent:", r.UserAgent())

	switch r.Method {
	case "POST": // 消息处理
		msgSignature1 := queryValues.Get("msg_signature")
		if msgSignature1 == "" {
			errHandler.ServeError(w, r, errors.New("msg_signature is empty"))
			return
		}

		timestampStr := queryValues.Get("timestamp")
		if timestampStr == "" {
			errHandler.ServeError(w, r, errors.New("timestamp is empty"))
			return
		}

		timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
		if err != nil {
			err = errors.New("can not parse timestamp to int64: " + timestampStr)
			errHandler.ServeError(w, r, err)
			return
		}

		nonce := queryValues.Get("nonce")
		if nonce == "" {
			errHandler.ServeError(w, r, errors.New("nonce is empty"))
			return
		}

		reqBody, err := ioutil.ReadAll(r.Body)
		if err != nil {
			errHandler.ServeError(w, r, err)
			return
		}
		LogInfoln("[WECHAT_DEBUG] request msg http body:\r\n", string(reqBody))

		// 解析 RequestHttpBody
		var requestHttpBody RequestHttpBody
		if err := xml.Unmarshal(reqBody, &requestHttpBody); err != nil {
			errHandler.ServeError(w, r, err)
			return
		}

		haveCorpId := requestHttpBody.CorpId
		wantCorpId := srv.CorpId()
		if wantCorpId != "" && !security.SecureCompareString(haveCorpId, wantCorpId) {
			err = fmt.Errorf("the RequestHttpBody's ToUserName mismatch, have: %s, want: %s", haveCorpId, wantCorpId)
			errHandler.ServeError(w, r, err)
			return
		}

		haveAgentId := requestHttpBody.AgentId
		wantAgentId := srv.AgentId()
		if wantCorpId != "" && wantAgentId != -1 {
			if haveAgentId != wantAgentId && haveAgentId != 0 {
				err = fmt.Errorf("the RequestHttpBody's AgentId mismatch, have: %d, want: %d", haveAgentId, wantAgentId)
				errHandler.ServeError(w, r, err)
				return
			}
			// 此时
			// 要么 haveAgentId == wantAgentId,
			// 要么 haveAgentId == 0
		}

		agentToken := srv.Token()

		// 验证签名
		msgSignature2 := util.MsgSign(agentToken, timestampStr, nonce, requestHttpBody.EncryptedMsg)
		if !security.SecureCompareString(msgSignature1, msgSignature2) {
			err := fmt.Errorf("check msg_signature failed, input: %s, local: %s", msgSignature1, msgSignature2)
			errHandler.ServeError(w, r, err)
			return
		}

		// 解密
		encryptedMsgBytes, err := base64.StdEncoding.DecodeString(requestHttpBody.EncryptedMsg)
		if err != nil {
			errHandler.ServeError(w, r, err)
			return
		}

		aesKey := srv.CurrentAESKey()
		random, rawMsgXML, aesAppId, err := util.AESDecryptMsg(encryptedMsgBytes, aesKey)
		if err != nil {
			// 尝试用上一次的 AESKey 来解密
			lastAESKey, isLastAESKeyValid := srv.LastAESKey()
			if !isLastAESKeyValid {
				errHandler.ServeError(w, r, err)
				return
			}

			aesKey = lastAESKey // NOTE

			random, rawMsgXML, aesAppId, err = util.AESDecryptMsg(encryptedMsgBytes, aesKey)
			if err != nil {
				errHandler.ServeError(w, r, err)
				return
			}
		}
		if haveCorpId != string(aesAppId) {
			err = fmt.Errorf("the RequestHttpBody's ToUserName(==%s) mismatch the CorpId with aes encrypt(==%s)", haveCorpId, aesAppId)
			errHandler.ServeError(w, r, err)
			return
		}

		LogInfoln("[WECHAT_DEBUG] request msg raw xml:\r\n", string(rawMsgXML))

		// 解密成功, 解析 MixedMessage
		var mixedMsg MixedMessage
		if err = xml.Unmarshal(rawMsgXML, &mixedMsg); err != nil {
			errHandler.ServeError(w, r, err)
			return
		}

		// 安全考虑再次验证
		if haveCorpId != mixedMsg.ToUserName {
			err = fmt.Errorf("the RequestHttpBody's ToUserName(==%s) mismatch the MixedMessage's ToUserName(==%s)", haveCorpId, mixedMsg.ToUserName)
			errHandler.ServeError(w, r, err)
			return
		}
		if haveAgentId != mixedMsg.AgentId {
			err = fmt.Errorf("the RequestHttpBody's AgentId(==%d) mismatch the MixedMessage's AgengId(==%d)", haveAgentId, mixedMsg.AgentId)
			errHandler.ServeError(w, r, err)
			return
		}

		// 如果是订阅/取消订阅 整个企业号, haveAgentId == 0
		if wantCorpId != "" && wantAgentId != -1 && haveAgentId != wantAgentId {
			if mixedMsg.MsgType == "event" &&
				(mixedMsg.Event == "subscribe" || mixedMsg.Event == "unsubscribe") {
				// do nothing
			} else {
				err = fmt.Errorf("the RequestHttpBody's AgentId mismatch, have: %d, want: %d", haveAgentId, wantAgentId)
				errHandler.ServeError(w, r, err)
				return
			}
		}

		// 成功, 交给 MessageHandler
		req := &Request{
			AgentToken: agentToken,

			HttpRequest: r,
			QueryValues: queryValues,

			MsgSignature: msgSignature1,
			Timestamp:    timestamp,
			Nonce:        nonce,

			RawMsgXML: rawMsgXML,
			MixedMsg:  &mixedMsg,

			AESKey:  aesKey,
			Random:  random,
			CorpId:  haveCorpId,
			AgentId: haveAgentId,
		}
		srv.MessageHandler().ServeMessage(w, req)

	case "GET": // 首次验证
		msgSignature1 := queryValues.Get("msg_signature")
		if msgSignature1 == "" {
			errHandler.ServeError(w, r, errors.New("msg_signature is empty"))
			return
		}

		timestamp := queryValues.Get("timestamp")
		if timestamp == "" {
			errHandler.ServeError(w, r, errors.New("timestamp is empty"))
			return
		}

		nonce := queryValues.Get("nonce")
		if nonce == "" {
			errHandler.ServeError(w, r, errors.New("nonce is empty"))
			return
		}

		encryptedMsg := queryValues.Get("echostr")
		if encryptedMsg == "" {
			errHandler.ServeError(w, r, errors.New("echostr is empty"))
			return
		}

		msgSignature2 := util.MsgSign(srv.Token(), timestamp, nonce, encryptedMsg)
		if !security.SecureCompareString(msgSignature1, msgSignature2) {
			err := fmt.Errorf("check msg_signature failed, input: %s, local: %s", msgSignature1, msgSignature2)
			errHandler.ServeError(w, r, err)
			return
		}

		// 解密
		encryptedMsgBytes, err := base64.StdEncoding.DecodeString(encryptedMsg)
		if err != nil {
			errHandler.ServeError(w, r, err)
			return
		}

		aesKey := srv.CurrentAESKey()
		_, echostr, aesAppId, err := util.AESDecryptMsg(encryptedMsgBytes, aesKey)
		if err != nil {
			errHandler.ServeError(w, r, err)
			return
		}

		wantCorpId := srv.CorpId()
		if wantCorpId != "" && !security.SecureCompare(aesAppId, []byte(wantCorpId)) {
			err = fmt.Errorf("AppId with aes encrypt mismatch, have: %s, want: %s", aesAppId, wantCorpId)
			errHandler.ServeError(w, r, err)
			return
		}

		w.Write(echostr)
	}
}
Example #4
0
// ServeHTTP 处理 http 消息请求
//  NOTE: 调用者保证所有参数有效
func ServeHTTP(w http.ResponseWriter, r *http.Request, queryValues url.Values, srv Server, errHandler corp.ErrorHandler) {
	switch r.Method {
	case "POST": // 消息处理
		msgSignature1 := queryValues.Get("msg_signature")
		if msgSignature1 == "" {
			errHandler.ServeError(w, r, errors.New("msg_signature is empty"))
			return
		}

		timestampStr := queryValues.Get("timestamp")
		if timestampStr == "" {
			errHandler.ServeError(w, r, errors.New("timestamp is empty"))
			return
		}

		timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
		if err != nil {
			err = errors.New("can not parse timestamp to int64: " + timestampStr)
			errHandler.ServeError(w, r, err)
			return
		}

		nonce := queryValues.Get("nonce")
		if nonce == "" {
			errHandler.ServeError(w, r, errors.New("nonce is empty"))
			return
		}

		// 解析 RequestHttpBody
		var requestHttpBody RequestHttpBody
		if err := xml.NewDecoder(r.Body).Decode(&requestHttpBody); err != nil {
			errHandler.ServeError(w, r, err)
			return
		}

		haveSuiteId := requestHttpBody.SuiteId
		wantSuiteId := srv.SuiteId()
		if wantSuiteId != "" && !security.SecureCompareString(haveSuiteId, wantSuiteId) {
			err = fmt.Errorf("the RequestHttpBody's ToUserName mismatch, have: %s, want: %s", haveSuiteId, wantSuiteId)
			errHandler.ServeError(w, r, err)
			return
		}

		suiteToken := srv.SuiteToken()

		// 验证签名
		msgSignature2 := util.MsgSign(suiteToken, timestampStr, nonce, requestHttpBody.EncryptedMsg)
		if !security.SecureCompareString(msgSignature1, msgSignature2) {
			err = fmt.Errorf("check msg_signature failed, input: %s, local: %s", msgSignature1, msgSignature2)
			errHandler.ServeError(w, r, err)
			return
		}

		// 解密
		encryptedMsgBytes, err := base64.StdEncoding.DecodeString(requestHttpBody.EncryptedMsg)
		if err != nil {
			errHandler.ServeError(w, r, err)
			return
		}

		aesKey := srv.CurrentAESKey()
		random, rawMsgXML, aesSuiteId, err := util.AESDecryptMsg(encryptedMsgBytes, aesKey)
		if err != nil {
			// 尝试用上一次的 AESKey 来解密
			lastAESKey, isLastAESKeyValid := srv.LastAESKey()
			if !isLastAESKeyValid {
				errHandler.ServeError(w, r, err)
				return
			}

			aesKey = lastAESKey // NOTE

			random, rawMsgXML, aesSuiteId, err = util.AESDecryptMsg(encryptedMsgBytes, aesKey)
			if err != nil {
				errHandler.ServeError(w, r, err)
				return
			}
		}
		if haveSuiteId != string(aesSuiteId) {
			err = fmt.Errorf("the RequestHttpBody's ToUserName(==%s) mismatch the SuiteId with aes encrypt(==%s)", haveSuiteId, aesSuiteId)
			errHandler.ServeError(w, r, err)
			return
		}

		// 解密成功, 解析 MixedMessage
		var mixedMsg MixedMessage
		if err = xml.Unmarshal(rawMsgXML, &mixedMsg); err != nil {
			errHandler.ServeError(w, r, err)
			return
		}

		// 安全考虑再次验证
		if haveSuiteId != mixedMsg.SuiteId {
			err = fmt.Errorf("the RequestHttpBody's ToUserName(==%s) mismatch the MixedMessage's SuiteId(==%s)", haveSuiteId, mixedMsg.SuiteId)
			errHandler.ServeError(w, r, err)
			return
		}

		// 成功, 交给 MessageHandler
		req := &Request{
			SuiteToken: suiteToken,

			HttpRequest: r,
			QueryValues: queryValues,

			MsgSignature: msgSignature1,
			Timestamp:    timestamp,
			Nonce:        nonce,

			RawMsgXML: rawMsgXML,
			MixedMsg:  &mixedMsg,

			AESKey:  aesKey,
			Random:  random,
			SuiteId: haveSuiteId,
		}
		srv.MessageHandler().ServeMessage(w, req)

	case "GET": // 首次验证
		msgSignature1 := queryValues.Get("msg_signature")
		if msgSignature1 == "" {
			errHandler.ServeError(w, r, errors.New("msg_signature is empty"))
			return
		}

		timestamp := queryValues.Get("timestamp")
		if timestamp == "" {
			errHandler.ServeError(w, r, errors.New("timestamp is empty"))
			return
		}

		nonce := queryValues.Get("nonce")
		if nonce == "" {
			errHandler.ServeError(w, r, errors.New("nonce is empty"))
			return
		}

		encryptedMsg := queryValues.Get("echostr")
		if encryptedMsg == "" {
			errHandler.ServeError(w, r, errors.New("echostr is empty"))
			return
		}

		msgSignature2 := util.MsgSign(srv.SuiteToken(), timestamp, nonce, encryptedMsg)
		if !security.SecureCompareString(msgSignature1, msgSignature2) {
			err := fmt.Errorf("check msg_signature failed, input: %s, local: %s", msgSignature1, msgSignature2)
			errHandler.ServeError(w, r, err)
			return
		}

		// 解密
		encryptedMsgBytes, err := base64.StdEncoding.DecodeString(encryptedMsg)
		if err != nil {
			errHandler.ServeError(w, r, err)
			return
		}

		aesKey := srv.CurrentAESKey()
		_, echostr, aesAppId, err := util.AESDecryptMsg(encryptedMsgBytes, aesKey)
		if err != nil {
			errHandler.ServeError(w, r, err)
			return
		}

		wantAppId := srv.SuiteId()
		if wantAppId != "" && !security.SecureCompare(aesAppId, []byte(wantAppId)) {
			err = fmt.Errorf("AppId with aes encrypt mismatch, have: %s, want: %s", aesAppId, wantAppId)
			errHandler.ServeError(w, r, err)
			return
		}

		w.Write(echostr)
	}
}