initial commit of cloudflare api

Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
Jeff Carr 2024-01-01 15:31:33 -06:00
commit f1a0d18ac1
10 changed files with 1110 additions and 0 deletions

228
api.go Normal file
View File

@ -0,0 +1,228 @@
// This is a simple example
package cloudflare
import (
"encoding/json"
"io/ioutil"
"net/http"
"go.wit.com/log"
)
/*
This function should run each time
the user chanegs anything in the GUi
or each time something in general changes
It returns a RR record which then can be
turned into JSON and sent via http
to cloudflare's API
*/
func DoChange() *RRT {
var dnsRow *RRT
dnsRow = new(RRT)
log.Println("DoChange() START")
if (CFdialog.proxyNode.S == "On") {
dnsRow.Proxied = true
} else {
dnsRow.Proxied = false
}
dnsRow.Auth = CFdialog.apiNode.S
dnsRow.Email = CFdialog.emailNode.S
dnsRow.Domain = CFdialog.zoneNode.S
dnsRow.ZoneID = CFdialog.zoneIdNode.S
dnsRow.ID = CFdialog.rrNode.S
dnsRow.Content = CFdialog.ValueNode.S
dnsRow.Name = CFdialog.NameNode.S
dnsRow.Type = CFdialog.TypeNode.S
dnsRow.url = CFdialog.urlNode.S
dnsRow.data = makeJSON(dnsRow)
// show the JSON
log.Println(dnsRow)
if (CFdialog.curlNode != nil) {
pretty, _ := FormatJSON(dnsRow.data)
log.Println("http PUT curl =", pretty)
CFdialog.curlNode.SetText(pretty)
}
return dnsRow
}
func SetRow(dnsRow *RRT) {
log.Println("Look for changes in row", dnsRow.ID)
if (CFdialog.proxyNode != nil) {
log.Println("Proxy", dnsRow.Proxied, "vs", CFdialog.proxyNode.S)
if (dnsRow.Proxied == true) {
CFdialog.proxyNode.SetText("On")
} else {
CFdialog.proxyNode.SetText("Off")
}
}
if (CFdialog.zoneNode != nil) {
CFdialog.zoneNode.SetText(dnsRow.Domain)
}
if (CFdialog.zoneIdNode != nil) {
CFdialog.zoneIdNode.SetText(dnsRow.ZoneID)
}
log.Println("zoneIdNode =", dnsRow.ZoneID)
if (CFdialog.rrNode != nil) {
CFdialog.rrNode.SetText(dnsRow.ID)
}
if (CFdialog.ValueNode != nil) {
log.Println("Content", dnsRow.Content, "vs", CFdialog.ValueNode.S)
CFdialog.ValueNode.SetText(dnsRow.Content)
}
if (CFdialog.NameNode != nil) {
CFdialog.NameNode.SetText(dnsRow.Name)
}
if (CFdialog.TypeNode != nil) {
CFdialog.TypeNode.SetText(dnsRow.Type)
}
if (CFdialog.urlNode != nil) {
url := cloudflareURL + dnsRow.ZoneID + "/dns_records/" + dnsRow.ID
CFdialog.urlNode.SetText(url)
}
// show the JSON
tmp := makeJSON(dnsRow)
log.Println(tmp)
if (CFdialog.curlNode != nil) {
pretty, _ := FormatJSON(tmp)
log.Println("http PUT curl =", pretty)
CFdialog.curlNode.SetText(pretty)
}
}
func GetZonefile(c *ConfigT) *DNSRecords {
var url = cloudflareURL + c.ZoneID + "/dns_records/?per_page=100"
log.Println("getZonefile()", c.Domain, url)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Println("http.NewRequest error:", err)
return nil
}
// Set headers
req.Header.Set("X-Auth-Key", c.Auth)
req.Header.Set("X-Auth-Email", c.Email)
log.Println("getZonefile() auth, email", c.Auth, c.Email)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Println("http.Client error:", err)
return nil
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println("ioutil.ReadAll() error", err)
return nil
}
var records DNSRecords
if err := json.Unmarshal(body, &records); err != nil {
log.Println("json.Unmarshal() error", err)
return nil
}
log.Println("getZonefile() worked", records)
return &records
}
/*
pass in a DNS Resource Records (the stuff in a zonefile)
This will talk to the cloudflare API and generate a resource record in the zonefile:
For example:
gitea.wit.com. 3600 IN CNAME git.wit.com.
go.wit.com. 3600 IN A 1.1.1.9
test.wit.com. 3600 IN NS ns1.wit.com.
*/
func makeJSON(dnsRow *RRT) string {
// make a json record to send on port 80 to cloudflare
var tmp string
tmp = `{"content": "` + dnsRow.Content + `", `
tmp += `"name": "` + dnsRow.Name + `", `
tmp += `"type": "` + dnsRow.Type + `", `
tmp+= `"ttl": "` + "1" + `", `
tmp += `"comment": "WIT DNS Control Panel"`
tmp += `}`
return tmp
}
// https://api.cloudflare.com/client/v4/zones
func GetZones(auth, email string) *DNSRecords {
var url = "https://api.cloudflare.com/client/v4/zones?per_page=100"
log.Println("getZones()", url)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Println("http.NewRequest error:", err)
return nil
}
// Set headers
req.Header.Set("X-Auth-Key", auth)
req.Header.Set("X-Auth-Email", email)
log.Println("getZones() auth, email", auth, email)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Println("getZones() http.Client error:", err)
return nil
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println("getZones() ioutil.ReadAll() error", err)
return nil
}
var records DNSRecords
if err := json.Unmarshal(body, &records); err != nil {
log.Println("getZones() json.Unmarshal() error", err)
return nil
}
/* Cloudflare API returns struct[] of:
struct { ID string "json:\"id\""; Type string "json:\"type\""; Name string "json:\"name\"";
Content string "json:\"content\""; Proxied bool "json:\"proxied\"";
Proxiable bool "json:\"proxiable\""; TTL int "json:\"ttl\"" }
*/
// log.Println("getZones() worked", records)
// log.Println("spew dump:")
// spew.Dump(records)
for _, record := range records.Result {
log.Println("spew record:", record)
log.Println("record:", record.Name, record.ID)
var newc *ConfigT
newc = new(ConfigT)
newc.Domain = record.Name
newc.ZoneID = record.ID
newc.Auth = auth
newc.Email = email
Config[record.Name] = newc
log.Println("zonedrop.AddText:", record.Name, record.ID)
}
for d, _ := range Config {
log.Println("Config entry:", d)
}
return &records
}

