-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrequest.go
110 lines (89 loc) · 2.59 KB
/
request.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
package xmrrpc
import (
"bytes"
"crypto/md5"
"encoding/base64"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"math/rand"
"net/http"
"strings"
"time"
)
func digestAuthParams(response *http.Response) map[string]string {
s := strings.SplitN(response.Header.Get("WWW-Authenticate"), " ", 2)
if len(s) != 2 || s[0] != "Digest" {
return nil
}
result := map[string]string{}
for _, kv := range strings.Split(s[1], ",") {
parts := strings.SplitN(kv, "=", 2)
if len(parts) != 2 {
continue
}
result[strings.Trim(parts[0], "\" ")] = strings.Trim(parts[1], "\" ")
}
return result
}
func randomKey() string {
k := make([]byte, 8)
if _, err := rand.Read(k); err != nil {
panic(err)
}
return base64.StdEncoding.EncodeToString(k)
}
func h(s string) string {
digest := md5.New()
if _, err := digest.Write([]byte(s)); err != nil {
panic(err)
}
return hex.EncodeToString(digest.Sum(nil))
}
func request(method string, url string, body []byte, username string, password string) (*http.Response, error) {
rand.Seed(time.Now().UnixNano())
req1, err := http.NewRequest(method, url, bytes.NewReader(body))
if err != nil {
return nil, err
}
req1.Header.Set("Content-Type", "application/json")
res1, err := http.DefaultClient.Do(req1)
if err != nil {
return nil, err
}
if res1.StatusCode == http.StatusUnauthorized {
io.Copy(ioutil.Discard, res1.Body)
res1.Body.Close()
var authorization = digestAuthParams(res1)
var realmHeader = authorization["realm"]
var qopHeader = authorization["qop"]
var nonceHeader = authorization["nonce"]
var algorithm = authorization["algorithm"]
var realm = realmHeader
var nc = "00000001"
hash := md5.New()
a1 := fmt.Sprintf("%s:%s:%s", username, realm, password)
io.WriteString(hash, a1)
ha1 := hex.EncodeToString(hash.Sum(nil))
hash = md5.New()
a2 := fmt.Sprintf("%s:%s", method, "/json_rpc")
io.WriteString(hash, a2)
ha2 := hex.EncodeToString(hash.Sum(nil))
cnonce := randomKey()
response := h(strings.Join([]string{ha1, nonceHeader, nc, cnonce, qopHeader, ha2}, ":"))
authHeader := fmt.Sprintf(`Digest username="%s", realm="%s", nonce="%s", uri="%s", algorithm="%s", response="%s", qop=%s, nc=%s, cnonce="%s"`, username, realmHeader, nonceHeader, "/json_rpc", algorithm, response, qopHeader, nc, cnonce)
req2, err := http.NewRequest(method, url, bytes.NewReader(body))
if err != nil {
return nil, err
}
req2.Header.Set("Content-Type", "application/json")
req2.Header.Set("Authorization", authHeader)
res2, err := http.DefaultClient.Do(req2)
if err != nil {
return nil, err
}
return res2, nil
}
return res1, nil
}