summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
authorMike Crute <mike@crute.us>2022-01-30 12:24:26 -0800
committerMike Crute <mike@crute.us>2022-01-30 12:24:26 -0800
commit1c24090da6b95ea304677d36f7cb6458034c08b9 (patch)
treeb375186f692a1e850f2f35ad5a3295e90ab7906c /web
parent74c33667f4c317bed29a014306130b9dd8990538 (diff)
downloadgo_ddns_manager-1c24090da6b95ea304677d36f7cb6458034c08b9.tar.bz2
go_ddns_manager-1c24090da6b95ea304677d36f7cb6458034c08b9.tar.xz
go_ddns_manager-1c24090da6b95ea304677d36f7cb6458034c08b9.zip
Add ACMEv2 endpoints
The ACMEv2 endpoints are easier to use for clients running the Golang acme.autocert.Manager. They require no tracking of state and also handle DNS propagation checking so the client can remain simple. Once the legacy REST client for the v1 endpoints is gone those old endpoints can be removed.
Diffstat (limited to 'web')
-rw-r--r--web/controllers/acmev2.go90
1 files changed, 90 insertions, 0 deletions
diff --git a/web/controllers/acmev2.go b/web/controllers/acmev2.go
new file mode 100644
index 0000000..a2fadf5
--- /dev/null
+++ b/web/controllers/acmev2.go
@@ -0,0 +1,90 @@
1package controllers
2
3import (
4 "fmt"
5 "log"
6 "net/http"
7
8 "code.crute.me/mcrute/go_ddns_manager/dns"
9 "code.crute.me/mcrute/go_ddns_manager/web/middleware"
10 "github.com/gin-gonic/gin"
11)
12
13func CreateAcmeChallengeV2(c *gin.Context) {
14 cfg := middleware.GetServerConfig(c)
15
16 var ch AcmeChallenge
17 if err := c.ShouldBindJSON(&ch); err != nil {
18 jsonError(c, http.StatusBadRequest, err)
19 return
20 }
21
22 zone, prefix := cfg.BindConfig.FindClosestZone(ch.Zone, cfg.AcmeView)
23 if zone == nil {
24 jsonError(c, http.StatusNotFound, "Zone not found")
25 return
26 }
27
28 if !cfg.IsAcmeClientAllowed(middleware.GetAcmeAuthContext(c), zone.Name) {
29 jsonError(c, http.StatusForbidden, "Zone update not allowed")
30 return
31 }
32
33 txn := cfg.DNSClient.StartUpdate(zone).Upsert(&dns.TXT{
34 Name: joinDomainParts("_acme-challenge", prefix),
35 Ttl: 5,
36 Txt: []string{ch.Challenge},
37 })
38
39 if err := cfg.DNSClient.SendUpdate(txn); err != nil {
40 log.Printf("error Insert: %s", err)
41 jsonError(c, http.StatusInternalServerError, err)
42 return
43 }
44
45 if err := cfg.DNSClient.WaitForDNSPropagation(
46 c.Request.Context(),
47 fmt.Sprintf("_acme-challenge.%s.", prefix),
48 ch.Challenge,
49 ); err != nil {
50 jsonError(c, http.StatusInternalServerError, fmt.Errorf("Error polling for DNS propagation: %w", err))
51 return
52 }
53
54 c.JSON(http.StatusCreated, "")
55}
56
57func DeleteAcmeChallengeV2(c *gin.Context) {
58 cfg := middleware.GetServerConfig(c)
59
60 var ch AcmeChallenge
61 if err := c.ShouldBindJSON(&ch); err != nil {
62 jsonError(c, http.StatusBadRequest, err)
63 return
64 }
65
66 zone, prefix := cfg.BindConfig.FindClosestZone(ch.Zone, cfg.AcmeView)
67 if zone == nil {
68 jsonError(c, http.StatusNotFound, "Zone not found")
69 return
70 }
71
72 if !cfg.IsAcmeClientAllowed(middleware.GetAcmeAuthContext(c), zone.Name) {
73 jsonError(c, http.StatusForbidden, "Zone update not allowed")
74 return
75 }
76
77 txn := cfg.DNSClient.StartUpdate(zone).Remove(&dns.TXT{
78 Name: joinDomainParts("_acme-challenge", prefix),
79 Ttl: 5,
80 Txt: []string{ch.Challenge},
81 })
82
83 if err := cfg.DNSClient.SendUpdate(txn); err != nil {
84 log.Printf("error Remove: %s", err)
85 jsonError(c, http.StatusInternalServerError, err)
86 return
87 }
88
89 c.String(http.StatusNoContent, "")
90}