add fs.go to internal, make makeLocal do the majority of lifting for tmp and perm files, made save() call makeLocal

This commit is contained in:
grumbulon 2023-02-04 20:41:16 -05:00 committed by Gitea
parent 2426a8b393
commit 92100e27a0
4 changed files with 87 additions and 107 deletions

69
internal/api/fs.go Normal file
View file

@ -0,0 +1,69 @@
package api
import (
"errors"
"fmt"
"os"
"path/filepath"
"git.freecumextremist.com/grumbulon/pomme/internal"
)
var errEmptyFile = errors.New("will not save empty file to FS")
// makeLocal takes a type path and then saves a zone file to either tmp or a permanent location
func makeLocal(where path, zone *ZoneRequest) error {
var (
path string
file string
c *internal.Config
err error
)
if _, err := os.Stat(fmt.Sprintf(zone.FileName, zone.User)); !os.IsNotExist(err) {
return fmt.Errorf("file %s already exists: %w", zone.FileName, err)
}
if len([]byte(zone.Body)) == 0 {
return errEmptyFile
}
switch where {
case Tmp:
path = fmt.Sprintf("/tmp/tmpfile-%s-%s", zone.RawFileName, zone.User)
case Perm:
c, err = internal.ReadConfig()
if err != nil {
logHandler(genericResponseFields{"error": err.Error(), "message": "no config file defined"})
return fmt.Errorf("unable to parse directory: %w", err)
}
path = fmt.Sprintf("%s/%s/", c.ZoneDir, zone.RawFileName)
file = zone.RawFileName
if err = os.MkdirAll(path, 0o750); err != nil {
logHandler(genericResponseFields{"error": err.Error(), "message": "unable to make directory for zone files"})
return fmt.Errorf("unable to make zone directory: %w", err)
}
}
f, err := os.Create(filepath.Clean(path + file)) //nolint: gosec
if err != nil {
return fmt.Errorf("failed to write file locally: %w", err)
}
// close and remove the temporary file at the end of the program
defer func() {
if err = f.Close(); err != nil {
return
}
}()
err = os.WriteFile(f.Name(), []byte(zone.Body), 0o600)
if err != nil {
return fmt.Errorf("failed to write file locally: %w", err)
}
return nil
}

View file