57
create.go Normal file
View File

@ -0,0 +1,57 @@
/*
This will attempt to create a RR in a DNS zone file.
Create("wit.com", "test.wit.com", "1.1.1.1"
*/
package cloudflare
import (
"os"
"go.wit.com/log"
)
func Create(zone string, hostname string, value string) bool {
log.Info("cloudflare.Create() START", zone, hostname, value)
key := os.Getenv("CF_API_KEY")
email := os.Getenv("CF_API_EMAIL")
if (key == "") {
log.Warn("cloudflare.Create() MISSING environment variable CF_API_KEY")
return false
}
if (email == "") {
log.Warn("cloudflare.Create() MISSING environment variable CF_API_EMAIL")
return false
}
GetZones(key, email)
var z *ConfigT
for d, v := range Config {
log.Info("cloudflare.Create() zone =", d, "value =", v)
if (zone == d) {
z = Config[zone]
log.Info("cloudflare.Create() FOUND ZONE", zone, "ID =", z.ZoneID)
}
}
if (z == nil) {
log.Warn("cloudflare.Create() COULD NOT FIND ZONE", zone)
return false
}
log.Info("cloudflare.Create() FOUND ZONE", z)
// make a json record to send on port 80 to cloudflare
var data string
data = `{"content": "` + value + `", `
data += `"name": "` + hostname + `", `
data += `"type": "AAAA", `
data += `"ttl": "1", `
data += `"comment": "WIT DNS Control Panel"`
data += `}`
result := doCurlCreate(key, email, z.ZoneID, data)
pretty, _ := FormatJSON(result)
log.Info("cloudflare.Create() result =", pretty)
return true
}

