Skip to content

Commit 4adab92

Browse files
committed
APIv2: Initial release
1 parent 10f4f72 commit 4adab92

File tree

13 files changed

+244
-373
lines changed

13 files changed

+244
-373
lines changed

.github/workflows/build.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- name: Set up Go
1717
uses: actions/setup-go@v5
1818
with:
19-
go-version: '1.21'
19+
go-version: '1.24'
2020

2121
- name: Check out code
2222
uses: actions/checkout@v4

.golangci.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
---
1+
version: "2"
2+
23
linters:
4+
default: none
35
enable:
46
- staticcheck
5-
disable-all: true

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ repos:
77
- id: check-yaml
88
- id: check-merge-conflict
99
- repo: https://github.com/golangci/golangci-lint
10-
rev: v1.63.4
10+
rev: v2.3.1
1111
hooks:
1212
- id: golangci-lint
1313
- repo: https://github.com/dnephin/pre-commit-golang

README.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
# Active24.cz client in Go
22

3-
This is client library to interact with [Active24 API](https://faq.active24.com/eng/739445-REST-API-for-developers?l=en-US).
3+
This is client library to interact with [Active24 APIv2](https://www.active24.cz/centrum-napovedy/api-rozhrani).
44
Currently, only subset of API is implemented, but contributions are always welcome.
55

66
## Usage
77

88
```go
99
package main
1010

11-
import "github.com/rkosegi/active24-go/active24"
11+
import "github.com/hostalp/active24-go/active24"
1212

1313
func main() {
14-
client := active24.New("my-secret-api-token")
14+
client := active24.New("my-secret-api-key", "my-secret-api-secret")
1515

16-
alias := "host1"
17-
_, err := client.Dns().With("example.com").Create(active24.DnsRecordTypeA, &active24.DnsRecord{
18-
Alias: &alias,
16+
recordType := string(active24.DnsRecordTypeA)
17+
hostName := "host1" // Short hostname (excl. the domain)
18+
ipAddress := "1.2.3.4"
19+
ttl := 600
20+
21+
_, err := client.Dns().With("example.com", 12345678).Create(&active24.DnsRecord{
22+
Type: &recordType,
23+
Name: hostName;
24+
Content: &ipAddress,
25+
Ttl: ttl,
1926
})
2027
if err != nil {
2128
panic(err)

active24/client.go

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,17 @@ limitations under the License.
1717
package active24
1818

1919
import (
20+
"crypto/hmac"
21+
"crypto/sha1"
22+
"encoding/hex"
2023
"fmt"
2124
"io"
22-
"k8s.io/klog/v2"
2325
"net/http"
26+
"net/url"
27+
"path"
2428
"time"
25-
)
2629

27-
const (
28-
SandboxToken = "123456qwerty-ok"
30+
"k8s.io/klog/v2"
2931
)
3032

3133
type Option func(c *client)
@@ -50,19 +52,19 @@ type ApiError interface {
5052
type Client interface {
5153
// Dns provides interface to interact with DNS records
5254
Dns() Dns
53-
// Domains provides interface to interact with domains
54-
Domains() Domains
5555
}
5656

57-
func New(apiKey string, opts ...Option) Client {
57+
func New(apiKey string, apiSecret string, opts ...Option) Client {
5858
c := &client{
5959
h: helper{
60-
apiEndpoint: "https://api.active24.com",
61-
auth: apiKey,
60+
apiEndpoint: "https://rest.active24.cz",
61+
authKey: apiKey,
62+
authSecret: apiSecret,
6263
c: http.Client{
6364
Timeout: time.Second * 10,
6465
},
65-
l: klog.NewKlogr(),
66+
l: klog.NewKlogr(),
67+
maxPages: 100, // default max pages to prevent infinite loops
6668
},
6769
}
6870
for _, opt := range opts {
@@ -81,12 +83,6 @@ func (c *client) Dns() Dns {
8183
}
8284
}
8385

84-
func (c *client) Domains() Domains {
85-
return &domains{
86-
h: c.h,
87-
}
88-
}
89-
9086
type apiError struct {
9187
err error
9288
resp *http.Response
@@ -102,21 +98,57 @@ func (a *apiError) Response() *http.Response {
10298

10399
type helper struct {
104100
apiEndpoint string
105-
auth string
101+
authKey string
102+
authSecret string
106103
c http.Client
107104
l klog.Logger
105+
maxPages int
106+
}
107+
108+
func (ch *helper) getSignature(message, key string) string {
109+
h := hmac.New(sha1.New, []byte(key))
110+
h.Write([]byte(message))
111+
return hex.EncodeToString(h.Sum(nil))
108112
}
109113

110-
func (ch *helper) do(method string, suffix string, body io.Reader) (*http.Response, error) {
111-
r, err := http.NewRequest(method, fmt.Sprintf("%s/%s", ch.apiEndpoint, suffix), body)
114+
func (ch *helper) do(reqMethod string, reqPath string, reqBody io.Reader) (*http.Response, error) {
115+
return ch.doWithParams(reqMethod, reqPath, nil, reqBody)
116+
}
117+
118+
func (ch *helper) doWithParams(reqMethod string, reqPath string, reqParams url.Values, reqBody io.Reader) (*http.Response, error) {
119+
reqPath = path.Join("/", reqPath)
120+
reqTimestamp := time.Now()
121+
canonicalRequest := fmt.Sprintf("%s %s %d", reqMethod, reqPath, reqTimestamp.Unix())
122+
authSignature := ch.getSignature(canonicalRequest, ch.authSecret)
123+
124+
r, err := http.NewRequest(reqMethod, fmt.Sprintf("%s%s", ch.apiEndpoint, reqPath), reqBody)
112125
if err != nil {
113126
return nil, err
114127
}
115-
r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", ch.auth))
128+
r.URL.RawQuery = reqParams.Encode()
116129
r.Header.Set("Content-Type", "application/json")
117130
r.Header.Set("Accept", "application/json")
118-
ch.l.V(4).Info("Calling API", "method", method, "url", r.URL.String())
119-
return ch.c.Do(r)
131+
r.Header.Set("Date", reqTimestamp.UTC().Format(time.RFC3339))
132+
r.SetBasicAuth(ch.authKey, authSignature)
133+
ch.l.V(4).Info("Calling API", "method", reqMethod, "URL", r.URL.String())
134+
135+
// Log the request
136+
/* dumpReq, dumpErr := httputil.DumpRequestOut(r, true)
137+
if dumpErr != nil {
138+
return nil, dumpErr
139+
}
140+
ch.l.V(4).Info("doWithParams", "REQUEST", string(dumpReq)) */
141+
142+
resp, err := ch.c.Do(r)
143+
144+
// Log the response
145+
/* dumpResp, dumpErr := httputil.DumpResponse(resp, true)
146+
if dumpErr != nil {
147+
return nil, dumpErr
148+
}
149+
ch.l.V(4).Info("doWithParams", "RESPONSE", string(dumpResp)) */
150+
151+
return resp, err
120152
}
121153

122154
func apiErr(resp *http.Response, err error) ApiError {

active24/client_test.go

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)