github.com/prebid/prebid-server/v2@v2.18.0/pbs/usersync.go (about)

     1  package pbs
     2  
     3  import (
     4  	"crypto/tls"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net/http"
     8  	"net/url"
     9  	"strings"
    10  
    11  	"github.com/golang/glog"
    12  	"github.com/julienschmidt/httprouter"
    13  	"github.com/prebid/prebid-server/v2/config"
    14  	"github.com/prebid/prebid-server/v2/server/ssl"
    15  	"github.com/prebid/prebid-server/v2/usersync"
    16  )
    17  
    18  // Recaptcha code from https://github.com/haisum/recaptcha/blob/master/recaptcha.go
    19  const RECAPTCHA_URL = "https://www.google.com/recaptcha/api/siteverify"
    20  
    21  type UserSyncDeps struct {
    22  	ExternalUrl      string
    23  	RecaptchaSecret  string
    24  	HostCookieConfig *config.HostCookie
    25  	PriorityGroups   [][]string
    26  }
    27  
    28  // Struct for parsing json in google's response
    29  type googleResponse struct {
    30  	Success    bool
    31  	ErrorCodes []string `json:"error-codes"`
    32  }
    33  
    34  func (deps *UserSyncDeps) VerifyRecaptcha(response string) error {
    35  	ts := &http.Transport{
    36  		Proxy:           http.ProxyFromEnvironment,
    37  		TLSClientConfig: &tls.Config{RootCAs: ssl.GetRootCAPool()},
    38  	}
    39  
    40  	client := &http.Client{
    41  		Transport: ts,
    42  	}
    43  	resp, err := client.PostForm(RECAPTCHA_URL,
    44  		url.Values{"secret": {deps.RecaptchaSecret}, "response": {response}})
    45  	if err != nil {
    46  		return err
    47  	}
    48  	defer resp.Body.Close()
    49  	var gr = googleResponse{}
    50  	if err := json.NewDecoder(resp.Body).Decode(&gr); err != nil {
    51  		return err
    52  	}
    53  	if !gr.Success {
    54  		return fmt.Errorf("Captcha verify failed: %s", strings.Join(gr.ErrorCodes, ", "))
    55  	}
    56  	return nil
    57  }
    58  
    59  func (deps *UserSyncDeps) OptOut(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    60  	optout := r.FormValue("optout")
    61  	rr := r.FormValue("g-recaptcha-response")
    62  	encoder := usersync.Base64Encoder{}
    63  	decoder := usersync.Base64Decoder{}
    64  
    65  	if rr == "" {
    66  		http.Redirect(w, r, fmt.Sprintf("%s/static/optout.html", deps.ExternalUrl), http.StatusMovedPermanently)
    67  		return
    68  	}
    69  
    70  	err := deps.VerifyRecaptcha(rr)
    71  	if err != nil {
    72  		if glog.V(2) {
    73  			glog.Infof("Opt Out failed recaptcha: %v", err)
    74  		}
    75  		w.WriteHeader(http.StatusUnauthorized)
    76  		return
    77  	}
    78  
    79  	// Read Cookie
    80  	pc := usersync.ReadCookie(r, decoder, deps.HostCookieConfig)
    81  	usersync.SyncHostCookie(r, pc, deps.HostCookieConfig)
    82  	pc.SetOptOut(optout != "")
    83  
    84  	// Write Cookie
    85  	encodedCookie, err := encoder.Encode(pc)
    86  	if err != nil {
    87  		w.WriteHeader(http.StatusBadRequest)
    88  		return
    89  	}
    90  	usersync.WriteCookie(w, encodedCookie, deps.HostCookieConfig, false)
    91  
    92  	if optout == "" {
    93  		http.Redirect(w, r, deps.HostCookieConfig.OptInURL, http.StatusMovedPermanently)
    94  	} else {
    95  		http.Redirect(w, r, deps.HostCookieConfig.OptOutURL, http.StatusMovedPermanently)
    96  	}
    97  }