23
curl.sh Executable file
View File

@ -0,0 +1,23 @@
#
# this curl POST will create a new DNS resource record (RR) in zone the wit.com
# In this case it will map www3.wit.com to a IPv6 address
# replace the auth key (e088...) and zone ID (27b9...) with the ones from your cloudflare account
#
curl --request POST \
--url https://api.cloudflare.com/client/v4/zones/27llxxPutYourZoneIDherexxx497f90/dns_records \
--header 'Content-Type: application/json' \
--header 'X-Auth-Key: e08806adxxxPutYourAPIKeyHerexxxxa7d417a7x' \
--header 'X-Auth-Email: test@wit.com' \
--data '{
"name": "www3",
"type": "AAAA"
"content": "2001:4860:4860::5555",
"ttl": 3600,
"proxied": false,
"comment": "WIT DNS Control Panel",
}'
# This will verify an API token
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer AAAPutYourTokenInHereSoYouCanTestItL5Cl3" \
-H "Content-Type:application/json"

64
delete.go Normal file
View File

@ -0,0 +1,64 @@
/*
This will attempt to delete a RR in a DNS zone file.
Delete("wit.com", "test.wit.com", "1.1.1.1"
*/
package cloudflare
import (
"os"
"go.wit.com/log"
)
func Delete(zone string, hostname string, value string) bool {
// CFdialog.emailNode.SetText(os.Getenv("CF_API_EMAIL"))
// CFdialog.apiNode.SetText(os.Getenv("CF_API_KEY"))
log.Info("cloudflare.Delete() START", zone, hostname, value)
key := os.Getenv("CF_API_KEY")
email := os.Getenv("CF_API_EMAIL")
if (key == "") {
log.Warn("cloudflare.Delete() MISSING environment variable CF_API_KEY")
return false
}
if (email == "") {
log.Warn("cloudflare.Delete() MISSING environment variable CF_API_EMAIL")
return false
}
GetZones(key, email)
var z *ConfigT
for d, v := range Config {
log.Info("cloudflare.Delete() zone =", d, "value =", v)
if (zone == d) {
z = Config[zone]
log.Info("cloudflare.Delete() FOUND ZONE", zone, "ID =", z.ZoneID)
}
}
if (z == nil) {
log.Warn("cloudflare.Delete() COULD NOT FIND ZONE", zone)
return false
}
log.Info("cloudflare.Delete() FOUND ZONE", z)
records := GetZonefile(z)
for i, record := range records.Result {
if (record.Name == hostname) {
log.Info("cloudflare.Delete() FOUND hostname:", i, record.ID, record.Type, record.Name, record.Content)
}
if (record.Content == value) {
log.Info("cloudflare.Delete() FOUND CONTENT:", i, record.ID, record.Type, record.Name, record.Content)
log.Info("cloudflare.Delete() DO THE ACTUAL cloudflare DELETE here")
result := doCurlDelete(key, email, z.ZoneID, record.ID)
pretty, _ := FormatJSON(result)
log.Info("cloudflare.Delete() result =", pretty)
return true
}
}
log.Info("cloudflare.Delete() NEVER FOUND cloudflare value:", value)
return false
}

190
http.go Normal file
View File

