From 6fec144dab6176e76033da9917868fd0208a6936 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sat, 19 Oct 2019 13:51:24 +0200 Subject: [PATCH] Cloudflare DDNS bee Updates a Cloudflare domain name record with the given IP. --- assets/bees/cfddns.png | Bin 0 -> 1068 bytes bees/cfddns/README.md | 19 ++++++ bees/cfddns/cfddnsbee.go | 93 ++++++++++++++++++++++++++ bees/cfddns/cfddnsbeefactory.go | 115 ++++++++++++++++++++++++++++++++ go.mod | 6 +- go.sum | 13 ++++ hives.go | 1 + 7 files changed, 242 insertions(+), 5 deletions(-) create mode 100644 assets/bees/cfddns.png create mode 100644 bees/cfddns/README.md create mode 100644 bees/cfddns/cfddnsbee.go create mode 100644 bees/cfddns/cfddnsbeefactory.go diff --git a/assets/bees/cfddns.png b/assets/bees/cfddns.png new file mode 100644 index 0000000000000000000000000000000000000000..6ab9dd44b92720580ab614423b87a17486a187bf GIT binary patch literal 1068 zcmV+{1k?M8P) zf*<>?K>Xmx{_D^9p;!9BkN)@Z_KGd}v2**-tNg-n{_o@a$es3*JOBFg_nJxl%!vKx z)%dAp{nw!RxqYGB{oJd;1Ql}t00V?c zL_t(|obB4_a)K}v1z-s%3MfTzuWjG|DVyMeEW%C5f-~p)@0c@5ZZ>8!0000000000 z0000000000000000000Ow)Kw-VeR{_o1!d z)v8X@EX7-iVfCg2H zFrjn%@{ad28~_2jU+p;z7Dk}U1z&{3UwSQ}f0 zb66W&M#q(4t8R@ra1hzau`r&)&f>0qk|pDF|!K{ zmi<&OG1pnmzDTv_NQ~zYyT%J^%5+CDy@v3Goo_&YT0z*M&>O^j%@X%?`*sk0)%DrJHM)me~8c3ozxQ^yeAf@W%?K}|Vpj3k`bw}-+fuSx@*g%eX5|pv4eZ`Ru zB$4kDOF3E}JEhnDB+|3QLXO83ctenN?&a@Jk~ygJW8Si8Tl;POpPhXNL2xOG;wO&d z#$c0MONj3TODkU~)%W&)GC!r>{MfmNsvm!)7DaO5T{Z_+-Z8SGj*&Ic06wyUKR&cF zKD3%MMk0rW3lna$>WY(|d*?bA80e6(^5z`-&JO)4m`nk-(;=m=`fAv58PrB!+%4RV zR!Ls|HyG{>;Yto-X>W2t66tvDehz$B3X0000. + * + * Authors: + * Sergio Rubio + */ + +package cfddns + +import ( + "regexp" + + "github.com/cloudflare/cloudflare-go" + "github.com/muesli/beehive/bees" +) + +var domainSplitter = regexp.MustCompile(".+\\.(.+\\..+)") + +// CFDDNSBee updates a Cloudflare domain name +type CFDDNSBee struct { + bees.Bee + client *cloudflare.API + domain string +} + +// Run executes the Bee's event loop. +func (mod *CFDDNSBee) Run(eventChan chan bees.Event) { +} + +// Action triggers the action passed to it. +func (mod *CFDDNSBee) Action(action bees.Action) []bees.Placeholder { + outs := []bees.Placeholder{} + + switch action.Name { + case "update_domain": + address := action.Options.Value("address").(string) + domain := mod.domain + zoneName := domainSplitter.FindStringSubmatch(domain)[1] + // Resolve the zone and record id for the host + zone, err := mod.client.ZoneIDByName(zoneName) + if err != nil { + mod.LogErrorf("zone id resolution failed: %v", err) + return outs + } + recs, err := mod.client.DNSRecords(zone, cloudflare.DNSRecord{Name: domain, Type: "A"}) + if err != nil { + mod.LogErrorf("record id resolution failed: %v", err) + return outs + } + if len(recs) != 1 { + mod.LogErrorf("invalid number of DNS records found: %+v", recs) + return outs + } + record := recs[0] + + // Post the Cloudflare dns update + record.Content = address + + if err := mod.client.UpdateDNSRecord(zone, record.ID, record); err != nil { + mod.LogErrorf("dns record update for %s failed: %v", domain, err) + } + default: + mod.LogDebugf("Unknown action triggered in %s: %s", mod.Name(), action.Name) + } + + return outs +} + +// ReloadOptions parses the config options and initializes the Bee. +func (mod *CFDDNSBee) ReloadOptions(options bees.BeeOptions) { + mod.SetOptions(options) + key := options.Value("key").(string) + user := options.Value("email").(string) + mod.domain = options.Value("domain").(string) + c, err := cloudflare.New(key, user) + if err != nil { + mod.LogFatal(err) + } + mod.client = c +} diff --git a/bees/cfddns/cfddnsbeefactory.go b/bees/cfddns/cfddnsbeefactory.go new file mode 100644 index 00000000..4dc65a40 --- /dev/null +++ b/bees/cfddns/cfddnsbeefactory.go @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2019 Sergio Rubio + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * Sergio Rubio + */ + +package cfddns + +import ( + "github.com/muesli/beehive/bees" +) + +// CFDDNSBeeFactory takes care of initializing CFDDNSBee +type CFDDNSBeeFactory struct { + bees.BeeFactory +} + +// New returns a new Bee instance configured with the supplied options. +func (factory *CFDDNSBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface { + bee := CFDDNSBee{ + Bee: bees.NewBee(name, factory.ID(), description, options), + } + bee.ReloadOptions(options) + + return &bee +} + +// ID returns the ID of this Bee. +func (factory *CFDDNSBeeFactory) ID() string { + return "cfddns" +} + +// Name returns the name of this Bee. +func (factory *CFDDNSBeeFactory) Name() string { + return "cfddns" +} + +// Description returns the description of this Bee. +func (factory *CFDDNSBeeFactory) Description() string { + return "Updates the IP address of a Cloudflare domain name" +} + +// Image returns the asset name of this Bee (in the assets/bees folder) +func (factory *CFDDNSBeeFactory) Image() string { + return factory.Name() + ".png" +} + +// Events describes the available events provided by this Bee. +func (factory *CFDDNSBeeFactory) Events() []bees.EventDescriptor { + return []bees.EventDescriptor{} +} + +// Actions describes the available actions provided by this Bee. +func (factory *CFDDNSBeeFactory) Actions() []bees.ActionDescriptor { + actions := []bees.ActionDescriptor{ + { + Namespace: factory.Name(), + Name: "update_domain", + Description: "Updates the DNS name", + Options: []bees.PlaceholderDescriptor{ + { + Name: "address", + Description: "IP addresss", + Type: "string", + Mandatory: true, + }, + }, + }, + } + return actions +} + +// Options returns the options available to configure this Bee. +func (factory *CFDDNSBeeFactory) Options() []bees.BeeOptionDescriptor { + opts := []bees.BeeOptionDescriptor{ + { + Name: "email", + Description: "CF API user email", + Type: "string", + Mandatory: true, + }, + { + Name: "key", + Description: "CF API Key", + Type: "string", + Mandatory: true, + }, + { + Name: "domain", + Description: "CF domain to update", + Type: "string", + Mandatory: true, + }, + } + return opts +} + +func init() { + f := CFDDNSBeeFactory{} + bees.RegisterFactory(&f) +} diff --git a/go.mod b/go.mod index f18df898..197a33a0 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/briandowns/openweathermap v0.0.0-20180804155945-5f41b7c9d92d github.com/bwmarrin/discordgo v0.19.0 github.com/carlosdp/twiliogo v0.0.0-20161027183705-b26045ebb9d1 + github.com/cloudflare/cloudflare-go v0.10.6 github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect @@ -51,7 +52,6 @@ require ( github.com/mattn/go-colorable v0.1.1 github.com/mattn/go-isatty v0.0.7 // indirect github.com/mattn/go-mastodon v0.0.3 - github.com/mattn/go-runewidth v0.0.4 // indirect github.com/mattn/go-xmpp v0.0.0-20190124093244-6093f50721ed github.com/minio/minio-go v6.0.14+incompatible github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -67,8 +67,6 @@ require ( github.com/nlopes/slack v0.6.0 github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7 - github.com/olekukonko/tablewriter v0.0.1 // indirect - github.com/pkg/errors v0.8.1 // indirect github.com/prometheus/client_golang v0.9.2 github.com/rdegges/go-ipify v0.0.0-20150526035502-2d94a6a86c40 github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4 // indirect @@ -84,7 +82,6 @@ require ( github.com/technoweenie/multipartstreamer v1.0.1 // indirect github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 // indirect - golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 // indirect golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872 // indirect golang.org/x/text v0.3.2 // indirect @@ -94,6 +91,5 @@ require ( gopkg.in/ini.v1 v1.42.0 // indirect gopkg.in/mail.v2 v2.3.1 // indirect gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect - gopkg.in/yaml.v2 v2.2.2 // indirect layeh.com/gumble v0.0.0-20180508205105-1ea1159c4956 ) diff --git a/go.sum b/go.sum index ed290309..44a340c2 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/ChimeraCoder/anaconda v2.0.0+incompatible h1:F0eD7CHXieZ+VLboCD5UAqCeAzJZxcr90zSCcuJopJs= github.com/ChimeraCoder/anaconda v2.0.0+incompatible/go.mod h1:TCt3MijIq3Qqo9SBtuW/rrM4x7rDfWqYWHj8T7hLcLg= github.com/ChimeraCoder/tokenbucket v0.0.0-20131201223612-c5a927568de7 h1:r+EmXjfPosKO4wfiMLe1XQictsIlhErTufbWUsjOTZs= @@ -29,6 +30,9 @@ github.com/bwmarrin/discordgo v0.19.0 h1:kMED/DB0NR1QhRcalb85w0Cu3Ep2OrGAqZH1R5a github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= github.com/carlosdp/twiliogo v0.0.0-20161027183705-b26045ebb9d1 h1:hXakhQtPnXH839q1pBl/GqfTSchqE+R5Fqn98Iu7UQM= github.com/carlosdp/twiliogo v0.0.0-20161027183705-b26045ebb9d1/go.mod h1:pAxCBpjl/0JxYZlWGP/Dyi8f/LQSCQD2WAsG/iNzqQ8= +github.com/cloudflare/cloudflare-go v0.10.6 h1:mbv0IrcrrLlPLxAzCdW6aQ/CPlqhyXrXTjviU0Tb+34= +github.com/cloudflare/cloudflare-go v0.10.6/go.mod h1:dcRl7AXBH5Bf7QFTBVc3TRzwvotSeO4AlnMhuxORAX8= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -177,10 +181,12 @@ github.com/rdegges/go-ipify v0.0.0-20150526035502-2d94a6a86c40 h1:31Y7UZ1yTYBU4E github.com/rdegges/go-ipify v0.0.0-20150526035502-2d94a6a86c40/go.mod h1:j4c6zEU0eMG1oiZPUy+zD4ykX0NIpjZAEOEAviTWC18= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4 h1:BN/Nyn2nWMoqGRA7G7paDNDqTXE30mXGqzzybrfo05w= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shuheiktgw/go-travis v0.1.9 h1:qfu71EtAGkloDGS4jIA0f19g6goejqw782qParyaLPw= github.com/shuheiktgw/go-travis v0.1.9/go.mod h1:QJJOek1pLVgh75HK4mUDw99bME0MIyam8+fH6Ebnjq4= github.com/shuheiktgw/go-travis v0.1.10-0.20190502100712-2d0b3e9898f0 h1:+VL5INItDu3Gf4Wak1XZRgsmSTI482GzkTc7Rf2DjI8= github.com/shuheiktgw/go-travis v0.1.10-0.20190502100712-2d0b3e9898f0/go.mod h1:QJJOek1pLVgh75HK4mUDw99bME0MIyam8+fH6Ebnjq4= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/simplepush/simplepush-go v0.0.0-20170307205831-8980e96b7b02 h1:1wFJqw2JrDwoJRJmq/NtlZHRRUGTt7W9uHbWjJ6X2bE= github.com/simplepush/simplepush-go v0.0.0-20170307205831-8980e96b7b02/go.mod h1:3SZdv/t76bM6vmmSa251/VnQMn9S8gRuZcRFy2Ack9A= github.com/simplereach/timeutils v1.2.0 h1:btgOAlu9RW6de2r2qQiONhjgxdAG7BL6je0G6J/yPnA= @@ -205,10 +211,13 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -224,6 +233,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 h1:KaQtG+aDELoNmXYas3TVkGNYRuq8JQ1aa7LJt8EXVyo= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA= +golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -239,6 +250,8 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w= +golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/hives.go b/hives.go index af9601d3..b4e14b9a 100644 --- a/hives.go +++ b/hives.go @@ -23,6 +23,7 @@ package main import ( _ "github.com/muesli/beehive/bees/alertoverbee" _ "github.com/muesli/beehive/bees/anelpowerctrlbee" + _ "github.com/muesli/beehive/bees/cfddns" _ "github.com/muesli/beehive/bees/cleverbotbee" _ "github.com/muesli/beehive/bees/cricketbee" _ "github.com/muesli/beehive/bees/cronbee"