github.com/massongit/reviewdog@v0.0.0-20240331071725-4a16675475a8/doghouse/server/ciutil/ciutil.go (about)

     1  package ciutil
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net"
     7  	"net/http"
     8  	"strings"
     9  	"sync"
    10  )
    11  
    12  var (
    13  	// Set Travis CI addrs by default though UpdateTravisCIIPAddrs will update it
    14  	// with latest one.
    15  	// $ dig +short nat.travisci.net | sort
    16  	// # Updated on 2018-06-03.
    17  	muTravisIPAddrs sync.RWMutex
    18  	travisIPAddrs   = map[string]bool{
    19  		"104.154.113.151": true,
    20  		"104.154.120.187": true,
    21  		"104.197.236.150": true,
    22  		"146.148.51.141":  true,
    23  		"146.148.58.237":  true,
    24  		"147.75.192.163":  true,
    25  		"207.254.16.35":   true,
    26  		"207.254.16.36":   true,
    27  		"207.254.16.37":   true,
    28  		"207.254.16.38":   true,
    29  		"207.254.16.39":   true,
    30  		"34.233.56.198":   true,
    31  		"34.234.4.53":     true,
    32  		"35.184.226.236":  true,
    33  		"35.184.48.144":   true,
    34  		"35.184.96.71":    true,
    35  		"35.188.184.134":  true,
    36  		"35.188.1.99":     true,
    37  		"35.188.73.34":    true,
    38  		"35.192.136.167":  true,
    39  		"35.192.187.174":  true,
    40  		"35.192.19.50":    true,
    41  		"35.192.217.12":   true,
    42  		"35.192.85.2":     true,
    43  		"35.193.203.142":  true,
    44  		"35.193.211.2":    true,
    45  		"35.193.7.13":     true,
    46  		"35.202.145.110":  true,
    47  		"35.202.68.136":   true,
    48  		"35.202.78.106":   true,
    49  		"35.224.112.202":  true,
    50  		"35.226.126.204":  true,
    51  		"52.3.55.28":      true,
    52  		"52.45.185.117":   true,
    53  		"52.45.220.64":    true,
    54  		"52.54.31.11":     true,
    55  		"52.54.40.118":    true,
    56  		"54.208.31.17":    true,
    57  	}
    58  
    59  	// https://www.appveyor.com/docs/build-environment/#ip-addresses
    60  	appveyorIPAddrs = map[string]bool{
    61  		"74.205.54.20":    true,
    62  		"104.197.110.30":  true,
    63  		"104.197.145.181": true,
    64  		"146.148.85.29":   true,
    65  		"67.225.139.254":  true,
    66  		"67.225.138.82":   true,
    67  		"67.225.139.144":  true,
    68  		"138.91.141.243":  true,
    69  	}
    70  )
    71  
    72  // IsFromCI returns true if given request is from trusted CI provider.
    73  func IsFromCI(r *http.Request) bool {
    74  	return IsFromTravisCI(r) || IsFromAppveyor(r)
    75  }
    76  
    77  // IsFromTravisCI returns true if given request is from Travis CI.
    78  // https://docs.travis-ci.com/user/ip-addresses/
    79  func IsFromTravisCI(r *http.Request) bool {
    80  	muTravisIPAddrs.RLock()
    81  	defer muTravisIPAddrs.RUnlock()
    82  	return travisIPAddrs[IPFromReq(r)]
    83  }
    84  
    85  // https://docs.travis-ci.com/user/ip-addresses/
    86  func UpdateTravisCIIPAddrs(cli *http.Client) error {
    87  	ips, err := ipAddrs("nat.travisci.net", cli)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	muTravisIPAddrs.Lock()
    92  	defer muTravisIPAddrs.Unlock()
    93  	travisIPAddrs = map[string]bool{}
    94  	for _, ip := range ips {
    95  		travisIPAddrs[ip] = true
    96  	}
    97  	return nil
    98  }
    99  
   100  // IsFromAppveyor returns true if given request is from Appveyor.
   101  // https://www.appveyor.com/docs/build-environment/#ip-addresses
   102  func IsFromAppveyor(r *http.Request) bool {
   103  	return appveyorIPAddrs[IPFromReq(r)]
   104  }
   105  
   106  func IPFromReq(r *http.Request) string {
   107  	if f := r.Header.Get("Forwarded"); f != "" {
   108  		for _, kv := range strings.Split(f, ";") {
   109  			if kvPair := strings.SplitN(kv, "=", 2); len(kvPair) == 2 &&
   110  				strings.ToLower(strings.TrimSpace(kvPair[0])) == "for" {
   111  				return strings.Trim(kvPair[1], ` "`)
   112  			}
   113  		}
   114  	}
   115  
   116  	ip, _, err := net.SplitHostPort(r.RemoteAddr)
   117  	if err != nil {
   118  		return r.RemoteAddr
   119  	}
   120  	return ip
   121  }
   122  
   123  // Cannot use "github.com/miekg/dns" in Google App Engine.
   124  // Use dnsjson.com instead as workaround.
   125  func ipAddrs(target string, cli *http.Client) ([]string, error) {
   126  	url := fmt.Sprintf("https://dnsjson.com/%s/A.json", target)
   127  	c := http.DefaultClient
   128  	if cli != nil {
   129  		c = cli
   130  	}
   131  	r, err := c.Get(url)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	defer r.Body.Close()
   136  
   137  	var res struct {
   138  		Results struct {
   139  			Records []string `json:"records"`
   140  		} `json:"results"`
   141  	}
   142  
   143  	if err := json.NewDecoder(r.Body).Decode(&res); err != nil {
   144  		return nil, err
   145  	}
   146  
   147  	if len(res.Results.Records) == 0 {
   148  		return nil, fmt.Errorf("failed to get IP addresses of %s", target)
   149  	}
   150  
   151  	return res.Results.Records, nil
   152  }