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) } }