save flaresolverr solution to use it again
All checks were successful
build / build (push) Successful in 1m1s
All checks were successful
build / build (push) Successful in 1m1s
Signed-off-by: ngn <ngn@ngn.tf>
This commit is contained in:
parent
c9e2cf1a44
commit
d133b45575
10
.dockerignore
Normal file
10
.dockerignore
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.git
|
||||||
|
|
||||||
|
ups.json
|
||||||
|
renovate.json
|
||||||
|
|
||||||
|
README.md
|
||||||
|
LICENSE.txt
|
||||||
|
|
||||||
|
docker-compose.example.yml
|
||||||
|
Dockerfile
|
@ -51,15 +51,15 @@ func GetImage(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// download the image
|
// download the image
|
||||||
body, _, headers, err := utils.GET(claims.ImageURL)
|
res, err := utils.GET(claims.ImageURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithStatus(500)
|
c.AbortWithStatus(500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the content type
|
// set the content type
|
||||||
c.Header("Content-Type", headers.Get("Content-Type"))
|
c.Header("Content-Type", res.Header().Get("Content-Type"))
|
||||||
|
|
||||||
// write the image to the response
|
// write the image to the response
|
||||||
c.Writer.Write(body)
|
c.Writer.Write(res.Body())
|
||||||
}
|
}
|
||||||
|
@ -53,18 +53,25 @@ func ViewQuestion(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
soLink := fmt.Sprintf("https://%s/questions/%s/%s?answertab=%s", domain, questionId, params.QuestionTitle, params.SoSortValue)
|
soLink := fmt.Sprintf("https://%s/questions/%s/%s?answertab=%s", domain, questionId, params.QuestionTitle, params.SoSortValue)
|
||||||
body, code, _, err := utils.GET(soLink)
|
res, err := utils.GET(soLink)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed to get %s: %s", soLink, err.Error())
|
||||||
|
|
||||||
if code != 200 {
|
|
||||||
utils.Render(c, 500, "home", gin.H{
|
utils.Render(c, 500, "home", gin.H{
|
||||||
"errorMessage": fmt.Sprintf("Received a non-OK status code %d", code),
|
"errorMessage": fmt.Sprintf("Request to server failed"),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
respBodyReader := bytes.NewReader(body)
|
if res.StatusCode() != 200 {
|
||||||
|
utils.Render(c, 500, "home", gin.H{
|
||||||
|
"errorMessage": fmt.Sprintf("Received a non-OK status code: %d", res.StatusCode()),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
doc, err := goquery.NewDocumentFromReader(respBodyReader)
|
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(res.Body()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Render(c, 500, "home", gin.H{
|
utils.Render(c, 500, "home", gin.H{
|
||||||
"errorMessage": "Unable to parse question data",
|
"errorMessage": "Unable to parse question data",
|
||||||
|
@ -1,70 +1,150 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://github.com/FlareSolverr/FlareSolverr#-requestget
|
// https://github.com/FlareSolverr/FlareSolverr#-requestget
|
||||||
type request struct {
|
type Request struct {
|
||||||
Cmd string `json:"cmd"`
|
Cmd string `json:"cmd"`
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
MaxTimeout int `json:"maxTimeout"`
|
MaxTimeout int `json:"maxTimeout"`
|
||||||
|
OnlyCookies bool `json:"returnOnlyCookies"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type solution struct {
|
type Cookie struct {
|
||||||
Status int `json:"status"`
|
Name string `json:"name"`
|
||||||
Response []byte `json:"response"`
|
Value string `json:"value"`
|
||||||
Headers map[string]string `json:"headers"`
|
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 response struct {
|
type Solution struct {
|
||||||
Solution solution `json:"solution"`
|
Status int `json:"status"`
|
||||||
|
Cookies []Cookie `json:"cookies"`
|
||||||
|
Agent string `json:"userAgent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GET(target string) ([]byte, int, http.Header, error) {
|
type Response struct {
|
||||||
var (
|
Solution Solution `json:"solution"`
|
||||||
client *resty.Client = resty.New()
|
}
|
||||||
frurl string = ""
|
|
||||||
)
|
|
||||||
|
|
||||||
if frurl = os.Getenv("FLARESOLVER"); frurl == "" {
|
func (c *Cookie) ToCookie() *http.Cookie {
|
||||||
if res, err := client.R().Get(target); err != nil {
|
ss := http.SameSiteNoneMode
|
||||||
return nil, 0, nil, err
|
|
||||||
} else {
|
switch c.SameSite {
|
||||||
return res.Body(), res.StatusCode(), res.Header(), nil
|
case "Lax":
|
||||||
}
|
ss = http.SameSiteLaxMode
|
||||||
|
|
||||||
|
case "Strict":
|
||||||
|
ss = http.SameSiteStrictMode
|
||||||
|
|
||||||
|
case "Default":
|
||||||
|
ss = http.SameSiteDefaultMode
|
||||||
}
|
}
|
||||||
|
|
||||||
frurl, _ = url.JoinPath(frurl, "/v1")
|
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"
|
||||||
|
|
||||||
|
var solution *Solution = nil
|
||||||
|
|
||||||
|
func Solve(target string) error {
|
||||||
|
fsurl := os.Getenv("FLARESOLVER")
|
||||||
|
|
||||||
|
if fsurl == "" {
|
||||||
|
return fmt.Errorf("flaresolver is not configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
fsurl, _ = url.JoinPath(fsurl, "/v1")
|
||||||
|
response := Response{}
|
||||||
|
client := resty.New()
|
||||||
|
|
||||||
res, err := client.R().
|
res, err := client.R().
|
||||||
SetBody(request{
|
SetBody(Request{
|
||||||
Cmd: "request.get",
|
Cmd: "request.get",
|
||||||
Url: target,
|
Url: target,
|
||||||
MaxTimeout: 40_000,
|
MaxTimeout: 40_000,
|
||||||
|
OnlyCookies: true,
|
||||||
}).
|
}).
|
||||||
SetResult(&response{}).
|
Post(fsurl)
|
||||||
Post(frurl)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, nil, err
|
return fmt.Errorf("request failed: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.StatusCode() != 200 {
|
if res.StatusCode() != 200 {
|
||||||
return nil, 0, nil, fmt.Errorf("flaresolver failure")
|
return fmt.Errorf("bad status code: %d", res.StatusCode())
|
||||||
}
|
}
|
||||||
|
|
||||||
response := res.Result().(*response)
|
if err := json.Unmarshal(res.Body(), &response); err != nil {
|
||||||
headers := http.Header{}
|
return fmt.Errorf("failed to parse body: %s", err.Error())
|
||||||
|
|
||||||
for k, v := range response.Solution.Headers {
|
|
||||||
headers.Add(k, v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.Solution.Response, response.Solution.Status, headers, nil
|
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")
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user