Преглед на файлове

signature for intra api using token signature and nonance timestamp , TestGetAccessToken worked.

master
Patrick Peng Sun преди 8 години
родител
ревизия
8ab694dd19
променени са 5 файла, в които са добавени 126 реда и са изтрити 29 реда
  1. +3
    -0
      common_test.go
  2. +32
    -0
      configIntraApi.go
  3. +3
    -0
      intrapi_config.json
  4. +32
    -3
      server.go
  5. +56
    -26
      server_test.go

+ 3
- 0
common_test.go Целия файл

@@ -31,6 +31,9 @@ func SetupConfig() {
"wechat",
"crmwechat.api",
"/tmp/"}
IntraAPIConfig = ConfigIntraAPI{
"cAT/ckkfjajvczxiaufodqdfakpozcczfas341fda.vfasdk/8934125",
}
GlobalPath = PathsConfig{"/tmp"}
KFUsers.kfRenewList()
}

+ 32
- 0
configIntraApi.go Целия файл

@@ -0,0 +1,32 @@
package main

import (
"encoding/json"
"errors"
"io/ioutil"
"log"
)

//ConfigIntraAPI config for intra server api
type ConfigIntraAPI struct {
CRMSecrete string `json:"CRMScrete,omitempty"`
}

//IntraAPIConfig Configuration Data for Intra Server API
var IntraAPIConfig ConfigIntraAPI

func (m *ConfigIntraAPI) readConfig() (err error) {
path := "intrapi_config.json"
log.Printf("read Intra API config from %s\r\n", path)
body, err := ioutil.ReadFile(path)
if err != nil {
log.Fatalf("Cannot read config from %s ", path)
return err
}
err = json.Unmarshal(body, &IntraAPIConfig)
if IntraAPIConfig.CRMSecrete == "" {
return errors.New("CRM CRMSecrete not available not available")
}

return
}

+ 3
- 0
intrapi_config.json Целия файл

@@ -0,0 +1,3 @@
{
"CRMScrete": "cAT/ckkfjajvczxiaufodqdfakpozcczfas341fda.vfasdk/8934125"
}

+ 32
- 3
server.go Целия файл