@ -0,0 +1,190 @@
// This is a simple example
package cloudflare
import (
"io/ioutil"
"net/http"
"bytes"
"go.wit.com/log"
)
/*
curl --request POST \
--url https://api.cloudflare.com/client/v4/zones/zone_identifier/dns_records \
--header 'Content-Type: application/json' \
--header 'X-Auth-Email: ' \
--data '{
"content": "198.51.100.4",
"name": "example.com",
"proxied": false,
"type": "A",
"comment": "Domain verification record",
"tags": [
"owner:dns-team"
],
"ttl": 3600
}'
*/
func doCurlDelete(auth string, email string, zoneId string, rrId string) string {
var err error
var req *http.Request
if zoneId == "" {
log.Warn("doCurlDelete() zoneId == nil")
return ""
}
if rrId == "" {
log.Warn("doCurlDelete() rrId == nil")
return ""
}
data := []byte("")
url := "https://api.cloudflare.com/client/v4/zones/" + zoneId + "/dns_records/" + rrId
req, err = http.NewRequest(http.MethodDelete, url, bytes.NewBuffer(data))
// Set headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Auth-Key", auth)
req.Header.Set("X-Auth-Email", email)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Println(err)
return ""
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(err)
return ""
}
return string(body)
}
func doCurlCreate(auth string, email string, zoneId string, data string) string {
var err error
var req *http.Request
if zoneId == "" {
log.Warn("doCurlDelete() zoneId == nil")
return ""
}
url := "https://api.cloudflare.com/client/v4/zones/" + zoneId + "/dns_records/"
log.Info("doCurlCreate() POST url =", url)
log.Info("doCurlCreate() POST Auth =", auth)
log.Info("doCurlCreate() POST Email =", email)
log.Info("doCurlCreate() POST data =", data)
req, err = http.NewRequest(http.MethodPost, url, bytes.NewBuffer( []byte(data) ))
// Set headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Auth-Key", auth)
req.Header.Set("X-Auth-Email", email)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Println(err)
return ""
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(err)
return ""
}
return string(body)
}
func doCurl(method string, rr *RRT) string {
var err error
var req *http.Request
data := []byte(rr.data)
if (method == "PUT") {
req, err = http.NewRequest(http.MethodPut, rr.url, bytes.NewBuffer(data))
} else {
req, err = http.NewRequest(http.MethodPost, rr.url, bytes.NewBuffer(data))
}
// Set headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Auth-Key", rr.Auth)
req.Header.Set("X-Auth-Email", rr.Email)
log.Println("http PUT url =", rr.url)
log.Println("http PUT Auth =", rr.Auth)
log.Println("http PUT Email =", rr.Email)
log.Println("http PUT data =", rr.data)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Println(err)
return ""
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(err)
return ""
}
return string(body)
}
func curlPost(dnsRow *RRT) string {
var authKey string = dnsRow.Auth
var email string = dnsRow.Email
url := dnsRow.url
tmp := dnsRow.data
log.Println("curlPost() START")
log.Println("curlPost() authkey = ", authKey)
log.Println("curlPost() email = ", email)
log.Println("curlPost() url = ", url)
data := []byte(tmp)
req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(data))
// Set headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Auth-Key", authKey)
req.Header.Set("X-Auth-Email", email)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Println(err)
return ""
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(err)
return ""
}
// log.Println("http PUT body =", body)
// spew.Dump(body)
log.Println("result =", string(body))
log.Println("curl() END")
pretty, _ := FormatJSON(string(body))
return pretty
}

25
json.go Normal file
View File

@ -0,0 +1,25 @@
// This is a simple example
package cloudflare
import (
"encoding/json"
)
// formatJSON takes an unformatted JSON string and returns a formatted version.
func FormatJSON(unformattedJSON string) (string, error) {
var jsonData interface{}
// Decode the JSON string into an interface
err := json.Unmarshal([]byte(unformattedJSON), &jsonData)
if err != nil {
return "", err
}
// Re-encode the JSON with indentation for formatting
formattedJSON, err := json.MarshalIndent(jsonData, "", " ")
if err != nil {
return "", err
}
return string(formattedJSON), nil
}

91
loadZoneWindow.go Normal file
View File

