Skip to content

Commit

Permalink
Add check to not overwrite an existing key when migrating after downg…
Browse files Browse the repository at this point in the history
…rade (#5709)

## Motivation

Downgrading to v1.3.x after upgrading to v1.4.x will generate a new key that when the node is updated again to v1.4.x will overwrite the existing key.

This adds a check that prevents the node from overwriting a possibly already existing key.
  • Loading branch information
fasmat committed Mar 15, 2024
1 parent f114349 commit 7252bed
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 2 deletions.
18 changes: 16 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

See [RELEASE](./RELEASE.md) for workflow instructions.

## UNRELEASED

### Upgrade information

### Highlights

### Features

### Improvements

* [#5709](https://github.com/spacemeshos/go-spacemesh/pull/5709) Prevent users from accidentally deleting their keys,
if they downgrade to v1.3.x and upgrade again.

## Release v1.4.0

### Upgrade information
Expand Down Expand Up @@ -228,9 +241,10 @@ and permanent ineligibility for rewards.

### Features

* [#5678](https://github.com/spacemeshos/go-spacemesh/pull/5678) API to for changing log level without restarting a node. Examples:
> grpcurl -plaintext -d '{"module": "sync", "level": "debug"}' 127.0.0.1:9093 spacemesh.v1.DebugService.ChangeLogLevel
* [#5678](https://github.com/spacemeshos/go-spacemesh/pull/5678) API to for changing log level without restarting a
node. Examples:

> grpcurl -plaintext -d '{"module": "sync", "level": "debug"}' 127.0.0.1:9093 spacemesh.v1.DebugService.ChangeLogLevel
> grpcurl -plaintext -d '{"module": "*", "level": "debug"}' 127.0.0.1:9093 spacemesh.v1.DebugService.ChangeLogLevel
"*" will replace log level for all known modules, expect that some of them will spam too much.
Expand Down
22 changes: 22 additions & 0 deletions node/node_identities.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,28 @@ func (app *App) MigrateExistingIdentity() error {
return fmt.Errorf("failed to create directory for identity file: %w", err)
}

_, err = os.Stat(newKey)
switch {
case errors.Is(err, fs.ErrNotExist):
// no new key, migrate old to new
case err == nil:
// both exist, error
return fmt.Errorf("%w: both %s and %s exist", fs.ErrExist, newKey, oldKey)
case err != nil:
return fmt.Errorf("stat %s: %w", newKey, err)
}

_, err = os.Stat(oldKey + ".bak")
switch {
case errors.Is(err, fs.ErrNotExist):
// no backup, migrate old to new
case err == nil:
// backup already exists - something is wrong
return fmt.Errorf("%w: backup %s already exists", fs.ErrExist, oldKey+".bak")
case err != nil:
return fmt.Errorf("stat %s: %w", oldKey+".bak", err)
}

dst, err := os.Create(newKey)
if err != nil {
return fmt.Errorf("failed to create new identity file: %w", err)
Expand Down
99 changes: 99 additions & 0 deletions node/node_identities_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,102 @@ func TestSpacemeshApp_LoadIdentities(t *testing.T) {
require.Len(t, app.signers, 3)
})
}

func Test_MigrateExistingIdentity(t *testing.T) {
t.Run("no key - no migration", func(t *testing.T) {
app := New(WithLog(logtest.New(t)))
app.Config.DataDirParent = t.TempDir()
app.Config.SMESHING.Opts.DataDir = t.TempDir()
err := app.MigrateExistingIdentity()
require.NoError(t, err)
})

t.Run("existing key is migrated", func(t *testing.T) {
app := New(WithLog(logtest.New(t)))
app.Config.DataDirParent = t.TempDir()
app.Config.SMESHING.Opts.DataDir = t.TempDir()

sig, err := signing.NewEdSigner()
require.NoError(t, err)

err = os.WriteFile(filepath.Join(app.Config.SMESHING.Opts.DataDir, legacyKeyFileName), sig.PrivateKey(), 0o600)
require.NoError(t, err)

err = app.MigrateExistingIdentity()
require.NoError(t, err)

require.FileExists(t, filepath.Join(app.Config.DataDirParent, keyDir, supervisedIDKeyFileName))
require.NoFileExists(t, filepath.Join(app.Config.SMESHING.Opts.DataDir, legacyKeyFileName))
require.FileExists(t, filepath.Join(app.Config.SMESHING.Opts.DataDir, legacyKeyFileName+".bak"))
})

t.Run("migration does not overwrite existing key", func(t *testing.T) {
app := New(WithLog(logtest.New(t)))
app.Config.DataDirParent = t.TempDir()
app.Config.SMESHING.Opts.DataDir = t.TempDir()

sigOld, err := signing.NewEdSigner()
require.NoError(t, err)

oldKey := filepath.Join(app.Config.SMESHING.Opts.DataDir, legacyKeyFileName)
err = os.WriteFile(oldKey, sigOld.PrivateKey(), 0o600)
require.NoError(t, err)

sigNew, err := signing.NewEdSigner()
require.NoError(t, err)

newKey := filepath.Join(app.Config.DataDirParent, keyDir, supervisedIDKeyFileName)
err = os.MkdirAll(filepath.Dir(newKey), 0o700)
require.NoError(t, err)
err = os.WriteFile(newKey, sigNew.PrivateKey(), 0o600)
require.NoError(t, err)

err = app.MigrateExistingIdentity()
require.ErrorIs(t, err, fs.ErrExist)
require.ErrorContains(t, err, fmt.Sprintf("both %s and %s exist", newKey, oldKey))
require.FileExists(t, newKey)
require.FileExists(t, oldKey)

newKeyBin, err := os.ReadFile(newKey)
require.NoError(t, err)
require.Equal(t, []byte(sigNew.PrivateKey()), newKeyBin)

oldKeyBin, err := os.ReadFile(oldKey)
require.NoError(t, err)
require.Equal(t, []byte(sigOld.PrivateKey()), oldKeyBin)
})

t.Run("migrate with an already existing backup", func(t *testing.T) {
app := New(WithLog(logtest.New(t)))
app.Config.DataDirParent = t.TempDir()
app.Config.SMESHING.Opts.DataDir = t.TempDir()

sigOld, err := signing.NewEdSigner()
require.NoError(t, err)

oldKey := filepath.Join(app.Config.SMESHING.Opts.DataDir, legacyKeyFileName)
err = os.WriteFile(oldKey, sigOld.PrivateKey(), 0o600)
require.NoError(t, err)

sigBackup, err := signing.NewEdSigner()
require.NoError(t, err)

backupKey := filepath.Join(app.Config.SMESHING.Opts.DataDir, legacyKeyFileName+".bak")
err = os.WriteFile(backupKey, sigBackup.PrivateKey(), 0o600)
require.NoError(t, err)

err = app.MigrateExistingIdentity()
require.ErrorIs(t, err, fs.ErrExist)
require.ErrorContains(t, err, fmt.Sprintf("backup %s already exists", backupKey))
require.FileExists(t, filepath.Join(app.Config.SMESHING.Opts.DataDir, legacyKeyFileName))
require.FileExists(t, filepath.Join(app.Config.SMESHING.Opts.DataDir, legacyKeyFileName+".bak"))

oldKeyBin, err := os.ReadFile(oldKey)
require.NoError(t, err)
require.Equal(t, []byte(sigOld.PrivateKey()), oldKeyBin)

backupKeyBin, err := os.ReadFile(backupKey)
require.NoError(t, err)
require.Equal(t, []byte(sigBackup.PrivateKey()), backupKeyBin)
})
}

0 comments on commit 7252bed

Please sign in to comment.