github.com/aldelo/common@v1.5.1/helper-net.go (about) 1 package helper 2 3 /* 4 * Copyright 2020-2023 Aldelo, LP 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "fmt" 23 "github.com/aldelo/common/rest" 24 "io/ioutil" 25 "net" 26 "net/http" 27 "net/url" 28 "strings" 29 "time" 30 ) 31 32 // GetNetListener triggers the specified port to listen via tcp 33 func GetNetListener(port uint) (net.Listener, error) { 34 if l, e := net.Listen("tcp", fmt.Sprintf(":%d", port)); e != nil { 35 return nil, fmt.Errorf("Listen Tcp on Port %d Failed: %v", port, e) 36 } else { 37 return l, nil 38 } 39 } 40 41 // IsHttpsEndpoint returns true if url is https, false if otherwise 42 func IsHttpsEndpoint(url string) bool { 43 return strings.ToLower(Left(url, 8)) == "https://" 44 } 45 46 // GetLocalIP returns the first non loopback ip 47 func GetLocalIP() string { 48 if addrs, err := net.InterfaceAddrs(); err != nil { 49 return "" 50 } else { 51 for _, a := range addrs { 52 if ip, ok := a.(*net.IPNet); ok && !ip.IP.IsLoopback() && !ip.IP.IsInterfaceLocalMulticast() && !ip.IP.IsLinkLocalMulticast() && !ip.IP.IsLinkLocalUnicast() && !ip.IP.IsMulticast() && !ip.IP.IsUnspecified() { 53 if ip.IP.To4() != nil { 54 return ip.IP.String() 55 } 56 } 57 } 58 59 return "" 60 } 61 } 62 63 // DnsLookupIps returns list of IPs for the given host 64 // if host is private on aws route 53, then lookup ip will work only when within given aws vpc that host was registered with 65 func DnsLookupIps(host string) (ipList []net.IP) { 66 if ips, err := net.LookupIP(host); err != nil { 67 return []net.IP{} 68 } else { 69 for _, ip := range ips { 70 ipList = append(ipList, ip) 71 } 72 return ipList 73 } 74 } 75 76 // DnsLookupSrvs returns list of IP and port addresses based on host 77 // if host is private on aws route 53, then lookup ip will work only when within given aws vpc that host was registered with 78 func DnsLookupSrvs(host string) (ipList []string) { 79 if _, addrs, err := net.LookupSRV("", "", host); err != nil { 80 return []string{} 81 } else { 82 for _, v := range addrs { 83 ipList = append(ipList, fmt.Sprintf("%s:%d", v.Target, v.Port)) 84 } 85 86 return ipList 87 } 88 } 89 90 // ParseHostFromURL will parse out the host name from url 91 func ParseHostFromURL(url string) string { 92 parts := strings.Split(strings.ReplaceAll(strings.ReplaceAll(strings.ToLower(url), "https://", ""), "http://", ""), "/") 93 94 if len(parts) >= 0 { 95 return parts[0] 96 } else { 97 return "" 98 } 99 } 100 101 // VerifyGoogleReCAPTCHAv2 will verify recaptcha v2 response data against given secret and obtain a response from google server 102 func VerifyGoogleReCAPTCHAv2(response string, secret string) (success bool, challengeTs time.Time, hostName string, err error) { 103 if LenTrim(response) == 0 { 104 return false, time.Time{}, "", fmt.Errorf("ReCAPTCHA Response From CLient is Required") 105 } 106 107 if LenTrim(secret) == 0 { 108 return false, time.Time{}, "", fmt.Errorf("ReCAPTCHA Secret Key is Required") 109 } 110 111 u := fmt.Sprintf("https://www.google.com/recaptcha/api/siteverify?secret=%s&response=%s", url.PathEscape(secret), url.PathEscape(response)) 112 113 if statusCode, responseBody, e := rest.POST(u, []*rest.HeaderKeyValue{}, ""); e != nil { 114 return false, time.Time{}, "", fmt.Errorf("ReCAPTCHA Service Failed: %s", e) 115 } else { 116 if statusCode != 200 { 117 return false, time.Time{}, "", fmt.Errorf("ReCAPTCHA Service Failed: Status Code %d", statusCode) 118 } else { 119 m := make(map[string]json.RawMessage) 120 if err = json.Unmarshal([]byte(responseBody), &m); err != nil { 121 return false, time.Time{}, "", fmt.Errorf("ReCAPTCHA Service Response Failed: (Parse Json Response Error) %s", err) 122 } else { 123 if m == nil { 124 return false, time.Time{}, "", fmt.Errorf("ReCAPTCHA Service Response Failed: %s", "Json Response Map Nil") 125 } else { 126 // response json from google is valid 127 if strings.ToLower(string(m["success"])) == "true" { 128 success = true 129 } 130 131 challengeTs = ParseDateTime(string(m["challenge_ts"])) 132 hostName = string(m["hostname"]) 133 134 if !success { 135 errs := string(m["error-codes"]) 136 s := []string{} 137 138 if err = json.Unmarshal([]byte(errs), &s); err != nil { 139 err = fmt.Errorf("Parse ReCAPTCHA Verify Errors Failed: %s", err) 140 } else { 141 buf := "" 142 143 for _, v := range s { 144 if LenTrim(v) > 0 { 145 if LenTrim(buf) > 0 { 146 buf += ", " 147 } 148 149 buf += v 150 } 151 } 152 153 err = fmt.Errorf("ReCAPTCHA Verify Errors: %s", buf) 154 } 155 } 156 157 return success, challengeTs, hostName, err 158 } 159 } 160 } 161 } 162 } 163 164 // ReadHttpRequestBody reads raw body from http request body object, 165 // and then sets the read body back to the request (once reading will remove the body content if not restored) 166 func ReadHttpRequestBody(req *http.Request) ([]byte, error) { 167 if req == nil { 168 return []byte{}, fmt.Errorf("Http Request Nil") 169 } 170 171 if body, err := ioutil.ReadAll(req.Body); err != nil { 172 return []byte{}, err 173 } else { 174 req.Body = ioutil.NopCloser(bytes.NewBuffer(body)) 175 return body, nil 176 } 177 } 178 179 // ReadHttpRequestHeaders parses headers into map 180 func ReadHttpRequestHeaders(req *http.Request) (map[string]string, error) { 181 if req == nil { 182 return nil, fmt.Errorf("Http Request Nil") 183 } 184 185 m := make(map[string]string) 186 187 for k, v := range req.Header { 188 buf := "" 189 190 for _, d := range v { 191 if LenTrim(buf) > 0 { 192 buf += "; " 193 } 194 195 buf += d 196 } 197 198 m[k] = buf 199 } 200 201 return m, nil 202 } 203 204 // ParseHttpHeader parses headers into map[string]string, 205 // where slice of header values for a key is delimited with semi-colon (;) 206 func ParseHttpHeader(respHeader http.Header) (map[string]string, error) { 207 if respHeader == nil { 208 return nil, fmt.Errorf("Http Response Header Nil") 209 } 210 211 m := make(map[string]string) 212 213 for k, v := range respHeader { 214 buf := "" 215 216 for _, d := range v { 217 if LenTrim(buf) > 0 { 218 buf += "; " 219 } 220 221 buf += d 222 } 223 224 m[k] = buf 225 } 226 227 return m, nil 228 } 229 230 // EncodeHttpHeaderMapToString converts header map[string]string to string representation 231 func EncodeHttpHeaderMapToString(headerMap map[string]string) string { 232 if headerMap == nil { 233 return "" 234 } else { 235 buf := "" 236 237 for k, v := range headerMap { 238 buf += fmt.Sprintf("%s: %s\n", k, v) 239 } 240 241 return buf 242 } 243 }