You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 satır
2.9KB

  1. package main
  2. import (
  3. "crypto/sha1"
  4. "fmt"
  5. "io/ioutil"
  6. "log"
  7. "net/http"
  8. "net/http/httputil"
  9. "net/url"
  10. "sort"
  11. "strings"
  12. )
  13. //apiV1Main version 1 main entry for all wechat callbacks
  14. //
  15. func apiV1Main(w http.ResponseWriter, r *http.Request) {
  16. logRequestDebug(httputil.DumpRequest(r, true))
  17. if checkSignature(r) == false {
  18. log.Println("signature of URL incorrect")
  19. w.WriteHeader(http.StatusUnauthorized)
  20. fmt.Fprintf(w, "") //empty string
  21. return
  22. }
  23. switch r.Method {
  24. case "POST":
  25. answerWechatPost(w, r)
  26. case "GET":
  27. answerInitialAuth(w, r)
  28. default:
  29. log.Fatalln(fmt.Sprintf("Unhandled HTTP %s", r.Method))
  30. fmt.Fprintf(w, "Protocol Error: Expect GET or POST only")
  31. }
  32. }
  33. //
  34. //answerInitialAuth, when wechat first verify our URL for API hooks
  35. //
  36. func answerInitialAuth(w http.ResponseWriter, r *http.Request) {
  37. rq := r.URL.RawQuery
  38. m, _ := url.ParseQuery(rq)
  39. echostr, eok := m["echostr"]
  40. if checkSignature(r) && eok {
  41. fmt.Fprintf(w, echostr[0])
  42. } else {
  43. fmt.Fprintf(w, "wtf is wrong with the Internet")
  44. }
  45. }
  46. //answerWechatPost distribute PostRequest according to xml body info
  47. //
  48. func answerWechatPost(w http.ResponseWriter, r *http.Request) {
  49. body, _ := ioutil.ReadAll(r.Body)
  50. //fmt.Printf("get body: %s", string(body))
  51. s := ReadEncryptedMsg(string(body))
  52. //fmt.Printf("to decrypt %s", s.Encrypt)
  53. d := Decode(s.Encrypt)
  54. fmt.Printf("decrypt as: %s", d)
  55. h := ReadCommonHeader(d)
  56. reply, _ := BuildTextMsg(h.MsgType, h.FromUserName)
  57. fmt.Fprint(w, reply)
  58. return
  59. }
  60. //
  61. func checkSignature(r *http.Request) bool {
  62. rq := r.URL.RawQuery
  63. m, _ := url.ParseQuery(rq)
  64. signature, sok := m["signature"]
  65. timestamp, tok := m["timestamp"]
  66. nonce, nok := m["nonce"]
  67. token := APIConfig.Token
  68. if sok && tok && nok {
  69. //sort token, timestamp, nonce and join them
  70. strs := []string{token, timestamp[0], nonce[0]}
  71. sort.Strings(strs)
  72. s := strings.Join(strs, "")
  73. //calculate sha1
  74. h := sha1.New()
  75. h.Write([]byte(s))
  76. calculated := fmt.Sprintf("%x", h.Sum(nil))
  77. return signature[0] == calculated
  78. }
  79. return false
  80. }
  81. func checkSignature1() bool {
  82. s1 := "e39de9f2e28079c01ebb4b803dfc3442b819545c"
  83. t1 := "1492970761"
  84. n1 := "1850971833"
  85. token := APIConfig.Token
  86. strs := []string{token, t1, n1}
  87. sort.Strings(strs)
  88. s := strings.Join(strs, "")
  89. h := sha1.New()
  90. h.Write([]byte(s))
  91. us := fmt.Sprintf("%x", h.Sum(nil))
  92. return s1 == us
  93. }
  94. //webrootHandler sending contents to client when request "/"
  95. // essentially to prove the webserver is still alive
  96. // echo query string to the client
  97. func webrootHandler(w http.ResponseWriter, r *http.Request) {
  98. fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
  99. rq := r.URL.RawQuery
  100. m, _ := url.ParseQuery(rq)
  101. for index, element := range m {
  102. fmt.Fprintf(w, "\n%s => %s", index, element)
  103. }
  104. logRequestDebug(httputil.DumpRequest(r, true))
  105. }
  106. func logRequestDebug(data []byte, err error) {
  107. if err == nil {
  108. fmt.Printf("%s\n\n", data)
  109. } else {
  110. log.Fatalf("%s\n\n", err)
  111. }
  112. }