All checks were successful
docker / docker (push) Successful in 27m21s
Signed-off-by: ngn <ngn@ngn.tf>
175 lines
3.5 KiB
Go
175 lines
3.5 KiB
Go
package utils
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/go-resty/resty/v2"
|
|
)
|
|
|
|
// https://github.com/FlareSolverr/FlareSolverr#-requestget
|
|
type Request struct {
|
|
Cmd string `json:"cmd"`
|
|
Url string `json:"url"`
|
|
MaxTimeout int `json:"maxTimeout"`
|
|
OnlyCookies bool `json:"returnOnlyCookies"`
|
|
}
|
|
|
|
type Cookie struct {
|
|
Name string `json:"name"`
|
|
Value string `json:"value"`
|
|
Domain string `json:"domain"`
|
|
Path string `json:"path"`
|
|
Expires time.Time `json:"expires"`
|
|
Size uint64 `json:"size"`
|
|
HttpOnly bool `json:"httpOnly"`
|
|
Secure bool `json:"secure"`
|
|
Session bool `json:"session"`
|
|
SameSite string `json:"sameSite"`
|
|
}
|
|
|
|
type Solution struct {
|
|
Status int `json:"status"`
|
|
Cookies []Cookie `json:"cookies"`
|
|
Agent string `json:"userAgent"`
|
|
}
|
|
|
|
type Response struct {
|
|
Solution Solution `json:"solution"`
|
|
}
|
|
|
|
func (c *Cookie) ToCookie() *http.Cookie {
|
|
ss := http.SameSiteNoneMode
|
|
|
|
switch c.SameSite {
|
|
case "Lax":
|
|
ss = http.SameSiteLaxMode
|
|
|
|
case "Strict":
|
|
ss = http.SameSiteStrictMode
|
|
|
|
case "Default":
|
|
ss = http.SameSiteDefaultMode
|
|
}
|
|
|
|
return &http.Cookie{
|
|
Name: c.Name,
|
|
Value: c.Value,
|
|
Domain: c.Domain,
|
|
Path: c.Path,
|
|
Expires: c.Expires,
|
|
HttpOnly: c.HttpOnly,
|
|
Secure: c.Secure,
|
|
SameSite: ss,
|
|
}
|
|
}
|
|
|
|
func (s *Solution) HttpCookies() []*http.Cookie {
|
|
cookies := []*http.Cookie{}
|
|
|
|
for i := range s.Cookies {
|
|
cookies = append(cookies, s.Cookies[i].ToCookie())
|
|
}
|
|
|
|
return cookies
|
|
}
|
|
|
|
const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.3"
|
|
const DEFAULT_TIMEOUT = 120
|
|
|
|
var (
|
|
solution *Solution = nil
|
|
fs_url string = ""
|
|
fs_timeout int = DEFAULT_TIMEOUT
|
|
)
|
|
|
|
func Solve(target string) error {
|
|
if fs_url == "" {
|
|
return fmt.Errorf("flaresolver is not configured")
|
|
}
|
|
|
|
url, _ := url.JoinPath(fs_url, "/v1")
|
|
response := Response{}
|
|
client := resty.New()
|
|
|
|
res, err := client.R().
|
|
SetBody(Request{
|
|
Cmd: "request.get",
|
|
Url: target,
|
|
MaxTimeout: fs_timeout * 100,
|
|
OnlyCookies: true,
|
|
}).
|
|
Post(url)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("request failed: %s", err.Error())
|
|
}
|
|
|
|
if res.StatusCode() != 200 {
|
|
return fmt.Errorf("bad status code: %d", res.StatusCode())
|
|
}
|
|
|
|
if err := json.Unmarshal(res.Body(), &response); err != nil {
|
|
return fmt.Errorf("failed to parse body: %s", err.Error())
|
|
}
|
|
|
|
solution = &response.Solution
|
|
return nil
|
|
}
|
|
|
|
func GET(target string, no_retry ...bool) (*resty.Response, error) {
|
|
client := resty.New()
|
|
req := client.R()
|
|
|
|
if solution != nil {
|
|
req.SetCookies(solution.HttpCookies())
|
|
req.SetHeader("User-Agent", solution.Agent)
|
|
} else {
|
|
req.SetHeader("User-Agent", USER_AGENT)
|
|
}
|
|
|
|
res, err := req.Get(target)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if res.StatusCode() != http.StatusForbidden {
|
|
return res, err
|
|
}
|
|
|
|
if err = Solve(target); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(no_retry) == 0 {
|
|
return GET(target)
|
|
}
|
|
|
|
return nil, fmt.Errorf("solution did not work")
|
|
}
|
|
|
|
func ReqSetup() {
|
|
fs_url = os.Getenv("FLARESOLVER")
|
|
timeout := os.Getenv("TIMEOUT")
|
|
|
|
if timeout == "" {
|
|
return
|
|
}
|
|
|
|
if to, err := strconv.Atoi(timeout); err != nil {
|
|
fmt.Printf("failed to parse timeout: %s\n", err.Error())
|
|
} else if to <= 0 {
|
|
fmt.Println("invalid timeout, timeout should be greater than zero")
|
|
} else {
|
|
return
|
|
}
|
|
|
|
fmt.Printf("using the default timeout instead (%d secs)\n", DEFAULT_TIMEOUT)
|
|
fs_timeout = DEFAULT_TIMEOUT
|
|
}
|