Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

175 lines
4.2KB

  1. package main
  2. import (
  3. "encoding/base64"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "log"
  8. "math/rand"
  9. "net/http"
  10. "net/url"
  11. "strconv"
  12. "strings"
  13. "time"
  14. )
  15. func crmpixelImage() (pixel []byte, err error) {
  16. b64pixel := "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QcIBzEJ3JY/6wAAAAh0RVh0Q29tbWVudAD2zJa/AAAADUlEQVQI12NgYGBgAAAABQABXvMqOgAAAABJRU5ErkJggg=="
  17. pixel, err = base64.StdEncoding.DecodeString(b64pixel)
  18. return
  19. }
  20. func crmpixel(w http.ResponseWriter, r *http.Request) {
  21. //log.Println("a")
  22. log.Println(getHTTPRequestQuery(r, "abc"))
  23. cookie := crmpixelCookie(r)
  24. http.SetCookie(w, &cookie)
  25. //send out pixel 1x1 transparent png file
  26. pixel, err := crmpixelImage()
  27. if err == nil {
  28. w.Write(pixel)
  29. } else {
  30. fmt.Fprint(w, "decodig wrong")
  31. }
  32. }
  33. func crmpixelCookie(r *http.Request) (ret http.Cookie) {
  34. cookie, leadok := r.Cookie("biukop_cl") //crm lead
  35. if leadok != nil {
  36. ret, _ = createNewCookie(r)
  37. return
  38. }
  39. valid := isValidCookieBiukopCL(cookie.Value)
  40. if !valid {
  41. ret, _ = createNewCookie(r)
  42. return
  43. }
  44. //refresh expiration
  45. ret = *cookie
  46. ret.Expires = time.Now().Add(10 * 365 * 24 * time.Hour)
  47. return
  48. }
  49. func createNewCookie(r *http.Request) (ret http.Cookie, info crmdLead) {
  50. expiration := time.Now().Add(10 * 365 * 24 * time.Hour)
  51. info = crmCreateNewAnonymousLeadByHTTPRequest(r)
  52. cookieValue := buildBiukopCLValue(info.ID)
  53. ret = http.Cookie{Name: "biukop_cl", Value: cookieValue, Expires: expiration}
  54. return
  55. }
  56. func crmCreateNewAnonymousLeadByHTTPRequest(r *http.Request) (info crmdLead) {
  57. info.FirstName = "Anonymous"
  58. info.LastName = "User " + r.RemoteAddr
  59. info.Password = "Password"
  60. info.Status = "Anonymous"
  61. info.Description = "Anonymous user from " + r.RemoteAddr
  62. info.ForceDuplicate = true
  63. b, err := json.Marshal(info)
  64. if err != nil {
  65. return
  66. }
  67. entity, err := crmCreateEntity("Lead", b)
  68. if err == nil || isErrIndicateDuplicate(err) {
  69. info, _ = entity.(crmdLead)
  70. }
  71. return
  72. }
  73. func isValidCookieBiukopCL(cookieValue string) (valid bool) {
  74. valid = false
  75. //correctly split string
  76. s := strings.Split(cookieValue, "|")
  77. if len(s) != 4 || s[0] == "" {
  78. return
  79. }
  80. id, nonce, timestamp, signature := s[0], s[1], s[2], s[3]
  81. //check signature
  82. combined := id + nonce
  83. expected := calculateSignature(timestamp, combined, IntraAPIConfig.CRMSecrete)
  84. if expected != signature {
  85. return
  86. }
  87. ts, err := strconv.Atoi(timestamp)
  88. if err != nil {
  89. return
  90. }
  91. if timestampOldThan(int32(ts), 86400) { //older than 1 day
  92. //find lead data
  93. _, err := crmpixelLead(id)
  94. if err != nil {
  95. return
  96. }
  97. }
  98. valid = true
  99. return
  100. }
  101. func buildBiukopCLsignature(id, nonce string) (timestamp, signature string) {
  102. combined := id + nonce
  103. timestamp = fmt.Sprintf("%d", time.Now().Unix())
  104. signature = calculateSignature(timestamp, combined, IntraAPIConfig.CRMSecrete)
  105. return
  106. }
  107. func buildBiukopCLValue(id string) (ret string) {
  108. rand.Seed(time.Now().Unix())
  109. nonce := fmt.Sprintf("%d", rand.Intn(655352017))
  110. timestamp, signature := buildBiukopCLsignature(id, nonce)
  111. strs := []string{id, nonce, timestamp, signature} //order is very important
  112. ret = strings.Join(strs, "|")
  113. return
  114. }
  115. func crmpixelLead(id string) (info crmdLead, err error) {
  116. entity, err := crmGetEntity("Lead", id)
  117. if err != nil {
  118. return
  119. }
  120. info, ok := entity.(crmdLead)
  121. if !ok {
  122. err = errors.New("search lead, return a bad entity type")
  123. }
  124. return
  125. }
  126. //for user's initial registration, especially for wechat users
  127. //they visit a url that is specifically designed for them to
  128. //auth and input their profile data.
  129. //the url's query string will contains a token and a signature
  130. //so that it's verified, by single get request, to allow people to
  131. //enter their details into the CRM system.
  132. //
  133. //this handler, check's the query sting ,set an auth cookie to the client
  134. //and serve angular app, through an URL "/profile/edit"
  135. //or if the user has already been registered,
  136. //redirect user to a URL "/pages/dashboard"
  137. //
  138. func setTrackingCookieAndRecirect(w http.ResponseWriter, r *http.Request) {
  139. cookie := crmpixelCookie(r)
  140. http.SetCookie(w, &cookie)
  141. rq := r.URL.RawQuery
  142. m, _ := url.ParseQuery(rq)
  143. url, ok := m["url"]
  144. if ok {
  145. http.Redirect(w, r, url[0], 307) //302 temp redirect
  146. return
  147. }
  148. w.WriteHeader(http.StatusNotFound)
  149. fmt.Fprintf(w, "Not Found URL")
  150. }