diff options
| -rw-r--r-- | cloudflare/api.go | 235 | ||||
| -rw-r--r-- | cloudflare/cloudflare.go | 123 | ||||
| -rw-r--r-- | cloudflare/http.go | 110 | ||||
| -rw-r--r-- | cloudflare/json.go | 2 | ||||
| -rw-r--r-- | cloudflare/loadZoneWindow.go (renamed from examples/cloudflare/gui.go) | 40 | ||||
| -rw-r--r-- | cloudflare/mainWindow.go | 156 | ||||
| -rw-r--r-- | cloudflare/structs.go (renamed from examples/cloudflare/structs.go) | 67 | ||||
| -rw-r--r-- | examples/cloudflare/api.go | 219 | ||||
| -rwxr-xr-x | examples/cloudflare/cloudflare | bin | 13104752 -> 0 bytes | |||
| -rw-r--r-- | examples/cloudflare/config.go | 71 | ||||
| -rw-r--r-- | examples/cloudflare/main.go | 240 |
11 files changed, 696 insertions, 567 deletions
diff --git a/cloudflare/api.go b/cloudflare/api.go new file mode 100644 index 0000000..1769f6b --- /dev/null +++ b/cloudflare/api.go @@ -0,0 +1,235 @@ +// This is a simple example +package cloudflare + +import ( + "log" + "encoding/json" + "io/ioutil" + "net/http" + + "github.com/davecgh/go-spew/spew" +) + +func DoChange() *RRT { + var dnsRow *RRT + dnsRow = new(RRT) + + log.Println("Look for changes in row", dnsRow.ID) + 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) + } + + return + log.Println("UPDATE VALUE", CFdialog.NameNode.Name, CFdialog.TypeNode.Name, "to", CFdialog.ValueNode.S) + stuff, result := httpPut(dnsRow) + if (CFdialog.curlNode != nil) { + pretty, _ := FormatJSON(stuff) + log.Println("http PUT curl =", pretty) + CFdialog.curlNode.SetText(pretty) + } + if (CFdialog.resultNode != nil) { + pretty, _ := FormatJSON(result) + log.Println("http PUT result =", pretty) + CFdialog.resultNode.SetText(pretty) + } + // CFdialog.saveNode.Disable() +} + +func GetZonefile(c *ConfigT) *DNSRecords { + var url = cloudflareURL + c.ZoneID + "/dns_records/" + 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" + 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/cloudflare/cloudflare.go b/cloudflare/cloudflare.go index f9452ce..db98c92 100644 --- a/cloudflare/cloudflare.go +++ b/cloudflare/cloudflare.go @@ -4,63 +4,12 @@ package cloudflare import ( "log" "os" - "bytes" - "io/ioutil" - "net/http" "go.wit.com/gui" ) -/* -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 -}' -*/ - -// CFdialog is everything you need forcreating -// a new record: name, TTL, type (CNAME, A, etc) -var CFdialog RRT - -// Resource Record (used in a DNS zonefile) -type RRT struct { - 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 - - 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) - - ID string - Type string - Name string - Content string - ProxyS string - Proxied bool - Proxiable bool - Ttl string +func init() { + Config = make(map[string]*ConfigT) } func CreateRR(myGui *gui.Node, zone string, zoneID string) { @@ -77,8 +26,6 @@ func CreateRR(myGui *gui.Node, zone string, zoneID string) { CFdialog.cloudflareB.Enable() } - CFdialog.ID = zoneID - group := CFdialog.cloudflareW.NewGroup("Create a new DNS Resource Record (rr)") // make a grid 2 things wide @@ -100,6 +47,10 @@ func CreateRR(myGui *gui.Node, zone string, zoneID string) { 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") @@ -109,7 +60,7 @@ func CreateRR(myGui *gui.Node, zone string, zoneID string) { CFdialog.TypeNode.AddText("MX") CFdialog.TypeNode.AddText("NS") CFdialog.TypeNode.Custom = func () { - CreateCurlRR() + DoChange() } CFdialog.TypeNode.SetText("AAAA") @@ -122,7 +73,7 @@ func CreateRR(myGui *gui.Node, zone string, zoneID string) { CFdialog.NameNode.AddText("blog") CFdialog.NameNode.AddText("ns1") CFdialog.NameNode.Custom = func () { - CreateCurlRR() + DoChange() } CFdialog.NameNode.SetText("www") @@ -131,7 +82,7 @@ func CreateRR(myGui *gui.Node, zone string, zoneID string) { CFdialog.proxyNode.AddText("On") CFdialog.proxyNode.AddText("Off") CFdialog.proxyNode.Custom = func () { - CreateCurlRR() + DoChange() } CFdialog.proxyNode.SetText("Off") @@ -141,15 +92,18 @@ func CreateRR(myGui *gui.Node, zone string, zoneID string) { CFdialog.ValueNode.AddText("2001:4860:4860::8888") CFdialog.ValueNode.AddText("ipv6.wit.com") CFdialog.ValueNode.Custom = func () { - CreateCurlRR() + 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 () { - CreateCurlRR() + DoChange() } CFdialog.curlNode.SetText("put the curl text here") @@ -157,17 +111,22 @@ func CreateRR(myGui *gui.Node, zone string, zoneID string) { CFdialog.resultNode.SetText("API response will show here") CFdialog.saveNode = group.NewButton("Save", func () { - url, data := CreateCurlRR() - result := curl(url, data) + dnsRow := DoChange() + result := curlPost(dnsRow) CFdialog.resultNode.SetText(result) + // CreateCurlRR() + // url, data := CreateCurlRR() + // result := curl(url, data) + // CFdialog.resultNode.SetText(result) }) - CFdialog.saveNode.Disable() + // CFdialog.saveNode.Disable() group.Pad() grid.Pad() grid.Expand() } +/* func CreateCurlRR() (string, string) { // enable the Save/Create Button if (CFdialog.saveNode != nil) { @@ -211,7 +170,7 @@ func CreateCurlRR() (string, string) { log.Println("http PUT url =", url) // log.Println("http PUT data =", data) // spew.Dump(data) - pretty, _ := formatJSON(string(data)) + pretty, _ := FormatJSON(string(data)) log.Println("http URL =", url) log.Println("http PUT data =", pretty) if (CFdialog.curlNode != nil) { @@ -220,38 +179,4 @@ func CreateCurlRR() (string, string) { return url, tmp } - -func curl(url string, tmp string) string { - var authKey string = CFdialog.apiNode.S - var email string = CFdialog.emailNode.S - - log.Println("curl() START") - 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 -} +*/ diff --git a/cloudflare/http.go b/cloudflare/http.go new file mode 100644 index 0000000..f258f61 --- /dev/null +++ b/cloudflare/http.go @@ -0,0 +1,110 @@ +// This is a simple example +package cloudflare + +import ( + "log" + "fmt" + "io/ioutil" + "net/http" + "bytes" +) + +/* +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 httpPut(dnsRow *RRT) (string, string) { + var url string = cloudflareURL + dnsRow.ZoneID + "/dns_records/" + dnsRow.ID + var authKey string = dnsRow.Auth + var email string = dnsRow.Email + + var tmp string + tmp = makeJSON(dnsRow) + data := []byte(tmp) + + log.Println("http PUT url =", url) + // log.Println("http PUT data =", data) + // spew.Dump(data) + pretty, _ := FormatJSON(string(data)) + log.Println("http PUT data =", pretty) + + req, err := http.NewRequest(http.MethodPut, 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 tmp, fmt.Sprintf("blah err =", err) + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Println(err) + return tmp, fmt.Sprintf("blah err =", err) + } + // log.Println("http PUT body =", body) + // spew.Dump(body) + + return tmp, 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("curl() START") + log.Println("curl() authkey = ", authKey) + log.Println("curl() email = ", email) + log.Println("curl() 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 +} diff --git a/cloudflare/json.go b/cloudflare/json.go index f91b724..b7c71a8 100644 --- a/cloudflare/json.go +++ b/cloudflare/json.go @@ -6,7 +6,7 @@ import ( ) // formatJSON takes an unformatted JSON string and returns a formatted version. -func formatJSON(unformattedJSON string) (string, error) { +func FormatJSON(unformattedJSON string) (string, error) { var jsonData interface{} // Decode the JSON string into an interface diff --git a/examples/cloudflare/gui.go b/cloudflare/loadZoneWindow.go index 587a9bc..71fc2d3 100644 --- a/examples/cloudflare/gui.go +++ b/cloudflare/loadZoneWindow.go @@ -1,23 +1,24 @@ // This is a simple example -package main +package cloudflare import ( "log" "strconv" - "go.wit.com/control-panel-dns/cloudflare" + "go.wit.com/gui" ) -func loadDNS(c *configT) { - hostname := c.domain +func LoadZoneWindow(n *gui.Node, c *ConfigT) { + hostname := c.Domain + zoneID := c.ZoneID log.Println("adding DNS record", hostname) - newt := mainWindow.NewTab(hostname) + newt := n.NewTab(hostname) vb := newt.NewBox("vBox", false) - newg := vb.NewGroup("more zoneID = " + c.zoneID) + newg := vb.NewGroup("more zoneID = " + zoneID) // make a grid 6 things wide - grid := newg.NewGrid("gridnuts", 6, gridH) + grid := newg.NewGrid("gridnuts", 6, 1) // grid.NewButton("Type", func () { // log.Println("sort by Type") @@ -30,14 +31,9 @@ func loadDNS(c *configT) { grid.NewLabel("Value") grid.NewLabel("Save") - masterSave = vb.NewButton("Master Save", func () { - log.Println("save stuff to cloudflare") - }) - masterSave.Disable() - - records := getZonefile(c) + records := GetZonefile(c) for _, record := range records.Result { - var rr cloudflare.RRT // dns zonefile resource record + var rr RRT // dns zonefile resource record // copy all the JSON values into the row record. rr.ID = record.ID @@ -46,8 +42,14 @@ func loadDNS(c *configT) { 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) @@ -73,7 +75,15 @@ func loadDNS(c *configT) { load.Custom = func () { name := "save stuff to cloudflare for " + rr.ID log.Println(name) - // doChange(&rr) + + /* + rr.Domain = domainWidget.S + rr.ZoneID = zoneWidget.S + rr.Auth = authWidget.S + rr.Email = emailWidget.S + */ + + SetRow(&rr) } } diff --git a/cloudflare/mainWindow.go b/cloudflare/mainWindow.go new file mode 100644 index 0000000..dddb0b7 --- /dev/null +++ b/cloudflare/mainWindow.go @@ -0,0 +1,156 @@ +// This is a simple example +package cloudflare + +import ( + "os" + "log" + + "go.wit.com/gui" +) + +// This creates a window +func MakeCloudflareWindow(n *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) +} + +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) + + grid.Pad() + + 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) + }) +} diff --git a/examples/cloudflare/structs.go b/cloudflare/structs.go index fa5516b..f0a23d8 100644 --- a/examples/cloudflare/structs.go +++ b/cloudflare/structs.go @@ -1,5 +1,5 @@ // This is a simple example -package main +package cloudflare import ( "go.wit.com/gui" @@ -21,28 +21,46 @@ type DNSRecords struct { } `json:"result"` } -var masterSave *gui.Node +// CFdialog is everything you need forcreating +// a new record: name, TTL, type (CNAME, A, etc) +var CFdialog dialogT -var domainWidget *gui.Node -var zoneWidget *gui.Node -var authWidget *gui.Node -var emailWidget *gui.Node +type dialogT struct { + rootGui *gui.Node // the root node + mainWindow *gui.Node // the window node + zonedrop *gui.Node // the drop down menu of zones -var loadButton *gui.Node -var saveButton *gui.Node -var zonedrop *gui.Node + domainWidget *gui.Node + zoneWidget *gui.Node + authWidget *gui.Node + emailWidget *gui.Node -// Resource Record (used in a DNS zonefile) -type RRT struct { - typeNode *gui.Node // CNAME, A, AAAA, ... - nameNode *gui.Node // www, mail, ... + 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 - valueNode *gui.Node // 4.2.2.2, "dkim stuff", etc 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 @@ -51,6 +69,13 @@ type RRT struct { Proxied bool Proxiable bool Ttl string + + Domain string + ZoneID string + Auth string + Email string + url string + data string } /* @@ -67,14 +92,14 @@ type RRT struct { */ type hostT struct { hostname string - RRs []configT + RRs []ConfigT } -type configT struct { - domain string - zoneID string - auth string - email string +type ConfigT struct { + Domain string + ZoneID string + Auth string + Email string } -var config map[string]*configT +var Config map[string]*ConfigT diff --git a/examples/cloudflare/api.go b/examples/cloudflare/api.go deleted file mode 100644 index c65fbde..0000000 --- a/examples/cloudflare/api.go +++ /dev/null @@ -1,219 +0,0 @@ -// This is a simple example -package main - -import ( - "os" - "log" - "fmt" - "encoding/json" - "io/ioutil" - "net/http" -// "strconv" - "bytes" - - "github.com/davecgh/go-spew/spew" -) - -func doChange(dnsRow *RRT) { - log.Println("Look for changes in row", dnsRow.ID) - log.Println("Proxy", dnsRow.Proxied, "vs", dnsRow.proxyNode.S) - log.Println("Content", dnsRow.Content, "vs", dnsRow.valueNode.S) - if (dnsRow.Content != dnsRow.valueNode.S) { - log.Println("UPDATE VALUE", dnsRow.nameNode.Name, dnsRow.typeNode.Name, "to", dnsRow.valueNode.S) - stuff, result := httpPut(dnsRow) - if (dnsRow.curlNode != nil) { - pretty, _ := formatJSON(stuff) - log.Println("http PUT curl =", pretty) - dnsRow.curlNode.SetText(pretty) - } - if (dnsRow.resultNode != nil) { - pretty, _ := formatJSON(result) - log.Println("http PUT result =", pretty) - dnsRow.resultNode.SetText(pretty) - } - } - dnsRow.saveNode.Disable() -} - -func getZonefile(c *configT) *DNSRecords { - var url = cloudflareURL + c.zoneID + "/dns_records/" - 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 httpPut(dnsRow *RRT) (string, string) { - var url string = cloudflareURL + os.Getenv("CF_API_ZONEID") + "/dns_records/" + dnsRow.ID - var authKey string = os.Getenv("CF_API_KEY") - var email string = os.Getenv("CF_API_EMAIL") - - // make a json record to send on port 80 to cloudflare - var tmp string - tmp = `{"content": "` + dnsRow.valueNode.S + `", ` - tmp += `"name": "` + dnsRow.Name + `", ` - tmp += `"type": "` + dnsRow.Type + `", ` - tmp+= `"ttl": "` + "1" + `", ` - tmp += `"comment": "WIT DNS Control Panel"` - tmp += `}` - data := []byte(tmp) - - log.Println("http PUT url =", url) - // log.Println("http PUT data =", data) - // spew.Dump(data) - pretty, _ := formatJSON(string(data)) - log.Println("http PUT data =", pretty) - - req, err := http.NewRequest(http.MethodPut, 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 tmp, fmt.Sprintf("blah err =", err) - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.Println(err) - return tmp, fmt.Sprintf("blah err =", err) - } - // log.Println("http PUT body =", body) - // spew.Dump(body) - - return tmp, string(body) -} - -// https://api.cloudflare.com/client/v4/zones -func getZones(auth, email string) *DNSRecords { - var url = "https://api.cloudflare.com/client/v4/zones" - 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 - zonedrop.AddText(record.Name) - log.Println("zonedrop.AddText:", record.Name, record.ID) - } - for d, _ := range config { - log.Println("config entry:", d) - } - - return &records -} - -// 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/examples/cloudflare/cloudflare b/examples/cloudflare/cloudflare Binary files differdeleted file mode 100755 index 8efdd89..0000000 --- a/examples/cloudflare/cloudflare +++ /dev/null diff --git a/examples/cloudflare/config.go b/examples/cloudflare/config.go new file mode 100644 index 0000000..a65ad25 --- /dev/null +++ b/examples/cloudflare/config.go @@ -0,0 +1,71 @@ +// This is a simple example +package main + +import ( + "os" + "log" + "bufio" + "strings" + + "go.wit.com/control-panel-dns/cloudflare" +) + +func saveConfig() { + log.Println("TODO") +} + +func readConfig() { + homeDir, err := os.UserHomeDir() + if err != nil { + log.Println("searchPaths() error. exiting here?") + } + filename := homeDir + "/" + configfile + log.Println("filename =", filename) + + readFileLineByLine(filename) + // os.Exit(0) +} + +// readFileLineByLine opens a file and reads through each line. +func readFileLineByLine(filename string) error { + // Open the file. + file, err := os.Open(filename) + if err != nil { + return err + } + defer file.Close() + + log.Println("readFileLineByLine() =", filename) + + // Create a new Scanner for the file. + scanner := bufio.NewScanner(file) + + // Read through each line using scanner. + for scanner.Scan() { + var newc *cloudflare.ConfigT + newc = new(cloudflare.ConfigT) + + line := scanner.Text() + parts := strings.Fields(line) + + if (len(parts) < 4) { + log.Println("readFileLineByLine() SKIP =", parts) + continue + } + + newc.Domain = parts[0] + newc.ZoneID = parts[1] + newc.Auth = parts[2] + newc.Email = parts[3] + + cloudflare.Config[parts[0]] = newc + log.Println("readFileLineByLine() =", newc.Domain, newc.ZoneID, newc.Auth, newc.Email) + } + + // Check for errors during Scan. + if err := scanner.Err(); err != nil { + return err + } + + return nil +} diff --git a/examples/cloudflare/main.go b/examples/cloudflare/main.go index 64dabc5..2308478 100644 --- a/examples/cloudflare/main.go +++ b/examples/cloudflare/main.go @@ -2,12 +2,6 @@ package main import ( - "os" - "fmt" - "log" - "bufio" - "strings" - "go.wit.com/gui" "go.wit.com/control-panel-dns/cloudflare" ) @@ -15,222 +9,44 @@ import ( var title string = "Cloudflare DNS Control Panel" var outfile string = "/tmp/guilogfile" var configfile string = ".config/wit/cloudflare" -var myGui *gui.Node - -var buttonCounter int = 5 -var gridW int = 5 -var gridH int = 3 - -var mainWindow, more, more2 *gui.Node - -func main() { - config = make(map[string]*configT) - readConfig() - myGui = gui.New().Default() - makeCloudflareWindow() - - // This is just a optional goroutine to watch that things are alive - gui.Watchdog() - gui.StandardExit() -} - -// This creates a window -func makeCloudflareWindow() { - var t *gui.Node - - log.Println("buttonWindow() START") - - mainWindow = myGui.NewWindow(title).SetText(title) - - // this tab has the master cloudflare API credentials - makeConfigTab(mainWindow) - - t = mainWindow.NewTab("Zones") - vb := t.NewBox("vBox", false) - g1 := vb.NewGroup("zones") - - // make dropdown list of zones - zonedrop = g1.NewDropdown("zone") - zonedrop.AddText("example.org") - for d, _ := range config { - zonedrop.AddText(d) - } - zonedrop.AddText("stablesid.org") - - zonedrop.Custom = func () { - domain := zonedrop.S - log.Println("custom dropdown() zone (domain name) =", zonedrop.Name, domain) - if (config[domain] == nil) { - log.Println("custom dropdown() config[domain] = nil for domain =", domain) - domainWidget.SetText(domain) - zoneWidget.SetText("") - authWidget.SetText("") - emailWidget.SetText("") - } else { - log.Println("custom dropdown() a =", domain, config[domain].zoneID, config[domain].auth, config[domain].email) - domainWidget.SetText(config[domain].domain) - zoneWidget.SetText(config[domain].zoneID) - authWidget.SetText(config[domain].auth) - emailWidget.SetText(config[domain].email) - } - } - - more = g1.NewGroup("data") - showCloudflareCredentials(more) - - makeDebugTab(mainWindow) -} - -func makeConfigTab(window *gui.Node) { - t := window.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) - - grid.Pad() - - vb.NewButton("getZones()", func () { - log.Println("getZones()") - getZones(aw.S, ew.S) - }) - - vb.NewButton("cloudflare wit.com", func () { - cloudflare.CreateRR(myGui, "wit.com", "3777302ac4a78cd7fa4f6d3f72086d06") - }) - - t.Pad() - t.Margin() - vb.Pad() - vb.Margin() - g1.Pad() - g1.Margin() -} - -func makeDebugTab(window *gui.Node) { - t2 := window.NewTab("debug") - g := t2.NewGroup("debug") - g.NewButton("Load 'gocui'", func () { - // this set the xterm and mate-terminal window title. maybe works generally? - fmt.Println("\033]0;" + title + "blah \007") - myGui.LoadToolkit("gocui") - }) - - g.NewButton("Load 'andlabs'", func () { - myGui.LoadToolkit("andlabs") - }) - - g.NewButton("gui.DebugWindow()", func () { - gui.DebugWindow() - }) - - g.NewButton("List all Widgets", func () { - myGui.ListChildren(true) - }) - g.NewButton("Dump all Widgets", func () { - myGui.Dump() - }) -} - -func showCloudflareCredentials(box *gui.Node) { - // make grid to display credentials - grid := box.NewGrid("credsGrid", 2, 4) // width = 2 - - grid.NewLabel("Domain") - domainWidget = grid.NewEntryLine("CF_API_DOMAIN") - - grid.NewLabel("Zone ID") - zoneWidget = grid.NewEntryLine("CF_API_ZONEID") - - grid.NewLabel("Auth Key") - authWidget = grid.NewEntryLine("CF_API_KEY") - - grid.NewLabel("Email") - 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() - - loadButton = box.NewButton("Load Cloudflare DNS zonefile", func () { - var domain configT - domain.domain = domainWidget.S - domain.zoneID = zoneWidget.S - domain.auth = authWidget.S - domain.email = emailWidget.S - loadDNS(&domain) - }) -} - -func readConfig() { - homeDir, err := os.UserHomeDir() - if err != nil { - log.Println("searchPaths() error. exiting here?") - } - filename := homeDir + "/" + configfile - log.Println("filename =", filename) +var myGui *gui.Node - readFileLineByLine(filename) - // os.Exit(0) -} +// var buttonCounter int = 5 +// var gridW int = 5 +// var gridH int = 3 -// readFileLineByLine opens a file and reads through each line. -func readFileLineByLine(filename string) error { - // Open the file. - file, err := os.Open(filename) - if err != nil { - return err - } - defer file.Close() +// var mainWindow, more, more2 *gui.Node - log.Println("readFileLineByLine() =", filename) +// var cloudflareURL string = "https://api.cloudflare.com/client/v4/zones/" - // Create a new Scanner for the file. - scanner := bufio.NewScanner(file) +/* +var zonedrop *gui.Node +var domainWidget *gui.Node +var masterSave *gui.Node - // Read through each line using scanner. - for scanner.Scan() { - var newc *configT - newc = new(configT) +var zoneWidget *gui.Node +var authWidget *gui.Node +var emailWidget *gui.Node - line := scanner.Text() - parts := strings.Fields(line) +var loadButton *gui.Node +var saveButton *gui.Node +*/ - if (len(parts) < 4) { - log.Println("readFileLineByLine() SKIP =", parts) - continue - } +func main() { + // parse the config file + readConfig() - newc.domain = parts[0] - newc.zoneID = parts[1] - newc.auth = parts[2] - newc.email = parts[3] + // initialize a new GO GUI instance + myGui = gui.New().Default() - config[parts[0]] = newc - log.Println("readFileLineByLine() =", newc.domain, newc.zoneID, newc.auth, newc.email) - } + // draw the cloudflare control panel window + cloudflare.MakeCloudflareWindow(myGui) - // Check for errors during Scan. - if err := scanner.Err(); err != nil { - return err - } + // This is just a optional goroutine to watch that things are alive + gui.Watchdog() + gui.StandardExit() - return nil + // update the config file + saveConfig() } |
