package configui import ( "encoding/json" "io/ioutil" "log" "net/http" "os" "path/filepath" "strings" ) func (cui *ConfigUI) ServeHTTP(w http.ResponseWriter, r *http.Request) { cui.middleware(cui.mux()).ServeHTTP(w, r) } func (cui *ConfigUI) middleware(next http.Handler) http.Handler { return http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { rw := &CuiResponseWriter{w, 0} defer catch(rw, r) ip := GetIP(r) if cui.AllowIP != "" { if !matchIPGlob(ip, cui.AllowIP) { rw.WriteHeader(403) panic("permission denied") } } next.ServeHTTP(rw, r) //logging if !strings.HasPrefix(r.URL.Path, "/public") && r.URL.Query().Get("f") != "true" { log.Printf("%s %s %d %s %s\n", ip, r.Method, rw.StatueCode, r.URL, r.Header.Get("User-Agent")) } }, ) } func (cui *ConfigUI) mux() *http.ServeMux { cuiR := http.NewServeMux() cuiR.HandleFunc("/api/conf", func(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { cui.GetConfig(w, r) } else if r.Method == "POST" { cui.PostConfig(w, r) } else { w.WriteHeader(404) } }) cuiR.HandleFunc("/api/files", func(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { cui.ListFiles(w, r) } else { w.WriteHeader(404) } }) cuiR.HandleFunc("/api/file", func(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { cui.GetFile(w, r) } else if r.Method == "POST" { cui.PostFile(w, r) } else { w.WriteHeader(404) } }) cuiR.HandleFunc("/api/apply", func(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { cui.Apply(w, r) } else { w.WriteHeader(404) } }) cuiR.HandleFunc("/api/export", func(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { cui.Download(w, r) } else { w.WriteHeader(404) } }) cuiR.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.FS(cui.PublicFS)))) cuiR.HandleFunc("/", cui.App) return cuiR } func (cui *ConfigUI) ListFiles(w http.ResponseWriter, r *http.Request) { data, err := json.Marshal(cui.Files) if err != nil { panic(err) } w.Write(data) } func (cui *ConfigUI) GetFile(w http.ResponseWriter, r *http.Request) { name := r.URL.Query().Get("name") file, err := cui.File(name) if err != nil { response(w, 404, []byte("file not found")) return } data, err := file.Read() if err != nil { panic(err) } response, err := json.Marshal(map[string]string{ "path": file.Path, "name": file.Name, "action": file.Action, "data": string(data), }) if err != nil { panic(err) } w.Header().Set("Content-Type", "application/json") w.Write(response) } func (cui *ConfigUI) PostFile(w http.ResponseWriter, r *http.Request) { data, err := ioutil.ReadAll(r.Body) r.Body.Close() if err != nil { panic(err) } f := File{} if err := json.Unmarshal(data, &f); err != nil { panic(err) } file, err := cui.File(f.Name) if err != nil { response(w, 404, []byte("file not found")) return } if err := file.Write([]byte(f.Data)); err != nil { panic(err) } w.Write([]byte("ok")) } func (cui *ConfigUI) Apply(w http.ResponseWriter, r *http.Request) { name := r.URL.Query().Get("name") file, err := cui.File(name) if err != nil { response(w, 404, []byte("file not found")) return } result, err := file.Do() if err != nil { panic(err) } w.Write([]byte(result)) } func (cui *ConfigUI) Download(w http.ResponseWriter, r *http.Request) { if name := r.URL.Query().Get("name"); name != "" { if name == cui.AppName { data, err := cui.Config() if err != nil { panic(err) } w.Header().Set( "Content-Disposition", ` attachment; filename="`+cui.AppName+`.json"`, ) w.Write(data) return } file, err := cui.File(name) if err != nil { response(w, 404, []byte("file not found")) return } data, err := file.Read() if err != nil { panic(err) } w.Header().Set("Content-Disposition", `attachment; filename="`+filepath.Base(file.Path)+`"`) w.Write(data) return } fs := []string{} for _, i := range cui.fileIndex { fs = append(fs, cui.Files[i].Path) } if cui.ConfigPath != "" { fs = append(fs, cui.ConfigPath) } w.Header().Set("Content-Disposition", `attachment; filename="export.tar.gz"`) bundle(w, fs, cui.AppName, false) } func (cui *ConfigUI) PostConfig(w http.ResponseWriter, r *http.Request) { if cui.NoReconfig { panic("system reconfig is disabled") } data, err := ioutil.ReadAll(r.Body) r.Body.Close() if err != nil { panic(err) } err = cui.LoadConfig(string(data)) if err != nil { panic(err) } if cui.ConfigPath != "" { info, err := os.Stat(cui.ConfigPath) if err != nil { panic(err) } err = os.WriteFile(cui.ConfigPath, data, info.Mode()) if err != nil { panic(err) } } w.Write([]byte("ok")) } func (cui *ConfigUI) GetConfig(w http.ResponseWriter, r *http.Request) { data, err := cui.Config() if err != nil { panic(err) } w.Write(data) }