github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/utils/utils.go (about)

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