Allow passing embedded "ReturnHeaders" object to get response headers in handlers if necessary e.g. captcha cookie?

Parse set-cookie header and store session cookie in client if set-cookie contains connect.sid cookie
Remove some json definitions for option arguments to client methods
master
Thomas Lynch 1 year ago
parent 0bd911d6bf
commit 3fac0d046f
  1. 40
      app/auth.go
  2. 20
      app/boardlist.go
  3. 42
      app/jschan.go
  4. 14
      app/overboard.go
  5. 21
      example.go

@ -0,0 +1,40 @@
package jschan
import (
"context"
"fmt"
"net/http"
"net/url"
"strings"
)
type PostLoginOptions struct {
Username string
Password string
Twofactor string
}
func (c *Client) Login(ctx context.Context, options *PostLoginOptions) error {
formData := url.Values{}
formData.Set("username", options.Username)
formData.Set("password", options.Password)
formData.Set("twofactor", options.Twofactor)
endodedBody := strings.NewReader(formData.Encode())
url := fmt.Sprintf("%s/forms/login", c.BaseURL)
req, err := http.NewRequest(http.MethodPost, url, endodedBody)
if err != nil {
return err
}
req = req.WithContext(ctx)
if err := c.sendRequest(req, nil, nil); err != nil {
return err
}
return nil
}

@ -15,12 +15,12 @@ type GetBoardsResponse struct {
}
type GetBoardsPublicOptions struct {
Search string `json:"search"`
Sort string `json:"sort"`
SortDirection string `json:"direction"`
Page int `json:"page"`
LocalFirst bool `json:"local_first"`
Sites []string `json:"sites"`
Search string
Sort string
SortDirection string
Page int
LocalFirst bool
Sites []string
}
func (c *Client) GetBoardsPublic(ctx context.Context, options *GetBoardsPublicOptions) (*GetBoardsResponse, error) {
@ -54,7 +54,7 @@ func (c *Client) GetBoardsPublic(ctx context.Context, options *GetBoardsPublicOp
url := fmt.Sprintf("%s/boards.json?%s", c.BaseURL, query.Encode())
req, err := http.NewRequest("GET", url, nil)
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
@ -62,7 +62,7 @@ func (c *Client) GetBoardsPublic(ctx context.Context, options *GetBoardsPublicOp
req = req.WithContext(ctx)
res := GetBoardsResponse{}
if err := c.sendRequest(req, &res); err != nil {
if err := c.sendRequest(req, &res, nil); err != nil {
return nil, err
}
@ -116,7 +116,7 @@ func (c *Client) GetBoardsGlobalmanage(ctx context.Context, options *GetBoardsGl
url := fmt.Sprintf("%s/boards.json?%s", c.BaseURL, query.Encode())
req, err := http.NewRequest("GET", url, nil)
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
@ -125,7 +125,7 @@ func (c *Client) GetBoardsGlobalmanage(ctx context.Context, options *GetBoardsGl
req = req.WithContext(ctx)
res := GetBoardsResponse{}
if err := c.sendRequest(req, &res); err != nil {
if err := c.sendRequest(req, &res, nil); err != nil {
return nil, err
}

@ -22,6 +22,9 @@ func NewClient(baseURL string) *Client {
CsrfToken: "",
HTTPClient: &http.Client{
Timeout: time.Minute,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
},
}
}
@ -32,9 +35,27 @@ type DynamicResponse struct {
Redirect string `json:"redirect,omitempty"`
}
func (c *Client) sendRequest(req *http.Request, v interface{}) error {
type ReturnHeaders struct {
*http.Header
}
func cookieHeader(rawCookies string) []*http.Cookie {
header := http.Header{}
header.Add("Cookie", rawCookies)
req := http.Request{Header: header}
return req.Cookies()
}
func (c *Client) sendRequest(req *http.Request, v interface{}, h *ReturnHeaders) error {
if req.Method == http.MethodGet {
req.Header.Set("Content-Type", "application/json; charset=utf-8")
} else {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
req.Header.Set("Accept", "application/json; charset=utf-8")
//req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.Header.Set("X-Using-XHR", "true")
req.Header.Set("Referer", c.BaseURL)
if c.SessionCookie != "" {
req.Header.Set("Cookie", fmt.Sprintf("connect.sid=%s", c.SessionCookie))
}
@ -56,9 +77,20 @@ func (c *Client) sendRequest(req *http.Request, v interface{}) error {
return fmt.Errorf("unknown error, status code: %d", res.StatusCode)
}
fullResponse := v
if err = json.NewDecoder(res.Body).Decode(&fullResponse); err != nil {
return err
h = &ReturnHeaders{
&res.Header,
}
setCookieValue := h.Get("Set-Cookie")
if setCookieValue != "" {
parsedSetCookie := cookieHeader(setCookieValue)
c.SessionCookie = parsedSetCookie[0].Value
}
if v != nil {
fullResponse := v
if err = json.NewDecoder(res.Body).Decode(&fullResponse); err != nil {
return err
}
}
return nil

@ -10,9 +10,9 @@ import (
)
type GetOverboardOptions struct {
AddBoards []string `json:"search"`
RemoveBoards []string `json:"sort"`
IncludeDefault bool `json:"include_default"`
AddBoards []string
RemoveBoards []string
IncludeDefault bool
}
type GetOverboardResponse struct {
@ -45,7 +45,7 @@ func (c *Client) GetOverboardIndex(ctx context.Context, options *GetOverboardOpt
url := fmt.Sprintf("%s/overboard.json?%s", c.BaseURL, query.Encode())
req, err := http.NewRequest("GET", url, nil)
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
@ -53,7 +53,7 @@ func (c *Client) GetOverboardIndex(ctx context.Context, options *GetOverboardOpt
req = req.WithContext(ctx)
res := GetOverboardResponse{}
if err := c.sendRequest(req, &res); err != nil {
if err := c.sendRequest(req, &res, nil); err != nil {
return nil, err
}
@ -70,7 +70,7 @@ func (c *Client) GetOverboardCatalog(ctx context.Context, options *GetOverboardO
url := fmt.Sprintf("%s/catalog.json?%s", c.BaseURL, query.Encode())
req, err := http.NewRequest("GET", url, nil)
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
@ -78,7 +78,7 @@ func (c *Client) GetOverboardCatalog(ctx context.Context, options *GetOverboardO
req = req.WithContext(ctx)
res := GetOverboardResponse{}
if err := c.sendRequest(req, &res); err != nil {
if err := c.sendRequest(req, &res, nil); err != nil {
return nil, err
}

@ -8,15 +8,26 @@ import (
func main() {
jschanClient := jschan.NewClient("https://ptchan.org")
jschanClient := jschan.NewClient("https://fatchan.org")
ctx := context.Background()
options := &jschan.GetOverboardOptions{
IncludeDefault: true,
loginOptions := &jschan.PostLoginOptions{
Username: "",
Password: "",
Twofactor: "",
}
err := jschanClient.Login(ctx, loginOptions)
if err != nil {
fmt.Println(err)
return
}
res, err := jschanClient.GetOverboardCatalog(ctx, options)
overboardOptions := &jschan.GetOverboardOptions{
IncludeDefault: true,
}
res, err := jschanClient.GetOverboardCatalog(ctx, overboardOptions)
if err != nil {
fmt.Println("an error occurred")
fmt.Println(err)
return
}

Loading…
Cancel
Save