-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathliqpay.go
132 lines (110 loc) · 2.57 KB
/
liqpay.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
package liqpay
import (
"bytes"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"html/template"
"net/http"
"net/url"
)
const liqpayURL = "https://www.liqpay.ua/api/"
type formData struct {
Data string
Signature string
}
type Client struct {
httpClient *http.Client
publicKey []byte
privateKey []byte
}
type Request map[string]interface{}
type Response map[string]interface{}
func New(pubKey string, privKey string, client *http.Client) *Client {
var c *http.Client
if client == nil {
c = &http.Client{}
} else {
c = client
}
return &Client{
httpClient: c,
publicKey: []byte(pubKey),
privateKey: []byte(privKey),
}
}
func (c Client) Send(apiUrl string, req Request) (Response, error) {
req.addMissingPubKey(string(c.publicKey))
encodedJSON, err := req.Encode()
if err != nil {
return nil, err
}
signature := c.Sign([]byte(encodedJSON))
form := url.Values{
"data": {encodedJSON},
"signature": {signature},
}
reqBody := bytes.NewBufferString(form.Encode())
resp, err := http.Post(liqpayURL+apiUrl, "application/x-www-form-urlencoded", reqBody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, errors.New(fmt.Sprintf("bad response status code, status code is %d", resp.StatusCode))
}
var res Response
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
return nil, err
}
if res["status"] == "error" {
errMsg, ok := res["err_description"].(string)
if ok {
return nil, errors.New(errMsg)
}
return nil, errors.New("response body has status error but didn't get error description")
}
return res, nil
}
func (c Client) RenderForm(req Request) (string, error) {
req.addMissingPubKey(string(c.publicKey))
encodedJSON, err := req.Encode()
if err != nil {
return "", err
}
signature := c.Sign([]byte(encodedJSON))
t, err := template.ParseFiles("liqpay_form.html")
if err != nil {
return "", err
}
buf := bytes.Buffer{}
if err := t.Execute(&buf, formData{
Data: encodedJSON,
Signature: signature,
}); err != nil {
return "", err
}
return buf.String(), nil
}
func (r Request) addMissingPubKey(key string) {
if r["public_key"] == key {
return
}
r["public_key"] = key
}
func (r Request) Encode() (string, error) {
obj, err := json.Marshal(r)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(obj), nil
}
func (c Client) Sign(data []byte) string {
hasher := sha1.New()
hasher.Write(c.privateKey)
hasher.Write(data)
hasher.Write(c.privateKey)
return base64.StdEncoding.EncodeToString(hasher.Sum(nil))
}