├── .gcloudignore ├── README.md ├── akamai ├── abck.go └── generator.go ├── app.yaml ├── cmd └── api │ └── api.go ├── config.json ├── config └── config.go ├── db ├── db.go └── types.go ├── doc └── PX.md ├── go.mod ├── go.sum ├── http └── ratelimiter │ └── ratelimiter.go ├── px ├── generator.go └── px.go ├── source └── script_v6.2.1.js └── utils └── encrypt.go /.gcloudignore: -------------------------------------------------------------------------------- 1 | # This file specifies files that are *not* uploaded to Google Cloud Platform 2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of 3 | # "#!include" directives (which insert the entries of the given .gitignore-style 4 | # file at that point). 5 | # 6 | # For more information, run: 7 | # $ gcloud topic gcloudignore 8 | # 9 | .gcloudignore 10 | # If you would like to upload your .git directory, .gitignore file or files 11 | # from your .gitignore file, remove the corresponding line 12 | # below: 13 | .git 14 | .gitignore 15 | 16 | # Binaries for programs and plugins 17 | *.exe 18 | *.exe~ 19 | *.dll 20 | *.so 21 | *.dylib 22 | # Test binary, build with `go test -c` 23 | *.test 24 | # Output of the go coverage tool, specifically when used with LiteIDE 25 | *.out -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **NOTE: This project used to be a fork but the original author deleted the repository, which automatically made me the new 'owner'. See [GitHub docs](https://docs.github.com/en/github/collaborating-with-pull-requests/working-with-forks/what-happens-to-forks-when-a-repository-is-deleted-or-changes-visibility#deleting-a-public-repository) for more information about this topic. I do not wish to continue maintenance of this project myself though.** 2 | 3 | --- 4 | 5 | # Cookie API 6 | 7 | This API made in Go is used to generate cookie for Akamai & PX. Made by @obito. 8 | 9 | Every secret config value doesn't work anymore. Don't try to connect to the PSQL database, won't work. 10 | 11 | # Notes 12 | 13 | I got a lot of message/emails and hate about this repo. I'm not going to delete it, it's a very good project to show my skills, no matter if others can reuse it for their sneaker bot and add more competition for some. Be greatful of this kind of repo, because if you were a beginner, you would have loved it. 14 | 15 | Here are note about: 16 | * [PX](doc/PX.md) 17 | -------------------------------------------------------------------------------- /akamai/abck.go: -------------------------------------------------------------------------------- 1 | package akamai 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log" 7 | "math" 8 | "math/rand" 9 | "reflect" 10 | "regexp" 11 | "sort" 12 | "strconv" 13 | "strings" 14 | "time" 15 | ) 16 | 17 | func randomNumberInt(min int, max int) int { 18 | rand.Seed(time.Now().UnixNano()) 19 | return rand.Intn(max-min) + min 20 | } 21 | 22 | func randomNumberFloat() float64 { 23 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 24 | return r.Float64() 25 | } 26 | 27 | func FpVal(bmak *Bmak) Fpcf { 28 | return Fpcf{ 29 | RVal: fmt.Sprintf("%.f", math.Floor(randomNumberFloat()*(1000-1+1))+1), 30 | RCfp: "-1249560680", 31 | Td: math.Floor(randomNumberFloat()*(23-17+1)) + 17, 32 | } 33 | 34 | } 35 | 36 | func DeviceAct(bmak *Bmak) *Bmak { 37 | do := math.Floor(randomNumberFloat()*(50-15+1)) + 15 38 | 39 | if do < 25 { 40 | bmak.Doact = "" 41 | bmak.DoeVel = 0 42 | bmak.Dmact = "" 43 | bmak.DmeVel = 0 44 | bmak.Ta = 0 45 | } else { 46 | DoActTime := math.Floor(randomNumberFloat()*(310-50+1)) + 50 47 | bmak.Doact = "0," + fmt.Sprintf("%.f", DoActTime) + ",-1,-1,-1;" 48 | bmak.DoeVel = DoActTime 49 | bmak.Ta = bmak.Ta + DoActTime 50 | 51 | DMacTime := DoActTime - math.Floor(randomNumberFloat()*(60-5+1)) + 5 52 | bmak.Dmact = "0," + fmt.Sprintf("%.f", DMacTime) + ",-1,-1,-1,-1,-1,-1,-1,-1,-1;" 53 | bmak.DmeVel = DMacTime 54 | bmak.Ta = bmak.Ta + DMacTime 55 | } 56 | 57 | return bmak 58 | } 59 | 60 | func GetCfDate() int64 { 61 | t := time.Now() 62 | tUnixMilli := int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond) 63 | return tUnixMilli 64 | } 65 | 66 | func D3() int64 { 67 | return GetCfDate() % 1e7 68 | } 69 | 70 | func rir(t int, a int, e int, n int) int { 71 | if t > a && t <= e { 72 | t += n % (e - a) 73 | if t > e { 74 | t = t - e + a 75 | } 76 | } 77 | return t 78 | } 79 | 80 | func Od(t string, a string) string { 81 | var e []string 82 | n := len(a) 83 | if n > 0 { 84 | for o := 0; o < len(t); o++ { 85 | m := []rune(t)[o] 86 | r := string(t[o]) 87 | i := a[(o % n)] 88 | m = rune(rir(int(m), 47, 57, int(i))) 89 | if m != []rune(t)[o] { 90 | r = string(m) 91 | } 92 | e = append(e, r) 93 | } 94 | if len(e) > 0 { 95 | return strings.Join(e[:], "") 96 | } 97 | } 98 | return t 99 | } 100 | 101 | func Ab(t string) int { 102 | a := 0 103 | for e := 0; e < len(t); e++ { 104 | n := []rune(t)[e] 105 | if n < 128 { 106 | a += int(n) 107 | } 108 | } 109 | return a 110 | } 111 | 112 | func Uar(userAgent string) string { 113 | return regexp.MustCompile(`/\\|"/g`).ReplaceAllString(userAgent, "") 114 | } 115 | 116 | func Fas(browser string) (int, error) { 117 | if browser == "chrome" { 118 | return 30261693, nil 119 | } else if browser == "firefox" { 120 | return 26067385, nil 121 | } else { 122 | return 0, errors.New("Unsupported browser specified (use \"chrome\" or \"firefox\")") 123 | } 124 | } 125 | 126 | func mrjp(flt float64) float64 { 127 | return flt 128 | } 129 | 130 | func mrinf(flt float64) bool { 131 | return math.IsInf(flt, 0) 132 | } 133 | 134 | func invoke(fn interface{}, args ...float64) { 135 | v := reflect.ValueOf(fn) 136 | rargs := make([]reflect.Value, len(args)) 137 | for i, a := range args { 138 | rargs[i] = reflect.ValueOf(a) 139 | } 140 | v.Call(rargs) 141 | } 142 | 143 | func Getmr() string { 144 | t := "" 145 | var e []interface{} 146 | e = append(e, math.Abs, math.Acos, math.Asin, math.Atanh, math.Cbrt, math.Exp, mrjp, math.Sqrt, mrinf, math.IsNaN, mrjp, mrjp, mrjp, mrjp) 147 | for n := 0; n < len(e); n++ { 148 | var o []float64 149 | var m float64 150 | m = 0.0 151 | r := time.Now() 152 | c := 0 153 | for i := 0; i < 1000 && m < .6; i++ { 154 | b := time.Now() 155 | for d := 0; d < 4e3; d++ { 156 | invoke(e[n], 3.14) 157 | } 158 | k := time.Now() 159 | o = append(o, 1000*math.Round(float64(k.UnixNano()/1000000)-float64(b.UnixNano()/1000000))) 160 | m = float64(k.UnixNano()/1000000) - float64(r.UnixNano()/1000000) 161 | s := o 162 | sort.Float64s(s) 163 | c = int(s[int(math.Floor(float64(len(s)/2)))]) / 5 164 | t = fmt.Sprintf("%v%v,", t, c) 165 | } 166 | } 167 | return t 168 | } 169 | 170 | func Sed(browser string) string { 171 | return "0,0,0,0,1,0,0" 172 | } 173 | 174 | func Np(browser string) (string, error) { 175 | if browser == "chrome" { 176 | return "10321144241322243122", nil 177 | } else if browser == "firefox" { 178 | return "11133333331333333333", nil 179 | } else { 180 | return "", errors.New("Unsupported browser specified (use \"chrome\" or \"firefox\")") 181 | } 182 | } 183 | 184 | func calDis(t []int) float64 { 185 | a := t[0] - t[1] 186 | e := t[2] - t[3] 187 | n := t[4] - t[5] 188 | return math.Floor(math.Sqrt(float64(a*a + e*e + n*n))) 189 | } 190 | 191 | func Jrs(t int) ([]float64, error) { 192 | a := int(math.Floor(100000*randomNumberFloat() + 10000)) 193 | e := strconv.Itoa(t * a) 194 | m := len(e) >= 18 195 | n := 0 196 | var o []int 197 | for len(o) < 6 { 198 | num, err := strconv.Atoi(e[n:(n + 2)]) 199 | if err != nil { 200 | return []float64{}, err 201 | } 202 | o = append(o, num) 203 | if m { 204 | n = n + 3 205 | } else { 206 | n = n + 2 207 | } 208 | } 209 | return []float64{float64(a), calDis(o)}, nil 210 | } 211 | 212 | func cc(t int) func(int, int) int { 213 | a := t % 4 214 | if 2 == a { 215 | a = 3 216 | } 217 | e := 42 + a 218 | var n func(int, int) int 219 | n = func(t int, a int) int { 220 | return 0 221 | } 222 | if 42 == e { 223 | n = func(t int, a int) int { 224 | return t * a 225 | } 226 | } else if 43 == e { 227 | n = func(t int, a int) int { 228 | return t + a 229 | } 230 | } else { 231 | n = func(t int, a int) int { 232 | return t - a 233 | } 234 | } 235 | return n 236 | } 237 | 238 | func O9(d3 int64) int { 239 | a := int(d3) 240 | for n := 0; n < 5; n++ { 241 | o := math.Mod(math.Floor(float64(d3)/math.Pow(10, float64(n))), 10) 242 | m := o + 1 243 | op := cc(int(o)) 244 | a = op(int(a), int(m)) 245 | } 246 | 247 | return a * 3 248 | } 249 | 250 | func GetType(t string) int { 251 | t = strings.ToLower(t) 252 | if "text" == t || "search" == t || "url" == t || "email" == t || "tel" == t || "number" == t { 253 | return 0 254 | } else if "password" == t { 255 | return 1 256 | } else { 257 | return 2 258 | } 259 | } 260 | 261 | func Z1(startTimestamp int64) int64 { 262 | return startTimestamp / 2016 * 2016 263 | } 264 | 265 | func floatToString(flt float64, precision int) string { 266 | return strconv.FormatFloat(flt, 'f', precision, 64) 267 | } 268 | 269 | type ScreenData struct { 270 | AvailWidth int 271 | AvailHeight int 272 | Width int 273 | Height int 274 | InnerWidth int 275 | InnerHeight int 276 | OuterWidth int 277 | } 278 | 279 | type BrowserData struct { 280 | Lang string 281 | UserAgent string 282 | ScreenData ScreenData 283 | } 284 | 285 | func Gd(browser string, browserData BrowserData, startTimestamp int64, d3 int64) (string, error) { 286 | userAgent := Uar(browserData.UserAgent) 287 | d := randomNumberFloat() 288 | xagg := 0 289 | psub := 0 290 | plen := 0 291 | bd := "" 292 | if browser == "chrome" { 293 | xagg = 12147 294 | psub = 20030107 295 | plen = 3 296 | bd = ",cpen:0,i1:0,dm:0,cwen:0,non:1,opc:0,fc:0,sc:0,wrc:1,isc:0,vib:1,bat:1,x11:0,x12:1" 297 | } else if browser == "firefox" { 298 | xagg = 11059 299 | psub = 20100101 300 | plen = 0 301 | bd = fmt.Sprintf(",cpen:0,i1:0,dm:0,cwen:0,non:1,opc:0,fc:1,sc:0,wrc:1,isc:%v,vib:1,bat:0,x11:0,x12:1", randomNumberInt(60, 100)) 302 | } else { 303 | return "", errors.New("Unsupported browser specified (use \"chrome\" or \"firefox\")") 304 | } 305 | return fmt.Sprintf( 306 | "%v,uaend,%v,%v,%v,Gecko,%v,0,0,0,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,loc:", 307 | userAgent, 308 | xagg, 309 | psub, 310 | browserData.Lang, 311 | plen, 312 | Z1(startTimestamp), 313 | d3, 314 | browserData.ScreenData.AvailWidth, 315 | browserData.ScreenData.AvailHeight, 316 | browserData.ScreenData.Width, 317 | browserData.ScreenData.Height, 318 | browserData.ScreenData.InnerWidth, 319 | browserData.ScreenData.InnerHeight, 320 | browserData.ScreenData.OuterWidth, 321 | bd, 322 | Ab(userAgent), 323 | floatToString(d, 16)[0:11]+floatToString(math.Floor(1000*d/2), -1), 324 | startTimestamp/2), nil 325 | } 326 | 327 | func GetH(bmak *Bmak) string { 328 | d2 := int(bmak.Z1 / 23) 329 | log.Print(bmak.Z1 / 23) 330 | f := int(d2 / 6) 331 | updateT := GetCfDate() - bmak.StartTimeStamp 332 | startDif := GetCfDate() - bmak.StartTimeStamp 333 | u, err := Jrs(int(bmak.StartTimeStamp)) 334 | if err != nil { 335 | log.Fatal(err) 336 | } 337 | 338 | var velSum = bmak.KeVel + bmak.MeVel + bmak.DoeVel + bmak.DmeVel + bmak.TeVel + bmak.PeVel 339 | 340 | fas, err := Fas("chrome") 341 | if err != nil { 342 | log.Fatal(err) 343 | } 344 | 345 | return fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v", bmak.KeVel+1, bmak.MeVel+32, bmak.TeVel+32, bmak.DoeVel, bmak.DmeVel, bmak.PeVel, velSum, updateT, bmak.InitTime, bmak.StartTimeStamp, bmak.Fpcf.Td, d2, bmak.KeCnt, bmak.MeCnt, f, bmak.PeCnt, bmak.TeCnt, startDif, bmak.Ta, bmak.NCk, bmak.Abck, Ab(bmak.Abck), bmak.Fpcf.RVal, bmak.Fpcf.RCfp, fas, "PiZtE", u[0], u[1]) 346 | } 347 | -------------------------------------------------------------------------------- /akamai/generator.go: -------------------------------------------------------------------------------- 1 | package akamai 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "strconv" 7 | 8 | "github.com/GuapAIO/akamai-api/db" 9 | ) 10 | 11 | type Fpcf struct { 12 | FpValStr string `json:"fpValstr"` 13 | RVal string `json:"rVal"` 14 | RCfp string `json:"rCFP"` // need to collect this from users 15 | Td float64 `json:"td"` 16 | } 17 | 18 | type Bmak struct { 19 | UserAgent string `json:"useragent"` 20 | URL string `json:"url"` // URL to generate abck for 21 | 22 | Z1 int64 `json:"z1"` 23 | Abck string 24 | 25 | StartTimeStamp int64 `json:"start_ts"` 26 | Xagg string `json:"xagg"` 27 | Psub string `json:"psub"` 28 | Lang string `json:"lang"` 29 | Prod string `json:"prod"` 30 | Plen string `json:"plen"` 31 | Pen string `json:"pen"` 32 | Wen string `json:"wen"` 33 | Den string `json:"den"` 34 | DeviceEvents string `json:"device_events"` 35 | Fas string `json:"fas"` 36 | Sed string `json:"sed"` 37 | Kact string `json:"kact"` 38 | Mact string `json:"mact"` 39 | Tact string `json:"tact"` 40 | Doact string `json:"doact"` 41 | Dmact string `json:"dmact"` 42 | Pact string `json:"pact"` 43 | Vcact string `json:"vcact"` 44 | KeVel float64 `json:"ke_vel"` 45 | MeVel float64 `json:"me_vel"` 46 | TeVel float64 `json:"te_vel"` 47 | DoeVel float64 `json:"doe_vel"` 48 | DmeVel float64 `json:"dme_vel"` 49 | PeVel float64 `json:"pe_vel"` 50 | InitTime float64 `json:"init_time"` 51 | KeCnt float64 `json:"ke_cnt"` 52 | MeCnt float64 `json:"me_cnt"` 53 | PeCnt float64 `json:"pe_cnt"` 54 | TeCnt float64 `json:"te_cnt"` 55 | Ta float64 `json:"ta"` 56 | NCk float64 `json:"n_ck"` 57 | AjType string `json:"aj_type"` 58 | AjIndx string `json:"aj_indx"` 59 | Mr string `json:"mr"` 60 | NavPerm string `json:"nav_perm"` 61 | APIPublicKey string `json:"api_public_key"` 62 | Cs string `json:"cs"` 63 | Tst int64 `json:"tst"` 64 | WebGLRender string `json:"webglRender"` 65 | Ts float64 `json:"ts"` 66 | 67 | Fpcf Fpcf `json:"fpcf"` 68 | } 69 | 70 | func GenCookie(url string, abckCookie string, sensorInfo db.SensorData) (string, error) { 71 | startTimestamp := GetCfDate() 72 | 73 | abck := &Bmak{ 74 | UserAgent: sensorInfo.Navigator.UserAgent, 75 | URL: url, 76 | StartTimeStamp: startTimestamp, 77 | Z1: Z1(startTimestamp), 78 | Abck: abckCookie, 79 | Xagg: "12147", 80 | Psub: sensorInfo.Navigator.ProductSub, 81 | Lang: sensorInfo.Navigator.Language, 82 | Prod: "Gecko", 83 | Plen: "3", 84 | Pen: "0", 85 | Wen: "0", 86 | Den: "0", 87 | DeviceEvents: "do_en,dm_en,t_en", 88 | Fas: "30261693", 89 | Sed: "0,0,0,0,1,0,0", 90 | Kact: "", 91 | Mact: "", 92 | Tact: "", 93 | Doact: "", 94 | Dmact: "", 95 | Pact: "", 96 | Vcact: "", 97 | KeVel: 0, 98 | MeVel: 0, 99 | TeVel: 0, 100 | DoeVel: 0, 101 | DmeVel: 0, 102 | PeVel: 0, 103 | InitTime: 0, 104 | KeCnt: 0, 105 | MeCnt: 0, 106 | PeCnt: 0, 107 | TeCnt: 0, 108 | Ta: 0, 109 | NCk: 0, 110 | AjType: "0", 111 | AjIndx: "0", 112 | Mr: sensorInfo.Mr, 113 | NavPerm: "8", 114 | APIPublicKey: "afSbep8yjnZUjq3aL010jO15Sawj2VZfdYK8uY90uxq", 115 | Cs: "0a46G5m17Vrp4o4c", 116 | Tst: -1, 117 | WebGLRender: "", 118 | Ts: float64(GetCfDate()) - math.Floor(randomNumberFloat()*(11-5+1)+5), 119 | 120 | Fpcf: Fpcf{ 121 | FpValStr: sensorInfo.FpValstr, 122 | RVal: "-1", 123 | RCfp: sensorInfo.RCFP, 124 | Td: -999999, 125 | }, 126 | } 127 | 128 | akamaiVersion := "1.66" 129 | 130 | d3 := D3() 131 | 132 | gd, err := Gd("chrome", BrowserData{ 133 | UserAgent: abck.UserAgent, 134 | Lang: abck.Lang, 135 | ScreenData: ScreenData{ 136 | AvailHeight: sensorInfo.ScreenData.AvailHeight, 137 | AvailWidth: sensorInfo.ScreenData.AvailWidth, 138 | Height: sensorInfo.ScreenData.Height, 139 | Width: sensorInfo.ScreenData.Width, 140 | InnerHeight: sensorInfo.ScreenData.InnerHeight, 141 | InnerWidth: sensorInfo.ScreenData.InnerWidth, 142 | }, 143 | }, int64(abck.StartTimeStamp), d3) 144 | if err != nil { 145 | return "", err 146 | } 147 | 148 | abck = DeviceAct(abck) 149 | 150 | v := GetH(abck) 151 | 152 | informInfo := "0,0,0,0,-1,113,0;0,0,0,1,1125,-1,0;0,-1,0,0,993,-1,0;" 153 | ajCount := abck.AjType + "," + abck.AjIndx 154 | 155 | sensorData := akamaiVersion + "-1,2,-94,-100," + gd + "-1,2,-94,-101," + abck.DeviceEvents + "-1,2,-94,-105," + informInfo + "-1,2,-94,-102," + informInfo + "-1,2,-94,-108," + abck.Kact + "-1,2,-94,-110," + abck.Mact + "-1,2,-94,-114," + abck.Tact + "-1,2,-94,-111," + abck.Doact + "-1,2,-94,-109," + abck.Dmact + "-1,2,-94,-114," + abck.Pact + "-1,2,-94,-103," + abck.Vcact + "-1,2,-94,-112," + abck.URL + "-1,2,-94,-115," + v + "-1,2,-94,-106," + ajCount + "-1,2,-94,-119," + abck.Mr + "-1,2,-94,-122," + abck.Sed + "-1,2,-94,-123," + "-1,2,-94,-124," + "-1,2,-94,-126," + "-1,2,-94,-127," + abck.NavPerm 156 | 157 | sdHash := 24 ^ Ab(sensorData) 158 | 159 | sensorData = sensorData + "-1,2,-94,-70," + abck.Fpcf.FpValStr + "-1,2,-94,-80," + "" + strconv.Itoa(Ab(abck.Fpcf.FpValStr)) + "-1,2,-94,-116," + strconv.Itoa(O9(d3)) + "-1,2,-94,-118," + strconv.Itoa(sdHash) + "-1,2,-94,-129," + abck.WebGLRender + "-1,2,-94,-121," 160 | 161 | t := Od(abck.Cs, abck.APIPublicKey)[0:16] 162 | f := math.Floor(float64(GetCfDate() / 36e5)) 163 | d := GetCfDate() 164 | 165 | b := t + Od(fmt.Sprintf("%.f", f), t) + sensorData 166 | 167 | sensorData = b + ";" + strconv.Itoa(int(GetCfDate()-abck.StartTimeStamp)) + ";" + strconv.Itoa(int(abck.Tst)) + ";" + strconv.Itoa(int(GetCfDate()-d)) 168 | 169 | return sensorData, nil 170 | } 171 | -------------------------------------------------------------------------------- /app.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | runtime: go114 # replace with go111 for Go 1.11 16 | main: cmd/api 17 | 18 | env_variables: 19 | INSTANCE_CONNECTION_NAME: /cloudsql/handy-reference-296015:europe-west2:sensor/.s.PGSQL.5432 20 | DB_USER: postgres 21 | DB_PASS: 0okgANm3kD3q1viO 22 | DB_NAME: sensor -------------------------------------------------------------------------------- /cmd/api/api.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/json" 6 | "log" 7 | "net/http" 8 | "os" 9 | 10 | "github.com/GuapAIO/akamai-api/akamai" 11 | "github.com/GuapAIO/akamai-api/config" 12 | "github.com/GuapAIO/akamai-api/db" 13 | "github.com/GuapAIO/akamai-api/px" 14 | "github.com/GuapAIO/akamai-api/utils" 15 | "github.com/gin-contrib/cors" 16 | "github.com/gin-gonic/gin" 17 | "github.com/go-pg/pg" 18 | ) 19 | 20 | type GeneratorRequest struct { 21 | LicenseKey string `json:"licenseKey,omitempty"` 22 | 23 | Payload string `json:"payload"` 24 | } 25 | 26 | type AkamaiGeneratorRequest struct { 27 | Abck string `json:"abck"` 28 | URL string `json:"url"` 29 | } 30 | 31 | type PXGeneratorRequest struct { 32 | TargetURL string `json:"target"` 33 | URL string `json:"url"` 34 | } 35 | 36 | // mustGetEnv is a helper function for getting environment variables. 37 | // Displays a warning if the environment variable is not set. 38 | func mustGetenv(k string) string { 39 | v := os.Getenv(k) 40 | if v == "" { 41 | log.Fatalf("Warning: %s environment variable not set.\n", k) 42 | } 43 | return v 44 | } 45 | 46 | func main() { 47 | config.LoadConfig() 48 | 49 | var dbPostgres *pg.DB 50 | 51 | if config.Conf.Database.Addr != "" { 52 | dbPostgres = db.ConnectDb(&pg.Options{ 53 | Addr: config.Conf.Database.Addr, 54 | User: config.Conf.Database.Username, 55 | Password: config.Conf.Database.Password, 56 | Database: config.Conf.Database.Database, 57 | }) 58 | 59 | } else { 60 | dbPostgres = db.ConnectDb(&pg.Options{ 61 | Network: "unix", 62 | Addr: mustGetenv("INSTANCE_CONNECTION_NAME"), 63 | User: mustGetenv("DB_USER"), 64 | Password: mustGetenv("DB_PASS"), 65 | Database: mustGetenv("DB_NAME"), 66 | }) 67 | } 68 | 69 | r := gin.Default() 70 | 71 | // Enable CORS 72 | r.Use(cors.Default()) 73 | 74 | r.GET("/ping", func(c *gin.Context) { 75 | c.JSON(200, gin.H{ 76 | "message": "pong", 77 | }) 78 | }) 79 | 80 | r.POST("/gen/akamai", func(c *gin.Context) { 81 | // Unmarshal the JSON 82 | var genJSON GeneratorRequest 83 | if err := c.ShouldBindJSON(&genJSON); err != nil { 84 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 85 | return 86 | } 87 | 88 | // Decode the base64 string 89 | decodedPayload, err := base64.RawStdEncoding.DecodeString(genJSON.Payload) 90 | if err != nil { 91 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 92 | return 93 | } 94 | 95 | // Decrypt the decoded base64 payload with our secret encryption key 96 | decryptedPayload, err := utils.Decrypt(string(decodedPayload), utils.EncryptionKey) 97 | if err != nil { 98 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 99 | return 100 | } 101 | 102 | // Unmarhsal the real gen request! 103 | var akamaiJSON AkamaiGeneratorRequest 104 | err = json.Unmarshal(decryptedPayload, &akamaiJSON) 105 | if err != nil { 106 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 107 | return 108 | } 109 | 110 | // Get a random sensor in the DB 111 | randomSensor, err := db.GetRandomSensor(dbPostgres) 112 | if err != nil { 113 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 114 | return 115 | } 116 | 117 | // Gen our Akamai Cookie 118 | sensorData, err := akamai.GenCookie(akamaiJSON.URL, akamaiJSON.Abck, *randomSensor) 119 | if err != nil { 120 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 121 | return 122 | } 123 | 124 | // Encrypt our Payload back 125 | encryptedPayload, err := utils.Encrypt(sensorData, utils.EncryptionKey) 126 | if err != nil { 127 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 128 | return 129 | } 130 | 131 | // Encode our encrypted payload in base64 132 | sEnc := base64.RawStdEncoding.EncodeToString([]byte(encryptedPayload)) 133 | 134 | c.JSON(http.StatusOK, gin.H{"sensor_data": sEnc}) 135 | }) 136 | 137 | r.POST("/gen/px", func(c *gin.Context) { 138 | var genJSON GeneratorRequest 139 | if err := c.ShouldBindJSON(&genJSON); err != nil { 140 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 141 | return 142 | } 143 | 144 | // Decode the base64 string 145 | decodedPayload, err := base64.RawStdEncoding.DecodeString(genJSON.Payload) 146 | if err != nil { 147 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 148 | return 149 | } 150 | 151 | // Decrypt the decoded base64 payload with our secret encryption key 152 | decryptedPayload, err := utils.Decrypt(string(decodedPayload), utils.EncryptionKey) 153 | if err != nil { 154 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 155 | return 156 | } 157 | 158 | var pxJSON PXGeneratorRequest 159 | err = json.Unmarshal(decryptedPayload, &pxJSON) 160 | if err != nil { 161 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 162 | return 163 | } 164 | 165 | randomSensor, err := db.GetRandomSensor(dbPostgres) 166 | if err != nil { 167 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 168 | return 169 | } 170 | 171 | // Generate PX Cookies 172 | cookies, err := px.GenCookie(pxJSON.TargetURL, pxJSON.URL, *randomSensor) 173 | if err != nil { 174 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 175 | return 176 | } 177 | 178 | // Encrypt the payload 179 | encryptedPayload, err := utils.Encrypt(cookies, utils.EncryptionKey) 180 | if err != nil { 181 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 182 | return 183 | } 184 | 185 | // Encode our encrypted payload in base64 186 | sEnc := base64.RawStdEncoding.EncodeToString([]byte(encryptedPayload)) 187 | 188 | c.JSON(http.StatusOK, gin.H{"cookies": sEnc}) 189 | }) 190 | 191 | r.POST("/collector", func(c *gin.Context) { 192 | var json db.SensorData 193 | if err := c.ShouldBindJSON(&json); err != nil { 194 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 195 | return 196 | } 197 | 198 | err := db.InsertSensor(json, dbPostgres) 199 | if err != nil { 200 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 201 | return 202 | } 203 | 204 | c.JSON(http.StatusOK, gin.H{"success": true, "message": "thanks you!"}) 205 | }) 206 | 207 | r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080") 208 | } 209 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": { 3 | "port": 8080 4 | }, 5 | "database": { 6 | "addr": "35.246.36.177:5432", 7 | "username": "postgres", 8 | "password": "0okgANm3kD3q1viO", 9 | "database": "sensor" 10 | }, 11 | "ratelimit": { 12 | "gen-per-seconds": 300 13 | } 14 | } -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "log" 7 | ) 8 | 9 | type ( 10 | Config struct { 11 | Server Server 12 | Database Database 13 | Ratelimit Ratelimit 14 | } 15 | 16 | Server struct { 17 | Address string 18 | } 19 | 20 | Database struct { 21 | Addr string 22 | Username string 23 | Password string 24 | Database string 25 | } 26 | 27 | Ratelimit struct { 28 | GenPerSecond float64 `json:"gen-per-second"` 29 | } 30 | ) 31 | 32 | var ( 33 | Conf Config 34 | ) 35 | 36 | func LoadConfig() { 37 | log.Println("Loading config") 38 | 39 | bytes, err := ioutil.ReadFile("config.json") 40 | if err != nil { 41 | panic(err) 42 | } 43 | 44 | err = json.Unmarshal(bytes, &Conf) 45 | if err != nil { 46 | panic(err) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /db/db.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/go-pg/pg" 7 | "github.com/go-pg/pg/orm" 8 | ) 9 | 10 | // ConnectDb is used to create a new schema for each model 11 | func ConnectDb(options *pg.Options) *pg.DB { 12 | db := pg.Connect(options) 13 | 14 | log.Print("Connected to the DB successfully.") 15 | 16 | err := createSchema(db) 17 | if err != nil { 18 | panic(err) 19 | } 20 | 21 | log.Print("Synchronized all the schemas.") 22 | 23 | return db 24 | } 25 | 26 | func InsertSensor(sensorData SensorData, db *pg.DB) error { 27 | _, err := db.Model(&sensorData).Insert() 28 | if err != nil { 29 | return err 30 | } 31 | 32 | return nil 33 | } 34 | 35 | func GetAllSensors(db *pg.DB) (*[]SensorData, error) { 36 | // Select all users. 37 | var sensors []SensorData 38 | err := db.Model(&sensors).Select() 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | return &sensors, nil 44 | } 45 | 46 | func GetRandomSensor(db *pg.DB) (*SensorData, error) { 47 | var sensor SensorData 48 | 49 | err := db.Model(&sensor). 50 | Limit(1). 51 | OrderExpr("random()"). 52 | Select() 53 | 54 | if err != nil { 55 | return nil, err 56 | } 57 | 58 | return &sensor, nil 59 | } 60 | 61 | // createSchema creates database schema for SensorData 62 | func createSchema(db *pg.DB) error { 63 | err := db.Model(&SensorData{}).CreateTable(&orm.CreateTableOptions{ 64 | IfNotExists: true, 65 | }) 66 | 67 | if err != nil { 68 | return err 69 | } 70 | 71 | return nil 72 | } 73 | -------------------------------------------------------------------------------- /db/types.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | type SensorData struct { 4 | Id int64 5 | 6 | ScreenData struct { 7 | AvailWidth int `json:"availWidth"` 8 | AvailHeight int `json:"availHeight"` 9 | Width int `json:"width"` 10 | Height int `json:"height"` 11 | ColorDepth int `json:"colorDepth"` 12 | PixelDepth int `json:"pixelDepth"` 13 | InnerWidth int `json:"innerWidth"` 14 | InnerHeight int `json:"innerHeight"` 15 | OuterWidth int `json:"outerWidth"` 16 | } `json:"screenData"` 17 | Navigator struct { 18 | UserAgent string `json:"userAgent"` 19 | ProductSub string `json:"productSub"` 20 | Language string `json:"language"` 21 | Product string `json:"product"` 22 | OnLine bool `json:"onLine"` 23 | Vibrate bool `json:"vibrate"` 24 | GetBattery bool `json:"getBattery"` 25 | Credentials bool `json:"credentials"` 26 | AppMinorVersion bool `json:"appMinorVersion"` 27 | Bluetooth bool `json:"bluetooth"` 28 | Storage bool `json:"storage"` 29 | GetGamepads bool `json:"getGamepads"` 30 | GetStorageUpdates bool `json:"getStorageUpdates"` 31 | HardwareConcurrency bool `json:"hardwareConcurrency"` 32 | MediaDevices bool `json:"mediaDevices"` 33 | MozAlarms bool `json:"mozAlarms"` 34 | MozConnection bool `json:"mozConnection"` 35 | MozIsLocallyAvailable bool `json:"mozIsLocallyAvailable"` 36 | MozPhoneNumberService bool `json:"mozPhoneNumberService"` 37 | MsManipulationViewsEnabled bool `json:"msManipulationViewsEnabled"` 38 | Permissions bool `json:"permissions"` 39 | RegisterProtocolHandler bool `json:"registerProtocolHandler"` 40 | RequestMediaKeySystemAccess bool `json:"requestMediaKeySystemAccess"` 41 | RequestWakeLock bool `json:"requestWakeLock"` 42 | SendBeacon bool `json:"sendBeacon"` 43 | ServiceWorker bool `json:"serviceWorker"` 44 | StoreWebWideTrackingException bool `json:"storeWebWideTrackingException"` 45 | WebkitGetGamepads bool `json:"webkitGetGamepads"` 46 | WebkitTemporaryStorage bool `json:"webkitTemporaryStorage"` 47 | CookieEnabled bool `json:"cookieEnabled"` 48 | JavaEnabled bool `json:"javaEnabled"` 49 | DoNotTrack int `json:"doNotTrack"` 50 | Plugins []string `json:"plugins"` 51 | } `json:"navigator"` 52 | AddEventListener bool `json:"addEventListener"` 53 | XMLHTTPRequest bool `json:"XMLHttpRequest"` 54 | XDomainRequest bool `json:"XDomainRequest"` 55 | DeviceOrientationEvent bool `json:"DeviceOrientationEvent"` 56 | DeviceMotionEvent bool `json:"DeviceMotionEvent"` 57 | TouchEvent bool `json:"TouchEvent"` 58 | Chrome struct { 59 | App struct { 60 | IsInstalled bool `json:"isInstalled"` 61 | InstallState struct { 62 | DISABLED string `json:"DISABLED"` 63 | INSTALLED string `json:"INSTALLED"` 64 | NOTINSTALLED string `json:"NOT_INSTALLED"` 65 | } `json:"InstallState"` 66 | RunningState struct { 67 | CANNOTRUN string `json:"CANNOT_RUN"` 68 | READYTORUN string `json:"READY_TO_RUN"` 69 | RUNNING string `json:"RUNNING"` 70 | } `json:"RunningState"` 71 | } `json:"app"` 72 | } `json:"chrome"` 73 | PrototypeBind bool `json:"prototype_bind"` 74 | PointerEvent bool `json:"PointerEvent"` 75 | CCON bool `json:"CC_ON"` 76 | Document struct { 77 | DocumentMode string `json:"documentMode"` 78 | Webdriver bool `json:"webdriver"` 79 | Driver bool `json:"driver"` 80 | Selenium bool `json:"selenium"` 81 | Hidden bool `json:"hidden"` 82 | WebkitHidden bool `json:"webkitHidden"` 83 | } `json:"document"` 84 | InstallTrigger bool `json:"InstallTrigger"` 85 | HTMLElement bool `json:"HTMLElement"` 86 | WebRTC bool `json:"webRTC"` 87 | MozInnerScreenY int `json:"mozInnerScreenY"` 88 | PrototypeForEach bool `json:"prototype_forEach"` 89 | FileReader bool `json:"FileReader"` 90 | Imul bool `json:"imul"` 91 | ParseInt bool `json:"parseInt"` 92 | Hypot bool `json:"hypot"` 93 | Value1 bool `json:"value1"` 94 | XPathResult bool `json:"XPathResult"` 95 | SessionStorage bool `json:"sessionStorage"` 96 | LocalStorage bool `json:"localStorage"` 97 | IndexedDB bool `json:"indexedDB"` 98 | Canvas struct { 99 | Value1 string `json:"value1"` 100 | Value2 string `json:"value2"` 101 | } `json:"canvas"` 102 | RCFP string `json:"rCFP"` 103 | FontsOptm string `json:"fonts_optm"` 104 | Fonts string `json:"fonts"` 105 | FpValstr string `json:"fpValstr"` 106 | SSH string `json:"ssh"` 107 | Mr string `json:"mr"` 108 | Brave string `json:"brave"` 109 | Wv string `json:"wv"` 110 | Wr string `json:"wr"` 111 | Weh string `json:"weh"` 112 | Wl int `json:"wl"` 113 | Fmh string `json:"fmh"` 114 | Fmz int `json:"fmz"` 115 | Np string `json:"np"` 116 | 117 | PX400 int `json:"px400"` 118 | } 119 | -------------------------------------------------------------------------------- /doc/PX.md: -------------------------------------------------------------------------------- 1 | PayLoad 1: `aUkQRhAIEGJqABAeEFYQCEkQYmoLBBAIEFpGRkJBCB0dRUVFHEVTXl9TQEYcUV1fHVtCHX5XXF1EXR97VldTQlNWHwEdAAcHCwIKAwsLEB4QYmoEARAIEGVbXAEAEB4QYmoDCwMQCAIeEGJqCgcCEAgCHhBiagoHAxAIAwELAB4QYmoDAgIKEAgBBAICHhBiagMCBwcQCAMEAgcACgcFAgECAQMeEGJqAwIHBBAIAwQCBwAKBwUCAQIBAB4QYmoDAgEKEAgQA1EEUVdTBwIfAAdRVB8DA1dQH1NTVAMfUQEEAwtXVwQDAlQHEB4QYmoBBQMQCEZAR1dPT28=` 2 | 3 | Action: `{"do":["cls|92962558686788384609|55926328522834768625","sts|1605285703428","wcs|bunbehtq2i55d5op9qm0","drc|2353","cs|08c6346adf24b17075b91323f0ca3096c2d5d66bd497c932f6ec951ad698f907","vid|1ca5ec80-25cf-11eb-989f-0242ac12000d|31536000|true","sff|cc|60|U2FtZVNpdGU9TGF4Ow==","en|_pxde|330|4ef187d3949d08b9a5eb278208dd531644fe69fa25b903bcd089d59b06c6198a:eyJ0aW1lc3RhbXAiOjE2MDUyODU3MDM0MjgsImZfa2IiOjAsImlwY19pZCI6W119|true|300"]}` 4 | 5 | PayLoad 2: `aUkQRhAIEGJqARAeEFYQCEkQYmoAAQYQCFRTXkFXHhBiagABBxAIVFNeQVceEGJqAwcDEAhUU15BVx4QYmoAAQsQCFRTXkFXHhBiagAGAhAIVFNeQVceEGJqAwcAEAhUU15BVx4QYmoDBwEQCFRTXkFXHhBiagEDBhAIVFNeQVceEGJqAwsAEAhUU15BVx4QYmoDCwQQCFRTXkFXHhBiagACBRAIVFNeQVceEGJqAAcDEAhUU15BVx4QYmoLCgAQCAMEAgcACgcFAgEGAAoeEGJqCwoBEAgQCwALBAAHBwoECgQFCgoBCgYEAgsQHhABCgEOCg0NAA4ADg8AAAsADA4IARAIEAIJAg0JDg4DDQMNDAMDCAMPDQsCEB4QYmoLCgQQCBAHBwsABAEACgcAAAoBBgUECgQABxAeEGJqCwoHEAgAAQcBHhBiagMCAQEQCBBXAldTVAMCVxAeEGJqAwIDCxAIEAFUAFAHUwECEB4QYmoDAgACEAgQBQUEBFMHAFYQHhBiagMCAAMQCBAFAwZQAwEDBRAeEGJqAwIAABAIEARTCwIBBQpWEB4QYmoDAgEHEAhUU15BVx4QYmoDAgAHEAhUU15BVx4QYmoBBwsQCBBUUQAFBApRUwsEAFQCUVcGAQYDUQUBAQoBC1NRUQULABAeEGJqCwYBEAgQUEdcUFdaRkMAWwcHVgddQgtDXwIQHhBiagEHBRAIEAQEAQZUBApQVAQCVlMKUFNRUwUAUQEABwtTAVAKC1EFEB4QYmoBBwoQCBAGU1NQVwALAgoBBgdQAAsCAlFWAVdTUAICCgUFAQoHVBAeEGJqAAALEAgABh4QYmoAAQIQCAAGHhBiagsDEAgBCgYCHhBiagsAEAgDBAICHhBiagAECxAIAQoGAh4QYmoABQIQCAMHBAIeEGJqCwEQCBABCgYCagMEAgIQHhBiagMKBxAIBAQFHhBiagMKBBAIBQUKHhBiagMKBRAIAh4QYmoDCgoQCAIeEGJqCwcQCEZAR1ceEGJqBgICEAgDAwMeEGJqBgIGEAgQAwYGTgcGTgcGTgMKAk4EChAeEGJqCwIQCGkQXl1TVmZbX1dBEB4QUUFbEB4QU0JCEB4QQEdcRltfVxBvHhBiagMLAhAIEBAeEGJqBwcAEAgQR1xWV1RbXFdWEB4QYmoBCwsQCBBHXFZXVFtcV1YQHhBiagcGCxAIAh4QYmoGAwMQCAIeEGJqBgIAEAgDHhBiagcGChAIAx4QYmoGAgcQCEZAR1ceEGJqBwYFEAhGQEdXHhBiagMBBhAIRkBHVx4QYmoKCxAIRkBHVx4QYmoDBQIQCAEeEGJqCgcQCGkQcVpAXV9XEmJ2dBJiXkdVW1wQHhBxWkBdX1cSYnZ0EmRbV0VXQBAeEHxTRltEVxJxXltXXEYQbx4QYmoHCxAIEH9dSFteXlMdBxwCEhplW1xWXUVBEnxmEgMCHAIJEmVbXAQGCRJKBAYbEnNCQl5XZVdQeVtGHQcBBRwBBBIaeXpmf34eEl5bWVcSdVdRWV0bEnFaQF1fVx0KBBwCHAYABgIcAwsKEmFTVFNAWx0HAQUcAQQQHhBiagQDEAgQVEAfdGAQHhBiagEDARAIaRBUQB90YBAeEFRAEB4QV1wfZ2EQHhBXXBBvHhBiagQBEAgQZVtcAQAQHhBiagoEEAhGQEdXHhBiagMHBhAIHwQCHhBiagMBARAIRkBHVx4QYmoKChAIRkBHVx4QYmoDBAsQCAYeEGJqBAAQCBB1V1FZXRAeEGJqBAsQCBAAAgIBAgMCBRAeEGJqBAYQCBAHHAISGmVbXFZdRUESfGYSAwIcAgkSZVtcBAYJEkoEBhsSc0JCXldlV1B5W0YdBwEFHAEEEhp5emZ/fh4SXltZVxJ1V1FZXRsScVpAXV9XHQoEHAIcBgAGAhwDCwoSYVNUU0BbHQcBBRwBBBAeEGJqBAcQCBB8V0ZBUVNCVxAeEGJqBAQQCBB/XUhbXl5TEB4QYmoEAhAIRkBHVx4QYmoKBRAIRkBHVx4QYmoKAAMQCAYACwYFAgcDBwAeEGJqCgAAEAgGAgYFBAMECx4QYmoKAAEQCAEHAgYCAgQLHhBiagMGBRAIVFNeQVceEGJqAwcHEAgQdEBbEnxdRBIDARIAAgACEgMFCAYDCAYBEnV/ZhkCAwICEhpaV0dAVxJcXUBfU15XElbigKt3R0BdQlcSUVdcRkBTXlcbEB4QYmoAAQQQCFRTXkFXHhBiagMLBhAIVFNeQVceEGJqAwsHEAhGQEdXHhBiagABBRAIAh4QYmoAAQoQCBBfW0FBW1xVEB4QYmoAAgoQCBBEW0FbUF5XEB4QYmoAAwoQCAIeEGJqAAEDEAgFCgUeEGJqAAEAEAgDCwEGHhBiagAHBhAIVFNeQVceEGJqAAsHEAhUU15BVx4QYmoABAoQCFRTXkFXHhBiagMEBBAIRkBHVx4QYmoDAQoQCEZAR1ceEGJqAwYBEAhGQEdXHhBiagUDBhAIEAQGBwcEUQUFEB4QYmoFAwcQCBAQHhBiagUABhAIEAMCAAIFUABUEB4QYmoFAAcQCBADAgACBVAAVBAeEGJqBQALEAgQEB4QYmoGBgEQCEZAR1ceEGJqBgQEEAhGQEdXHhBiagYEBRAIRkBHVx4QYmoGBAoQCEZAR1ceEGJqAwsDEAgCHhBiagsGEAgBHhBiagMAAhAIaW8eEGJqAwYDEAhUU15BVx4QYmoLBBAIEFpGRkJBCB0dRUVFHEVTXl9TQEYcUV1fHVtCHX5XXF1EXR97VldTQlNWHwEdAAcHCwIKAwsLEB4QYmoHBxAIEBAeEGJqAwIEBxAIAx4QYmoKBwIQCAMeEGJqCgcDEAgDCwYHHhBiagMCBwYQCAMEAgcACgcFAgEHBwEeEGJqAwICChAIAQQCAh4QYmoDAgcHEAgDBAIHAAoHBQIBAgEDHhBiagMCBwQQCAMEAgcACgcFAgYBAQAeEGJqAwIBChAIEANRBFFXUwcCHwAHUVQfAwNXUB9TU1QDH1EBBAMLV1cEAwJUBxAeEGJqAQUDEAhGQEdXT09v` 6 | 7 | Action: `{"do":["bake|_px3|330|3046de2dec2161b4f429c743ad267cca8746af6cdf67d104920965dfb3556be6:fpfVljIq9sp6eNiTGXrfT78FqSttJDqlXVFiBcHX6wVhaj1hKZkEZfyS+sfXTX0TnqjcwhuAi2Y58NPdSFUAlA==:1000:3e0qQWt3Uh8hEJ76NOykK9JVUu1Ke9rifX02DNL0ye8yTsI4ugLmuSxzZiW9ENDamLYRcsE4hpO2cOcb0xubJgSbA5huT8aTd58EJRD9B6r8o2SxnQIKKHqwuuSEFNJyArIGKhjvEcF0OA746yOw72qGTP5lC5ee8IpxZFFcDds=|true|300","en|_pxde|330|a52308ac6ce9ede0f3a5cb00b88d430fefa20564b7ac390000f1cf939c80e561:eyJ0aW1lc3RhbXAiOjE2MDUyODU3MDQ3MjcsImZfa2IiOjAsImlwY19pZCI6W119|true|300"]}` 8 | 9 | ## Value already given by first response 10 | 11 | - **PX982**: sts 12 | - **PX983**: cls - first part 13 | - **PX986:** cls - second part 14 | - **PX943:** wcs 15 | 16 | ## Value working with TimeStamp 17 | 18 | * When the script started: 19 | * PX1054: Current timestamp (in MilliSecond) (ex: 1605262581195) 20 | 21 | * When the script ended: 22 | * PX1055: Current timestamp (in MilliSecond) (ex: 1605262580765) 23 | 24 | * Don't know yet: 25 | * PX1056: Current timestamp (in MilliSecond) (ex: 1605262581995) 26 | 27 | ## Random value 28 | 29 | PX851: Math.round(window.performance.now()) (how much time we've been on the page) 30 | 31 | ## Value needing data collection 32 | 33 | 34 | ``` 35 | "PX59": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36", 36 | "PX64": "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36", 37 | "PX65": "Netscape", 38 | "PX66": "Mozilla", 39 | ``` 40 | 41 | UserAgent, we should get more 42 | 43 | ``` 44 | "PX91": 3840, 45 | "PX92": 1600, 46 | "PX269": 3840, 47 | "PX270": 1560, 48 | "PX93": "3840X1600", 49 | "PX185": 667, 50 | "PX186": 778, 51 | ``` 52 | 53 | Screen Size & Window Size (PX185, 186) 54 | 55 | ``` 56 | "PX821": 4294705152, 57 | "PX822": 40963834, 58 | "PX823": 36334082, 59 | ``` 60 | 61 | MemoryInfo: 62 | * jsHeapSizeLimit 63 | * totalJSHeapSize 64 | * usedJSHeapSize 65 | 66 | 67 | ``` 68 | "PX231": 787, 69 | "PX232": 1934, 70 | ``` 71 | 72 | PX231: window.outerHeight 73 | PX232: window.outerWidth 74 | 75 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/GuapAIO/akamai-api 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/gin-contrib/cors v1.3.1 7 | github.com/gin-gonic/gin v1.6.3 8 | github.com/go-pg/pg v8.0.7+incompatible 9 | github.com/go-playground/validator/v10 v10.4.1 // indirect 10 | github.com/golang/protobuf v1.4.3 // indirect 11 | github.com/google/go-cmp v0.5.2 // indirect 12 | github.com/google/uuid v1.1.2 13 | github.com/jinzhu/inflection v1.0.0 // indirect 14 | github.com/json-iterator/go v1.1.10 // indirect 15 | github.com/karlseguin/ccache v2.0.3+incompatible 16 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 17 | github.com/modern-go/reflect2 v1.0.1 // indirect 18 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect 19 | github.com/obito/cclient v0.0.0-20201117150318-86a8395711f8 20 | github.com/onsi/ginkgo v1.14.2 // indirect 21 | github.com/onsi/gomega v1.10.3 // indirect 22 | github.com/refraction-networking/utls v0.0.0-20201112193908-f7e7360167ed 23 | github.com/stretchr/testify v1.6.1 // indirect 24 | github.com/ugorji/go v1.2.0 // indirect 25 | golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 // indirect 26 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect 27 | golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba // indirect 28 | golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e 29 | google.golang.org/protobuf v1.25.0 // indirect 30 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect 31 | mellium.im/sasl v0.2.1 // indirect 32 | ) 33 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 4 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 9 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 10 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 11 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= 12 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 13 | github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA= 14 | github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk= 15 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 16 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 17 | github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= 18 | github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= 19 | github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= 20 | github.com/go-pg/pg v8.0.7+incompatible h1:ty/sXL1OZLo+47KK9N8llRcmbA9tZasqbQ/OO4ld53g= 21 | github.com/go-pg/pg v8.0.7+incompatible/go.mod h1:a2oXow+aFOrvwcKs3eIA0lNFmMilrxK2sOkB5NWe0vA= 22 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= 23 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 24 | github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= 25 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 26 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 27 | github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= 28 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 29 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 30 | github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= 31 | github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= 32 | github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= 33 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 34 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 35 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 36 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 37 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 38 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= 39 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 40 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 41 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 42 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 43 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 44 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 45 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 46 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 47 | github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= 48 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 49 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 50 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 51 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 52 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 53 | github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= 54 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 55 | github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= 56 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 57 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 58 | github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= 59 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 60 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 61 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 62 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 63 | github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 64 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= 65 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 66 | github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= 67 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 68 | github.com/karlseguin/ccache v1.0.1 h1:0gpC6z1qtv0cKmsi5Su5tTB6bJ2vm9bfOLACpDEB/Ro= 69 | github.com/karlseguin/ccache v2.0.3+incompatible h1:j68C9tWOROiOLWTS/kCGg9IcJG+ACqn5+0+t8Oh83UU= 70 | github.com/karlseguin/ccache v2.0.3+incompatible/go.mod h1:CM9tNPzT6EdRh14+jiW8mEF9mkNZuuE51qmgGYUB93w= 71 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 72 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 73 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 74 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 75 | github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= 76 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 77 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 78 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 79 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 80 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 81 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= 82 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 83 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 84 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 85 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= 86 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 87 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 88 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 89 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= 90 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 91 | github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= 92 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 93 | github.com/obito/cclient v0.0.0-20201117150318-86a8395711f8 h1:g4vKHN2I0XSsOqUHBKEJAHadT3fa+N1KAOQnwyYmHxA= 94 | github.com/obito/cclient v0.0.0-20201117150318-86a8395711f8/go.mod h1:NGiTPiSGtaTwUDakavkpQpvVZ2bfb/kkBVFuAtn1QFA= 95 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 96 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 97 | github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= 98 | github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= 99 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 100 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 101 | github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= 102 | github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= 103 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 104 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 105 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 106 | github.com/refraction-networking/utls v0.0.0-20200806014556-219d12d0a4a1/go.mod h1:tz9gX959MEFfFN5whTIocCLUG57WiILqtdVxI8c6Wj0= 107 | github.com/refraction-networking/utls v0.0.0-20201112193908-f7e7360167ed h1:irMKCwE4WqQXGnuDskus/fhXQ60fy69YjJnuPDHYRSI= 108 | github.com/refraction-networking/utls v0.0.0-20201112193908-f7e7360167ed/go.mod h1:tz9gX959MEFfFN5whTIocCLUG57WiILqtdVxI8c6Wj0= 109 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 110 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 111 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 112 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 113 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 114 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 115 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= 116 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 117 | github.com/ugorji/go v1.2.0 h1:6eXlzYLLwZwXroJx9NyqbYcbv/d93twiOzQLDewE6qM= 118 | github.com/ugorji/go v1.2.0/go.mod h1:1ny++pKMXhLWrwWV5Nf+CbOuZJhMoaFD+0GMFfd8fEc= 119 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 120 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 121 | github.com/ugorji/go/codec v1.2.0 h1:As6RccOIlbm9wHuWYMlB30dErcI+4WiKWsYsmPkyrUw= 122 | github.com/ugorji/go/codec v1.2.0/go.mod h1:dXvG35r7zTX6QImXOSFhGMmKtX+wJ7VTWzGvYQGIjBs= 123 | github.com/x04/cclient v0.0.0-20201021191927-d653321f9ecb h1:VL+PWFCeRuocfRk2WQJa/hYJdaYBBIrlUvlU6ZRCDBY= 124 | github.com/x04/cclient v0.0.0-20201021191927-d653321f9ecb/go.mod h1:bzdlFUbmjuJjaIGTizTBfz9Srk/HsPRLBVIfS03oe9A= 125 | golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 126 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 127 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 128 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 129 | golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 130 | golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 h1:umElSU9WZirRdgu2yFHY0ayQkEnKiOC1TtM3fWXFnoU= 131 | golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 132 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 133 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 134 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 135 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 136 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 137 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 138 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 139 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 140 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 141 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 142 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 143 | golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 144 | golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 145 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= 146 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 147 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 148 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 149 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 150 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 151 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 152 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 153 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 154 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 155 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 156 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 157 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 158 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 159 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 160 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 161 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 162 | golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 163 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= 164 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 165 | golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba h1:xmhUJGQGbxlod18iJGqVEp9cHIPLl7QiX2aA3to708s= 166 | golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 167 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 168 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 169 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= 170 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 171 | golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= 172 | golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 173 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 174 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 175 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 176 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 177 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 178 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 179 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 180 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 181 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 182 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 183 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 184 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 185 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 186 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 187 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 188 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 189 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 190 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 191 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 192 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 193 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 194 | google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= 195 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 196 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 197 | google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= 198 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 199 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 200 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 201 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 202 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= 203 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 204 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 205 | gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= 206 | gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= 207 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 208 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 209 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 210 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 211 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 212 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 213 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= 214 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 215 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 216 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 217 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 218 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 219 | mellium.im/sasl v0.2.1 h1:nspKSRg7/SyO0cRGY71OkfHab8tf9kCts6a6oTDut0w= 220 | mellium.im/sasl v0.2.1/go.mod h1:ROaEDLQNuf9vjKqE1SrAfnsobm2YKXT1gnN1uDp1PjQ= 221 | -------------------------------------------------------------------------------- /http/ratelimiter/ratelimiter.go: -------------------------------------------------------------------------------- 1 | package ratelimiter 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | "net/http" 7 | "sync" 8 | "time" 9 | 10 | "github.com/gin-gonic/gin" 11 | "github.com/karlseguin/ccache" 12 | "golang.org/x/time/rate" 13 | ) 14 | 15 | const DefaultCacheTTL = time.Minute * 5 16 | 17 | var ( 18 | RateErr = errors.New("too many requests") 19 | ) 20 | 21 | type store interface { 22 | Get(string) (interface{}, bool) 23 | Set(string, interface{}) 24 | } 25 | 26 | type localCache struct { 27 | c *ccache.Cache 28 | } 29 | 30 | func newLocalCache() *localCache { 31 | return &localCache{ 32 | c: ccache.New(ccache.Configure()), 33 | } 34 | } 35 | 36 | func (lc *localCache) Get(k string) (interface{}, bool) { 37 | item := lc.c.Get(k) 38 | if item == nil || item.Expired() { 39 | return nil, false 40 | } 41 | return item.Value(), true 42 | } 43 | 44 | func (lc *localCache) Set(k string, v interface{}) { 45 | lc.c.Set(k, v, DefaultCacheTTL) 46 | } 47 | 48 | type Limiter struct { 49 | sync.Mutex 50 | reqStore store 51 | RateLimit rate.Limit 52 | BucketSize int 53 | } 54 | 55 | func New(limit float64, size int, reqStore store) *Limiter { 56 | if reqStore == nil { 57 | reqStore = newLocalCache() 58 | } 59 | return &Limiter{ 60 | Mutex: sync.Mutex{}, 61 | reqStore: reqStore, 62 | RateLimit: rate.Limit(limit), 63 | BucketSize: size, 64 | } 65 | } 66 | 67 | func (gl *Limiter) getReqLimiter(rid string) *rate.Limiter { 68 | l, ok := gl.reqStore.Get(rid) 69 | if ok { 70 | return l.(*rate.Limiter) 71 | } 72 | 73 | newL := rate.NewLimiter(gl.RateLimit, gl.BucketSize) 74 | gl.reqStore.Set(rid, newL) 75 | return newL 76 | } 77 | 78 | // Wrapper around the time/rate Allow func that first retrives the 79 | // limiter for a given request id (ip address) from the cache. 80 | func (gl *Limiter) isAllow(rid string) bool { 81 | gl.Lock() 82 | l := gl.getReqLimiter(rid) 83 | gl.Unlock() 84 | 85 | return l.Allow() 86 | } 87 | 88 | // RateLimit gin middleware that limit the requests per second per context. 89 | // Each request is identified by the ip address and cached in the limiter, 90 | // until dropped by the lru cache or until expired. 91 | func (gl *Limiter) Limit() gin.HandlerFunc { 92 | return func(c *gin.Context) { 93 | ipAddr := extractIPAddr(c) 94 | 95 | if !gl.isAllow(ipAddr) { 96 | c.AbortWithError(http.StatusTooManyRequests, RateErr) 97 | return 98 | } 99 | c.Next() 100 | } 101 | } 102 | 103 | func extractIPAddr(c *gin.Context) string { 104 | ip, _, err := net.SplitHostPort(c.Request.RemoteAddr) 105 | if err != nil { 106 | // TODO: figure out a fallback in cases where ip parsing from remote addr fails. 107 | return "" 108 | } 109 | return ip 110 | } 111 | -------------------------------------------------------------------------------- /px/generator.go: -------------------------------------------------------------------------------- 1 | package px 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | // CreatePX is used to create string between PX359-7 8 | // PX357 = vid; PX358 = sid; PX359 = uuid 9 | func CreatePX(uuid, useragent string) string { 10 | var a = h1(uuid, useragent) 11 | 12 | return h12(a) 13 | } 14 | 15 | // CreatePC Variable pass in jsonstring payload and uuid:tag:ftag 16 | func CreatePC(jsonstring string, tag string) string { 17 | var a = h1(jsonstring, tag) 18 | var e = h12(a) 19 | var r = h13(e) 20 | var pc = "" 21 | 22 | for i := 0; i < len(r); i += 2 { 23 | pc += string(r[i]) 24 | } 25 | return pc 26 | } 27 | 28 | // ObfuscateString is used to Obfuscate string using a factor 29 | func ObfuscateString(text string, amount int) string { 30 | var e string = "" 31 | 32 | for r := 0; r < len(text); r++ { 33 | e += string(amount ^ int([]rune(text)[r])) 34 | } 35 | return e 36 | } 37 | 38 | func h1(n string, t string) string { 39 | var e int 40 | r := h2(t) 41 | o := make([]int, 16) 42 | i := make([]int, 16) 43 | 44 | if len(r) > 16 { 45 | r = h3(r, 8*len(t)) 46 | } 47 | for e = 0; e < 16; e++ { 48 | if e >= len(r) { 49 | o[e] = 909522486 50 | i[e] = 1549556828 51 | } else { 52 | o[e] = 909522486 ^ r[e] 53 | i[e] = 1549556828 ^ r[e] 54 | } 55 | } 56 | a := h3(append(o, h2(n)...), 512+8*len(n)) 57 | x := h3(append(i, a...), 640) 58 | return h11(x) 59 | } 60 | 61 | func h2(t string) []int { 62 | e := make([]int, (len(t)*8)>>5+1) 63 | for n := 0; n < 8*len(t); n += 8 { 64 | charCode := int([]rune(t)[n/8]) 65 | e[n>>5] |= charCode << (n % 32) 66 | } 67 | return e 68 | } 69 | 70 | func h3(t []int, n int) []int { 71 | var x int32 = 128 << (n % 32) 72 | for i := len(t); i < ((n >> 5) + 1); i++ { 73 | t = append(t, 0) 74 | } 75 | t[n>>5] |= int(x) 76 | var y = 14 + ((n + 64) >> 9 << 4) 77 | for i := len(t); i < y+2; i++ { 78 | t = append(t, 0) 79 | } 80 | t[y] = n 81 | var e int 82 | var r = 0 83 | var o = 0 84 | var i = 0 85 | var a = 0 86 | var c = 1732584193 87 | var u = -271733879 88 | var f = -1732584194 89 | var s = 271733878 90 | for e = 0; e < len(t); e += 16 { 91 | r = c 92 | o = u 93 | i = f 94 | a = s 95 | c = h4(c, u, f, s, t[e], 7, -680876936) 96 | s = h4(s, c, u, f, t[e+1], 12, -389564586) 97 | f = h4(f, s, c, u, t[e+2], 17, 606105819) 98 | u = h4(u, f, s, c, t[e+3], 22, -1044525330) 99 | c = h4(c, u, f, s, t[e+4], 7, -176418897) 100 | s = h4(s, c, u, f, t[e+5], 12, 1200080426) 101 | f = h4(f, s, c, u, t[e+6], 17, -1473231341) 102 | u = h4(u, f, s, c, t[e+7], 22, -45705983) 103 | c = h4(c, u, f, s, t[e+8], 7, 1770035416) 104 | s = h4(s, c, u, f, t[e+9], 12, -1958414417) 105 | f = h4(f, s, c, u, t[e+10], 17, -42063) 106 | u = h4(u, f, s, c, t[e+11], 22, -1990404162) 107 | c = h4(c, u, f, s, t[e+12], 7, 1804603682) 108 | s = h4(s, c, u, f, t[e+13], 12, -40341101) 109 | f = h4(f, s, c, u, t[e+14], 17, -1502002290) 110 | u = h4(u, f, s, c, t[e+15], 22, 1236535329) 111 | c = h5(c, u, f, s, t[e+1], 5, -165796510) 112 | s = h5(s, c, u, f, t[e+6], 9, -1069501632) 113 | f = h5(f, s, c, u, t[e+11], 14, 643717713) 114 | u = h5(u, f, s, c, t[e], 20, -373897302) 115 | c = h5(c, u, f, s, t[e+5], 5, -701558691) 116 | s = h5(s, c, u, f, t[e+10], 9, 38016083) 117 | f = h5(f, s, c, u, t[e+15], 14, -660478335) 118 | u = h5(u, f, s, c, t[e+4], 20, -405537848) 119 | c = h5(c, u, f, s, t[e+9], 5, 568446438) 120 | s = h5(s, c, u, f, t[e+14], 9, -1019803690) 121 | f = h5(f, s, c, u, t[e+3], 14, -187363961) 122 | u = h5(u, f, s, c, t[e+8], 20, 1163531501) 123 | c = h5(c, u, f, s, t[e+13], 5, -1444681467) 124 | s = h5(s, c, u, f, t[e+2], 9, -51403784) 125 | f = h5(f, s, c, u, t[e+7], 14, 1735328473) 126 | u = h5(u, f, s, c, t[e+12], 20, -1926607734) 127 | c = h6(c, u, f, s, t[e+5], 4, -378558) 128 | s = h6(s, c, u, f, t[e+8], 11, -2022574463) 129 | f = h6(f, s, c, u, t[e+11], 16, 1839030562) 130 | u = h6(u, f, s, c, t[e+14], 23, -35309556) 131 | c = h6(c, u, f, s, t[e+1], 4, -1530992060) 132 | s = h6(s, c, u, f, t[e+4], 11, 1272893353) 133 | f = h6(f, s, c, u, t[e+7], 16, -155497632) 134 | u = h6(u, f, s, c, t[e+10], 23, -1094730640) 135 | c = h6(c, u, f, s, t[e+13], 4, 681279174) 136 | s = h6(s, c, u, f, t[e], 11, -358537222) 137 | f = h6(f, s, c, u, t[e+3], 16, -722521979) 138 | u = h6(u, f, s, c, t[e+6], 23, 76029189) 139 | c = h6(c, u, f, s, t[e+9], 4, -640364487) 140 | s = h6(s, c, u, f, t[e+12], 11, -421815835) 141 | f = h6(f, s, c, u, t[e+15], 16, 530742520) 142 | u = h6(u, f, s, c, t[e+2], 23, -995338651) 143 | c = h7(c, u, f, s, t[e], 6, -198630844) 144 | s = h7(s, c, u, f, t[e+7], 10, 1126891415) 145 | f = h7(f, s, c, u, t[e+14], 15, -1416354905) 146 | u = h7(u, f, s, c, t[e+5], 21, -57434055) 147 | c = h7(c, u, f, s, t[e+12], 6, 1700485571) 148 | s = h7(s, c, u, f, t[e+3], 10, -1894986606) 149 | f = h7(f, s, c, u, t[e+10], 15, -1051523) 150 | u = h7(u, f, s, c, t[e+1], 21, -2054922799) 151 | c = h7(c, u, f, s, t[e+8], 6, 1873313359) 152 | s = h7(s, c, u, f, t[e+15], 10, -30611744) 153 | f = h7(f, s, c, u, t[e+6], 15, -1560198380) 154 | u = h7(u, f, s, c, t[e+13], 21, 1309151649) 155 | c = h7(c, u, f, s, t[e+4], 6, -145523070) 156 | s = h7(s, c, u, f, t[e+11], 10, -1120210379) 157 | f = h7(f, s, c, u, t[e+2], 15, 718787259) 158 | u = h7(u, f, s, c, t[e+9], 21, -343485551) 159 | c = h9(c, r) 160 | u = h9(u, o) 161 | f = h9(f, i) 162 | s = h9(s, a) 163 | } 164 | return []int{c, u, f, s} 165 | } 166 | 167 | func h4(t int, n int, e int, r int, o int, i int, a int) int { 168 | return h8(n&e|^n&r, t, n, o, i, a) 169 | } 170 | 171 | func h5(t int, n int, e int, r int, o int, i int, a int) int { 172 | return h8(n&r | e & ^r, t, n, o, i, a) 173 | } 174 | 175 | func h6(t int, n int, e int, r int, o int, i int, a int) int { 176 | return h8(n^e^r, t, n, o, i, a) 177 | } 178 | 179 | func h7(t int, n int, e int, r int, o int, i int, a int) int { 180 | return h8(e^(n|^r), t, n, o, i, a) 181 | } 182 | 183 | func h8(t int, n int, e int, r int, o int, i int) int { 184 | return h9(h10(h9(h9(n, t), h9(r, i)), o), e) 185 | } 186 | 187 | func h9(t int, n int) int { 188 | var e = (65535 & t) + (65535 & n) 189 | return int(int32((int(int32(t>>16))+int(int32(n>>16))+int(int32(e>>16)))<<16)) | 65535&e 190 | } 191 | 192 | func h10(t int, n int) int { 193 | return int(int32(t<> (32 - n))) 194 | } 195 | 196 | func h11(t []int) string { 197 | var n int 198 | var e = "" 199 | for n = 0; n < 32*len(t); n += 8 { 200 | e += string((int(int32(int(uint32(t[n>>5])) >> (n % 32)))) & 255) 201 | } 202 | return e 203 | } 204 | 205 | func h12(t string) string { 206 | var n = "0123456789abcdef" 207 | var e = "" 208 | var r = 0 209 | var o int 210 | for o = 0; o < 16; o++ { 211 | r = int([]rune(t)[o]) 212 | e += string(n[int(uint32(r)>>4)&15]) + string(n[15&r]) 213 | } 214 | return e 215 | } 216 | 217 | func h13(t string) string { 218 | var n string = "" 219 | var e string = "" 220 | var r int 221 | for r = 0; r < len(t); r++ { 222 | var o = int([]rune(t)[r]) 223 | if o >= 48 && o <= 57 { 224 | n += string(t[r]) 225 | } else { 226 | e += strconv.Itoa(o % 10) 227 | } 228 | } 229 | return n + e 230 | } 231 | -------------------------------------------------------------------------------- /px/px.go: -------------------------------------------------------------------------------- 1 | package px 2 | 3 | import ( 4 | b64 "encoding/base64" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "time" 11 | 12 | "github.com/GuapAIO/akamai-api/db" 13 | "github.com/google/uuid" 14 | "github.com/obito/cclient" 15 | utls "github.com/refraction-networking/utls" 16 | ) 17 | 18 | // CollectorDo is used to transform body to json 19 | type CollectorDo struct { 20 | Do []string `json:"do"` 21 | } 22 | 23 | type Action struct { 24 | Value string 25 | Value2 string 26 | CookieName string 27 | ExpirationTime string 28 | } 29 | 30 | func GenCookie(targetWebsite, productPage string, sensorInfo db.SensorData) (string, error) { 31 | id := uuid.New().String() 32 | 33 | payload := createFirstPayload(id, productPage) 34 | 35 | pxDo, err := sendCollector(targetWebsite, payload, "PXu6b0qd2S", "v6.0.2", id, "179", false, "", "", "") 36 | if err != nil { 37 | return "", err 38 | } 39 | 40 | // Add all the action into a map 41 | toDoFirst := saveActions(pxDo) 42 | 43 | sts := toDoFirst["sts"].Value 44 | cls1 := toDoFirst["cls"].Value 45 | cls2 := toDoFirst["cls"].Value2 46 | wcs := toDoFirst["wcs"].Value 47 | drc := toDoFirst["drc"].Value 48 | 49 | vid := toDoFirst["vid"].Value 50 | sid := toDoFirst["sid"].Value 51 | cs := toDoFirst["cs"].Value 52 | 53 | secondPayload := createSecondPayload(id, sensorInfo, sts, cls1, cls2, wcs, drc, vid, sid, productPage) 54 | 55 | pxDoSecond, err := sendCollector(targetWebsite, secondPayload, "PXu6b0qd2S", "v6.0.2", id, "179", true, vid, sid, cs) 56 | if err != nil { 57 | return "", err 58 | } 59 | 60 | /* 61 | log.Print(pxDoSecond) 62 | 63 | toDoSecond := saveActions(pxDoSecond) 64 | 65 | log.Print(toDoSecond) 66 | 67 | px3 := toDoSecond["bake"].Value 68 | pxde := toDoSecond["en"].Value 69 | 70 | log.Printf("PX3: %v - PXDE: %v", px3, pxde) 71 | */ 72 | out, err := json.Marshal(pxDoSecond) 73 | if err != nil { 74 | return "", err 75 | } 76 | 77 | return string(out), nil 78 | } 79 | 80 | func saveActions(toDo *CollectorDo) map[string]Action { 81 | actions := make(map[string]Action) 82 | 83 | for _, action := range toDo.Do { 84 | parsedAction := strings.Split(action, "|") 85 | 86 | if len(parsedAction) == 3 { 87 | actions[parsedAction[0]] = Action{ 88 | Value: parsedAction[1], 89 | Value2: parsedAction[2], 90 | } 91 | } else if len(parsedAction) <= 4 { 92 | actions[parsedAction[0]] = Action{ 93 | Value: parsedAction[1], 94 | } 95 | } else { 96 | actions[parsedAction[0]] = Action{ 97 | Value: parsedAction[3], 98 | CookieName: parsedAction[1], 99 | ExpirationTime: parsedAction[2], 100 | } 101 | } 102 | } 103 | 104 | return actions 105 | } 106 | 107 | func createFirstPayload(id, productLink string) string { 108 | currentTime := time.Now() 109 | 110 | tUnixMicro := int64(time.Nanosecond) * currentTime.UnixNano() / int64(time.Microsecond) 111 | 112 | payload := fmt.Sprintf(`[ 113 | { 114 | "t": "PX2", 115 | "d": { 116 | "PX96": "%v", 117 | "PX63": "Win32", 118 | "PX191": 0, 119 | "PX850": 0, 120 | "PX851": 872, 121 | "PX1008": 3600, 122 | "PX1055": %v, 123 | "PX1056": %v, 124 | "PX1038": "%v", 125 | "PX371": true 126 | } 127 | } 128 | ]`, productLink, tUnixMicro, tUnixMicro+3, id) 129 | 130 | return payload 131 | } 132 | 133 | // send the second payload with much more info 134 | // NOTES: here are the value that you get from the actions of the first payload 135 | // sts: PX982 ; cls1: PX983 ; cls2: PX986 ; drc: PX985 ; wcs: PX943 136 | func createSecondPayload(id string, sensorInfo db.SensorData, sts, cls1, cls2, wcs, drc, vid, sid, productPage string) string { 137 | currentTime := time.Now() 138 | tUnixMicro := int64(time.Nanosecond) * currentTime.UnixNano() / int64(time.Microsecond) 139 | px357 := CreatePX(vid, sensorInfo.Navigator.UserAgent) 140 | px358 := CreatePX(sid, sensorInfo.Navigator.UserAgent) 141 | px359 := CreatePX(id, sensorInfo.Navigator.UserAgent) 142 | 143 | var cleanPlugins []string 144 | 145 | for _, plugin := range sensorInfo.Navigator.Plugins { 146 | cleanPlugins = append(cleanPlugins, fmt.Sprintf(`"%s"`, plugin)) 147 | } 148 | 149 | formatedDate := currentTime.Format("Mon Jan 02 2006 15:04:05") + " GMT+0000 (Coordinated Universal Time)" 150 | 151 | payload := fmt.Sprintf(`[ 152 | { 153 | "t": "PX3", 154 | "d": { 155 | "PX234": false, 156 | "PX235": false, 157 | "PX151": false, 158 | "PX239": false, 159 | "PX240": false, 160 | "PX152": false, 161 | "PX153": false, 162 | "PX314": false, 163 | "PX192": false, 164 | "PX196": false, 165 | "PX207": false, 166 | "PX251": false, 167 | "PX982": %v, 168 | "PX983": "%v", 169 | "PX986": "%v", 170 | "PX985": %v, 171 | "PX1033": "e0eaf10e", 172 | "PX1019": "3f2b5a30", 173 | "PX1020": "7766a52d", 174 | "PX1021": "714b1317", 175 | "PX1022": "6a90378d", 176 | "PX1035": false, 177 | "PX1025": false, 178 | "PX359": "%v", 179 | "PX943": "%v", 180 | "PX357": "%v", 181 | "PX358": "%v", 182 | "PX229": 24, 183 | "PX230": 24, 184 | "PX91": %v, 185 | "PX92": %v, 186 | "PX269": %v, 187 | "PX270": %v, 188 | "PX93": "%v", 189 | "PX185": %v, 190 | "PX186": %v, 191 | "PX187": 0, 192 | "PX188": 0, 193 | "PX95": true, 194 | "PX400": %v, 195 | "PX404": "144|54|54|180|68", 196 | "PX90": [ 197 | "loadTimes", 198 | "csi", 199 | "app", 200 | "runtime" 201 | ], 202 | "PX190": "", 203 | "PX552": "undefined", 204 | "PX399": "undefined", 205 | "PX549": 0, 206 | "PX411": 0, 207 | "PX402": 1, 208 | "PX548": 1, 209 | "PX405": true, 210 | "PX547": true, 211 | "PX134": true, 212 | "PX89": true, 213 | "PX170": 3, 214 | "PX85": [ 215 | %s 216 | ], 217 | "PX59": "%v", 218 | "PX61": "%v", 219 | "PX313": [ 220 | "%v", 221 | "fr", 222 | "en-US", 223 | "en" 224 | ], 225 | "PX63": "Win32", 226 | "PX86": true, 227 | "PX154": -60, 228 | "PX133": true, 229 | "PX88": true, 230 | "PX169": 4, 231 | "PX62": "Gecko", 232 | "PX69": "%v", 233 | "PX64": "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36", 234 | "PX65": "Netscape", 235 | "PX66": "Mozilla", 236 | "PX60": true, 237 | "PX87": true, 238 | "PX821": 4294705152, 239 | "PX822": 28398146, 240 | "PX823": 19947142, 241 | "PX147": false, 242 | "PX155": "%v", 243 | "PX236": false, 244 | "PX194": false, 245 | "PX195": true, 246 | "PX237": 0, 247 | "PX238": "missing", 248 | "PX208": "visible", 249 | "PX218": 0, 250 | "PX231": 1560, 251 | "PX232": 3840, 252 | "PX254": false, 253 | "PX295": false, 254 | "PX268": false, 255 | "PX166": true, 256 | "PX138": true, 257 | "PX143": true, 258 | "PX714": "64556c77", 259 | "PX715": "", 260 | "PX724": "10207b2f", 261 | "PX725": "10207b2f", 262 | "PX729": "", 263 | "PX443": true, 264 | "PX466": true, 265 | "PX467": true, 266 | "PX468": true, 267 | "PX191": 0, 268 | "PX94": 2, 269 | "PX120": [], 270 | "PX141": false, 271 | "PX96": "%v", 272 | "PX55": "", 273 | "PX1065": 1, 274 | "PX850": 1, 275 | "PX851": 1518, 276 | "PX1054": %v, 277 | "PX1008": 3600, 278 | "PX1055": %v, 279 | "PX1056": %v, 280 | "PX1038": "%v", 281 | "PX371": true 282 | } 283 | } 284 | ]`, sts, cls1, cls2, drc, px359, wcs, px357, px358, sensorInfo.ScreenData.Width, sensorInfo.ScreenData.Height, sensorInfo.ScreenData.AvailWidth, sensorInfo.ScreenData.AvailHeight, fmt.Sprintf("%vX%v", sensorInfo.ScreenData.Width, sensorInfo.ScreenData.Height), sensorInfo.ScreenData.InnerHeight, sensorInfo.ScreenData.InnerWidth, sensorInfo.PX400, strings.Join(cleanPlugins, ",\n"), sensorInfo.Navigator.UserAgent, sensorInfo.Navigator.Language, sensorInfo.Navigator.Language, sensorInfo.Navigator.ProductSub, formatedDate, productPage, tUnixMicro, tUnixMicro+420, tUnixMicro, id) 285 | 286 | return payload 287 | } 288 | 289 | // send third payload, with mouse events 290 | func createThirdPayload(id string) string { 291 | 292 | return "" 293 | } 294 | 295 | func sendCollector(website, payload, appID, tag, uuid, ft string, secondPayload bool, vid, sid, cs string) (*CollectorDo, error) { 296 | obfuscatedPayload := ObfuscateString(payload, 50) 297 | 298 | encodedPayload := b64.StdEncoding.EncodeToString([]byte(obfuscatedPayload)) 299 | 300 | pc := CreatePC(payload, fmt.Sprintf("%v:%v:%v", uuid, tag, ft)) 301 | 302 | var body *strings.Reader 303 | 304 | if secondPayload == false { 305 | body = strings.NewReader("payload=" + encodedPayload + "&appId=" + appID + "&tag=" + tag + "&uuid=" + uuid + "&ft=" + ft + "&seq=0&en=NTA&pc=" + pc + "&rsc=1") 306 | } else { 307 | body = strings.NewReader("payload=" + encodedPayload + "&appId=" + appID + "&tag=" + tag + "&uuid=" + uuid + "&ft=" + ft + "&seq=0&en=NTA&cs=" + cs + "&pc=" + pc + "&sid=" + sid + "&vid=" + vid + "&rsc=2") 308 | } 309 | 310 | client, err := cclient.NewClient(utls.HelloChrome_Auto, false) 311 | if err != nil { 312 | return nil, err 313 | } 314 | 315 | req, err := http.NewRequest("POST", "https://collector-pxu6b0qd2s.px-cloud.net/api/v2/collector", body) 316 | if err != nil { 317 | return nil, err 318 | } 319 | 320 | req.Host = "collector-pxu6b0qd2s.px-cloud.net" 321 | req.Header.Set("Sec-Ch-Ua", "\"Chromium\";v=\"86\", \"\"Not\\A;Brand\";v=\"99\", \"Google Chrome\";v=\"86\"") 322 | req.Header.Set("Sec-Ch-Ua-Mobile", "?0") 323 | req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36") 324 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 325 | req.Header.Set("Accept", "*/*") 326 | req.Header.Set("Origin", website) 327 | req.Header.Set("Sec-Fetch-Site", "cross-site") 328 | req.Header.Set("Sec-Fetch-Mode", "cors") 329 | req.Header.Set("Sec-Fetch-Dest", "empty") 330 | req.Header.Set("Referer", website) 331 | req.Header.Set("Accept-Language", "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7") 332 | 333 | resp, err := client.Do(req) 334 | if err != nil { 335 | return nil, err 336 | } 337 | defer resp.Body.Close() 338 | 339 | bodyResp, err := ioutil.ReadAll(resp.Body) 340 | if err != nil { 341 | return nil, err 342 | } 343 | 344 | var pxDo CollectorDo 345 | err = json.Unmarshal(bodyResp, &pxDo) 346 | if err != nil { 347 | return nil, err 348 | } 349 | 350 | return &pxDo, nil 351 | } 352 | -------------------------------------------------------------------------------- /utils/encrypt.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "crypto/rand" 7 | "encoding/hex" 8 | "errors" 9 | "io" 10 | ) 11 | 12 | var EncryptionKey = "d5e08ae9e844a4857dd57de560406054e715ccb55ebd130af00a9ea5f9e98162" 13 | 14 | func Encrypt(stringToEncrypt string, keyString string) ([]byte, error) { 15 | 16 | //Since the key is in string, we need to convert decode it to bytes 17 | key, err := hex.DecodeString(keyString) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | plaintext := []byte(stringToEncrypt) 23 | 24 | //Create a new Cipher Block from the key 25 | block, err := aes.NewCipher(key) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | //Create a new GCM - https://en.wikipedia.org/wiki/Galois/Counter_Mode 31 | //https://golang.org/pkg/crypto/cipher/#NewGCM 32 | aesGCM, err := cipher.NewGCM(block) 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | //Create a nonce. Nonce should be from GCM 38 | nonce := make([]byte, aesGCM.NonceSize()) 39 | if _, err = io.ReadFull(rand.Reader, nonce); err != nil { 40 | return nil, err 41 | } 42 | 43 | //Encrypt the data using aesGCM.Seal 44 | //Since we don't want to save the nonce somewhere else in this case, we add it as a prefix to the encrypted data. The first nonce argument in Seal is the prefix. 45 | ciphertext := aesGCM.Seal(nonce, nonce, plaintext, nil) 46 | 47 | return ciphertext, nil 48 | } 49 | 50 | func Decrypt(encryptedString string, keyString string) ([]byte, error) { 51 | key, err := hex.DecodeString(keyString) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | enc := []byte(encryptedString) 57 | 58 | //Create a new Cipher Block from the key 59 | block, err := aes.NewCipher(key) 60 | if err != nil { 61 | return nil, err 62 | } 63 | 64 | //Create a new GCM 65 | aesGCM, err := cipher.NewGCM(block) 66 | if err != nil { 67 | return nil, err 68 | } 69 | 70 | //Get the nonce size 71 | nonceSize := aesGCM.NonceSize() 72 | 73 | if len(enc) < nonceSize { 74 | return nil, errors.New("wrong size") 75 | } 76 | 77 | //Extract the nonce from the encrypted data 78 | nonce, ciphertext := enc[:nonceSize], enc[nonceSize:] 79 | 80 | //Decrypt the data 81 | plaintext, err := aesGCM.Open(nil, nonce, ciphertext, nil) 82 | if err != nil { 83 | return nil, err 84 | } 85 | 86 | return plaintext, nil 87 | } 88 | --------------------------------------------------------------------------------