diff options
Diffstat (limited to 'examples')
| -rwxr-xr-x | examples/buttons/buttons | bin | 6062120 -> 0 bytes | |||
| -rw-r--r-- | examples/cloudflare/Makefile | 3 | ||||
| -rw-r--r-- | examples/cloudflare/api.go | 187 | ||||
| -rw-r--r-- | examples/cloudflare/curl.sh | 3 | ||||
| -rw-r--r-- | examples/cloudflare/dns.go | 132 | ||||
| -rw-r--r-- | examples/cloudflare/gui.go | 122 | ||||
| -rw-r--r-- | examples/cloudflare/main.go | 186 | ||||
| -rw-r--r-- | examples/cloudflare/structs.go | 77 |
8 files changed, 559 insertions, 151 deletions
diff --git a/examples/buttons/buttons b/examples/buttons/buttons Binary files differdeleted file mode 100755 index 01ea9aa..0000000 --- a/examples/buttons/buttons +++ /dev/null diff --git a/examples/cloudflare/Makefile b/examples/cloudflare/Makefile index bcd88c6..fd82fdc 100644 --- a/examples/cloudflare/Makefile +++ b/examples/cloudflare/Makefile @@ -16,3 +16,6 @@ update: log: reset tail -f /tmp/witgui.* /tmp/guilogfile + +gocui: build + ./cloudflare -gui gocui >/tmp/witgui.log.stderr 2>&1 diff --git a/examples/cloudflare/api.go b/examples/cloudflare/api.go new file mode 100644 index 0000000..8cf550e --- /dev/null +++ b/examples/cloudflare/api.go @@ -0,0 +1,187 @@ +// This is a simple example +package main + +import ( + "os" + "log" + "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) + httpPut(dnsRow) + } + 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.org. + go.wit.com. 3600 IN A 1.1.1.9 + test.wit.com. 3600 IN NS ns1.wit.com. +*/ +func httpPut(dnsRow *RRT) { + var url string = cloudflareURL + os.Getenv("CLOUDFLARE_ZONEID") + "/dns_records/" + dnsRow.ID + var authKey string = os.Getenv("CLOUDFLARE_AUTHKEY") + var email string = os.Getenv("CLOUDFLARE_EMAIL") + + // make a json record to send on port 90 to cloudflare + var tmp string + tmp = `{"content": "` + dnsRow.valueNode.S + `", ` + tmp += `"name": "` + dnsRow.Name + `", ` + tmp += `"type": "` + dnsRow.Type + `", ` + tmp+= `"ttl": "` + strconv.Itoa(dnsRow.TTL) + `", ` + 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) + + 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 + } + 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) + + return +} + +// 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 +} diff --git a/examples/cloudflare/curl.sh b/examples/cloudflare/curl.sh new file mode 100644 index 0000000..ec8c014 --- /dev/null +++ b/examples/cloudflare/curl.sh @@ -0,0 +1,3 @@ +curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \ + -H "Authorization: Bearer AAAPutYourTokenInHereSoYouCanTestItL5Cl3" \ + -H "Content-Type:application/json" diff --git a/examples/cloudflare/dns.go b/examples/cloudflare/dns.go deleted file mode 100644 index eb8de23..0000000 --- a/examples/cloudflare/dns.go +++ /dev/null @@ -1,132 +0,0 @@ -// This is a simple example -package main - -import ( - "os" - "log" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "strconv" -) - -// 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"` -} - -// var domain string = "wit.org" -// var os.Getenv("CLOUDFLARE_DOMAIN") - -func loadDNS(hostname string) { - log.Println("adding DNS record") - - newt := mainWindow.NewTab(hostname) - newg := newt.NewGroup("more") - grid := newg.NewGrid("gridnuts", 5, gridH) - -// grid.NewButton("Type", func () { -// log.Println("sort by Type") -// }) - typedrop := grid.NewDropdown("type") - typedrop.AddText("A") - typedrop.AddText("AAAA") - typedrop.AddText("CNAME") - typedrop.Custom = func () { - log.Println("custom dropdown() a =", typedrop.Name, typedrop.S) - } - grid.NewButton("Name", func () { - log.Println("sort by Name") - }) - grid.NewButton("Protection", func () { - log.Println("sort proxied") - }) - grid.NewButton("TTL", func () { - log.Println("sort by TTL") - }) - grid.NewButton("Value", func () { - log.Println("sort by Value") - }) - - newt.NewButton("Save", func () { - log.Println("save stuff to cloudflare") - }) - - records := getRecords() - for _, record := range records.Result { - grid.NewLabel(record.Type) - textbox := grid.NewTextbox(record.Name) - textbox.SetText(record.Name) - if (record.Proxied) { - grid.NewLabel("Proxied") - } else { - grid.NewLabel("DNS") - } - var ttl, short string - if (record.TTL == 1) { - ttl = "Auto" - } else { - ttl = strconv.Itoa(record.TTL) - } - grid.NewLabel(ttl) - // short = fmt.Sprintf("%80s", record.Content) - short = record.Content - if len(short) > 40 { - short = short[:40] // Slice the first 20 characters - } - - namebox := grid.NewTextbox(short) - namebox.SetText(short) - - fmt.Printf("ID: %s, Type: %s, Name: %s, short Content: %s\n", record.ID, record.Type, record.Name, short) - fmt.Printf("\tproxied: %b, %b, string TTL: %i\n", record.Proxied, record.Proxiable, ttl) - } -} - -func getRecords() *DNSRecords { - var url string = os.Getenv("CLOUDFLARE_URL") - req, err := http.NewRequest("GET", url, nil) - if err != nil { - fmt.Println(err) - return nil - } - - var authKey string = os.Getenv("CLOUDFLARE_AUTHKEY") - var email string = os.Getenv("CLOUDFLARE_EMAIL") - - // Set headers - 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 { - fmt.Println(err) - return nil - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - fmt.Println(err) - return nil - } - - var records DNSRecords - if err := json.Unmarshal(body, &records); err != nil { - fmt.Println(err) - return nil - } - - return &records -} diff --git a/examples/cloudflare/gui.go b/examples/cloudflare/gui.go new file mode 100644 index 0000000..60fd5fe --- /dev/null +++ b/examples/cloudflare/gui.go @@ -0,0 +1,122 @@ +// This is a simple example +package main + +import ( + "log" + "strconv" +) + +func loadDNS(c *configT) { + hostname := c.domain + log.Println("adding DNS record", hostname) + + newt := mainWindow.NewTab(hostname) + newg := newt.NewGroup("more") + + // make a grid 6 things wide + grid := newg.NewGrid("gridnuts", 6, gridH) + +// grid.NewButton("Type", func () { +// log.Println("sort by Type") +// }) + typedrop := grid.NewDropdown("type") + typedrop.AddText("A") + typedrop.AddText("AAAA") + typedrop.AddText("CNAME") + typedrop.Custom = func () { + log.Println("custom dropdown() a =", typedrop.Name, typedrop.S) + } + nb := grid.NewButton("Name", func () { + log.Println("sort by Name") + }) + nb.Disable() + + grid.NewButton("Protection", func () { + log.Println("sort proxied") + }) + grid.NewButton("TTL", func () { + log.Println("sort by TTL") + }) + nb = grid.NewButton("Value", func () { + log.Println("sort by Value") + }) + nb.Disable() + nb = grid.NewButton("Save", func () { + log.Println("click below to save") + }) + nb.Disable() + + masterSave = newt.NewButton("Master Save", func () { + log.Println("save stuff to cloudflare") + }) + masterSave.Disable() + + 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.TTL = record.TTL + + rr.typeNode = grid.NewLabel(record.Type) + rr.nameNode = grid.NewEntryLine(record.Name) + rr.nameNode.SetText(record.Name) + rr.nameNode.Disable() + + // set proxy or unproxied + rr.proxyNode = grid.NewDropdown("proxy") + if (record.Proxied) { + rr.proxyNode.AddText("Proxied") + rr.proxyNode.AddText("DNS") + } else { + rr.proxyNode.AddText("DNS") + rr.proxyNode.AddText("Proxied") + } + rr.proxyNode.Custom = func () { + log.Println("proxy dropdown() a =", rr.proxyNode.Name, rr.proxyNode.S, rr.ID) + rr.saveNode.Enable() + masterSave.Enable() + } + + var ttl, short string + if (record.TTL == 1) { + ttl = "Auto" + } else { + ttl = strconv.Itoa(record.TTL) + } + rr.ttlNode = grid.NewLabel(ttl) + // short = fmt.Sprintf("%80s", record.Content) + short = record.Content + if len(short) > 40 { + short = short[:40] // Slice the first 20 characters + } + + rr.valueNode = grid.NewEntryLine(short) + rr.valueNode.SetText(record.Content) + + rr.valueNode.Custom = func () { + log.Println("value changed =", rr.valueNode.Name, rr.proxyNode.S, rr.ID) + rr.saveNode.Enable() + masterSave.Enable() + } + + // fmt.Printf("ID: %s, Type: %s, Name: %s, short Content: %s\n", record.ID, record.Type, record.Name, short) + // fmt.Printf("\tproxied: %b, %b, string TTL: %i\n", record.Proxied, record.Proxiable, ttl) + + rr.saveNode = grid.NewButton("Save", nil) + rr.saveNode.Disable() + rr.saveNode.Custom = func () { + name := "save stuff to cloudflare for " + rr.ID + log.Println(name) + doChange(&rr) + } + } + + grid.Pad() +} diff --git a/examples/cloudflare/main.go b/examples/cloudflare/main.go index b83d276..badf97a 100644 --- a/examples/cloudflare/main.go +++ b/examples/cloudflare/main.go @@ -5,11 +5,14 @@ import ( "os" "fmt" "log" + "bufio" + "strings" "git.wit.org/wit/gui" ) 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 @@ -19,8 +22,10 @@ var gridH int = 3 var mainWindow, more, more2 *gui.Node func main() { + config = make(map[string]*configT) + readConfig() myGui = gui.New().Default() - buttonWindow() + makeCloudflareWindow() // This is just a optional goroutine to watch that things are alive gui.Watchdog() @@ -28,30 +33,90 @@ func main() { } // This creates a window -func buttonWindow() { - var t, g *gui.Node +func makeCloudflareWindow() { + var t *gui.Node log.Println("buttonWindow() START") mainWindow = myGui.NewWindow(title).SetText(title) - t = mainWindow.NewTab("Cloudflare") - g = t.NewGroup("buttons") - g1 := t.NewGroup("buttonGroup 2") - more = g1.NewGroup("more") - showCloudflareCredentials(more) + // this tab has the master cloudflare API credentials + makeConfigTab(mainWindow) + + t = mainWindow.NewTab("Zones") + g1 := t.NewGroup("zones") - // more2 = g1.NewGrid("gridnuts", gridW, gridH) + // make dropdown list of zones + zonedrop = g1.NewDropdown("zone") + zonedrop.AddText("example.org") + for d, _ := range config { + zonedrop.AddText(d) + } - var domain string = os.Getenv("CLOUDFLARE_DOMAIN") - if (domain == "") { - domain = "example.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) + } } - g.NewButton("Load " + domain + " DNS", func () { - loadDNS(domain) + 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 $CLOUDFLARE_AUTHKEY \n env $CLOUDFLARE_EMAIL \n env $CLOUDFLARE_URL \n") + + // make grid to display credentials + grid := g1.NewGrid("credsGrid", 2, 4) // width = 2 + + grid.NewLabel("Auth Key") + aw := grid.NewEntryLine(os.Getenv("CLOUDFLARE_AUTHKEY")) + aw.SetText(os.Getenv("CLOUDFLARE_AUTHKEY")) + + grid.NewLabel("Email") + ew := grid.NewEntryLine(os.Getenv("CLOUDFLARE_EMAIL")) + ew.SetText(os.Getenv("CLOUDFLARE_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) }) + 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") @@ -65,20 +130,103 @@ func buttonWindow() { 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") - grid.NewLabel(os.Getenv("CLOUDFLARE_DOMAIN")) + domainWidget = grid.NewEntryLine(os.Getenv("CLOUDFLARE_DOMAIN")) + + grid.NewLabel("Zone ID") + zoneWidget = grid.NewEntryLine(os.Getenv("CLOUDFLARE_ZONEID")) grid.NewLabel("Auth Key") - grid.NewLabel(os.Getenv("CLOUDFLARE_AUTHKEY")) + authWidget = grid.NewEntryLine(os.Getenv("CLOUDFLARE_AUTHKEY")) grid.NewLabel("Email") - grid.NewLabel(os.Getenv("CLOUDFLARE_EMAIL")) + emailWidget = grid.NewEntryLine(os.Getenv("CLOUDFLARE_EMAIL")) + + var url string = "https://api.cloudflare.com/client/v4/zones/" + grid.NewLabel("Cloudflare API") + grid.NewLabel(url) + + grid.Pad() + + saveButton = box.NewButton("Save to config", func () { + }) + saveButton.Disable() + + 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) + + 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 *configT + newc = new(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] + + 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 + } - grid.NewLabel("URL") - grid.NewLabel(os.Getenv("CLOUDFLARE_URL")) + return nil } diff --git a/examples/cloudflare/structs.go b/examples/cloudflare/structs.go new file mode 100644 index 0000000..af4d7f3 --- /dev/null +++ b/examples/cloudflare/structs.go @@ -0,0 +1,77 @@ +// This is a simple example +package main + +import ( + "git.wit.org/wit/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"` +} + +var masterSave *gui.Node + +var domainWidget *gui.Node +var zoneWidget *gui.Node +var authWidget *gui.Node +var emailWidget *gui.Node + +var loadButton *gui.Node +var saveButton *gui.Node +var zonedrop *gui.Node + +// Resource Record (used in a DNS zonefile) +type RRT struct { + typeNode *gui.Node + nameNode *gui.Node + proxyNode *gui.Node + ttlNode *gui.Node + valueNode *gui.Node + saveNode *gui.Node + + ID string + Type string + Name string + Content string + Proxied bool + Proxiable bool + TTL int +} + +/* + 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 |
