NexSIS/main.go

184 lines
3.6 KiB
Go

package main
import (
"database/sql"
"encoding/json"
"encoding/xml"
"fmt"
"html/template"
"log"
"net"
"net/http"
"os"
"io"
"strings"
"bytes"
"errors"
_ "modernc.org/sqlite"
)
type Config struct {
Port uint
SiteName string
}
type page struct {
Title string
}
type xmlDomain struct {
authority string
registryType string
entityClass string
entityName string
}
var C = Config{}
var db *sql.DB
func main() {
var err error
domain := "snuff.fi"
av, err := checkDomainAvailability(domain)
if err != nil {
log.Fatal(err)
os.Exit(1)
}
fmt.Printf("Domain '%s' available: %t\n", domain, av)
return
// Load config
fmt.Println("Loading config.json")
cfgfile, err := os.Open("config.json")
if err != nil {
log.Fatal("Error reading config.json!")
os.Exit(1)
}
defer cfgfile.Close()
decoder := json.NewDecoder(cfgfile)
//Config := Config{}
err = decoder.Decode(&C)
if err != nil {
log.Fatal("Can't decode config.json!")
os.Exit(1)
}
db, err = sql.Open("sqlite", "database.db")
if err != nil {
log.Fatal(err)
os.Exit(1)
}
fmt.Printf("Starting listener on :%v", C.Port)
http.Handle("/static/", http.FileServer(http.Dir("./")))
http.HandleFunc("/", httpRootHandler)
err = http.ListenAndServe(fmt.Sprintf(":%v", C.Port), nil)
if err != nil {
log.Fatal(err)
}
db.Close()
}
func httpRootHandler(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("index.html")
// var err := do_get_stuff()
// if err != nil {
// log.Fatal(err)
// http.Error(w, http.StatusText(500), 500)
// return
// }
var p page
p.Title = C.SiteName;
t.Execute(w, p)
}
func checkDomainAvailability(domain string) (bool, error) {
dasHost := "das.domain.fi";
dasPort := 715
dasAddr := fmt.Sprintf("%s:%d", dasHost, dasPort)
request := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?>
<iris1:request xmlns:iris1="urn:ietf:params:xml:ns:iris1">
<iris1:searchSet>
<iris1:lookupEntity registryType="dchk1" entityClass="domain-name" entityName="%s"/>
</iris1:searchSet>
</iris1:request>`, domain)
conn, err := net.Dial("udp", dasAddr)
if err != nil {
log.Fatal(err)
return false, err
}
defer conn.Close()
fmt.Fprintf(conn, request)
response := make([]byte, 1024)
_, err = conn.Read(response)
if err != nil {
log.Fatal(err)
}
response = bytes.Trim(response, "\x00")
// Response can be:
// - active: already in use
// - available: go ahead and grab it while you can
// - invalid: malformed request: maybe check domain has .fi in the end
isAvailable, err := xmlCheckTag(string(response), "available")
if err != nil {
log.Fatal(err)
return false, err
} else if isAvailable {
// Domain is available
return true, nil
}
isActive, err := xmlCheckTag(string(response), "active")
if err != nil {
log.Fatal(err)
return false, err
} else if isActive {
// Domain is already registered taken
return false, nil
}
isInvalid, err := xmlCheckTag(string(response), "invalid")
if err != nil {
log.Fatal(err)
return false, err
} else if isInvalid {
// We got bonked for our request
return false, errors.New("Request or domain invalid")
}
// Execution should not lead here but hey might as well error it out
return false, errors.New("Error: Status field not found")
}
func xmlCheckTag(src, tag string) (bool, error) {
// Thanks icza for your stackoverflow
// https://stackoverflow.com/a/51649834
decoder := xml.NewDecoder(strings.NewReader(src))
for {
t, err := decoder.Token()
if err != nil {
if err == io.EOF {
return false, nil
}
return false, err
}
if se, ok := t.(xml.StartElement); ok {
if se.Name.Local == tag {
return true, nil
}
}
}
}