| @@ -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 | |||
| <Event><![CDATA[CLICK]]></Event> | |||
| <EventKey><![CDATA[V1001_GOOD]]></EventKey> | |||
| <Encrypt><![CDATA[wVc64nmeL4VD+GusUXWFyVnNTPZh/QCn17AYtPKIkyLj3h7/Bp6ialT7bhw8+nWxwCx1GwhUHbyderOLLHm4GZ2D7ADf5vIZwGljW1UtjO5BnYvnJnBYfw+pAvFhIgTJwuLocFnrjJDdPKl8DhhUvDQXRLdVLpXG4eXu75YtbHQhNdVCbhfvGRnlSYZak/4rw9+JGGS8gNHI6FU6Sccp6zFBR45iCO70Ezxz3FJIXn3/rMtjAzReX3E6/i92wPqQv7AOZqNmwX/rPBlSG1F3hXwxhpsVuIutGyjCwa7u9fUNDquga8Y6jqmxpcUXuqgKhS2sP5D0LvHULULpON7yEUZDV9Q31RjD5YA8zuiYwxLuQTP7o9fsNp/x0OEHbTxtbNAHo/cMzMxEq+6SKIxerp3X9DVN4EFlqnF8XvntEXlh+dGvdZOEiF6QQsrkITSHneMelzsMucWizxW3e2hwRw==]]></Encrypt> | |||
| </xml> | |||
| 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 | |||
| <xml> | |||
| <ToUserName><![CDATA[gh_f09231355c68]]></ToUserName> | |||
| <FromUserName><![CDATA[oUN420bxqFqlx0ZQHciUOesZO3PE]]></FromUserName> | |||
| <CreateTime>1492829058</CreateTime> | |||
| <MsgType><![CDATA[text]]></MsgType> | |||
| <Content><![CDATA[songbook]]></Content> | |||
| <MsgId>6411651983041024410</MsgId> | |||
| <Encrypt><![CDATA[3muEH/vxWRf76hHB+G4WB744Ho4Fu4RmpYYwd3R0Ek//h3dZDmuzakVztD2ecG8lB0DKV9EAJHaSp/Q4nLQM36Dg9eQQb888e6Z6nyjMX/2Na8upraDHrfR2oW1Gv8AJ0bzrYKubpk7AYtvlvNpnhQ2kDKhn5v1L/Rd8CRSb5ODJ3xDhqQqYd6R4DTr4SF8ofCrqDp0taYkMt4e0eHuCDEp+/A/PLBX1PL8Xw+kv/7eW/aoJQIapXAGMgf61/Qj9RfFmNDG6hKz1bF4CU2u/y4XV63xBepDQ7ZfOmtfALa1pIQGhHzyf5jReArmkLu4yERBzQYwc8G5eDq2WDQrrwaaiaVYo1SDNk0F88zjENobf9I+9lVAFbCly4vhdtlLbRHrUomiAjgzN3nHTza9E6NdCpsJ46C8l+1u/3H7Vq0g=]]></Encrypt> | |||
| </xml> | |||
| @@ -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) | |||
| } | |||
| @@ -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 "/" | |||
| @@ -0,0 +1,6 @@ | |||
| { | |||
| "Token": "skdq8vklaurfqemfszuif", | |||
| "EncodingAESKey": "cmtWK2teRnLOXyO5dw7lJkETv9jCeNAqYyguEu5D8gG", | |||
| "Appid": "wx876e233fde456b7b", | |||
| "AppSecret": "4a91aa328569b10a9fb97adeb8b0af58" | |||
| } | |||