Skip to content

Commit 15effbf

Browse files
authored
Merge pull request #1 from Craze1997/add-spaceship-provider
feat: add Spaceship DNS provider support
2 parents 5b5c7d5 + d23e426 commit 15effbf

2 files changed

Lines changed: 165 additions & 0 deletions

File tree

docs/PARAMETERS.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Plugin Parameters
2+
3+
- [Retrievers](#retrievers)
4+
- [ifconfigco](#ifconfigco)
5+
- [unifi](#unifi)
6+
7+
- [Providers](#providers)
8+
- [hetzner_cloud](#hetzner_cloud)
9+
- [spaceship](#spaceship)
10+
11+
## Retrievers
12+
13+
### `ifconfigco`
14+
15+
| Parameter | Type | Required | Default | Description |
16+
|-----------|------|----------|---------|-------------|
17+
| `base_url` | `string` | No | "https://ifconfig.co" | API base URL |
18+
19+
### `unifi`
20+
21+
| Parameter | Type | Required | Default | Description |
22+
|-----------|------|----------|---------|-------------|
23+
| `base_url` | `string` | Yes | | Unifi controller base URL (e.g. https://192.168.1.1) |
24+
| `api_token` | `string` | Yes | | API authentication token |
25+
| `site_id` | `string` | No | "default" | Site ID |
26+
| `verify_tls` | `bool` | No | false | Enable TLS certificate verification |
27+
28+
## Providers
29+
30+
### `hetzner_cloud`
31+
32+
| Parameter | Type | Required | Default | Description |
33+
|-----------|------|----------|---------|-------------|
34+
| `api_token` | `string` | Yes | | Hetzner Cloud API token |
35+
| `zone` | `string` | Yes | | DNS zone (e.g. homelab.com) |
36+
| `rr_name` | `string` | Yes | | Resource record name (e.g. @) |
37+
38+
### `spaceship`
39+
40+
| Parameter | Type | Required | Default | Description |
41+
|-----------|------|----------|---------|-------------|
42+
| `api_key` | `string` | Yes | | Spaceship API key |
43+
| `api_secret` | `string` | Yes | | Spaceship API secret |
44+
| `domain` | `string` | Yes | | The domain name (e.g. example.com) |
45+
| `subdomain` | `string` | Yes | | The (sub)domain name |
46+
| `ttl` | `int` | No | 3600 | The TTL (Time to live) for the entry |
47+
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package plugins
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"goddns/internal/plugin"
8+
"net/http"
9+
)
10+
11+
type spaceshipConfig struct {
12+
APIKey string `json:"api_key" required:"true" doc:"Spaceship API key"`
13+
APISecret string `json:"api_secret" required:"true" doc:"Spaceship API secret"`
14+
Domain string `json:"domain" required:"true" doc:"The domain name (e.g. example.com)"`
15+
Subdomain string `json:"subdomain" required:"true" doc:"The (sub)domain name"`
16+
TTL int `json:"ttl" default:"3600" doc:"The TTL (Time to live) for the entry"`
17+
}
18+
19+
type spaceshipProvider struct {
20+
apiKey string
21+
apiSecret string
22+
subdomain string
23+
domain string
24+
ttl int
25+
}
26+
27+
func init() {
28+
plugin.RegisterProvider("spaceship", newSpaceshipFromConfig, spaceshipConfig{})
29+
}
30+
31+
func newSpaceshipFromConfig(params map[string]any) (plugin.Provider, error) {
32+
cfg, err := plugin.Decode[spaceshipConfig](params)
33+
if err != nil {
34+
return nil, fmt.Errorf("spaceship: %w", err)
35+
}
36+
37+
if cfg.APIKey == "" {
38+
return nil, fmt.Errorf("spaceship: api_key is required")
39+
}
40+
if cfg.APISecret == "" {
41+
return nil, fmt.Errorf("spaceship: api_secret is required")
42+
}
43+
if cfg.Domain == "" {
44+
return nil, fmt.Errorf("spaceship: domain is required")
45+
}
46+
if cfg.Subdomain == "" {
47+
return nil, fmt.Errorf("spaceship: subdomain is required")
48+
}
49+
if cfg.TTL == 0 {
50+
cfg.TTL = 3600
51+
}
52+
53+
return spaceshipProvider{
54+
apiKey: cfg.APIKey,
55+
apiSecret: cfg.APISecret,
56+
domain: cfg.Domain,
57+
subdomain: cfg.Subdomain,
58+
ttl: cfg.TTL,
59+
}, nil
60+
}
61+
62+
func (p spaceshipProvider) SetIPAddress(ip string) error {
63+
client := http.DefaultClient
64+
65+
reqData := struct {
66+
Force bool `json:"force"`
67+
Items []struct {
68+
Type string `json:"type"`
69+
Name string `json:"name"`
70+
TTL int `json:"ttl"`
71+
Address string `json:"address"`
72+
} `json:"items"`
73+
}{
74+
Items: []struct {
75+
Type string `json:"type"`
76+
Name string `json:"name"`
77+
TTL int `json:"ttl"`
78+
Address string `json:"address"`
79+
}{
80+
{Type: "A", Name: p.subdomain, TTL: p.ttl, Address: ip},
81+
},
82+
}
83+
84+
reqDataBytes, err := json.Marshal(reqData)
85+
if err != nil {
86+
return err
87+
}
88+
89+
url := fmt.Sprintf("https://spaceship.dev/api/v1/dns/records/%v", p.domain)
90+
req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(reqDataBytes))
91+
if err != nil {
92+
return err
93+
}
94+
95+
req.Header.Add("X-API-Key", p.apiKey)
96+
req.Header.Add("X-API-Secret", p.apiSecret)
97+
req.Header.Add("Content-Type", "application/json")
98+
99+
res, err := client.Do(req)
100+
if err != nil {
101+
return err
102+
}
103+
104+
defer res.Body.Close()
105+
106+
if res.StatusCode != http.StatusNoContent {
107+
return fmt.Errorf("expected status 204, got %d", res.StatusCode)
108+
}
109+
110+
var data map[string]any
111+
if json.NewDecoder(res.Body).Decode(&data) != nil {
112+
return err
113+
}
114+
115+
return nil
116+
}
117+
118+
var _ plugin.Provider = spaceshipProvider{}

0 commit comments

Comments
 (0)