-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathapi.go
164 lines (153 loc) · 3.98 KB
/
api.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Package p2pubapi : P2PUB APIクライアントモジュール
package p2pubapi
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"crypto/tls"
"encoding/base64"
"encoding/json"
"fmt"
"hash"
"io"
"net/http"
"net/url"
"sort"
"strings"
"time"
log "github.com/sirupsen/logrus"
)
const (
HmacSHA1 = "HmacSHA1"
HmacSHA256 = "HmacSHA256"
SignatureVersion2 = "2"
APIVersion20151130 = "20151130"
EndpointJSON = "https://p2pub.api.iij.jp/"
// EndpointJSON = "http://localhost:9999/"
TimeLayout = "2006-01-02T15:04:05Z"
PostContentType = "application/json"
)
// API の呼び出し先に関連する構造
type API struct {
AccessKey string
SecretKey string
Endpoint string
SignMethod string
Expires time.Duration
Insecure bool
}
// NewAPI API構造体のコンストラクタ
func NewAPI(accesskey, secretkey string) *API {
dur, _ := time.ParseDuration("1h")
return &API{AccessKey: accesskey,
SecretKey: secretkey,
Endpoint: EndpointJSON,
SignMethod: HmacSHA256,
Expires: dur,
}
}
func convert1(r byte) string {
passchar := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_~.-"
if strings.ContainsRune(passchar, rune(r)) {
return string(r)
}
return fmt.Sprintf("%%%02X", r)
}
// CustomEscape escape string
func CustomEscape(v string) string {
res := ""
for _, c := range []byte(v) {
res += convert1(c)
}
return res
}
// String2Sign get string to calculate signature
func String2Sign(method string, header http.Header, param url.URL) string {
var keys []string
ctflag := false
for k := range header {
hdr := strings.ToLower(k)
if strings.HasPrefix(hdr, "x-iijapi-") {
keys = append(keys, hdr)
} else if hdr == "content-type" || hdr == "content-md5" {
keys = append(keys, hdr)
ctflag = true
}
}
sort.Strings(keys)
var target []string
target = append(target, method)
target = append(target, "")
if !ctflag {
target = append(target, "")
}
for _, k := range keys {
if k == "content-type" || k == "content-md5" {
target = append(target, header.Get(k))
} else {
target = append(target, k+":"+header.Get(k))
}
}
target = append(target, param.Path)
return strings.Join(target, "\n")
}
// Sign get signature string
func (a API) Sign(method string, header http.Header, param url.URL, signmethod string) http.Header {
header.Set("x-iijapi-Expire", time.Now().Add(a.Expires).UTC().Format(TimeLayout))
header.Set("x-iijapi-SignatureMethod", signmethod)
header.Set("x-iijapi-SignatureVersion", SignatureVersion2)
tgtstr := String2Sign(method, header, param)
var hfn func() hash.Hash
switch signmethod {
case HmacSHA1:
hfn = sha1.New
case HmacSHA256:
hfn = sha256.New
}
mac := hmac.New(hfn, []byte(a.SecretKey))
io.WriteString(mac, tgtstr)
macstr := mac.Sum(nil)
header.Set("Authorization", "IIJAPI "+a.AccessKey+":"+base64.StdEncoding.EncodeToString(macstr))
return header
}
// Get : low-level Get
func (a API) Get(param url.URL) (resp *http.Response, err error) {
return a.PostSome("GET", param, nil)
}
// PostSome : low-level Call
func (a API) PostSome(method string, param url.URL, body interface{}) (resp *http.Response, err error) {
cl := http.Client{}
if a.Insecure {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
cl.Transport = tr
}
log.Debug("param", param)
var buf *bytes.Buffer
if body != nil {
var bufb []byte
bufb, err = json.Marshal(body)
if len(bufb) > 2 {
log.Debug("call with body", method, string(bufb))
buf = bytes.NewBuffer(bufb)
} else {
// string(bufb)=="{}"
log.Debug("call without body(empty)", method)
buf = bytes.NewBufferString("")
body = nil
}
} else {
log.Debug("call without body(nil)", method)
buf = bytes.NewBufferString("")
}
req, err := http.NewRequest(method, param.String(), buf)
if body != nil {
req.Header.Add("content-type", PostContentType)
}
req.Header = a.Sign(method, req.Header, param, HmacSHA256)
log.Debug("sign", req.Header)
resp, err = cl.Do(req)
return
}