diff --git a/.gitignore b/.gitignore index e87f353..b39d27c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ -# Created by .ignore support plugin (hsz.mobi) -### Go template # Binaries for programs and plugins *.exe *.exe~ @@ -10,6 +8,7 @@ *.tbz2 *.tgz *.key +go-transip-dyndns # Test binary, built with `go test -c` *.test @@ -20,17 +19,15 @@ # Dependency directories (remove the comment below to include it) # vendor/ -.idea/.gitignore -.idea/go-transip-dyndns.iml -.idea/misc.xml -.idea/modules.xml -.idea/vcs.xml cmd/transip-dyndns/private.key cmd/transip-dyndns/transip-dyndns cmd/transip-dyndns/transip.toml -go.mod -go.sum -internal/gipify/get_test.go /go-transip-dyndns.toml + +# IDE project files /.idea + +# OS Artifacts .DS_Store + +/dist diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..fbcde7d --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,72 @@ +# This is an example .goreleaser.yml file with some sane defaults. +# Make sure to check the documentation at http://goreleaser.com +before: + hooks: + # You may remove this if you don't use go modules. + - go mod download + # you may remove this if you don't need go generate + - go generate ./... +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + goarch: + - 386 + - amd64 + - arm + - arm64 + - mips64 + goarm: + - 5 + - 6 + - 7 + ldflags: + - -w -s -X main.ApplicationVersion={{.Version}} +archives: + - name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' + replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 + format_overrides: + - goos: windows + format: zip + files: + - README.md + - LICENSE.md + - example.go-transip-dyndns.toml + - completions/* +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ .Tag }}-next" +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' +dockers: + - + goos: linux + goarch: amd64 + goarm: '' + image_templates: + - "jlentink/go-transip-dyndns:{{ .Tag }}-amd64" + skip_push: false + dockerfile: Dockerfile + - + goos: linux + goarch: arm + goarm: 5 + use_buildx: true + image_templates: + - "jlentink/go-transip-dyndns:pi-{{ .Tag }}-pi" + - "jlentink/go-transip-dyndns:pi-{{ .Tag }}-arm5" + skip_push: false + dockerfile: Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a3084d1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:latest + +COPY go-transip-dyndns /usr/bin +RUN echo '* * * * * /usr/bin/go-transip-dyndns' > /etc/crontabs/root +CMD crond -l 2 -f \ No newline at end of file diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/Makefile b/Makefile index a7d9f3d..b2087b0 100644 --- a/Makefile +++ b/Makefile @@ -24,9 +24,13 @@ golintci: card: goreportcard-cli -v -t 100 -build: linux macos windows +build: + goreleaser build --skip-validate --skip-publish --rm-dist -linux: linux32 linux64 linuxarm linuxarm64 linuxpi +release: + goreleaser release --skip-validate --skip-publish --rm-dist + +linux: linux32 linux64 linuxarm linuxarm64 linuxpi mips64 windows: windows32 windows64 @@ -115,3 +119,9 @@ ifeq ("$(TRAVISBUILD)","off") endif cp README.md ./builds/windows-32/ @cd builds/windows-32/ && zip ../../go-transip-dyndns-windows-386-${BUILT_VERSION}.zip go-transip-dyndns.exe README.md + +mips64: + env GOOS=linux GOARCH=mips64 go build ${LDFLAGS} -o ./builds/linux-mips64/go-transip-dyndns + cp README.md ./builds/linux-mips64/ + @cd ./builds/linux-mips64 && tar -jcf ../../go-transip-dyndns-linux-mips64-${BUILT_VERSION}.tbz2 go-transip-dyndns README.md + @cd ./builds/linux-mips64 && tar -zcf ../../go-transip-dyndns-linux-mips64-${BUILT_VERSION}.tgz go-transip-dyndns README.md diff --git a/commands/update.go b/commands/update.go index 8b3a3ff..ea4bb75 100644 --- a/commands/update.go +++ b/commands/update.go @@ -19,11 +19,13 @@ func Update(cmd *cobra.Command, args []string) { if err != nil { logger.Get().Fatalf("Error accessing the API. please verify configuration (%s)", err.Error()) } + tld.SetRecordInformation( config.Get().GetString("domain"), config.Get().GetString("domain-entry"), config.Get().GetInt("domain-ttl"), ) + changed, err := tld.UpdateRecord(IP) if err != nil { logger.Get().Fatalf("Unable to create record. (%s)", err.Error()) diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index 2afde3d..0000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM alpine:latest - -COPY ./go-transip-dyndns /usr/local/bin -RUN echo '* * * * * /usr/local/bin/go-transip-dyndns' > /etc/crontabs/root -CMD crond -l 2 -f \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7e8e7fe --- /dev/null +++ b/go.mod @@ -0,0 +1,12 @@ +module github.com/jlentink/go-transip-dyndns + +go 1.12 + +require ( + github.com/kyokomi/emoji v2.2.2+incompatible + github.com/sirupsen/logrus v1.6.0 + github.com/spf13/cobra v0.0.5 + github.com/spf13/viper v1.3.2 + github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 + github.com/transip/gotransip/v6 v6.1.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..9a2f496 --- /dev/null +++ b/go.sum @@ -0,0 +1,71 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +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= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kyokomi/emoji v2.2.2+incompatible h1:gaQFbK2+uSxOR4iGZprJAbpmtqTrHhSdgOyIMD6Oidc= +github.com/kyokomi/emoji v2.2.2+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA= +github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 h1:J6v8awz+me+xeb/cUTotKgceAYouhIB3pjzgRd6IlGk= +github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816/go.mod h1:tzym/CEb5jnFI+Q0k4Qq3+LvRF4gO3E2pxS8fHP8jcA= +github.com/transip/gotransip/v6 v6.1.0 h1:t8wV8jKPKf58dQWqWQAUXa5HznpUWKutkqugCV+5IDA= +github.com/transip/gotransip/v6 v6.1.0/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a h1:1n5lsVfiQW3yfsRGu98756EH1YthsFqr/5mxHduZW2A= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/gipify/get_test.go b/internal/gipify/get_test.go new file mode 100644 index 0000000..a09f26f --- /dev/null +++ b/internal/gipify/get_test.go @@ -0,0 +1,178 @@ +package gipify + +import ( + "fmt" + "github.com/sirupsen/logrus" + "io" + "net/http" + "net/http/httptest" + "reflect" + "strings" + "testing" +) + +func TestGet(t *testing.T) { + + type httpResponse struct { + contentType string + body string + status int + } + type want struct { + IP string + Type int + } + tests := []struct { + name string + want want + http httpResponse + wantErr bool + }{ + { + name: "GetIP IPv4", + http: httpResponse{contentType: `application/json`, body: `{"ip":"98.207.254.136"}`, status: 200}, + want: want{IP: "98.207.254.136", Type: IPV4}, + }, + { + name: "GetIP IPv6", + http: httpResponse{contentType: `application/json`, body: `{"ip":"2a00:1450:400f:80d::200e"}`, status: 200}, + want: want{IP: "2a00:1450:400f:80d::200e", Type: IPV6}, + }, + { + name: "400 error", + http: httpResponse{contentType: `application/json`, body: `{"ip":"2a00:1450:400f:80d::200e"}`, status: 400}, + want: want{IP: "2a00:1450:400f:80d::200e", Type: IPV6}, + wantErr: true, + }, + { + name: "500 error", + http: httpResponse{contentType: `application/json`, body: `{"ip":"2a00:1450:400f:80d::200e"}`, status: 500}, + want: want{IP: "2a00:1450:400f:80d::200e", Type: IPV6}, + wantErr: true, + }, + } + for _, tt := range tests { + logrus.SetLevel(logrus.DebugLevel) + logrus.New() + t.Run(tt.name, func(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(tt.http.status) + w.Header().Set("Content-Type", tt.http.contentType) + fmt.Fprintln(w, tt.http.body) + })) + defer ts.Close() + + ipURL = ts.URL + ipWant := IP{IP: tt.want.IP, Type: tt.want.Type} + got, err := GetIP() + if (err != nil) != tt.wantErr { + t.Errorf("GetIP() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr && !reflect.DeepEqual(got, &ipWant) { + t.Errorf("GetIP() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_parse(t *testing.T) { + type args struct { + i io.Reader + } + + type want struct { + IP string + Type int + } + + tests := []struct { + name string + args args + want want + wantErr bool + }{ + { + name: "Parse json ip 192.168.0.1", + args: args{i: strings.NewReader(`{"ip":"192.168.0.1"}`)}, + want: want{IP: "192.168.0.1", Type: IPV4}, + wantErr: false, + }, + { + name: "Parse json ip 127.0.0.1", + args: args{i: strings.NewReader(`{"ip":"127.0.0.1"}`)}, + want: want{IP: "127.0.0.1", Type: IPV4}, + wantErr: false, + }, + { + name: "Parse json ip ::1", + args: args{i: strings.NewReader(`{"ip":"::1"}`)}, + want: want{IP: "::1", Type: IPV6}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parse(tt.args.i) + if (err != nil) != tt.wantErr { + t.Errorf("parse() error = %v, wantErr %v", err, tt.wantErr) + return + } + + ipWant := IP{IP: tt.want.IP, Type: tt.want.Type} + + if !reflect.DeepEqual(got, &ipWant) { + t.Errorf("parse() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_ipType(t *testing.T) { + type args struct { + i string + } + tests := []struct { + name string + args args + want int + }{ + { + name: "IPv4: 192.168.0.1", + args: args{"192.168.0.1"}, + want: IPV4, + }, + { + name: "IPv4: 127.0.0.1", + args: args{"192.168.0.1"}, + want: IPV4, + }, + { + name: "IPv6: ::1", + args: args{"::1"}, + want: IPV6, + }, + { + name: "IPv6: 2001:4860:4860::8888", + args: args{"2001:4860:4860::8888"}, + want: IPV6, + }, + { + name: "Error: 127.0.0.", + args: args{"127.0.0."}, + want: UNKNOWN, + }, + { + name: "Error: Empty", + args: args{""}, + want: UNKNOWN, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ipType(tt.args.i); got != tt.want { + t.Errorf("ipType() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/logger/log.go b/internal/logger/log.go index 788b528..b88d2cd 100644 --- a/internal/logger/log.go +++ b/internal/logger/log.go @@ -31,6 +31,9 @@ func Init() { // Get Logger setup func Get() *logrus.Logger { + if _log == nil { + Init() + } return _log }