@ -0,0 +1,91 @@
// This is a simple example
package cloudflare
import (
"log"
"strconv"
"go.wit.com/gui/gui"
)
func LoadZoneWindow(n *gui.Node, c *ConfigT) {
hostname := c.Domain
zoneID := c.ZoneID
log.Println("adding DNS record", hostname)
newt := n.NewTab(hostname)
vb := newt.NewBox("vBox", false)
newg := vb.NewGroup("more zoneID = " + zoneID)
// make a grid 6 things wide
grid := newg.NewGrid("gridnuts", 6, 1)
// grid.NewButton("Type", func () {
// log.Println("sort by Type")
// })
grid.NewLabel("RR type")
grid.NewLabel("hostname")
grid.NewLabel("Proxy")
grid.NewLabel("TTL")
grid.NewLabel("Value")
grid.NewLabel("Save")
records := GetZonefile(c)
for _, record := range records.Result {
var rr RRT // dns zonefile resource record
// copy all the JSON values into the row record.
rr.ID = record.ID
rr.Type = record.Type
rr.Name = record.Name
rr.Content = record.Content
rr.Proxied = record.Proxied
rr.Proxiable = record.Proxiable
rr.ZoneID = zoneID
// rr.Ttl = record.TTL
rr.Domain = hostname
rr.ZoneID = zoneID
rr.Auth = c.Auth
rr.Email = c.Email
grid.NewLabel(record.Type)
grid.NewLabel(record.Name)
proxy := grid.NewLabel("proxy")
if (record.Proxied) {
proxy.SetText("On")
} else {
proxy.SetText("Off")
}
var ttl string
if (record.TTL == 1) {
ttl = "Auto"
} else {
ttl = strconv.Itoa(record.TTL)
}
grid.NewLabel(ttl)
val := grid.NewLabel("Value")
val.SetText(record.Content)
load := grid.NewButton("Load", nil)
load.Custom = func () {
name := "save stuff to cloudflare for " + rr.ID
log.Println(name)
/*
rr.Domain = domainWidget.S
rr.ZoneID = zoneWidget.S
rr.Auth = authWidget.S
rr.Email = emailWidget.S
*/
SetRow(&rr)
}
}
grid.Pad()
}

170
mainWindow.go Normal file
View File

