|
- package main
-
- import (
- "encoding/base64"
- "encoding/json"
- "errors"
- "fmt"
- "log"
- "math/rand"
- "net/http"
- "net/url"
- "strconv"
- "strings"
- "time"
- )
-
- var cookLeadID = "biukop_cl"
-
- func crmpixelImage() (pixel []byte, err error) {
- b64pixel := "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QcIBzEJ3JY/6wAAAAh0RVh0Q29tbWVudAD2zJa/AAAADUlEQVQI12NgYGBgAAAABQABXvMqOgAAAABJRU5ErkJggg=="
- pixel, err = base64.StdEncoding.DecodeString(b64pixel)
- return
- }
-
- func crmpixel(w http.ResponseWriter, r *http.Request) {
- cookie := crmpixelCookie(r)
- http.SetCookie(w, &cookie)
-
- //send out pixel 1x1 transparent png file
- pixel, err := crmpixelImage()
- if err == nil {
- w.Write(pixel)
- } else {
- fmt.Fprint(w, "decodig pixel image wrong")
- }
- }
-
- func crmpixelCookie(r *http.Request) (ret http.Cookie) {
- cookie, leadok := r.Cookie(cookLeadID) //crm lead
-
- if leadok != nil {
- ret, _ = createNewCookie(r)
- return
- }
-
- valid := isValidCookieBiukopCL(cookie.Value)
- if !valid {
- ret, _ = createNewCookie(r)
- return
- }
-
- //refresh expiration
- ret = *cookie
- ret.Expires = time.Now().Add(10 * 365 * 24 * time.Hour)
-
- return
- }
-
- func getLeadIDFromCookie(r *http.Request) (leadID string, ok bool) {
- ok = false
- cookie, leadok := r.Cookie(cookLeadID) //crm lead
- if leadok != nil {
- return
- }
- valid := isValidCookieBiukopCL(cookie.Value)
- if !valid {
- return
- }
-
- //correctly split string
- s := strings.Split(cookie.Value, "|")
- if len(s) != 4 || s[0] == "" {
- return
- }
- ok = true
- leadID = s[0]
- return
- }
-
- func createNewCookie(r *http.Request) (ret http.Cookie, info crmdLead) {
- info = crmCreateNewAnonymousLeadByHTTPRequest(r)
- ret = createNewCookieByLeadID(info.ID)
- return
- }
-
- func createNewCookieByLeadID(leadID string) (ret http.Cookie) {
- expiration := time.Now().Add(10 * 365 * 24 * time.Hour)
- cookieValue := buildBiukopCLValue(leadID)
- ret = http.Cookie{Name: cookLeadID, Value: cookieValue, Expires: expiration}
- return
- }
-
- func crmCreateNewAnonymousLeadByHTTPRequest(r *http.Request) (info crmdLead) {
- info.FirstName = "Anonymous"
- info.LastName = "User " + r.RemoteAddr
- info.Password = "Password"
- info.Status = "Anonymous"
- info.Description = "Anonymous user from " + r.RemoteAddr
- info.ForceDuplicate = true
- b, err := json.Marshal(info)
- if err != nil {
- return
- }
- entity, err := crmCreateEntity("Lead", b)
- if err == nil || isErrIndicateDuplicate(err) {
- info, _ = entity.(crmdLead)
- }
- return
- }
-
- func isValidCookieBiukopCL(cookieValue string) (valid bool) {
- valid = false
-
- //correctly split string
- s := strings.Split(cookieValue, "|")
- if len(s) != 4 || s[0] == "" {
- return
- }
- id, nonce, timestamp, signature := s[0], s[1], s[2], s[3]
-
- //check signature
- combined := id + nonce
- expected := calculateSignature(timestamp, combined, IntraAPIConfig.CRMSecrete)
- if expected != signature {
- return
- }
-
- ts, err := strconv.Atoi(timestamp)
- if err != nil {
- return
- }
-
- if timestampOldThan(int32(ts), 86400) { //older than 1 day
- //find lead data
- _, err := crmpixelLead(id)
- if err != nil {
- return
- }
- }
- valid = true
- return
- }
-
- func buildBiukopCLsignature(id, nonce string) (timestamp, signature string) {
- combined := id + nonce
- timestamp = fmt.Sprintf("%d", time.Now().Unix())
- signature = calculateSignature(timestamp, combined, IntraAPIConfig.CRMSecrete)
- return
- }
-
- func buildBiukopCLValue(id string) (ret string) {
- rand.Seed(time.Now().Unix())
- nonce := fmt.Sprintf("%d", rand.Intn(655352017))
- timestamp, signature := buildBiukopCLsignature(id, nonce)
- strs := []string{id, nonce, timestamp, signature} //order is very important
- ret = strings.Join(strs, "|")
- return
- }
-
- func crmpixelLead(id string) (info crmdLead, err error) {
- entity, err := crmGetEntity("Lead", id)
- if err != nil {
- return
- }
-
- info, ok := entity.(crmdLead)
- if !ok {
- err = errors.New("search lead, return a bad entity type")
- }
- return
- }
-
- //for user's initial registration, especially for wechat users
- //they visit a url that is specifically designed for them to
- //auth and input their profile data.
- //the url's query string will contains a token and a signature
- //so that it's verified, by single get request, to allow people to
- //enter their details into the CRM system.
- //
- //this handler, check's the query sting ,set an auth cookie to the client
- //and serve angular app, through an URL "/profile/edit"
- //or if the user has already been registered,
- //redirect user to a URL "/pages/dashboard"
- //
- func setTrackingCookieAndRecirect(w http.ResponseWriter, r *http.Request) {
-
- rq := r.URL.RawQuery
- m, _ := url.ParseQuery(rq)
-
- //set cookie if any
- leadID, ok := m["lid"]
- if ok {
- log.Println("setlead cookie :" + leadID[0])
- cookie := createNewCookieByLeadID(leadID[0])
- http.SetCookie(w, &cookie)
- } else {
- cookie := crmpixelCookie(r)
- http.SetCookie(w, &cookie)
- }
-
- url, ok := m["url"]
- if ok {
- http.Redirect(w, r, url[0], 307) //302 temp redirect
- return
- }
- w.WriteHeader(http.StatusNotFound)
- fmt.Fprintf(w, "Not Found URL")
- }
|