diff --git a/inMsg.go b/inMsg.go index c4c9a0f..98ab297 100644 --- a/inMsg.go +++ b/inMsg.go @@ -5,6 +5,12 @@ import ( "encoding/xml" ) +//EncryptedMsg encrypted message from Wechat +type EncryptedMsg struct { + ToUserName string + Encrypt string +} + //all xml message has these headers type CommonHeader struct { ToUserName string @@ -119,3 +125,10 @@ func ReadLinkMsg(s string) LinkMsg { xml.Unmarshal([]byte(s), &r) return r } + +//ReadEncryptedMsg get Encrypted Msg +func ReadEncryptedMsg(s string) EncryptedMsg { + var r = EncryptedMsg{} + xml.Unmarshal([]byte(s), &r) + return r +} diff --git a/inMsg_test.go b/inMsg_test.go index 5ec5b0a..1a76117 100644 --- a/inMsg_test.go +++ b/inMsg_test.go @@ -166,3 +166,13 @@ func TestLinkMsg(t *testing.T) { AssertEqual(t, m.Url, "url", "Url failed") AssertEqual(t, m.MsgId, int64(1234567890123456), "MsgId not match") } + +func TestReadEncryptMsg(t *testing.T) { + msg := ` + + +` + m := ReadEncryptedMsg(msg) + AssertEqual(t, m.ToUserName, "gh_f09231355c68", "ToUserName failed") + AssertEqual(t, m.Encrypt, "Dv3epMMhmmGU1o6lg71IfbpRrOYX1S8oZX3nwW0uBAHHMKx62T4KniS4efuf8fNHWf6gsF/YGaDraF6HhGOdKp8vbzluiIEsCnIveKN1pO+IUDOBBxzPAzQSFSYJ3OwVXWmBdBcC1S5guQrOxLysH+6UIWSor9cEef+94UAKTNw/MLB0zPfqK5TVoN1A0yobmP9OU8wtFJP0L1aKySPFGGbqBMfJkStRTrYLjIQfZ7pAIisB/g3c87w26r7LUz9hVh4ey3/T6cjQ8vKvgNKL3j8y4IwUdmnmTPrrdOsyA1pz69977xKHFtIptZYHKGD9dTW6PyPcKKTP6iOod6Agb8TI+is80auqHkjvUyvT/xPG8fxak/wI9BKzKndAnwxlcDG/8WElkHVl0TwxpsCb48ZxLEf4GFKaYaliC9xBVweKLNnqdbBmzwfe7GBNWC61h7KQYqwtZqMkZs3BBsStcQ==", "ToUserName failed") +} diff --git a/main.go b/main.go index 932ba65..bc2f7d4 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "crypto/sha1" "fmt" + "io/ioutil" "log" "net/http" "net/http/httputil" @@ -37,7 +38,7 @@ func apiV1Main(w http.ResponseWriter, r *http.Request) { case "GET": answerInitialAuth(w, r) default: - log.Fatalln("Unhandled HTTP %s", r.Method) + log.Fatalln(fmt.Sprintf("Unhandled HTTP %s", r.Method)) fmt.Fprintf(w, "Protocol Error: Expect GET or POST only") } } @@ -60,6 +61,15 @@ func answerInitialAuth(w http.ResponseWriter, r *http.Request) { //answerWechatPost distribute PostRequest according to xml body info // func answerWechatPost(w http.ResponseWriter, r *http.Request) { + body, _ := ioutil.ReadAll(r.Body) + fmt.Printf("get body: %s", string(body)) + s := ReadEncryptedMsg(string(body)) + //fmt.Printf("to decrypt %s", s.Encrypt) + d := Decode(s.Encrypt) + fmt.Printf("decrypt as: %s", d) + h := ReadCommonHeader(d) + reply, _ := BuildTextMsg(h.MsgType, h.FromUserName) + fmt.Fprint(w, reply) return } diff --git a/outMsg.go b/outMsg.go new file mode 100644 index 0000000..2429e63 --- /dev/null +++ b/outMsg.go @@ -0,0 +1,55 @@ +package main + +import ( + "crypto/sha1" + "fmt" + "math/rand" + "sort" + "strings" + "time" +) + +//BuildTextMsg Given a text message send it to wechat client +func BuildTextMsg(txt string, ToUserName string) (string, error) { + + template := ` + + + %d + + + ` + msg := fmt.Sprintf(template, ToUserName, "gh_f09231355c68", int32(time.Now().Unix()), txt) + fmt.Println(msg) + e := Encode(msg) + + str, _, _, _ := signMsg(e) + fmt.Println(str) + return str, nil +} + +func signMsg(content string) (xml string, timestamp int32, nonce int32, signature string) { + timestamp = int32(time.Now().Unix()) + nonce = rand.Int31() + + strTimestamp := fmt.Sprintf("%d", timestamp) + strNonce := fmt.Sprintf("%d", nonce) + signature = getSignature(APIConfig.Token, strTimestamp, strNonce, content) + xml = "" + + "" + content + "" + + "" + signature + "" + + "" + strTimestamp + "" + + "" + strNonce + "" + + "" + return +} + +func getSignature(token string, timestamp string, nonce string, content string) (signature string) { + strs := []string{token, timestamp, nonce, content} + sort.Strings(strs) + s := strings.Join(strs, "") + h := sha1.New() + h.Write([]byte(s)) + signature = fmt.Sprintf("%x", h.Sum(nil)) + return +} diff --git a/outMsg_test.go b/outMsg_test.go new file mode 100644 index 0000000..2392e16 --- /dev/null +++ b/outMsg_test.go @@ -0,0 +1,11 @@ +package main + +import "testing" + +func TestBuildTxtMsg(t *testing.T) { + BuildTextMsg("你好", "oUN420bxqFqlx0ZQHciUOesZO3PE") +} + +func TextCalculateSignature (t *testing.T ){ + +} \ No newline at end of file