@ -0,0 +1,170 @@
// This is a simple example
package cloudflare
import (
"os"
"log"
"go.wit.com/gui/gui"
"go.wit.com/gui/gadgets"
)
// This creates a window
func MakeCloudflareWindow(n *gui.Node) *gui.Node {
CFdialog.rootGui = n
var t *gui.Node
log.Println("buttonWindow() START")
CFdialog.mainWindow = n.NewWindow("Cloudflare Config")
// this tab has the master cloudflare API credentials
makeConfigWindow(CFdialog.mainWindow)
t = CFdialog.mainWindow.NewTab("Zones")
vb := t.NewBox("vBox", false)
g1 := vb.NewGroup("zones")
// make dropdown list of zones
CFdialog.zonedrop = g1.NewDropdown("zone")
CFdialog.zonedrop.AddText("example.org")
for d, _ := range Config {
CFdialog.zonedrop.AddText(d)
}
CFdialog.zonedrop.AddText("stablesid.org")
CFdialog.zonedrop.Custom = func () {
domain := CFdialog.zonedrop.S
log.Println("custom dropdown() zone (domain name) =", CFdialog.zonedrop.Name, domain)
if (Config[domain] == nil) {
log.Println("custom dropdown() Config[domain] = nil for domain =", domain)
CFdialog.domainWidget.SetText(domain)
CFdialog.zoneWidget.SetText("")
CFdialog.authWidget.SetText("")
CFdialog.emailWidget.SetText("")
} else {
log.Println("custom dropdown() a =", domain, Config[domain].ZoneID, Config[domain].Auth, Config[domain].Email)
CFdialog.domainWidget.SetText(Config[domain].Domain)
CFdialog.zoneWidget.SetText(Config[domain].ZoneID)
CFdialog.authWidget.SetText(Config[domain].Auth)
CFdialog.emailWidget.SetText(Config[domain].Email)
}
}
more := g1.NewGroup("data")
showCloudflareCredentials(more)
makeDebugWindow(CFdialog.mainWindow)
return CFdialog.mainWindow
}
func makeConfigWindow(n *gui.Node) {
t := n.NewTab("Get Zones")
vb := t.NewBox("vBox", false)
g1 := vb.NewGroup("Cloudflare API Config")
g1.NewLabel("If you have an API key with access to list all of /n your zone files, enter it here. \n \n Alternatively, you can set the enviroment variables: \n env $CF_API_KEY \n env $CF_API_EMAIL\n")
// make grid to display credentials
grid := g1.NewGrid("credsGrid", 2, 4) // width = 2
grid.NewLabel("Auth Key")
aw := grid.NewEntryLine("CF_API_KEY")
aw.SetText(os.Getenv("CF_API_KEY"))
grid.NewLabel("Email")
ew := grid.NewEntryLine("CF_API_EMAIL")
ew.SetText(os.Getenv("CF_API_EMAIL"))
var url string = "https://api.cloudflare.com/client/v4/zones/"
grid.NewLabel("Cloudflare API")
grid.NewLabel(url)
hostname := gadgets.NewBasicEntry(grid, "hostname")
zone := gadgets.NewBasicEntry(grid, "domain name")
grid.Pad()
vb.NewButton("Lookup Hostname", func () {
log.Println("Find all the Resource Records for hostname:", hostname.Get())
log.Println("Find all the Resource Records for zone:", zone.Get())
GetZones(aw.S, ew.S)
for d, v := range Config {
log.Println("Zone =", d, "v =", v)
}
})
vb.NewButton("getZones()", func () {
log.Println("getZones()")
GetZones(aw.S, ew.S)
for d, _ := range Config {
CFdialog.zonedrop.AddText(d)
}
})
vb.NewButton("cloudflare wit.com", func () {
CreateRR(CFdialog.rootGui, "wit.com", "3777302ac4a78cd7fa4f6d3f72086d06")
})
t.Pad()
t.Margin()
vb.Pad()
vb.Margin()
g1.Pad()
g1.Margin()
}
func makeDebugWindow(window *gui.Node) {
t2 := window.NewTab("debug")
g := t2.NewGroup("debug")
g.NewButton("Load 'gocui'", func () {
CFdialog.rootGui.LoadToolkit("gocui")
})
g.NewButton("Load 'andlabs'", func () {
CFdialog.rootGui.LoadToolkit("andlabs")
})
g.NewButton("gui.DebugWindow()", func () {
gui.DebugWindow()
})
g.NewButton("List all Widgets", func () {
CFdialog.rootGui.ListChildren(true)
})
g.NewButton("Dump all Widgets", func () {
CFdialog.rootGui.Dump()
})
}
func showCloudflareCredentials(box *gui.Node) {
// make grid to display credentials
grid := box.NewGrid("credsGrid", 2, 4) // width = 2
grid.NewLabel("Domain")
CFdialog.domainWidget = grid.NewEntryLine("CF_API_DOMAIN")
grid.NewLabel("Zone ID")
CFdialog.zoneWidget = grid.NewEntryLine("CF_API_ZONEID")
grid.NewLabel("Auth Key")
CFdialog.authWidget = grid.NewEntryLine("CF_API_KEY")
grid.NewLabel("Email")
CFdialog.emailWidget = grid.NewEntryLine("CF_API_EMAIL")
var url string = "https://api.cloudflare.com/client/v4/zones/"
grid.NewLabel("Cloudflare API")
grid.NewLabel(url)
grid.Pad()
CFdialog.loadButton = box.NewButton("Load Cloudflare DNS zonefile", func () {
var domain ConfigT
domain.Domain = CFdialog.domainWidget.S
domain.ZoneID = CFdialog.zoneWidget.S
domain.Auth = CFdialog.authWidget.S
domain.Email = CFdialog.emailWidget.S
LoadZoneWindow(CFdialog.mainWindow, &domain)
})
}

157
rr.go Normal file
View File

