github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/utils/utils.go (about)

     1  package utils
     2  
     3  import (
     4  	"io/ioutil"
     5  	"net"
     6  	"net/http"
     7  	"net/url"
     8  	"strings"
     9  
    10  	"github.com/masterhung0112/hk_server/v5/model"
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  func StringInSlice(a string, slice []string) bool {
    15  	for _, b := range slice {
    16  		if b == a {
    17  			return true
    18  		}
    19  	}
    20  	return false
    21  }
    22  
    23  // RemoveStringFromSlice removes the first occurrence of a from slice.
    24  func RemoveStringFromSlice(a string, slice []string) []string {
    25  	for i, str := range slice {
    26  		if str == a {
    27  			return append(slice[:i], slice[i+1:]...)
    28  		}
    29  	}
    30  	return slice
    31  }
    32  
    33  // RemoveStringsFromSlice removes all occurrences of strings from slice.
    34  func RemoveStringsFromSlice(slice []string, strings ...string) []string {
    35  	newSlice := []string{}
    36  
    37  	for _, item := range slice {
    38  		if !StringInSlice(item, strings) {
    39  			newSlice = append(newSlice, item)
    40  		}
    41  	}
    42  
    43  	return newSlice
    44  }
    45  
    46  func StringArrayIntersection(arr1, arr2 []string) []string {
    47  	arrMap := map[string]bool{}
    48  	result := []string{}
    49  
    50  	for _, value := range arr1 {
    51  		arrMap[value] = true
    52  	}
    53  
    54  	for _, value := range arr2 {
    55  		if arrMap[value] {
    56  			result = append(result, value)
    57  		}
    58  	}
    59  
    60  	return result
    61  }
    62  
    63  func RemoveDuplicatesFromStringArray(arr []string) []string {
    64  	result := make([]string, 0, len(arr))
    65  	seen := make(map[string]bool)
    66  
    67  	for _, item := range arr {
    68  		if !seen[item] {
    69  			result = append(result, item)
    70  			seen[item] = true
    71  		}
    72  	}
    73  
    74  	return result
    75  }
    76  
    77  func StringSliceDiff(a, b []string) []string {
    78  	m := make(map[string]bool)
    79  	result := []string{}
    80  
    81  	for _, item := range b {
    82  		m[item] = true
    83  	}
    84  
    85  	for _, item := range a {
    86  		if !m[item] {
    87  			result = append(result, item)
    88  		}
    89  	}
    90  	return result
    91  }
    92  
    93  func GetIPAddress(r *http.Request, trustedProxyIPHeader []string) string {
    94  	address := ""
    95  
    96  	for _, proxyHeader := range trustedProxyIPHeader {
    97  		header := r.Header.Get(proxyHeader)
    98  		if header != "" {
    99  			addresses := strings.Fields(header)
   100  			if len(addresses) > 0 {
   101  				address = strings.TrimRight(addresses[0], ",")
   102  			}
   103  		}
   104  
   105  		if address != "" {
   106  			return address
   107  		}
   108  	}
   109  
   110  	if address == "" {
   111  		address, _, _ = net.SplitHostPort(r.RemoteAddr)
   112  	}
   113  
   114  	return address
   115  }
   116  
   117  func GetHostnameFromSiteURL(siteURL string) string {
   118  	u, err := url.Parse(siteURL)
   119  	if err != nil {
   120  		return ""
   121  	}
   122  
   123  	return u.Hostname()
   124  }
   125  
   126  type RequestCache struct {
   127  	Data []byte
   128  	Date string
   129  	Key  string
   130  }
   131  
   132  // Fetch JSON data from the notices server
   133  // if skip is passed, does a fetch without touching the cache
   134  func GetURLWithCache(url string, cache *RequestCache, skip bool) ([]byte, error) {
   135  	// Build a GET Request, including optional If-None-Match header.
   136  	req, err := http.NewRequest("GET", url, nil)
   137  	if err != nil {
   138  		cache.Data = nil
   139  		return nil, err
   140  	}
   141  	if !skip && cache.Data != nil {
   142  		req.Header.Add("If-None-Match", cache.Key)
   143  		req.Header.Add("If-Modified-Since", cache.Date)
   144  	}
   145  
   146  	client := &http.Client{}
   147  	resp, err := client.Do(req)
   148  	if err != nil {
   149  		cache.Data = nil
   150  		return nil, err
   151  	}
   152  	defer resp.Body.Close()
   153  	// No change from latest known Etag?
   154  	if resp.StatusCode == http.StatusNotModified {
   155  		return cache.Data, nil
   156  	}
   157  
   158  	if resp.StatusCode != 200 {
   159  		cache.Data = nil
   160  		return nil, errors.Errorf("Fetching notices failed with status code %d", resp.StatusCode)
   161  	}
   162  
   163  	cache.Data, err = ioutil.ReadAll(resp.Body)
   164  	if err != nil {
   165  		cache.Data = nil
   166  		return nil, err
   167  	}
   168  
   169  	// If etags headers are missing, ignore.
   170  	cache.Key = resp.Header.Get("ETag")
   171  	cache.Date = resp.Header.Get("Date")
   172  	return cache.Data, err
   173  }
   174  
   175  // Append tokens to passed baseUrl as query params
   176  func AppendQueryParamsToURL(baseURL string, params map[string]string) string {
   177  	u, err := url.Parse(baseURL)
   178  	if err != nil {
   179  		return ""
   180  	}
   181  	q, err := url.ParseQuery(u.RawQuery)
   182  	if err != nil {
   183  		return ""
   184  	}
   185  	for key, value := range params {
   186  		q.Add(key, value)
   187  	}
   188  	u.RawQuery = q.Encode()
   189  	return u.String()
   190  }
   191  
   192  // Validates RedirectURL passed during OAuth or SAML
   193  func IsValidWebAuthRedirectURL(config *model.Config, redirectURL string) bool {
   194  	u, err := url.Parse(redirectURL)
   195  	if err == nil && (u.Scheme == "http" || u.Scheme == "https") {
   196  		if config.ServiceSettings.SiteURL != nil {
   197  			siteURL := *config.ServiceSettings.SiteURL
   198  			return strings.Index(strings.ToLower(redirectURL), strings.ToLower(siteURL)) == 0
   199  		}
   200  		return false
   201  	}
   202  	return true
   203  }
   204  
   205  // Validates Mobile Custom URL Scheme passed during OAuth or SAML
   206  func IsValidMobileAuthRedirectURL(config *model.Config, redirectURL string) bool {
   207  	for _, URLScheme := range config.NativeAppSettings.AppCustomURLSchemes {
   208  		if strings.Index(strings.ToLower(redirectURL), strings.ToLower(URLScheme)) == 0 {
   209  			return true
   210  		}
   211  	}
   212  	return false
   213  }