initial commit
This commit is contained in:
118
internal/webserver/httpServer.go
Normal file
118
internal/webserver/httpServer.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package webserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"compress/gzip"
|
||||
"net/http"
|
||||
|
||||
"istheinternetonfire.app/assets"
|
||||
"istheinternetonfire.app/internal/config"
|
||||
)
|
||||
|
||||
const (
|
||||
TYPE_APPLICATION_PEM string = "application/x-pem-file"
|
||||
TYPE_APPLICATION_JSON string = "application/json"
|
||||
TYPE_AUDIO_MPEG string = "audio/mpeg"
|
||||
TYPE_FONT_WOFF string = "font/woff"
|
||||
TYPE_FONT_WOFF2 string = "font/woff2"
|
||||
TYPE_IMAGE_JPG string = "image/jpg"
|
||||
TYPE_IMAGE_PNG string = "image/png"
|
||||
TYPE_TEXT_CSS string = "text/css"
|
||||
TYPE_TEXT_HTML string = "text/html"
|
||||
TYPE_TEXT_JS string = "text/javascript"
|
||||
TYPE_TEXT_PLAIN string = "text/plain"
|
||||
TYPE_TEXT_RAW string = "text/raw"
|
||||
)
|
||||
|
||||
var validFiles map[string]string = map[string]string{
|
||||
"/robots.txt": TYPE_TEXT_PLAIN,
|
||||
"/apple-touch-icon.png": TYPE_IMAGE_PNG,
|
||||
"/favicon.ico": TYPE_IMAGE_PNG,
|
||||
"/favicon-16x16.png": TYPE_IMAGE_PNG,
|
||||
"/favicon-32x32.png": TYPE_IMAGE_PNG,
|
||||
"/js/bootstrap.bundle.min.js": TYPE_TEXT_JS,
|
||||
"/js/bootstrap.bundle.min.js.map": TYPE_APPLICATION_JSON,
|
||||
"/js/jquery.min.js": TYPE_TEXT_JS,
|
||||
}
|
||||
|
||||
func isValidReq(file string) (string, error) {
|
||||
for f, t := range validFiles {
|
||||
if file == f {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Invalid file requested: %s", file)
|
||||
}
|
||||
|
||||
func httpAccessLog(req *http.Request) {
|
||||
config.Cfg.Log.Debug("http request", "method", req.Method, "remote-address", req.RemoteAddr, "request-uri", req.RequestURI)
|
||||
}
|
||||
|
||||
func crossSiteOrigin(w http.ResponseWriter) {
|
||||
w.Header().Add("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
|
||||
}
|
||||
|
||||
func Start() {
|
||||
path := http.NewServeMux()
|
||||
|
||||
connection := &http.Server{
|
||||
Addr: config.Cfg.WebServerIP + ":" + strconv.FormatInt(int64(config.Cfg.WebServerPort), 10),
|
||||
Handler: path,
|
||||
ReadTimeout: time.Duration(config.Cfg.WebServerReadTimeout) * time.Second,
|
||||
WriteTimeout: time.Duration(config.Cfg.WebServerWriteTimeout) * time.Second,
|
||||
IdleTimeout: time.Duration(config.Cfg.WebServerIdleTimeout) * time.Second,
|
||||
}
|
||||
|
||||
path.HandleFunc("/", webRoot)
|
||||
|
||||
if err := connection.ListenAndServe(); err != nil {
|
||||
config.Cfg.Log.Error("unable to start webserver", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func webRoot(w http.ResponseWriter, r *http.Request) {
|
||||
httpAccessLog(r)
|
||||
crossSiteOrigin(w)
|
||||
|
||||
if strings.ToLower(r.Method) != "get" {
|
||||
config.Cfg.Log.Debug("http invalid method", "url", r.URL.Path, "expected", "GET", "received", r.Method)
|
||||
tmpltError(w, http.StatusBadRequest, "Invalid http method.")
|
||||
return
|
||||
}
|
||||
|
||||
if r.URL.Path == "/" {
|
||||
tmpltWebRoot(w, r)
|
||||
} else {
|
||||
cType, err := isValidReq(r.URL.Path)
|
||||
if err != nil {
|
||||
config.Cfg.Log.Debug("request not found", "url", r.URL.Path)
|
||||
tmpltStatusNotFound(w, r.URL.Path)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Add("Content-Type", cType)
|
||||
o, err := assets.EmbedHTML.ReadFile("html" + r.URL.Path)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Unable to read local embedded file data: %v\n", err)
|
||||
tmpltError(w, http.StatusInternalServerError, "Server unable to retrieve file data.")
|
||||
return
|
||||
}
|
||||
|
||||
if regexp.MustCompile(`gzip`).Match([]byte(r.Header.Get("Accept-Encoding"))) {
|
||||
w.Header().Add("Content-Encoding", "gzip")
|
||||
gw := gzip.NewWriter(w)
|
||||
defer gw.Close()
|
||||
gw.Write(o)
|
||||
} else {
|
||||
w.Write(o)
|
||||
}
|
||||
}
|
||||
}
|
102
internal/webserver/httpTemplate.go
Normal file
102
internal/webserver/httpTemplate.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package webserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"text/template"
|
||||
|
||||
"istheinternetonfire.app/assets"
|
||||
"istheinternetonfire.app/internal/cisa"
|
||||
"istheinternetonfire.app/internal/config"
|
||||
)
|
||||
|
||||
type webErrStruct struct {
|
||||
Error bool `json:"error" yaml:"error"`
|
||||
ErrorMsg string `json:"error_message" yaml:"errorMessage"`
|
||||
}
|
||||
|
||||
func tmpltError(w http.ResponseWriter, serverStatus int, message string) {
|
||||
var (
|
||||
output []byte
|
||||
o = webErrStruct{
|
||||
Error: true,
|
||||
ErrorMsg: message,
|
||||
}
|
||||
err error
|
||||
)
|
||||
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
output, err = json.MarshalIndent(o, "", " ")
|
||||
if err != nil {
|
||||
config.Cfg.Log.Warn("marshal error", "error", err)
|
||||
w.WriteHeader(serverStatus)
|
||||
w.Write(output) //nolint:errcheck
|
||||
}
|
||||
}
|
||||
|
||||
func tmpltWebRoot(w http.ResponseWriter, r *http.Request) {
|
||||
tmplt, err := template.New("index.tplt").Funcs(template.FuncMap{
|
||||
"ToUpper": strings.ToUpper,
|
||||
}).ParseFS(
|
||||
assets.EmbedHTML,
|
||||
"html/index.tplt",
|
||||
"html/css/style.css",
|
||||
)
|
||||
if err != nil {
|
||||
config.Cfg.Log.Debug("unable to parse html template", "error", err)
|
||||
tmpltError(w, http.StatusInternalServerError, "Template Parse Error.")
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
msgBuffer bytes.Buffer
|
||||
cves []cisa.VulStruct
|
||||
)
|
||||
|
||||
c := cisa.Read()
|
||||
for _, i := range c.Vulnerabilities {
|
||||
t, _ := time.Parse("2006-01-02", i.DateAdded)
|
||||
if t.After(time.Now().Add(-time.Hour * 720)) {
|
||||
cves = append(cves, i)
|
||||
}
|
||||
}
|
||||
|
||||
if err := tmplt.Execute(&msgBuffer, struct {
|
||||
CVEs []cisa.VulStruct
|
||||
}{
|
||||
CVEs: cves[len(cves)-3:],
|
||||
}); err != nil {
|
||||
config.Cfg.Log.Debug("unable to execute html template", err)
|
||||
tmpltError(w, http.StatusInternalServerError, "Template Parse Error.")
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(msgBuffer.Bytes())
|
||||
}
|
||||
|
||||
func tmpltStatusNotFound(w http.ResponseWriter, path string) {
|
||||
tmplt, err := template.ParseFS(assets.EmbedHTML, "html/file-not-found.tplt")
|
||||
if err != nil {
|
||||
config.Cfg.Log.Debug("unable to parse html template", err)
|
||||
tmpltError(w, http.StatusInternalServerError, "Template Parse Error.")
|
||||
return
|
||||
}
|
||||
|
||||
var msgBuffer bytes.Buffer
|
||||
if err := tmplt.Execute(&msgBuffer, struct {
|
||||
Title string
|
||||
ErrorCode int
|
||||
}{
|
||||
Title: path,
|
||||
ErrorCode: http.StatusNotFound,
|
||||
}); err != nil {
|
||||
config.Cfg.Log.Debug("unable to execute html template", err)
|
||||
tmpltError(w, http.StatusInternalServerError, "Template Parse Error.")
|
||||
return
|
||||
}
|
||||
w.Write(msgBuffer.Bytes())
|
||||
}
|
Reference in New Issue
Block a user