@ -0,0 +1,157 @@
/*
This will let you edit a single Resource Record within
a DNS zone file. For example:
google-dns.wit.com. 1 IN A 8.8.8.8
*/
package cloudflare
import (
"log"
"os"
"go.wit.com/gui/gui"
)
func init() {
Config = make(map[string]*ConfigT)
}
func CreateRR(myGui *gui.Node, zone string, zoneID string) {
if (CFdialog.cloudflareW != nil) {
// skip this if the window has already been created
log.Println("createRR() the cloudflare window already exists")
CFdialog.cloudflareB.Disable()
return
}
CFdialog.cloudflareW = myGui.NewWindow("cloudflare " + zone + " API")
CFdialog.cloudflareW.Custom = func () {
log.Println("createRR() don't really exit here")
CFdialog.cloudflareW = nil
CFdialog.cloudflareB.Enable()
}
group := CFdialog.cloudflareW.NewGroup("Create a new DNS Resource Record (rr)")
// make a grid 2 things wide
grid := group.NewGrid("gridnuts", 2, 3)
grid.NewLabel("zone")
CFdialog.zoneNode = grid.NewLabel("zone")
CFdialog.zoneNode.SetText(zone)
grid.NewLabel("zone ID")
CFdialog.zoneIdNode = grid.NewLabel("zoneID")
CFdialog.zoneIdNode.SetText(zoneID)
grid.NewLabel("shell env $CF_API_EMAIL")
CFdialog.emailNode = grid.NewLabel("type")
CFdialog.emailNode.SetText(os.Getenv("CF_API_EMAIL"))
grid.NewLabel("shell env $CF_API_KEY")
CFdialog.apiNode = grid.NewLabel("type")
CFdialog.apiNode.SetText(os.Getenv("CF_API_KEY"))
grid.NewLabel("Resource Record ID")
CFdialog.rrNode = grid.NewLabel("type")
CFdialog.rrNode.SetText(os.Getenv("cloudflare RR id"))
grid.NewLabel("Record Type")
CFdialog.TypeNode = grid.NewCombobox("type")
CFdialog.TypeNode.AddText("A")
CFdialog.TypeNode.AddText("AAAA")
CFdialog.TypeNode.AddText("CNAME")
CFdialog.TypeNode.AddText("TXT")
CFdialog.TypeNode.AddText("MX")
CFdialog.TypeNode.AddText("NS")
CFdialog.TypeNode.Custom = func () {
DoChange()
}
CFdialog.TypeNode.SetText("AAAA")
grid.NewLabel("Name (usually the hostname)")
CFdialog.NameNode = grid.NewCombobox("name")
CFdialog.NameNode.AddText("www")
CFdialog.NameNode.AddText("mail")
CFdialog.NameNode.AddText("git")
CFdialog.NameNode.AddText("go")
CFdialog.NameNode.AddText("blog")
CFdialog.NameNode.AddText("ns1")
CFdialog.NameNode.Custom = func () {
DoChange()
}
CFdialog.NameNode.SetText("www")
grid.NewLabel("Cloudflare Proxy")
CFdialog.proxyNode = grid.NewDropdown("proxy")
CFdialog.proxyNode.AddText("On")
CFdialog.proxyNode.AddText("Off")
CFdialog.proxyNode.Custom = func () {
DoChange()
}
CFdialog.proxyNode.SetText("Off")
grid.NewLabel("Value")
CFdialog.ValueNode = grid.NewCombobox("value")
CFdialog.ValueNode.AddText("127.0.0.1")
CFdialog.ValueNode.AddText("2001:4860:4860::8888")
CFdialog.ValueNode.AddText("ipv6.wit.com")
CFdialog.ValueNode.Custom = func () {
DoChange()
}
CFdialog.ValueNode.SetText("127.0.0.1")
CFdialog.ValueNode.Expand()
grid.NewLabel("URL")
CFdialog.urlNode = grid.NewLabel("URL")
group.NewLabel("curl")
CFdialog.curlNode = group.NewTextbox("curl")
CFdialog.curlNode.Custom = func () {
DoChange()
}
CFdialog.curlNode.SetText("put the curl text here")
CFdialog.resultNode = group.NewTextbox("result")
CFdialog.resultNode.SetText("API response will show here")
CFdialog.SaveNode = group.NewButton("Save curlPost()", func () {
dnsRow := DoChange()
result := curlPost(dnsRow)
CFdialog.resultNode.SetText(result)
// CreateCurlRR()
// url, data := CreateCurlRR()
// result := curl(url, data)
// CFdialog.resultNode.SetText(result)
})
// CFdialog.saveNode.Disable()
group.NewButton("New RR doCurl(PUT)", func () {
rr := DoChange()
rr.url = "https://api.cloudflare.com/client/v4/zones/" + rr.ZoneID + "/dns_records"
result := doCurl("POST", rr)
CFdialog.resultNode.SetText(result)
pretty, _ := FormatJSON(result)
log.Println(pretty)
})
group.NewButton("Update RR doCurl(PUT)", func () {
rr := DoChange()
rr.url = "https://api.cloudflare.com/client/v4/zones/" + rr.ZoneID + "/dns_records/" + rr.ID
result := doCurl("PUT", rr)
CFdialog.resultNode.SetText(result)
pretty, _ := FormatJSON(result)
log.Println(pretty)
})
// CFdialog.saveNode.Disable()
group.Pad()
grid.Pad()
grid.Expand()
}