@ -6,8 +6,15 @@ const (
keyPrincipalContextID key = iota
)
const (
Tmp path = iota
Perm
)
type key int
type path int
// ZoneRequest represents a Zone file request.
type ZoneRequest struct {
*Zone
@ -31,7 +38,7 @@ type genericResponseFields map[string]any
type ndr interface {
parse() error
save() error
save(where path) error
}
var _ ndr = (*ZoneRequest)(nil)

View file

@ -10,7 +10,6 @@ import (
"strings"
"git.freecumextremist.com/grumbulon/pomme/internal"
"git.freecumextremist.com/grumbulon/pomme/internal/util"
"github.com/go-chi/jwtauth/v5"
"github.com/go-chi/render"
"github.com/miekg/dns"
@ -64,8 +63,10 @@ func ReceiveFile(w http.ResponseWriter, r *http.Request) {
return
}
if err = util.MakeLocal(header.Filename, claims["username"].(string), b); err != nil {
APIError(w, r, genericResponseFields{"message": "internal server error", "status": http.StatusInternalServerError, "error": err.Error()})
zoneFile := newDNSRequest(header.Filename, claims["username"].(string), b)
if err := zoneFile.save(Tmp); err != nil {
APIError(w, r, genericResponseFields{"message": "Unable to save zonefile", "status": http.StatusInternalServerError, "error": err.Error()})
return
}
@ -86,15 +87,13 @@ func ReceiveFile(w http.ResponseWriter, r *http.Request) {
},
})
zoneFile := newDNSRequest(header.Filename, claims["username"].(string))
if err := zoneFile.parse(); err != nil {
APIError(w, r, genericResponseFields{"message": "Unable to parse zonefile", "status": http.StatusInternalServerError, "error": err.Error()})
return
}
if err := zoneFile.save(); err != nil {
if err := zoneFile.save(Perm); err != nil {
APIError(w, r, genericResponseFields{"message": "Unable to save zonefile", "status": http.StatusInternalServerError, "error": err.Error()})
return
@ -111,12 +110,7 @@ func ReceiveFile(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, resp)
}
func newDNSRequest(filename string, user string) ndr {
dat, err := os.ReadFile(fmt.Sprintf("/tmp/tmpfile-%s-%s", filename, user))
if err != nil {
return &ZoneRequest{}
}
func newDNSRequest(filename string, user string, dat []byte) ndr {
return &ZoneRequest{
User: user,
Zone: &Zone{
@ -142,61 +136,11 @@ func (zone *ZoneRequest) parse() error {
return nil
}
func (zone *ZoneRequest) save() error {
c, err := internal.ReadConfig()
if err != nil {
logHandler(genericResponseFields{"error": err.Error(), "message": "no config file defined"})
func (zone *ZoneRequest) save(path) error {
// clean up the tmp file
defer os.Remove(filepath.Clean("/tmp/" + zone.FileName))
return fmt.Errorf("unable to parse directory: %w", err)
}
var path string = fmt.Sprintf("%s/%s/", c.ZoneDir, zone.RawFileName)
var tmpPath string = fmt.Sprintf("/tmp/tmpfile-%s-%s", zone.RawFileName, zone.User)
if err = os.MkdirAll(path, 0o750); err != nil {
logHandler(genericResponseFields{"error": err.Error(), "message": "unable to make directory for zone files"})
return fmt.Errorf("unable to make zone directory: %w", err)
}
if _, err = os.Create(filepath.Clean(path + zone.RawFileName)); err != nil {
logHandler(genericResponseFields{"error": err.Error(), "message": "unable to save zonefile to directory"})
return fmt.Errorf("unable to save zonefile to directory: %w", err)
}
f, err := os.Open(filepath.Clean(tmpPath))
if err != nil {
logHandler(genericResponseFields{"error": err.Error(), "message": "unable to save zonefile to directory"})
return fmt.Errorf("unable to save zonefile to directory: %w", err)
}
defer func() {
if err = f.Close(); err != nil {
logHandler(genericResponseFields{"message": "Error closing file", "error": err.Error()})
}
if err = os.Remove(filepath.Clean(tmpPath)); err != nil {
logHandler(genericResponseFields{"message": "Error removing tmp file", "error": err.Error()})
}
}()
b, err := io.ReadAll(f)
if err != nil {
logHandler(genericResponseFields{"error": err.Error(), "message": "unable to save zonefile to directory"})
return fmt.Errorf("unable to save zonefile to directory: %w", err)
}
if err = os.WriteFile(path+zone.RawFileName, b, 0o600); err != nil {
logHandler(genericResponseFields{"error": err.Error(), "message": "unable to save zonefile to directory"})
return fmt.Errorf("unable to save zonefile to directory: %w", err)
}
return nil
return makeLocal(Perm, zone)
}
func validateContentType(file io.Reader) bool {

View file

@ -1,40 +0,0 @@
package util
import (
"errors"
"fmt"
"os"
)
var errEmptyFile = errors.New("will not save empty file to FS")
func MakeLocal(filename, username string, buf []byte) error {
if _, err := os.Stat(fmt.Sprintf("/tmp/tmpfile-%s-%s", filename, username)); !os.IsNotExist(err) {
return fmt.Errorf("file %s already exists: %w", filename, err)
}
if len(buf) == 0 {
return errEmptyFile
}
f, err := os.Create("/tmp/tmpfile-" + filename + "-" + username) //nolint: gosec
// this is set to nolint because I am doing everything os.CreateTemp does but here since I don't like some of the limitations
if err != nil {
return fmt.Errorf("failed to write file locally: %w", err)
}
// close and remove the temporary file at the end of the program
defer func() {
if err = f.Close(); err != nil {
return
}
}()
err = os.WriteFile(f.Name(), buf, 0o600)
if err != nil {
return fmt.Errorf("failed to write file locally: %w", err)
}
return nil
}