dialburn/server/main.go

152 lines
3.5 KiB
Go

package main
import (
"encoding/xml"
"net/http"
"os"
"strings"
"sync"
"time"
"dialburn/common"
"github.com/gorilla/mux"
)
type TwiML struct {
XMLName xml.Name `xml:"Response"`
GatherTag Gather `xml:"Gather"`
Hangup string `xml:"Hangup"`
}
type Gather struct {
XMLName xml.Name `xml:"Gather"`
Action string `xml:"action,attr"`
NumDigits string `xml:"numDigits,attr"`
TimeOut string `xml:"timeout,attr"`
Play string `xml:"Play"`
}
type Feedback struct {
XMLName xml.Name `xml:"Response"`
Play string `xml:"Play"`
Hangup string `xml:"Hangup"`
}
var trigger = false
func twiml(w http.ResponseWriter, r *http.Request) {
g := Gather{Action: common.SERVPATH + "/code", NumDigits: "3", TimeOut: "120", Play: common.MUSIC}
twiml := TwiML{GatherTag: g}
x, err := xml.Marshal(twiml)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/xml")
w.Write(x)
}
func action(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
var twiml Feedback
if r.Form.Get("Digits") == "666" {
common.Info("received valid code")
twiml = Feedback{Play: common.ACCEPTED}
trigger = true
} else {
common.Info("received invalid code")
twiml = Feedback{Play: common.DENIED}
}
x, err := xml.Marshal(twiml)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/xml")
w.Write(x)
}
func enroll(w http.ResponseWriter, r *http.Request) {
addr := strings.Split(r.RemoteAddr, ":")[0]
data, _ := os.ReadFile(common.AGENTLOG)
if strings.Contains(string(data), addr) {
w.WriteHeader(http.StatusConflict)
} else {
fd, _ := os.OpenFile(common.AGENTLOG, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
defer fd.Close()
if _, err := fd.WriteString(addr + "\n"); err != nil {
common.Warning("error writing to " + common.AGENTLOG + " during enrollment")
} else {
common.Success("enrolled " + addr + " at " + time.Now().Format(time.RFC3339))
}
w.WriteHeader(http.StatusAccepted)
}
}
func shutitdown() {
data, _ := os.ReadFile(common.AGENTLOG)
var wg sync.WaitGroup
for _, addr := range strings.Split(string(data), "\n") {
if addr != "" {
wg.Add(1)
go func(addr string) {
defer wg.Done()
common.Info("sending burn request to " + addr)
_, err := http.Get("http://" + addr + ":" + common.AGENTLPORT + common.AGENTPATH)
if err != nil {
common.Warning("error sending burn request to " + addr)
}
}(addr)
}
}
wg.Wait()
}
func main() {
common.Banner()
if _, err := os.Stat(common.AGENTLOG); os.IsNotExist(err) {
fd, err := os.Create(common.AGENTLOG)
if err != nil {
common.Fatal("failed to create " + common.AGENTLOG)
} else {
common.Success("created " + common.AGENTLOG)
fd.Close()
}
}
go func() {
for {
if trigger {
shutitdown()
trigger = false
}
time.Sleep(500 * time.Millisecond)
}
}()
r := mux.NewRouter()
r.HandleFunc(common.SERVPATH, twiml).Methods("POST")
r.HandleFunc(common.SERVPATH+"/code", action).Methods("POST")
r.HandleFunc(common.SERVPATH+"/enroll", enroll).Methods("PUT")
http.Handle("/", r)
serv := &http.Server{
Addr: ":" + common.SERVLPORT,
Handler: r,
ErrorLog: nil,
IdleTimeout: 10 * time.Second,
}
common.Warning("dont get caught in the first place!")
common.Info("starting dialburn server port " + common.SERVLPORT)
if err := serv.ListenAndServe(); err != nil {
common.Fatal("failed to start listener on port " + common.SERVLPORT)
}
}