snapshot current state before gitea sync
This commit is contained in:
113
internal/httpapi/client.go
Normal file
113
internal/httpapi/client.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package httpapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"uberspace-cli/internal/config"
|
||||
"uberspace-cli/internal/session"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
BaseURL string
|
||||
HTTP *http.Client
|
||||
CSRF *session.CSRFToken
|
||||
}
|
||||
|
||||
func New(baseURL string, jar http.CookieJar, csrf *session.CSRFToken) (*Client, error) {
|
||||
if baseURL == "" {
|
||||
return nil, errors.New("base_url is required")
|
||||
}
|
||||
if jar == nil {
|
||||
jar, _ = cookiejar.New(nil)
|
||||
}
|
||||
return &Client{
|
||||
BaseURL: strings.TrimRight(baseURL, "/"),
|
||||
HTTP: &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
Jar: jar,
|
||||
},
|
||||
CSRF: csrf,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) DoEndpoint(ep config.Endpoint, vars map[string]string) (*http.Response, []byte, error) {
|
||||
body, err := renderTemplate(ep.Body, vars)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
urlStr := c.BaseURL + ep.Path
|
||||
req, err := http.NewRequest(ep.Method, urlStr, strings.NewReader(body))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for k, v := range ep.Headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
if c.CSRF != nil && c.CSRF.Header != "" && c.CSRF.Value != "" {
|
||||
req.Header.Set(c.CSRF.Header, c.CSRF.Value)
|
||||
}
|
||||
|
||||
resp, err := c.HTTP.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return resp, nil, err
|
||||
}
|
||||
return resp, respBody, nil
|
||||
}
|
||||
|
||||
func (c *Client) CaptureCSRF(ep config.Endpoint, resp *http.Response, body []byte) *session.CSRFToken {
|
||||
if ep.CSRF == nil {
|
||||
return nil
|
||||
}
|
||||
cfg := ep.CSRF
|
||||
switch strings.ToLower(cfg.From) {
|
||||
case "cookie":
|
||||
u, err := url.Parse(c.BaseURL)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
cookies := c.HTTP.Jar.Cookies(u)
|
||||
for _, c := range cookies {
|
||||
if c.Name == cfg.Name {
|
||||
return &session.CSRFToken{Header: cfg.Header, Value: c.Value}
|
||||
}
|
||||
}
|
||||
case "header":
|
||||
val := resp.Header.Get(cfg.Name)
|
||||
if val != "" {
|
||||
return &session.CSRFToken{Header: cfg.Header, Value: val}
|
||||
}
|
||||
}
|
||||
_ = body
|
||||
return nil
|
||||
}
|
||||
|
||||
func renderTemplate(tpl string, vars map[string]string) (string, error) {
|
||||
if tpl == "" {
|
||||
return "", nil
|
||||
}
|
||||
t, err := template.New("body").Option("missingkey=error").Parse(tpl)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid template: %w", err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := t.Execute(&buf, vars); err != nil {
|
||||
return "", fmt.Errorf("template render failed: %w", err)
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user