-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathapicall.go
134 lines (105 loc) · 2.73 KB
/
apicall.go
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package pr0gramm
import (
"encoding/json"
"errors"
"fmt"
"github.com/ajg/form"
"io"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
"strings"
)
type Session struct {
client http.Client
}
func NewSession(client http.Client) *Session {
client.Jar, _ = cookiejar.New(nil)
return &Session{client: client}
}
func (sess *Session) Login(username, password string) (*LoginResponse, error) {
body := make(url.Values)
body.Set("name", username)
body.Set("password", password)
uri := "https://pr0gramm.com/api/user/login"
resp, err := sess.client.PostForm(uri, body)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var response LoginResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return &response, err
}
func (sess *Session) apiGET(path string, query url.Values, target interface{}) error {
uri := "https://pr0gramm.com/api" + path
if query != nil {
uri += "?" + query.Encode()
}
response, err := sess.client.Get(uri)
if err != nil {
return err
}
defer func() {
_, _ = io.Copy(ioutil.Discard, response.Body)
_ = response.Body.Close()
}()
if response.StatusCode/100 != 2 {
return fmt.Errorf("error %d", response.StatusCode)
}
return json.NewDecoder(response.Body).Decode(target)
}
func (sess *Session) apiPOST(path string, query url.Values, body interface{}, target interface{}) error {
uri := "https://pr0gramm.com/api" + path
if query != nil {
uri += "?" + query.Encode()
}
bodyValues, err := encodeToValues(body)
if err != nil {
return fmt.Errorf("encode body: %s", err)
}
var nonce string
// extract nonce from 'id' in 'me' cookie.
cookies := sess.client.Jar.Cookies(&url.URL{Scheme: "https", Host: "pr0gramm.com", Path: "/api/"})
for _, cookie := range cookies {
if cookie.Name == "me" {
cookieValue, _ := url.QueryUnescape(cookie.Value)
var decoded struct{ Id string }
_ = json.Unmarshal([]byte(cookieValue), &decoded)
if len(decoded.Id) > 16 {
nonce = decoded.Id[:16]
break
}
}
}
if nonce == "" {
return errors.New("not authorized")
}
bodyContent := bodyValues.Encode() + "&_nonce=" + nonce
response, err := sess.client.Post(
uri, "application/x-www-form-urlencoded",
strings.NewReader(bodyContent))
if err != nil {
return fmt.Errorf("request failed: %s", err)
}
defer func() {
// discard and close body
_, _ = io.Copy(ioutil.Discard, response.Body)
_ = response.Body.Close()
}()
if response.StatusCode/100 != 2 {
return fmt.Errorf("error %d", response.StatusCode)
}
if target == nil {
return nil
}
return json.NewDecoder(response.Body).Decode(target)
}
func encodeToValues(body interface{}) (url.Values, error) {
if values, ok := body.(url.Values); ok {
return values, nil
} else {
return form.EncodeToValues(body)
}
}