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 }