fixing sec issues
Some checks failed
CloudSave/pipeline/head There was a failure building this commit
Some checks failed
CloudSave/pipeline/head There was a failure building this commit
This commit is contained in:
@@ -63,9 +63,15 @@ func (p *SyncCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{})
|
|||||||
|
|
||||||
pg := progressbar.New(-1)
|
pg := progressbar.New(-1)
|
||||||
destroyPg := func() {
|
destroyPg := func() {
|
||||||
pg.Finish()
|
if err := pg.Finish(); err != nil {
|
||||||
pg.Clear()
|
slog.Error("failed to finish progressbar", "err", err)
|
||||||
pg.Close()
|
}
|
||||||
|
if err := pg.Clear(); err != nil {
|
||||||
|
slog.Error("failed to clear progressbar", "err", err)
|
||||||
|
}
|
||||||
|
if err := pg.Close(); err != nil {
|
||||||
|
slog.Error("failed to close progressbar", "err", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pg.Describe(fmt.Sprintf("[%s] Checking status...", g.Name))
|
pg.Describe(fmt.Sprintf("[%s] Checking status...", g.Name))
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
datastorepath := filepath.Join(roaming, "cloudsave", "data")
|
datastorepath := filepath.Join(roaming, "cloudsave", "data")
|
||||||
err = os.MkdirAll(datastorepath, 0740)
|
err = os.MkdirAll(datastorepath, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("cannot make the datastore:" + err.Error())
|
panic("cannot make the datastore:" + err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ func save(store map[string]credential) error {
|
|||||||
Store: store,
|
Store: store,
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.OpenFile(filepath.Join(datastorePath, "credential.json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740)
|
f, err := os.OpenFile(filepath.Join(datastorePath, "credential.json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open datastore: %w", err)
|
return fmt.Errorf("failed to open datastore: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,8 +74,9 @@ func NewServer(documentRoot string, srv *data.Service, creds map[string]string,
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
s.Server = &http.Server{
|
s.Server = &http.Server{
|
||||||
Addr: fmt.Sprintf(":%d", port),
|
Addr: fmt.Sprintf(":%d", port),
|
||||||
Handler: router,
|
Handler: router,
|
||||||
|
ReadHeaderTimeout: 2,
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,9 @@ func run(updateChan <-chan struct{}) {
|
|||||||
for {
|
for {
|
||||||
<-updateChan
|
<-updateChan
|
||||||
if r, ok := repo.(*repository.EagerRepository); ok {
|
if r, ok := repo.(*repository.EagerRepository); ok {
|
||||||
r.Reload()
|
if err := r.Reload(); err != nil {
|
||||||
|
fatal("failed to reload data: "+err.Error(), 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
h, err := htpasswd.Open(filepath.Join(documentRoot, ".htpasswd"))
|
h, err := htpasswd.Open(filepath.Join(documentRoot, ".htpasswd"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -74,13 +74,19 @@ var (
|
|||||||
// NewServer start the http server
|
// NewServer start the http server
|
||||||
func NewServer(c config.Configuration) *HTTPServer {
|
func NewServer(c config.Configuration) *HTTPServer {
|
||||||
dashboardTemplate := template.New("dashboard")
|
dashboardTemplate := template.New("dashboard")
|
||||||
dashboardTemplate.Parse(DashboardHTMLPage)
|
if _, err := dashboardTemplate.Parse(DashboardHTMLPage); err != nil {
|
||||||
|
panic("failed to load template 'dashboard': " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
detailledTemplate := template.New("detailled")
|
detailledTemplate := template.New("detailled")
|
||||||
detailledTemplate.Parse(DetailledHTMLPage)
|
if _, err := detailledTemplate.Parse(DetailledHTMLPage); err != nil {
|
||||||
|
panic("failed to load template 'detailled': " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
systemTemplate := template.New("system")
|
systemTemplate := template.New("system")
|
||||||
systemTemplate.Parse(SystemHTMLPage)
|
if _, err := systemTemplate.Parse(SystemHTMLPage); err != nil {
|
||||||
|
panic("failed to load template 'system': " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
s := &HTTPServer{
|
s := &HTTPServer{
|
||||||
Config: c,
|
Config: c,
|
||||||
@@ -99,8 +105,9 @@ func NewServer(c config.Configuration) *HTTPServer {
|
|||||||
routerAPI.Get("/system", s.system)
|
routerAPI.Get("/system", s.system)
|
||||||
})
|
})
|
||||||
s.Server = &http.Server{
|
s.Server = &http.Server{
|
||||||
Addr: fmt.Sprintf(":%d", c.Server.Port),
|
Addr: fmt.Sprintf(":%d", c.Server.Port),
|
||||||
Handler: router,
|
Handler: router,
|
||||||
|
ReadHeaderTimeout: 2,
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ pipeline {
|
|||||||
steps {
|
steps {
|
||||||
sh '''
|
sh '''
|
||||||
go install github.com/securego/gosec/v2/cmd/gosec@v2.22.8
|
go install github.com/securego/gosec/v2/cmd/gosec@v2.22.8
|
||||||
/var/lib/jenkins/go/bin/gosec ./...
|
go install honnef.co/go/tools/cmd/staticcheck@v0.6.1
|
||||||
|
|
||||||
|
/var/lib/jenkins/go/bin/staticcheck ./...
|
||||||
|
/var/lib/jenkins/go/bin/gosec -exclude="G401,G501,G103" ./...
|
||||||
'''
|
'''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ func (l Service) PullCurrent(id, path string, cli *client.Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(path, 0740); err != nil {
|
if err := os.MkdirAll(path, 0600); err != nil {
|
||||||
return fmt.Errorf("failed to create destination directory: %w", err)
|
return fmt.Errorf("failed to create destination directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log/slog"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -220,7 +221,7 @@ func (c *Client) Pull(gameID, archivePath string) error {
|
|||||||
|
|
||||||
req.SetBasicAuth(c.username, c.password)
|
req.SetBasicAuth(c.username, c.password)
|
||||||
|
|
||||||
f, err := os.OpenFile(archivePath+".part", os.O_CREATE|os.O_WRONLY, 0740)
|
f, err := os.OpenFile(archivePath+".part", os.O_CREATE|os.O_WRONLY, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open file: %w", err)
|
return fmt.Errorf("failed to open file: %w", err)
|
||||||
}
|
}
|
||||||
@@ -275,20 +276,24 @@ func (c *Client) PullBackup(gameID, uuid, archivePath string) error {
|
|||||||
|
|
||||||
req.SetBasicAuth(c.username, c.password)
|
req.SetBasicAuth(c.username, c.password)
|
||||||
|
|
||||||
f, err := os.OpenFile(archivePath+".part", os.O_CREATE|os.O_WRONLY, 0740)
|
f, err := os.OpenFile(archivePath+".part", os.O_CREATE|os.O_WRONLY, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open file: %w", err)
|
return fmt.Errorf("failed to open file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := cli.Do(req)
|
res, err := cli.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.Close()
|
if err := f.Close(); err != nil {
|
||||||
|
slog.Error("failed to close file", "err", err)
|
||||||
|
}
|
||||||
return fmt.Errorf("cannot connect to remote: %w", err)
|
return fmt.Errorf("cannot connect to remote: %w", err)
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
f.Close()
|
if err := f.Close(); err != nil {
|
||||||
|
slog.Error("failed to close file", "err", err)
|
||||||
|
}
|
||||||
return fmt.Errorf("cannot connect to remote: server return code: %s", res.Status)
|
return fmt.Errorf("cannot connect to remote: server return code: %s", res.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,10 +304,14 @@ func (c *Client) PullBackup(gameID, uuid, archivePath string) error {
|
|||||||
defer bar.Close()
|
defer bar.Close()
|
||||||
|
|
||||||
if _, err := io.Copy(io.MultiWriter(f, bar), res.Body); err != nil {
|
if _, err := io.Copy(io.MultiWriter(f, bar), res.Body); err != nil {
|
||||||
f.Close()
|
if err := f.Close(); err != nil {
|
||||||
|
slog.Error("failed to close file", "err", err)
|
||||||
|
}
|
||||||
return fmt.Errorf("an error occured while copying the file from the remote: %w", err)
|
return fmt.Errorf("an error occured while copying the file from the remote: %w", err)
|
||||||
}
|
}
|
||||||
f.Close()
|
if err := f.Close(); err != nil {
|
||||||
|
slog.Error("failed to close file", "err", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := os.Rename(archivePath+".part", archivePath); err != nil {
|
if err := os.Rename(archivePath+".part", archivePath); err != nil {
|
||||||
return fmt.Errorf("failed to move temporary data: %w", err)
|
return fmt.Errorf("failed to move temporary data: %w", err)
|
||||||
@@ -431,9 +440,15 @@ func (c *Client) push(u, archivePath string, m repository.Metadata) error {
|
|||||||
return fmt.Errorf("failed to copy data: %w", err)
|
return fmt.Errorf("failed to copy data: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteField("name", m.Name)
|
if err := writer.WriteField("name", m.Name); err != nil {
|
||||||
writer.WriteField("version", strconv.Itoa(m.Version))
|
return err
|
||||||
writer.WriteField("date", m.Date.Format(time.RFC3339))
|
}
|
||||||
|
if err := writer.WriteField("version", strconv.Itoa(m.Version)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := writer.WriteField("date", m.Date.Format(time.RFC3339)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := writer.Close(); err != nil {
|
if err := writer.Close(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
datastorepath = filepath.Join(roaming, "cloudsave", "data")
|
datastorepath = filepath.Join(roaming, "cloudsave", "data")
|
||||||
err = os.MkdirAll(datastorepath, 0740)
|
err = os.MkdirAll(datastorepath, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("cannot make the datastore:" + err.Error())
|
panic("cannot make the datastore:" + err.Error())
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ func Set(gameID, url string) error {
|
|||||||
URL: url,
|
URL: url,
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.OpenFile(filepath.Join(datastorepath, gameID, "remote.json"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0740)
|
f, err := os.OpenFile(filepath.Join(datastorepath, gameID, "remote.json"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ func (bi BackupIdentifier) Key() string {
|
|||||||
func NewLazyRepository(dataRootPath string) (*LazyRepository, error) {
|
func NewLazyRepository(dataRootPath string) (*LazyRepository, error) {
|
||||||
if m, err := os.Stat(dataRootPath); err != nil {
|
if m, err := os.Stat(dataRootPath); err != nil {
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
if err := os.MkdirAll(dataRootPath, 0740); err != nil {
|
if err := os.MkdirAll(dataRootPath, 0600); err != nil {
|
||||||
return nil, fmt.Errorf("failed to make the directory: %w", err)
|
return nil, fmt.Errorf("failed to make the directory: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -137,8 +137,8 @@ func NewLazyRepository(dataRootPath string) (*LazyRepository, error) {
|
|||||||
func (l *LazyRepository) Mkdir(id Identifier) error {
|
func (l *LazyRepository) Mkdir(id Identifier) error {
|
||||||
path := l.DataPath(id)
|
path := l.DataPath(id)
|
||||||
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
|
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
|
||||||
slog.Debug("making directory", "path", path, "id", id, "perm", "0740")
|
slog.Debug("making directory", "path", path, "id", id, "perm", "0600")
|
||||||
return os.MkdirAll(path, 0740)
|
return os.MkdirAll(path, 0600)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ func (l *LazyRepository) WriteBlob(ID Identifier) (io.Writer, error) {
|
|||||||
path := l.DataPath(ID)
|
path := l.DataPath(ID)
|
||||||
|
|
||||||
slog.Debug("loading write buffer...", "id", ID)
|
slog.Debug("loading write buffer...", "id", ID)
|
||||||
dst, err := os.OpenFile(filepath.Join(path, "data.tar.gz"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740)
|
dst, err := os.OpenFile(filepath.Join(path, "data.tar.gz"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to open destination file: %w", err)
|
return nil, fmt.Errorf("failed to open destination file: %w", err)
|
||||||
}
|
}
|
||||||
@@ -195,7 +195,7 @@ func (l *LazyRepository) WriteMetadata(id GameIdentifier, m Metadata) error {
|
|||||||
path := l.DataPath(id)
|
path := l.DataPath(id)
|
||||||
|
|
||||||
slog.Debug("writing metadata", "id", id, "metadata", m)
|
slog.Debug("writing metadata", "id", id, "metadata", m)
|
||||||
dst, err := os.OpenFile(filepath.Join(path, "metadata.json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740)
|
dst, err := os.OpenFile(filepath.Join(path, "metadata.json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open destination file: %w", err)
|
return fmt.Errorf("failed to open destination file: %w", err)
|
||||||
}
|
}
|
||||||
@@ -292,7 +292,7 @@ func (l *LazyRepository) ResetLastScan(id GameIdentifier) error {
|
|||||||
path := l.DataPath(id)
|
path := l.DataPath(id)
|
||||||
|
|
||||||
slog.Debug("resetting last scan datetime for", "id", id)
|
slog.Debug("resetting last scan datetime for", "id", id)
|
||||||
f, err := os.OpenFile(filepath.Join(path, ".last_run"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740)
|
f, err := os.OpenFile(filepath.Join(path, ".last_run"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open file: %w", err)
|
return fmt.Errorf("failed to open file: %w", err)
|
||||||
}
|
}
|
||||||
@@ -325,7 +325,7 @@ func (l *LazyRepository) ReadBlob(id Identifier) (io.ReadSeekCloser, error) {
|
|||||||
func (l *LazyRepository) SetRemote(id GameIdentifier, url string) error {
|
func (l *LazyRepository) SetRemote(id GameIdentifier, url string) error {
|
||||||
path := l.DataPath(id)
|
path := l.DataPath(id)
|
||||||
|
|
||||||
src, err := os.OpenFile(filepath.Join(path, "remote.json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740)
|
src, err := os.OpenFile(filepath.Join(path, "remote.json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open remote description: %w", err)
|
return fmt.Errorf("failed to open remote description: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,17 @@ import (
|
|||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Tune these to your app’s needs
|
||||||
|
maxCompressedUpload = 500 << 20 // 500 MiB compressed
|
||||||
|
maxUncompressedOutput = 1000 << 20 // 100 MiB after inflate
|
||||||
|
)
|
||||||
|
|
||||||
func Untar(file io.Reader, path string) error {
|
func Untar(file io.Reader, path string) error {
|
||||||
gzr, err := gzip.NewReader(file)
|
gzr, err := gzip.NewReader(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -49,26 +56,35 @@ func Untar(file io.Reader, path string) error {
|
|||||||
// if its a dir and it doesn't exist create it
|
// if its a dir and it doesn't exist create it
|
||||||
case tar.TypeDir:
|
case tar.TypeDir:
|
||||||
if _, err := os.Stat(target); err != nil {
|
if _, err := os.Stat(target); err != nil {
|
||||||
if err := os.MkdirAll(target, 0755); err != nil {
|
if err := os.MkdirAll(target, 0600); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if it's a file create it
|
// if it's a file create it
|
||||||
case tar.TypeReg:
|
case tar.TypeReg:
|
||||||
f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
|
f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, header.FileInfo().Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
limited := &io.LimitedReader{R: gzr, N: maxUncompressedOutput}
|
||||||
|
|
||||||
// copy over contents
|
// copy over contents
|
||||||
if _, err := io.Copy(f, tr); err != nil {
|
if _, err := io.Copy(f, limited); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// manually close here after each file operation; defering would cause each file close
|
// manually close here after each file operation; defering would cause each file close
|
||||||
// to wait until all operations have completed.
|
// to wait until all operations have completed.
|
||||||
f.Close()
|
if err := f.Close(); err != nil {
|
||||||
|
slog.Error("failed to close file", "err", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if limited.N == 0 {
|
||||||
|
// Limit exhausted → likely bomb
|
||||||
|
return fmt.Errorf("payload too large after decompression")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ func FileMD5(fp string) (string, error) {
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
|
|
||||||
hasher := md5.New()
|
hasher := md5.New()
|
||||||
if _, err := io.Copy(hasher, f); err != nil {
|
if _, err := io.Copy(hasher, f); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|||||||
Reference in New Issue
Block a user