105
structs.go Normal file
View File

@ -0,0 +1,105 @@
// This is a simple example
package cloudflare
import (
"go.wit.com/gui/gui"
)
var cloudflareURL string = "https://api.cloudflare.com/client/v4/zones/"
// Define a struct to match the JSON structure of the response.
// This structure should be adjusted based on the actual format of the response.
type DNSRecords struct {
Result []struct {
ID string `json:"id"`
Type string `json:"type"`
Name string `json:"name"`
Content string `json:"content"`
Proxied bool `json:"proxied"`
Proxiable bool `json:"proxiable"`
TTL int `json:"ttl"`
} `json:"result"`
}
// CFdialog is everything you need forcreating
// a new record: name, TTL, type (CNAME, A, etc)
var CFdialog dialogT
type dialogT struct {
rootGui *gui.Node // the root node
mainWindow *gui.Node // the window node
zonedrop *gui.Node // the drop down menu of zones
domainWidget *gui.Node
zoneWidget *gui.Node
authWidget *gui.Node
emailWidget *gui.Node
loadButton *gui.Node
saveButton *gui.Node
cloudflareW *gui.Node // the window node
cloudflareB *gui.Node // the cloudflare button
TypeNode *gui.Node // CNAME, A, AAAA, ...
NameNode *gui.Node // www, mail, ...
ValueNode *gui.Node // 4.2.2.2, "dkim stuff", etc
rrNode *gui.Node // cloudflare Resource Record ID
proxyNode *gui.Node // If cloudflare is a port 80 & 443 proxy
ttlNode *gui.Node // just set to 1 which means automatic to cloudflare
curlNode *gui.Node // shows you what you could run via curl
resultNode *gui.Node // what the cloudflare API returned
SaveNode *gui.Node // button to send it to cloudflare
zoneNode *gui.Node // "wit.com"
zoneIdNode *gui.Node // cloudflare zone ID
apiNode *gui.Node // cloudflare API key (from environment var CF_API_KEY)
emailNode *gui.Node // cloudflare email (from environment var CF_API_EMAIL)
urlNode *gui.Node // the URL to POST, PUT, DELETE, etc
}
// Resource Record (used in a DNS zonefile)
type RRT struct {
ID string
Type string
Name string
Content string
ProxyS string
Proxied bool
Proxiable bool
Ttl string
Domain string
ZoneID string
Auth string
Email string
url string
data string
}
/*
This is a structure of all the RR's (Resource Records)
in the DNS zonefiile for a hostname. For example:
For the host test.wit.com:
test.wit.com A 127.0.0.1
test.wit.com AAAA
test.wit.com TXT email test@wit.com
test.wit.com TXT phone 212-555-1212
test.wit.com CNAME real.wit.com
*/
type hostT struct {
hostname string
RRs []ConfigT
}
type ConfigT struct {
Domain string
ZoneID string
Auth string
Email string
}
var Config map[string]*ConfigT