fix sec
Some checks failed
CloudSave/pipeline/head Something is wrong with the build of this commit

This commit is contained in:
2025-09-07 01:31:14 +02:00
parent af11e843a4
commit 46f312078d
12 changed files with 181 additions and 178 deletions

View File

@@ -1,60 +1,60 @@
package login package login
import ( import (
"cloudsave/cmd/cli/tools/prompt/credentials" "cloudsave/cmd/cli/tools/prompt/credentials"
"cloudsave/pkg/remote/client" "cloudsave/pkg/remote/client"
"context" "context"
"flag" "flag"
"fmt" "fmt"
"os" "os"
"github.com/google/subcommands" "github.com/google/subcommands"
) )
type ( type (
LoginCmd struct { LoginCmd struct {
} }
) )
func (*LoginCmd) Name() string { return "login" } func (*LoginCmd) Name() string { return "login" }
func (*LoginCmd) Synopsis() string { return "save IN PLAIN TEXT your credentials" } func (*LoginCmd) Synopsis() string { return "save IN PLAIN TEXT your credentials" }
func (*LoginCmd) Usage() string { func (*LoginCmd) Usage() string {
return `Usage: cloudsave login <SERVER_HOSTNAME> return `Usage: cloudsave login <SERVER_HOSTNAME>
Warning: this command saves the login into a plain text json file Warning: this command saves the login into a plain text json file
Options: Options:
` `
} }
func (p *LoginCmd) SetFlags(f *flag.FlagSet) { func (p *LoginCmd) SetFlags(f *flag.FlagSet) {
} }
func (p *LoginCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { func (p *LoginCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
if f.NArg() != 1 { if f.NArg() != 1 {
fmt.Fprintf(os.Stderr, "error: this command take 1 argument") fmt.Fprintf(os.Stderr, "error: this command take 1 argument")
return subcommands.ExitUsageError return subcommands.ExitUsageError
} }
server := f.Arg(0) server := f.Arg(0)
username, password, err := credentials.Read(server) username, password, err := credentials.Read(server)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "error: failed to read std output: %s", err) fmt.Fprintf(os.Stderr, "error: failed to read std output: %s", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
cli := client.New(server, username, password) cli := client.New(server, username, password)
if _, err := cli.Version(); err != nil { if _, err := cli.Version(); err != nil {
fmt.Fprintf(os.Stderr, "error: failed to login: %s", err) fmt.Fprintf(os.Stderr, "error: failed to login: %s", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
if err := credentials.Login(username, password, server); err != nil { if err := credentials.Login(username, password, server); err != nil {
fmt.Fprintf(os.Stderr, "error: failed to save login: %s", err) fmt.Fprintf(os.Stderr, "error: failed to save login: %s", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
fmt.Println("login information saved!") fmt.Println("login information saved!")
return subcommands.ExitSuccess return subcommands.ExitSuccess
} }

View File

@@ -1,43 +1,43 @@
package logout package logout
import ( import (
"cloudsave/cmd/cli/tools/prompt/credentials" "cloudsave/cmd/cli/tools/prompt/credentials"
"context" "context"
"flag" "flag"
"fmt" "fmt"
"os" "os"
"github.com/google/subcommands" "github.com/google/subcommands"
) )
type ( type (
LogoutCmd struct { LogoutCmd struct {
} }
) )
func (*LogoutCmd) Name() string { return "logout" } func (*LogoutCmd) Name() string { return "logout" }
func (*LogoutCmd) Synopsis() string { return "logout from a server" } func (*LogoutCmd) Synopsis() string { return "logout from a server" }
func (*LogoutCmd) Usage() string { func (*LogoutCmd) Usage() string {
return `Usage: cloudsave logout <SERVER_HOSTNAME> return `Usage: cloudsave logout <SERVER_HOSTNAME>
Options: Options:
` `
} }
func (p *LogoutCmd) SetFlags(f *flag.FlagSet) { func (p *LogoutCmd) SetFlags(f *flag.FlagSet) {
} }
func (p *LogoutCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { func (p *LogoutCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
if f.NArg() != 1 { if f.NArg() != 1 {
fmt.Fprintf(os.Stderr, "error: this command take 1 argument") fmt.Fprintf(os.Stderr, "error: this command take 1 argument")
return subcommands.ExitUsageError return subcommands.ExitUsageError
} }
if err := credentials.Logout(f.Arg(0)); err != nil { if err := credentials.Logout(f.Arg(0)); err != nil {
fmt.Fprintf(os.Stderr, "error: failed to logout: %s", err) fmt.Fprintf(os.Stderr, "error: failed to logout: %s", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
fmt.Println("bye!") fmt.Println("bye!")
return subcommands.ExitSuccess return subcommands.ExitSuccess
} }

View File

@@ -1,51 +1,51 @@
package show package show
import ( import (
"cloudsave/pkg/data" "cloudsave/pkg/data"
"context" "context"
"flag" "flag"
"fmt" "fmt"
"os" "os"
"github.com/google/subcommands" "github.com/google/subcommands"
) )
type ( type (
ShowCmd struct { ShowCmd struct {
Service *data.Service Service *data.Service
} }
) )
func (*ShowCmd) Name() string { return "show" } func (*ShowCmd) Name() string { return "show" }
func (*ShowCmd) Synopsis() string { return "show metadata about game" } func (*ShowCmd) Synopsis() string { return "show metadata about game" }
func (*ShowCmd) Usage() string { func (*ShowCmd) Usage() string {
return `Usage: cloudsave show <GAME_ID> return `Usage: cloudsave show <GAME_ID>
Show metdata about a game Show metdata about a game
` `
} }
func (p *ShowCmd) SetFlags(f *flag.FlagSet) { func (p *ShowCmd) SetFlags(f *flag.FlagSet) {
} }
func (p *ShowCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { func (p *ShowCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
if f.NArg() != 1 { if f.NArg() != 1 {
fmt.Fprintln(os.Stderr, "error: missing game ID") fmt.Fprintln(os.Stderr, "error: missing game ID")
return subcommands.ExitUsageError return subcommands.ExitUsageError
} }
gameID := f.Arg(0) gameID := f.Arg(0)
g, err := p.Service.One(gameID) g, err := p.Service.One(gameID)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "error: failed to apply: %s", err) fmt.Fprintf(os.Stderr, "error: failed to apply: %s", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
fmt.Println(g.Name) fmt.Println(g.Name)
fmt.Println("------") fmt.Println("------")
fmt.Println("Version: ", g.Version) fmt.Println("Version: ", g.Version)
fmt.Println("Path: ", g.Path) fmt.Println("Path: ", g.Path)
fmt.Println("MD5: ", g.MD5) fmt.Println("MD5: ", g.MD5)
return subcommands.ExitSuccess return subcommands.ExitSuccess
} }

View File

@@ -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, 0600) f, err := os.OpenFile(filepath.Clean(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)
} }
@@ -104,7 +104,7 @@ func save(store map[string]credential) error {
} }
func load() (map[string]credential, error) { func load() (map[string]credential, error) {
f, err := os.OpenFile(filepath.Join(datastorePath, "credential.json"), os.O_RDONLY, 0) f, err := os.OpenFile(filepath.Clean(filepath.Join(datastorePath, "credential.json")), os.O_RDONLY, 0)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
return make(map[string]credential), nil return make(map[string]credential), nil

View File

@@ -2,6 +2,7 @@ package htpasswd
import ( import (
"os" "os"
"path/filepath"
"strings" "strings"
) )
@@ -12,7 +13,7 @@ type (
) )
func Open(path string) (File, error) { func Open(path string) (File, error) {
c, err := os.ReadFile(path) c, err := os.ReadFile(filepath.Clean(path))
if err != nil { if err != nil {
return File{}, err return File{}, err
} }
@@ -26,7 +27,7 @@ func Open(path string) (File, error) {
if len(kv) != 2 { if len(kv) != 2 {
continue continue
} }
f.data[kv[0]] = kv[1] f.data[kv[0]] = kv[1]
} }
return f, nil return f, nil

View File

@@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"path/filepath"
) )
type ( type (
@@ -22,7 +23,7 @@ type (
) )
func Load(path string) (Configuration, error) { func Load(path string) (Configuration, error) {
f, err := os.OpenFile(path, os.O_RDONLY, 0) f, err := os.OpenFile(filepath.Clean(path), os.O_RDONLY, 0)
if err != nil { if err != nil {
return Configuration{}, fmt.Errorf("failed to open configuration file: %w", err) return Configuration{}, fmt.Errorf("failed to open configuration file: %w", err)
} }

View File

@@ -400,7 +400,7 @@ func (l Service) apply(src, dst string) error {
return fmt.Errorf("failed to remove old save: %w", err) return fmt.Errorf("failed to remove old save: %w", err)
} }
f, err := os.OpenFile(src, os.O_RDONLY, 0) f, err := os.OpenFile(filepath.Clean(src), os.O_RDONLY, 0)
if err != nil { if err != nil {
return fmt.Errorf("failed to open archive: %w", err) return fmt.Errorf("failed to open archive: %w", err)
} }

View File

@@ -14,6 +14,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"path/filepath"
"strconv" "strconv"
"time" "time"
@@ -221,12 +222,12 @@ 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, 0600) f, err := os.OpenFile(filepath.Clean(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)
} }
defer func() { defer func() {
if err := os.Rename(archivePath+".part", archivePath); err != nil { if err := os.Rename(filepath.Clean(archivePath+".part"), archivePath); err != nil {
panic(err) panic(err)
} }
}() }()
@@ -276,7 +277,7 @@ 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, 0600) f, err := os.OpenFile(filepath.Clean(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)
} }
@@ -422,7 +423,7 @@ func (c *Client) get(url string) (obj.HTTPObject, error) {
} }
func (c *Client) push(u, archivePath string, m repository.Metadata) error { func (c *Client) push(u, archivePath string, m repository.Metadata) error {
f, err := os.OpenFile(archivePath, os.O_RDONLY, 0) f, err := os.OpenFile(filepath.Clean(archivePath), os.O_RDONLY, 0)
if err != nil { if err != nil {
return fmt.Errorf("failed to open file: %w", err) return fmt.Errorf("failed to open file: %w", err)
} }

View File

@@ -39,7 +39,7 @@ func init() {
} }
func One(gameID string) (Remote, error) { func One(gameID string) (Remote, error) {
content, err := os.ReadFile(filepath.Join(datastorepath, gameID, "remote.json")) content, err := os.ReadFile(filepath.Clean(filepath.Join(datastorepath, gameID, "remote.json")))
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
return Remote{}, ErrNoRemote return Remote{}, ErrNoRemote
@@ -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, 0600) f, err := os.OpenFile(filepath.Join(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
} }

View File

@@ -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, 0600) dst, err := os.OpenFile(filepath.Clean(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, 0600) dst, err := os.OpenFile(filepath.Clean(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)
} }
@@ -213,7 +213,7 @@ func (l *LazyRepository) Metadata(id GameIdentifier) (Metadata, error) {
path := l.DataPath(id) path := l.DataPath(id)
slog.Debug("loading metadata", "id", id) slog.Debug("loading metadata", "id", id)
src, err := os.OpenFile(filepath.Join(path, "metadata.json"), os.O_RDONLY, 0) src, err := os.OpenFile(filepath.Clean(filepath.Join(path, "metadata.json")), os.O_RDONLY, 0)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
return Metadata{}, ErrNotFound return Metadata{}, ErrNotFound
@@ -272,7 +272,7 @@ func (l *LazyRepository) Backup(id BackupIdentifier) (Backup, error) {
func (l *LazyRepository) LastScan(id GameIdentifier) (time.Time, error) { func (l *LazyRepository) LastScan(id GameIdentifier) (time.Time, error) {
path := l.DataPath(id) path := l.DataPath(id)
data, err := os.ReadFile(filepath.Join(path, ".last_run")) data, err := os.ReadFile(filepath.Clean(filepath.Join(path, ".last_run")))
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
return time.Time{}, nil return time.Time{}, nil
@@ -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, 0600) f, err := os.OpenFile(filepath.Clean(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)
} }
@@ -311,7 +311,7 @@ func (l *LazyRepository) ReadBlob(id Identifier) (io.ReadSeekCloser, error) {
path := l.DataPath(id) path := l.DataPath(id)
slog.Debug("loading read buffer...", "id", id) slog.Debug("loading read buffer...", "id", id)
dst, err := os.OpenFile(filepath.Join(path, "data.tar.gz"), os.O_RDONLY, 0) dst, err := os.OpenFile(filepath.Clean(filepath.Join(path, "data.tar.gz")), os.O_RDONLY, 0)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
return nil, fmt.Errorf("failed to open blob: %w", ErrNotFound) return nil, fmt.Errorf("failed to open blob: %w", ErrNotFound)
@@ -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, 0600) src, err := os.OpenFile(filepath.Clean(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)
} }
@@ -345,7 +345,7 @@ func (l *LazyRepository) SetRemote(id GameIdentifier, url string) error {
func (l *LazyRepository) Remote(id GameIdentifier) (*Remote, error) { func (l *LazyRepository) Remote(id GameIdentifier) (*Remote, error) {
path := l.DataPath(id) path := l.DataPath(id)
src, err := os.OpenFile(filepath.Join(path, "remote.json"), os.O_RDONLY, 0) src, err := os.OpenFile(filepath.Clean(filepath.Join(path, "remote.json")), os.O_RDONLY, 0)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
return nil, nil return nil, nil

View File

@@ -44,7 +44,7 @@ func Untar(file io.Reader, path string) error {
} }
// the target location where the dir/file should be created // the target location where the dir/file should be created
target := filepath.Join(path, header.Name) target := filepath.Clean(filepath.Join(path, filepath.Clean(header.Name)))
// the following switch could also be done using fi.Mode(), not sure if there // the following switch could also be done using fi.Mode(), not sure if there
// a benefit of using one vs. the other. // a benefit of using one vs. the other.
@@ -122,7 +122,7 @@ func Tar(file io.Writer, root string) error {
return nil return nil
} }
file, err := os.Open(path) file, err := os.Open(filepath.Clean(path))
if err != nil { if err != nil {
return fmt.Errorf("failed to open file: %w", err) return fmt.Errorf("failed to open file: %w", err)
} }

View File

@@ -5,16 +5,16 @@ import (
"encoding/hex" "encoding/hex"
"io" "io"
"os" "os"
"path/filepath"
) )
func FileMD5(fp string) (string, error) { func FileMD5(fp string) (string, error) {
f, err := os.OpenFile(fp, os.O_RDONLY, 0) f, err := os.OpenFile(filepath.Clean(fp), os.O_RDONLY, 0)
if err != nil { if err != nil {
return "", err return "", err
} }
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