@@ -136,23 +136,51 @@ func answerWechatPostEcho(w http.ResponseWriter, r *http.Request) {

//
func checkSignature(r *http.Request) bool {
return checkSignatureByToken(r, APIConfig.Token)
}

func checkSignatureByToken(r *http.Request, token string) bool {
rq := r.URL.RawQuery
m, _ := url.ParseQuery(rq)

signature, sok := m["signature"]
timestamp, tok := m["timestamp"]
nonce, nok := m["nonce"]
token := APIConfig.Token
if sok && tok && nok {
token = strings.TrimSpace(token)
if sok && tok && nok && token != "" {
return verifySignature(signature[0], timestamp[0], nonce[0], token)
}
return false
}

func checkCookieSignatureBytoken(r *http.Request, token string) bool {
signature := ""
nonce := ""
timestamp := ""
for _, c := range r.Cookies() {
switch c.Name {
case "signature":
signature = c.Value
case "nonce":
nonce = c.Value
case "timestamp":
timestamp = c.Value
}
}
if signature != "" && nonce != "" && timestamp != "" {
return verifySignature(signature, timestamp, nonce, IntraAPIConfig.CRMSecrete)
}
return false
}

func verifySignature(signature, timestamp, nonce, token string) bool {
if timestampTooOldStr(timestamp) {
return false
}
return signature == calculateSignature(timestamp, nonce, token)
}

func calculateSignature(timestamp, nonce, token string) (signature string) {
//sort token, timestamp, nonce and join them
strs := []string{token, timestamp, nonce}
sort.Strings(strs)
@@ -162,7 +190,8 @@ func verifySignature(signature, timestamp, nonce, token string) bool {
h := sha1.New()
h.Write([]byte(s))
calculated := fmt.Sprintf("%x", h.Sum(nil))
return signature == calculated
signature = calculated
return
}

func timestampTooOldStr(timestamp string) bool {

+ 56
- 26
server_test.go Целия файл

@@ -7,19 +7,16 @@ import (
"net/http"
"net/http/httptest"
"testing"
"time"
)

//when we setup wechate parameters,we chat will verify us
func TestInitialSetup(t *testing.T) {


req := buildReqWechatAPISetup()
expected := `913461463450840893`
req := buildReqWechatAPISetup(expected)

rr, _ := getHTTPResponse(req, answerInitialAuth)

// Check the response body is what we expect.
expected := `913461463450840893`
if rr.Body.String() != expected {
t.Errorf("handler returned unexpected body: got %v want %v",
rr.Body.String(), expected)
@@ -27,7 +24,7 @@ func TestInitialSetup(t *testing.T) {
}

func TestWebRootHandler(t *testing.T) {
req := buildReqWechatWebRoot()
rr, _ := getHTTPResponse(req, webrootHandler)

@@ -46,7 +43,7 @@ echostr => [913461463450840893]`
//we only check decrypted ToUserName should be the one we sent out.
//as decrypt itself is already a good proof of its working state.
func TestPostTxtMsg(t *testing.T) {
req := buildReqWechatPostTxtMsg()
rr, _ := getHTTPResponse(req, apiV1Main)

@@ -62,6 +59,17 @@ func TestPostTxtMsg(t *testing.T) {

}

func TestGetAccesstoken(t *testing.T) {
req := buildReqGetAccessToken()
rr, _ := getHTTPResponse(req, supplyAccessToken)
errorResponse := "errortoken"
m := rr.Body.String()
expected, _ := GetAccessToken()
log.Printf("TestGetAccesstoken got: [%s] ", m)
AssertEqual(t, m != errorResponse, true, "Signature check failed, error response")
AssertEqual(t, m, expected, "token incorrect")
}

func getHTTPResponse(req *http.Request, handler http.HandlerFunc) (rr *httptest.ResponseRecorder, err error) {

// Our handlers satisfy http.Handler, so we can call their ServeHTTP method
@@ -109,9 +117,9 @@ func buildReqWechatPostTxtMsg() *http.Request {
<Encrypt><![CDATA[HKILXQjAOV4Zi5Zb8gQ8zt6EPA6cBCRYSq90PZuyMqZSGhtjMESSgveIps74rS2+Q5aZPJhytXIkmuE+dxMTkV06qGNSYuSurXsoJE7bNfrE/Nmxq6GwKH1rwHXk3c50NoHW/h6/jCXu8x0oY1oW/ea1tLRGY4xeoQ9voCuvVYRFSyuU7Zz2QjlbP+AG8mCnGBxUwqrthqWFe7wDEkYa38EoD9DrjrQKRc4Hn2ZIHYN569cn5PDvsif+5FUX4p+3gEkgk/HVxicC7wT9wYzNSk9HH7bET3V7hnhJ+PJa+ZEH7HAPzry61UZ1gghf4dJAGVE9D8R4/0M6DpKGCQBGXmlI/Q3NjN0jx9NAqffPRxsoW4BF7mLV8RmfDbJJEa0W5i0buwyluMyVcrF5KT9Bd2DBvsULCXfuwwp01DmJdfc=]]></Encrypt>
</xml>`
b := bytes.NewBufferString(xml)
req, _ := http.NewRequest("POST", "/api?signature=f06bb28c1d3847815d498fc0a343b11b4d03e095&timestamp=1493212928&nonce=1461107899&openid=oUN420bxqFqlx0ZQHciUOesZO3PE&encrypt_type=aes&msg_signature=61a50d4656b13a7bbeecf53a5a85fbf37835762f", b)
req, _ := http.NewRequest("POST", "/api?openid=oUN420bxqFqlx0ZQHciUOesZO3PE&encrypt_type=aes&msg_signature=61a50d4656b13a7bbeecf53a5a85fbf37835762f", b)
buildReqCommonSignature(req, APIConfig.Token)
buildReqCommonHeader(req)

return req
}

@@ -125,7 +133,7 @@ func buildReqWechatWebRoot() *http.Request {
return req
}

func buildReqWechatAPISetup() *http.Request {
func buildReqWechatAPISetup(echostr string) *http.Request {
// Create a request to pass to our handler.
//We don't have any query body for now, so we'll
// pass 'nil' as the third parameter.
@@ -133,18 +141,41 @@ func buildReqWechatAPISetup() *http.Request {
if err != nil {
log.Fatal(err)
}
buildReqCommonSignature(req, APIConfig.Token)
q := req.URL.Query()
q.Add("signature", "e39de9f2e28079c01ebb4b803dfc3442b819545c")
q.Add("echostr", "913461463450840893")
q.Add("timestamp", "1492970761")
q.Add("nonce", "1850971833")
q.Add("echostr", echostr)
req.URL.RawQuery = q.Encode()

buildReqCommonHeader(req)
return req
}

func buildReqGetAccessToken() *http.Request {
req, err := http.NewRequest("GET", "/iapi/getAccessToken", nil)
if err != nil {
log.Fatal(err)
}
buildReqCommonSignature(req, IntraAPIConfig.CRMSecrete)
buildReqCommonHeader(req)
return req
}

func buildSignature(token string) (signature, timestamp, nonce string) {
timestamp = fmt.Sprintf("%d", int32(time.Now().Unix()))
nonce = "1461107899" //a randome string cut from previous wechat request
signature = calculateSignature(timestamp, nonce, token)
return
}

func buildReqCommonSignature(req *http.Request, token string) {
signature, timestamp, nonce := buildSignature(token)
q := req.URL.Query()
q.Add("signature", signature)
q.Add("timestamp", timestamp)
q.Add("nonce", nonce)
req.URL.RawQuery = q.Encode()
}

func buildReqCommonHeader(r *http.Request) {
//
// example request
@@ -160,15 +191,14 @@ func buildReqCommonHeader(r *http.Request) {
// X-Forwarded-Host: wechat.hitxy.org.au
// X-Forwarded-Server: wechat.hitxy.org.au

h := r.Header
h.Set("Host", "wechat.hitxy.org.au")
h.Set("Accept", "*/*")
h.Set("Cache-Control", "no-cache")
h.Set("Connection", "Keep-Alive")
h.Set("Pragma", "no-cache")
h.Set("User-Agent", "Patrick testcase")
h.Set("X-Forwarded-For", "103.7.30.107")
h.Set("X-Forwarded-Host", "wechat.hitxy.org.au")
h.Set("X-Forwarded-Server", "wechat.hitxy.org.au")
r.Header.Set("Host", "wechat.hitxy.org.au")
r.Header.Set("Accept", "*/*")
r.Header.Set("Cache-Control", "no-cache")
r.Header.Set("Connection", "Keep-Alive")
r.Header.Set("Pragma", "no-cache")
r.Header.Set("User-Agent", "Patrick testcase")
r.Header.Set("X-Forwarded-For", "103.7.30.107")
r.Header.Set("X-Forwarded-Host", "wechat.hitxy.org.au")
r.Header.Set("X-Forwarded-Server", "wechat.hitxy.org.au")

}

Loading…
Отказ
Запис