Simple FI-domain availability checking
This commit is contained in:
commit
d40bfca474
8 changed files with 267 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/config.json
|
||||
/nexsis
|
4
Makefile
Normal file
4
Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
run:
|
||||
go run main.go
|
||||
build:
|
||||
go build -v -ldflags "-s -w"
|
4
config.json.example
Normal file
4
config.json.example
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"port": 6900,
|
||||
"siteName": "NexSIS"
|
||||
}
|
16
go.mod
Normal file
16
go.mod
Normal file
|
@ -0,0 +1,16 @@
|
|||
module nexsis
|
||||
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
modernc.org/libc v1.55.3 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
modernc.org/sqlite v1.34.5 // indirect
|
||||
)
|
21
go.sum
Normal file
21
go.sum
Normal file
|
@ -0,0 +1,21 @@
|
|||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
|
||||
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
|
||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
||||
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
||||
modernc.org/sqlite v1.34.5 h1:Bb6SR13/fjp15jt70CL4f18JIN7p7dnMExd+UFnF15g=
|
||||
modernc.org/sqlite v1.34.5/go.mod h1:YLuNmX9NKs8wRNK2ko1LW1NGYcc9FkBO69JOt1AR9JE=
|
23
index.html
Normal file
23
index.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{.Title}}</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cntrbox">
|
||||
<h1>{{.Title}}</h1>
|
||||
<p>
|
||||
Will be able to manage. Or not.
|
||||
</p>
|
||||
<footer>
|
||||
<hr>
|
||||
<small>
|
||||
2015 Jarkko Toivanen
|
||||
</small>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
183
main.go
Normal file
183
main.go
Normal file
|
@ -0,0 +1,183 @@
|
|||
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)
|
||||
return
|
||||
}
|
||||
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!")
|
||||
return
|
||||
}
|
||||
defer cfgfile.Close()
|
||||
|
||||
decoder := json.NewDecoder(cfgfile)
|
||||
//Config := Config{}
|
||||
err = decoder.Decode(&C)
|
||||
if err != nil {
|
||||
log.Fatal("Can't decode config.json!")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
db, err = sql.Open("sqlite", "database.db")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
static/style.css
Normal file
14
static/style.css
Normal file
|
@ -0,0 +1,14 @@
|
|||
body {
|
||||
background-color: #000000;
|
||||
color: #ffffff;
|
||||
font-family: "sans-serif";
|
||||
}
|
||||
|
||||
a, a:visited, a:active {
|
||||
color: #00ffff;
|
||||
}
|
||||
|
||||
.cntrbox {
|
||||
display: grid;
|
||||
place-content: center;
|
||||
}
|
Loading…
Add table
Reference in a new issue