152 lines
3.5 KiB
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)
|
||
|
}
|
||
|
|
||
|
}
|