-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.go
More file actions
87 lines (76 loc) · 2.67 KB
/
Copy pathconfig.go
File metadata and controls
87 lines (76 loc) · 2.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package main
import (
"encoding/json"
"fmt"
"os"
)
// Config holds everything the scraper needs for one run. Values that identify the
// browser (UserAgent / SecChUa / Platform) MUST stay internally consistent — the
// reese84 sensor, the client hints and the TLS fingerprint all have to agree.
type Config struct {
// Hyper Solutions API key (https://hypersolutions.co/keys).
HyperAPIKey string
// Sticky/session proxy in the form http://user:pass@host:port. The SAME IP must be
// used for every target request AND reported to the Hyper API — never rotating.
ProxyURL string
// Browser identity — taken verbatim from the recorded session.
UserAgent string
SecChUa string
SecChUaPlatform string
AcceptLanguage string
// Search parameters.
Search SearchParams
}
// SearchParams describes one air-bounds availability search.
type SearchParams struct {
Origin string // e.g. "CDG"
Destination string // e.g. "ICN"
DepartureDate string // "2006-01-02"
OriginCountry string // e.g. "FR" — used in the OAuth "fact" blob
Market string // e.g. "AU"
Flow string // "AWARD" (miles) or "REVENUE" (cash)
Adults int
FareFamilies []string // e.g. ["ECONOMY","BUSINESS"]
}
// LoadConfig builds a Config from environment variables, falling back to the values
// captured in the recorded browser session so the program is runnable out of the box.
func LoadConfig() (*Config, error) {
key := os.Getenv("HYPER_API_KEY")
if key == "" {
return nil, fmt.Errorf("HYPER_API_KEY is required (get one at https://hypersolutions.co/keys)")
}
cfg := &Config{
HyperAPIKey: key,
ProxyURL: os.Getenv("PROXY_URL"),
// Chrome 150 on Windows — matches the recorded session. Keep these three in sync
// with each other and with the TLS profile in tlsclient.go.
UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36",
SecChUa: `"Not;A=Brand";v="8", "Chromium";v="150", "Google Chrome";v="150"`,
SecChUaPlatform: `"Windows"`,
AcceptLanguage: "en-US,en;q=0.9",
Search: SearchParams{
Origin: envOr("EY_ORIGIN", "CDG"),
Destination: envOr("EY_DEST", "ICN"),
DepartureDate: envOr("EY_DATE", "2026-07-17"),
OriginCountry: envOr("EY_ORIGIN_COUNTRY", "FR"),
Market: envOr("EY_MARKET", "AU"),
Flow: envOr("EY_FLOW", "AWARD"),
Adults: 1,
FareFamilies: []string{"ECONOMY", "BUSINESS"},
},
}
return cfg, nil
}
func envOr(key, def string) string {
if v := os.Getenv(key); v != "" {
return v
}
return def
}
func mustJSON(v any) string {
b, err := json.Marshal(v)
if err != nil {
panic(err)
}
return string(b)
}