diff --git a/Api_request.txt b/Api_request.txt index 879f337..44b74bd 100644 --- a/Api_request.txt +++ b/Api_request.txt @@ -1,3 +1,18 @@ +Initial auth URL + +GET /api?signature=e39de9f2e28079c01ebb4b803dfc3442b819545c&echostr=913461463450840893×tamp=1492970761&nonce=1850971833 HTTP/1.1 +Host: wechat.hitxy.org.au +Accept: */* +Cache-Control: no-cache +Connection: Keep-Alive +Pragma: no-cache +User-Agent: Mozilla/4.0 +X-Forwarded-For: 103.7.30.107 +X-Forwarded-Host: wechat.hitxy.org.au +X-Forwarded-Server: wechat.hitxy.org.au + + + Unfollow: POST /api?signature=ed32de69a7977a8468ca72fa45125a6506cc2cde×tamp=1492790658&nonce=644867704&openid=oUN420bxqFqlx0ZQHciUOesZO3PE&encrypt_type=aes&msg_signature=00db32d3a36e80969c65d6ff94d85b73dfdede43 HTTP/1.1 @@ -170,4 +185,30 @@ X-Forwarded-Server: wechat.hitxy.org.au + + + +receive TxtMessage + +POST /api?signature=847523ccbd3d6db7ed77b78a89f4019a109bde82×tamp=1492829058&nonce=1739586053&openid=oUN420bxqFqlx0ZQHciUOesZO3PE&encrypt_type=aes&msg_signature=8fa8be1428e6ee3d8a3332213e00bec019821677 HTTP/1.1 +Host: wechat.hitxy.org.au +Accept: */* +Cache-Control: no-cache +Connection: Keep-Alive +Content-Length: 771 +Content-Type: text/xml +Pragma: no-cache +User-Agent: Mozilla/4.0 +X-Forwarded-For: 103.7.30.105 +X-Forwarded-Host: wechat.hitxy.org.au +X-Forwarded-Server: wechat.hitxy.org.au + + + + + 1492829058 + + + 6411651983041024410 + \ No newline at end of file diff --git a/config.go b/config.go new file mode 100644 index 0000000..537f92c --- /dev/null +++ b/config.go @@ -0,0 +1,35 @@ +package main + +import ( + "encoding/json" + "io/ioutil" + "log" +) + +//WechatAPIConfig all secret related API Config +type WechatAPIConfig struct { + //Token is the wechat API shared secrete + Token string `json:"Token"` + + //EncodingAESKey is the Key for encrypt messages + EncodingAESKey string `'json:"EncodingAESKey"` + + //Appid is wechat public account appid + Appid string `json:"Appid"` + + //AppSecret is how we identify ourselves. + AppSecret string `json:"AppSecret"` +} + +//APIConfig contains secrets that cannot store in source file +var APIConfig WechatAPIConfig + +func readConfig() error { + + log.Printf("read config from %s\r\n", "server_config.json") + body, err := ioutil.ReadFile("server_config.json") + if err != nil { + return err + } + return json.Unmarshal(body, &APIConfig) +} diff --git a/main.go b/main.go index 99fea28..6cc9fb7 100644 --- a/main.go +++ b/main.go @@ -1,18 +1,27 @@ package main import ( + "crypto/sha1" "fmt" "log" "net/http" "net/http/httputil" "net/url" + "sort" + "strings" ) func main() { + if readConfig() != nil { + log.Fatal("unable to read config, program quit") + return + } + //setup handler http.HandleFunc("/", webrootHandler) http.HandleFunc("/api", apiV1Main) + //http.ListenAndServe("127.0.0.1:65500", nil) - CreateDefaultMenu() + //CreateDefaultMenu() http.ListenAndServe(":65500", nil) } @@ -20,9 +29,77 @@ func main() { // func apiV1Main(w http.ResponseWriter, r *http.Request) { logRequestDebug(httputil.DumpRequest(r, true)) + + switch r.Method { + case "POST": + answerWechatPost(w, r) + case "GET": + answerInitialAuth(w, r) + default: + log.Fatalln("Unhandled HTTP %s", r.Method) + fmt.Fprintf(w, "Protocol Error: Expect GET or POST only") + } +} + +// +//answerInitialAuth, when wechat first verify our URL for API hooks +// +func answerInitialAuth(w http.ResponseWriter, r *http.Request) { + rq := r.URL.RawQuery + m, _ := url.ParseQuery(rq) + + echostr, eok := m["echostr"] + if checkSignature(r) && eok { + fmt.Fprintf(w, echostr[0]) + } else { + fmt.Fprintf(w, "wtf is wrong with the Internet") + } +} + +//answerWechatPost distribute PostRequest according to xml body info +// +func answerWechatPost(w http.ResponseWriter, r *http.Request) { + return +} + +// +func checkSignature(r *http.Request) bool { rq := r.URL.RawQuery m, _ := url.ParseQuery(rq) - fmt.Fprintf(w, m["echostr"][0]) + + signature, sok := m["signature"] + timestamp, tok := m["timestamp"] + nonce, nok := m["nonce"] + token := APIConfig.Token + if sok && tok && nok { + + strs := []string{token, timestamp[0], nonce[0]} + + sort.Strings(strs) + s := strings.Join(strs, "") + + h := sha1.New() + h.Write([]byte(s)) + us := fmt.Sprintf("%x", h.Sum(nil)) + return signature[0] == us + } + return false +} + +func checkSignature1() bool { + s1 := "e39de9f2e28079c01ebb4b803dfc3442b819545c" + t1 := "1492970761" + n1 := "1850971833" + token := APIConfig.Token + + strs := []string{token, t1, n1} + sort.Strings(strs) + s := strings.Join(strs, "") + + h := sha1.New() + h.Write([]byte(s)) + us := fmt.Sprintf("%x", h.Sum(nil)) + return s1 == us } //webrootHandler sending contents to client when request "/" diff --git a/server_config.json b/server_config.json new file mode 100644 index 0000000..9678c1d --- /dev/null +++ b/server_config.json @@ -0,0 +1,6 @@ +{ + "Token": "skdq8vklaurfqemfszuif", + "EncodingAESKey": "cmtWK2teRnLOXyO5dw7lJkETv9jCeNAqYyguEu5D8gG", + "Appid": "wx876e233fde456b7b", + "AppSecret": "4a91aa328569b10a9fb97adeb8b0af58" +} \ No newline at end of file