diff --git a/.gitignore b/.gitignore index 24c3851f21..a40c085753 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ vendor .bak .idea/ .vscode/ +.fleet/ /celestia /cel-shed /cel-key diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000000..e96968440a --- /dev/null +++ b/build.ps1 @@ -0,0 +1,6 @@ +del -Recurse -Force .\build\* +gofmt -e -s -w . +go mod tidy +$LDFLAGS="-ldflags=-X 'main.buildTime=$(date)' -X 'main.lastCommit=$(git rev-parse HEAD)' -X 'main.semanticVersion=$(git describe --tags --dirty=-dev)'" +go build -o build/ ${LDFLAGS} ./cmd/celestia +go build -o build/ ./cmd/cel-key \ No newline at end of file diff --git a/go.mod b/go.mod index 1c76383ffa..aa89937a2a 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/cosmos/cosmos-sdk v0.46.14 github.com/cosmos/cosmos-sdk/api v0.1.0 github.com/cristalhq/jwt v1.2.0 + github.com/danjacques/gofslock v0.0.0-20230227034627-eebdc482a3f5 github.com/etclabscore/go-openrpc-reflect v0.0.37 github.com/filecoin-project/dagstore v0.5.6 github.com/filecoin-project/go-jsonrpc v0.3.1 @@ -69,6 +70,7 @@ require ( golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 golang.org/x/sync v0.4.0 + golang.org/x/sys v0.13.0 golang.org/x/text v0.13.0 google.golang.org/grpc v1.58.2 google.golang.org/protobuf v1.31.0 @@ -324,7 +326,6 @@ require ( golang.org/x/mod v0.12.0 // indirect golang.org/x/net v0.14.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect - golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect diff --git a/go.sum b/go.sum index 4e31203f91..e0586598fc 100644 --- a/go.sum +++ b/go.sum @@ -517,6 +517,8 @@ github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TI github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/danjacques/gofslock v0.0.0-20230227034627-eebdc482a3f5 h1:/KFLY9ggaJT/mANX95q8ByhRR+9A3gWFrTz6ifkhOV8= +github.com/danjacques/gofslock v0.0.0-20230227034627-eebdc482a3f5/go.mod h1:9LABMmUSkKzt6FVQNEWdUTM0bz8Bt8MPyEcuZe0Sr8c= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/libs/fslock/lock_unix.go b/libs/fslock/lock_unix.go deleted file mode 100644 index bbb8db8537..0000000000 --- a/libs/fslock/lock_unix.go +++ /dev/null @@ -1,48 +0,0 @@ -//go:build darwin || freebsd || linux - -package fslock - -import ( - "fmt" - "os" - "strconv" - "syscall" -) - -func (l *Locker) lock() (err error) { - l.file, err = os.OpenFile(l.path, os.O_CREATE|os.O_RDWR, 0666) - if err != nil { - return fmt.Errorf("fslock: error opening file: %w", err) - } - - _, err = l.file.WriteString(strconv.Itoa(os.Getpid())) - if err != nil { - return fmt.Errorf("fslock: error writing process id: %w", err) - } - - err = syscall.Flock(int(l.file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) - if err != nil && err.Error() == "resource temporarily unavailable" { - return ErrLocked // we have to check here for a string in err, as there is no error types defined for this case. - } - if err != nil { - return fmt.Errorf("fslock: flocking error: %w", err) - } - - return -} - -func (l *Locker) unlock() error { - err := syscall.Flock(int(l.file.Fd()), syscall.LOCK_UN|syscall.LOCK_NB) - if err != nil { - return fmt.Errorf("fslock: unflocking error: %w", err) - } - - file := l.file - l.file = nil - err = file.Close() - if err != nil { - return fmt.Errorf("fslock: while closing file: %w", err) - } - - return os.Remove(l.path) -} diff --git a/libs/fslock/locker.go b/libs/fslock/locker.go deleted file mode 100644 index f451c42cc1..0000000000 --- a/libs/fslock/locker.go +++ /dev/null @@ -1,49 +0,0 @@ -package fslock - -import ( - "errors" - "os" -) - -// ErrLocked is signaled when someone tries to lock an already locked file. -var ErrLocked = errors.New("fslock: directory is locked") - -// Lock creates a new Locker under the given 'path' -// and immediately does Lock on it. -func Lock(path string) (*Locker, error) { - l := New(path) - err := l.Lock() - if err != nil { - return nil, err - } - - return l, nil -} - -// Locker is a simple utility meant to create lock files. -// This is to prevent multiple processes from managing the same working directory by purpose or -// accident. NOTE: Windows is not supported. -type Locker struct { - file *os.File - path string -} - -// New creates a new Locker with a File pointing to the given 'path'. -func New(path string) *Locker { - return &Locker{path: path} -} - -// Lock locks the file. -// Subsequent calls will error with ErrLocked on any Locker instance looking to the same path. -func (l *Locker) Lock() error { - return l.lock() -} - -// Unlock frees up the lock. -func (l *Locker) Unlock() error { - if l == nil || l.file == nil { - return nil - } - - return l.unlock() -} diff --git a/libs/fslock/locker_test.go b/libs/fslock/locker_test.go deleted file mode 100644 index c80ce51c16..0000000000 --- a/libs/fslock/locker_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package fslock - -import ( - "os" - "path/filepath" - "testing" -) - -func TestLocker(t *testing.T) { - path := filepath.Join(os.TempDir(), ".lock") - defer os.Remove(path) - - locker := New(path) - locker2 := New(path) - - err := locker.Lock() - if err != nil { - t.Fatal(err) - } - - err = locker2.Lock() - if err != ErrLocked { - t.Fatal("No locking") - } - - err = locker.Unlock() - if err != nil { - t.Fatal(err) - } - - err = locker2.Lock() - if err != nil { - t.Fatal(err) - } - - err = locker2.Unlock() - if err != nil { - t.Fatal(err) - } -} diff --git a/libs/keystore/fs_keystore.go b/libs/keystore/fs_keystore.go index 02361f0084..ac1891145e 100644 --- a/libs/keystore/fs_keystore.go +++ b/libs/keystore/fs_keystore.go @@ -59,7 +59,7 @@ func (f *fsKeystore) Put(n KeyName, pk PrivKey) error { func (f *fsKeystore) Get(n KeyName) (PrivKey, error) { path := f.pathTo(n.Base32()) - st, err := os.Stat(path) + _, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { return PrivKey{}, fmt.Errorf("%w: %s", ErrNotFound, n) @@ -68,7 +68,7 @@ func (f *fsKeystore) Get(n KeyName) (PrivKey, error) { return PrivKey{}, fmt.Errorf("keystore: check before reading key '%s' failed: %w", n, err) } - if err := checkPerms(st.Mode()); err != nil { + if err := keyAccess(path); err != nil { return PrivKey{}, fmt.Errorf("keystore: permissions of key '%s' are too relaxed: %w", n, err) } @@ -115,7 +115,7 @@ func (f *fsKeystore) List() ([]KeyName, error) { return nil, err } - if err := checkPerms(e.Type()); err != nil { + if err := keyAccess(f.pathTo(kn.Base32())); err != nil { return nil, fmt.Errorf("keystore: permissions of key '%s' are too relaxed: %w", kn, err) } @@ -136,10 +136,3 @@ func (f *fsKeystore) Keyring() keyring.Keyring { func (f *fsKeystore) pathTo(file string) string { return filepath.Join(f.path, file) } - -func checkPerms(perms os.FileMode) error { - if perms&0077 != 0 { - return fmt.Errorf("required: 0600, got: %#o", perms) - } - return nil -} diff --git a/libs/keystore/key_access_unix.go b/libs/keystore/key_access_unix.go new file mode 100644 index 0000000000..ae159e99da --- /dev/null +++ b/libs/keystore/key_access_unix.go @@ -0,0 +1,19 @@ +//go:build darwin || freebsd || linux + +package keystore + +import ( + "fmt" + "os" +) + +// keyAccess checks whether file is not accessible by all users. +func keyAccess(path string) error { + st, _ := os.Stat(path) + mode := st.Mode() + if mode&0077 != 0 { + return fmt.Errorf("required: 0600, got: %#o", mode) + } + + return nil +} diff --git a/libs/keystore/key_access_win.go b/libs/keystore/key_access_win.go new file mode 100644 index 0000000000..1caca82743 --- /dev/null +++ b/libs/keystore/key_access_win.go @@ -0,0 +1,30 @@ +//go:build windows + +package keystore + +import ( + "fmt" + "golang.org/x/sys/windows" + "unsafe" +) + +// keyAccess checks whether file is not accessible by all users. +func keyAccess(path string) error { + + // Check the file's DACL + securityDescriptor, err := windows.GetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION) + if err != nil { + return fmt.Errorf("Error getting file's DACL: %v\n", err) + } + defer func() { + if err != nil { + _, _ = windows.LocalFree((windows.Handle)(unsafe.Pointer(securityDescriptor))) + } + }() + _, _, err = securityDescriptor.DACL() + if err != nil { + return fmt.Errorf("File is too Open with no DACL: %v\n", err) + } + + return nil +} diff --git a/nodebuilder/config.go b/nodebuilder/config.go index 41f24d6d3d..5b595b6ac6 100644 --- a/nodebuilder/config.go +++ b/nodebuilder/config.go @@ -7,7 +7,6 @@ import ( "github.com/BurntSushi/toml" "github.com/imdario/mergo" - "github.com/celestiaorg/celestia-node/libs/fslock" "github.com/celestiaorg/celestia-node/nodebuilder/core" "github.com/celestiaorg/celestia-node/nodebuilder/das" "github.com/celestiaorg/celestia-node/nodebuilder/gateway" @@ -17,6 +16,8 @@ import ( "github.com/celestiaorg/celestia-node/nodebuilder/rpc" "github.com/celestiaorg/celestia-node/nodebuilder/share" "github.com/celestiaorg/celestia-node/nodebuilder/state" + + "github.com/danjacques/gofslock/fslock" ) // ConfigLoader defines a function that loads a config from any source. @@ -67,7 +68,7 @@ func SaveConfig(path string, cfg *Config) error { if err != nil { return err } - defer f.Close() + defer f.Close() //nolint: errcheck return cfg.Encode(f) } @@ -93,7 +94,7 @@ func RemoveConfig(path string) (err error) { flock, err := fslock.Lock(lockPath(path)) if err != nil { - if err == fslock.ErrLocked { + if err == fslock.ErrLockHeld { err = ErrOpened } return @@ -119,7 +120,7 @@ func UpdateConfig(tp node.Type, path string) (err error) { flock, err := fslock.Lock(lockPath(path)) if err != nil { - if err == fslock.ErrLocked { + if err == fslock.ErrLockHeld { err = ErrOpened } return err diff --git a/nodebuilder/init.go b/nodebuilder/init.go index 0593d88560..bd5399a312 100644 --- a/nodebuilder/init.go +++ b/nodebuilder/init.go @@ -12,10 +12,11 @@ import ( "github.com/celestiaorg/celestia-app/app" "github.com/celestiaorg/celestia-app/app/encoding" - "github.com/celestiaorg/celestia-node/libs/fslock" "github.com/celestiaorg/celestia-node/libs/utils" "github.com/celestiaorg/celestia-node/nodebuilder/node" "github.com/celestiaorg/celestia-node/nodebuilder/state" + + "github.com/danjacques/gofslock/fslock" ) // PrintKeyringInfo whether to print keyring information during init. @@ -37,7 +38,7 @@ func Init(cfg Config, path string, tp node.Type) error { flock, err := fslock.Lock(lockPath(path)) if err != nil { - if err == fslock.ErrLocked { + if err == fslock.ErrLockHeld { return ErrOpened } return err @@ -84,7 +85,7 @@ func Reset(path string, tp node.Type) error { flock, err := fslock.Lock(lockPath(path)) if err != nil { - if err == fslock.ErrLocked { + if err == fslock.ErrLockHeld { return ErrOpened } return err diff --git a/nodebuilder/init_test.go b/nodebuilder/init_test.go index e438a191bc..851220a74a 100644 --- a/nodebuilder/init_test.go +++ b/nodebuilder/init_test.go @@ -13,17 +13,18 @@ import ( "github.com/celestiaorg/celestia-app/app" "github.com/celestiaorg/celestia-app/app/encoding" - "github.com/celestiaorg/celestia-node/libs/fslock" "github.com/celestiaorg/celestia-node/nodebuilder/node" + + "github.com/danjacques/gofslock/fslock" ) func TestInit(t *testing.T) { dir := t.TempDir() nodes := []node.Type{node.Light, node.Bridge} - for _, node := range nodes { - cfg := DefaultConfig(node) - require.NoError(t, Init(*cfg, dir, node)) + for _, currentNode := range nodes { + cfg := DefaultConfig(currentNode) + require.NoError(t, Init(*cfg, dir, currentNode)) assert.True(t, IsInit(dir)) } } @@ -32,9 +33,9 @@ func TestInitErrForInvalidPath(t *testing.T) { path := "/invalid_path" nodes := []node.Type{node.Light, node.Bridge} - for _, node := range nodes { - cfg := DefaultConfig(node) - require.Error(t, Init(*cfg, path, node)) + for _, currentNode := range nodes { + cfg := DefaultConfig(currentNode) + require.Error(t, Init(*cfg, path, currentNode)) } } @@ -42,12 +43,12 @@ func TestIsInitWithBrokenConfig(t *testing.T) { dir := t.TempDir() f, err := os.Create(configPath(dir)) require.NoError(t, err) - defer f.Close() + defer f.Close() //nolint:errcheck //nolint:errcheck f.Write([]byte(` [P2P] ListenAddresses = [/ip4/0.0.0.0/tcp/2121] - `)) + `)) assert.False(t, IsInit(dir)) } @@ -63,9 +64,9 @@ func TestInitErrForLockedDir(t *testing.T) { defer flock.Unlock() //nolint:errcheck nodes := []node.Type{node.Light, node.Bridge} - for _, node := range nodes { - cfg := DefaultConfig(node) - require.Error(t, Init(*cfg, dir, node)) + for _, currentNode := range nodes { + cfg := DefaultConfig(currentNode) + require.Error(t, Init(*cfg, dir, currentNode)) } } diff --git a/nodebuilder/store.go b/nodebuilder/store.go index 6d313893b1..c31dd73160 100644 --- a/nodebuilder/store.go +++ b/nodebuilder/store.go @@ -13,8 +13,9 @@ import ( dsbadger "github.com/celestiaorg/go-ds-badger4" - "github.com/celestiaorg/celestia-node/libs/fslock" "github.com/celestiaorg/celestia-node/libs/keystore" + + "github.com/danjacques/gofslock/fslock" ) var ( @@ -58,7 +59,7 @@ func OpenStore(path string, ring keyring.Keyring) (Store, error) { flock, err := fslock.Lock(lockPath(path)) if err != nil { - if err == fslock.ErrLocked { + if err == fslock.ErrLockHeld { return nil, ErrOpened } return nil, err @@ -141,12 +142,11 @@ func (f *fsStore) Close() (err error) { } type fsStore struct { - path string - + path string dataMu sync.Mutex data datastore.Batching keys keystore.Keystore - dirLock *fslock.Locker // protects directory + dirLock fslock.Handle // protects directory } func storePath(path string) (string, error) {