wings/server/filesystem/stat.go
Matthew Penner d1c0ca5260
server(filesystem): rebuild everything imaginable
This wonderfully large commit replaces basically everything under the
`server/filesystem` package, re-implementing essentially everything.

This is related to
https://github.com/pterodactyl/wings/security/advisories/GHSA-494h-9924-xww9

If any vulnerabilities related to symlinks persist after this commit, I
will be very upset.

Signed-off-by: Matthew Penner <me@matthewp.io>
2024-03-13 12:27:29 -06:00

85 lines
1.9 KiB
Go

package filesystem
import (
"encoding/json"
"io"
"strconv"
"time"
"github.com/gabriel-vasile/mimetype"
"github.com/pterodactyl/wings/internal/ufs"
)
type Stat struct {
ufs.FileInfo
Mimetype string
}
func (s *Stat) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Name string `json:"name"`
Created string `json:"created"`
Modified string `json:"modified"`
Mode string `json:"mode"`
ModeBits string `json:"mode_bits"`
Size int64 `json:"size"`
Directory bool `json:"directory"`
File bool `json:"file"`
Symlink bool `json:"symlink"`
Mime string `json:"mime"`
}{
Name: s.Name(),
Created: s.CTime().Format(time.RFC3339),
Modified: s.ModTime().Format(time.RFC3339),
Mode: s.Mode().String(),
// Using `&ModePerm` on the file's mode will cause the mode to only have the permission values, and nothing else.
ModeBits: strconv.FormatUint(uint64(s.Mode()&ufs.ModePerm), 8),
Size: s.Size(),
Directory: s.IsDir(),
File: !s.IsDir(),
Symlink: s.Mode().Perm()&ufs.ModeSymlink != 0,
Mime: s.Mimetype,
})
}
func statFromFile(f ufs.File) (Stat, error) {
s, err := f.Stat()
if err != nil {
return Stat{}, err
}
var m *mimetype.MIME
if !s.IsDir() {
m, err = mimetype.DetectReader(f)
if err != nil {
return Stat{}, err
}
if _, err := f.Seek(0, io.SeekStart); err != nil {
return Stat{}, err
}
}
st := Stat{
FileInfo: s,
Mimetype: "inode/directory",
}
if m != nil {
st.Mimetype = m.String()
}
return st, nil
}
// Stat stats a file or folder and returns the base stat object from go along
// with the MIME data that can be used for editing files.
func (fs *Filesystem) Stat(p string) (Stat, error) {
f, err := fs.unixFS.Open(p)
if err != nil {
return Stat{}, err
}
defer f.Close()
st, err := statFromFile(f)
if err != nil {
return Stat{}, err
}
return st, nil
}