1
0
Fork 0

Initial commit
continuous-integration/drone/push Build is failing Details

master
Ambrose Chua 2019-02-16 20:35:47 +08:00
commit 7f2e6734ce
6 changed files with 265 additions and 0 deletions

15
.drone.yml Normal file
View File

@ -0,0 +1,15 @@
kind: pipeline
name: default
steps:
- name: docker
image: plugins/docker
settings:
registry: registry.makerforce.io
repo: registry.makerforce.io/cacti/he-dns-editor
tags:
- latest
username:
from_secret: docker_username
password:
from_secret: docker_password

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
he-dns-editor

36
Dockerfile Normal file
View File

@ -0,0 +1,36 @@
FROM golang:1.11-alpine as build
# args
ARG version="0.1"
ARG repo="git.makerforce.io/cacti/he-dns-editor"
# dependencies
RUN apk add --no-cache ca-certificates
# source
WORKDIR $GOPATH/src/${repo}
COPY . .
# build
ENV CGO_ENABLED=0
ENV GOOS=linux
ENV GOARCH=amd64
RUN go build -ldflags "-s -w" -o /he-dns-editor
FROM scratch
ARG version
# labels
LABEL org.label-schema.vcs-url="https://git.makerforce.io/cacti/he-dns-editor"
LABEL org.label-schema.version=${version}
LABEL org.label-schema.schema-version="1.0"
# copy binary and ca certs
COPY --from=build /he-dns-editor /email-collector
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
EXPOSE 8080
ENTRYPOINT ["/he-dns-editor"]

6
go.mod Normal file
View File

@ -0,0 +1,6 @@
module git.makerforce.io/cacti/he-dns-editor
require (
github.com/julienschmidt/httprouter v1.2.0
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd
)

4
go.sum Normal file
View File

@ -0,0 +1,4 @@
github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

203
main.go Normal file
View File

@ -0,0 +1,203 @@
package main // import "git.makerforce.io/cacti/he-dns-editor"
import (
"errors"
"flag"
"io"
"log"
"net/http"
"strings"
"github.com/julienschmidt/httprouter"
"golang.org/x/net/html"
)
var listen string
var username string
var password string
var zoneid string
func init() {
flag.StringVar(&listen, "listen", ":8080", "Listen on port")
flag.StringVar(&username, "username", "", "HE.net username")
flag.StringVar(&password, "password", "", "HE.net password")
flag.StringVar(&zoneid, "zoneid", "", "HE.net zone ID")
}
func main() {
flag.Parse()
if len(username) == 0 || len(password) == 0 || len(zoneid) == 0 {
flag.PrintDefaults()
log.Fatal("Please specify username, password and zoneid")
}
router := httprouter.New()
router.GET("/", Index)
router.POST("/", Post)
// Listen
log.Println("main: Listening on", listen)
log.Fatal(http.ListenAndServe(listen, router))
}
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.Header().Add("Content-Type", "text/html")
records, err := request("", "", "", "", "")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("An error occurred"))
log.Println(err)
return
}
res := `
<style>
form {
margin-bottom: 0;
}
</style>
<main>`
for _, record := range records {
disabled := ""
if record.Type == "NS" || record.Type == "SOA" {
disabled = ` disabled`
}
res += `<form method="POST">`
res += `<input type="hidden" name="recordid" value="` + record.ID + `"` + disabled + `>`
res += `<input name="recordname" value="` + record.Name + `"` + disabled + `>`
res += `<input name="recordtype" value="` + record.Type + `"` + disabled + `>`
res += `<input name="recordcontent" value="` + record.Content + `"` + disabled + `>`
res += `<input type="submit" name="editrecord" value="Update"` + disabled + `>`
res += `<input type="submit" name="editrecord" value="Delete"` + disabled + `>`
res += `</form>`
}
res += `<form method="POST">`
res += `<input name="recordname" placeholder="Name">`
res += `<input name="recordtype" placeholder="Type" value="CNAME">`
res += `<input name="recordcontent" placeholder="Data">`
res += `<input type="submit" name="editrecord" value="Submit">`
res += `</form>`
res += `</main>`
w.Write([]byte(res))
}
func Post(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
_, err := request(
r.FormValue("editrecord"),
r.FormValue("recordid"),
r.FormValue("recordname"),
r.FormValue("recordtype"),
r.FormValue("recordcontent"),
)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("An error occurred"))
log.Println(err)
return
}
w.Header().Add("Location", "/")
w.WriteHeader(http.StatusSeeOther)
}
var BadResponseError = errors.New("Bad response")
type Record struct {
ID string
Name string
Type string
Content string
}
func request(editrecord, recordid, recordname, recordtype, recordcontent string) ([]Record, error) {
log.Println("Operation", editrecord, recordid, recordname, recordtype, recordcontent)
body := "email=" + username + "&pass=" + password + "&account="
body += "&menu=edit_zone&hosted_dns_editzone=1&hosted_dns_zoneid=" + zoneid
if len(editrecord) > 0 {
if editrecord == "Delete" {
body += "&hosted_dns_delconfirm=DELETE&hosted_dns_delrecord=1"
} else {
body += "&hosted_dns_editrecord=" + editrecord
}
}
if len(recordid) > 0 {
body += "&hosted_dns_recordid=" + recordid
}
if len(recordname) > 0 {
body += "&Name=" + recordname
}
if len(recordtype) > 0 {
body += "&Type=" + recordtype
}
body += "&TTL=300"
if len(recordcontent) > 0 {
body += "&Content=" + recordcontent
}
buf := strings.NewReader(body)
resp, err := http.Post("https://dns.he.net", "application/x-www-form-urlencoded", buf)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, BadResponseError
}
return parseRequest(resp)
}
func parseRequest(resp *http.Response) ([]Record, error) {
d := html.NewTokenizer(resp.Body)
records := make([]Record, 0)
working := Record{}
tdCount := 0
var err error
for err == nil {
tok := d.Next()
switch tok {
case html.ErrorToken:
err = d.Err()
case html.TextToken:
text := string(d.Text())
switch tdCount {
case 2:
working.Name = text
case 3:
working.Type = text
case 6:
working.Content = text
}
case html.StartTagToken:
tagName, _ := d.TagName()
tagAttr := make(map[string]string)
var k, v []byte
more := true
for more {
k, v, more = d.TagAttr()
tagAttr[string(k)] = string(v)
}
if string(tagName) == "tr" {
if tagAttr["class"] == "dns_tr" || tagAttr["class"] == "dns_tr_dynamic" {
tdCount = 0
working = Record{}
}
if _, ok := tagAttr["id"]; ok {
working.ID = tagAttr["id"]
}
}
case html.EndTagToken:
tagName, _ := d.TagName()
if string(tagName) == "tr" {
if len(working.ID) == 0 {
break
}
records = append(records, working)
} else if string(tagName) == "td" {
tdCount += 1
}
}
}
if err == io.EOF {
err = nil
}
return records, err
}