diff options
| author | Jeff Carr <[email protected]> | 2024-01-01 15:31:33 -0600 | 
|---|---|---|
| committer | Jeff Carr <[email protected]> | 2024-01-01 15:31:33 -0600 | 
| commit | f1a0d18ac19d0db4f7060ea5a5c662348118e399 (patch) | |
| tree | f2e454da9c3ff512b6548ce741825261178a6a56 | |
initial commit of cloudflare api
Signed-off-by: Jeff Carr <[email protected]>
| -rw-r--r-- | api.go | 228 | ||||
| -rw-r--r-- | create.go | 57 | ||||
| -rwxr-xr-x | curl.sh | 23 | ||||
| -rw-r--r-- | delete.go | 64 | ||||
| -rw-r--r-- | http.go | 190 | ||||
| -rw-r--r-- | json.go | 25 | ||||
| -rw-r--r-- | loadZoneWindow.go | 91 | ||||
| -rw-r--r-- | mainWindow.go | 170 | ||||
| -rw-r--r-- | rr.go | 157 | ||||
| -rw-r--r-- | structs.go | 105 | 
10 files changed, 1110 insertions, 0 deletions
@@ -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 +} diff --git a/create.go b/create.go new file mode 100644 index 0000000..5d75b0c --- /dev/null +++ b/create.go @@ -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 +} @@ -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: [email protected]' \ +  --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" diff --git a/delete.go b/delete.go new file mode 100644 index 0000000..aa59105 --- /dev/null +++ b/delete.go @@ -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 +} @@ -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 +} @@ -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 +} diff --git a/loadZoneWindow.go b/loadZoneWindow.go new file mode 100644 index 0000000..56f65d8 --- /dev/null +++ b/loadZoneWindow.go @@ -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() +} diff --git a/mainWindow.go b/mainWindow.go new file mode 100644 index 0000000..3655600 --- /dev/null +++ b/mainWindow.go @@ -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) +	}) +} @@ -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() +} diff --git a/structs.go b/structs.go new file mode 100644 index 0000000..675cd5e --- /dev/null +++ b/structs.go @@ -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 [email protected] +	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  | 
