44 "crypto/ed25519"
55 "encoding/json"
66 "os"
7+ "path/filepath"
78
89 "github.com/pkg/errors"
910 "github.com/threefoldtech/zosbase/pkg/versioned"
@@ -39,19 +40,78 @@ func (f *FileStore) Kind() string {
3940
4041func (f * FileStore ) Set (key ed25519.PrivateKey ) error {
4142 seed := key .Seed ()
42- return versioned .WriteFile (f .path , SeedVersion1 , seed , 0400 )
43+ // write to primary location first
44+ if err := versioned .WriteFile (f .path , SeedVersion1 , seed , 0400 ); err != nil {
45+ return err
46+ }
47+
48+ // also mirror the seed to all mounted disks under /mnt/*/seed.txt
49+ mirrors , _ := f .mirrorPaths ()
50+ for _ , p := range mirrors {
51+ _ = versioned .WriteFile (p , SeedVersion1 , seed , 0400 )
52+ }
53+ return nil
4354}
4455
4556func (f * FileStore ) Annihilate () error {
4657 return os .Remove (f .path )
4758}
4859
4960func (f * FileStore ) Get () (ed25519.PrivateKey , error ) {
50- version , data , err := versioned .ReadFile (f .path )
61+ key , err := f .readKeyFrom (f .path )
62+ if errors .Is (err , ErrKeyDoesNotExist ) {
63+ // try to recover from any mirrored copies on mounted disks
64+ mirrors , _ := f .mirrorPaths ()
65+ for _ , p := range mirrors {
66+ if k , merr := f .readKeyFrom (p ); merr == nil {
67+ // write back to primary location for future boots
68+ _ = os .MkdirAll (filepath .Dir (f .path ), 0o700 )
69+ _ = versioned .WriteFile (f .path , SeedVersion1 , k .Seed (), 0400 )
70+ // ensure the seed is present across all mirrors
71+ _ = f .ensureMirrors (k .Seed ())
72+ return k , nil
73+ }
74+ }
75+ }
76+ if err == nil {
77+ // ensure the seed is present across all mirrors on every successful read
78+ _ = f .ensureMirrors (key .Seed ())
79+ }
80+ return key , err
81+ }
82+
83+ func (f * FileStore ) Exists () (bool , error ) {
84+ if _ , err := os .Stat (f .path ); os .IsNotExist (err ) {
85+ return false , nil
86+ } else if err != nil {
87+ return false , errors .Wrap (err , "failed to check seed file" )
88+ }
89+
90+ return true , nil
91+ }
92+
93+ // ensureMirrors guarantees that the seed file exists on all mirror locations under /mnt/*
94+ // It is best-effort; failures for individual mirrors are ignored.
95+ func (f * FileStore ) ensureMirrors (seed []byte ) error {
96+ mirrors , err := f .mirrorPaths ()
97+ if err != nil {
98+ return err
99+ }
100+ for _ , p := range mirrors {
101+ if _ , statErr := os .Stat (p ); os .IsNotExist (statErr ) {
102+ _ = versioned .WriteFile (p , SeedVersion1 , seed , 0400 )
103+ }
104+ }
105+ return nil
106+ }
107+
108+ // readKeyFrom reads and decodes an identity seed from a given path
109+ // supporting both 1.0.0 (raw seed) and 1.1.0 (mnemonic json) formats.
110+ func (f * FileStore ) readKeyFrom (path string ) (ed25519.PrivateKey , error ) {
111+ version , data , err := versioned .ReadFile (path )
51112 if versioned .IsNotVersioned (err ) {
52- // this is a compatibility code for seed files
53- // in case it does not have any version information
54- if err := versioned .WriteFile (f .path , SeedVersionLatest , data , 0400 ); err != nil {
113+ // compatibility for old non-versioned seed files
114+ if err := versioned .WriteFile (path , SeedVersionLatest , data , 0400 ); err != nil {
55115 return nil , err
56116 }
57117 version = SeedVersion1
@@ -68,6 +128,7 @@ func (f *FileStore) Get() (ed25519.PrivateKey, error) {
68128 if version .EQ (SeedVersion1 ) {
69129 return keyFromSeed (data )
70130 }
131+
71132 // it means we read json data instead of the secret
72133 type Seed110Struct struct {
73134 Mnemonics string `json:"mnemonic"`
@@ -85,12 +146,20 @@ func (f *FileStore) Get() (ed25519.PrivateKey, error) {
85146 return keyFromSeed (seed )
86147}
87148
88- func (f * FileStore ) Exists () (bool , error ) {
89- if _ , err := os .Stat (f .path ); os .IsNotExist (err ) {
90- return false , nil
91- } else if err != nil {
92- return false , errors .Wrap (err , "failed to check seed file" )
149+ // mirrorPaths lists candidate seed paths under all mounted disks in /mnt/*
150+ // The path is mirrored at: /mnt/<disk>/seed.txt (flat, no original directories)
151+ func (f * FileStore ) mirrorPaths () ([]string , error ) {
152+ entries , err := os .ReadDir ("/mnt" )
153+ if err != nil {
154+ return nil , err
93155 }
94-
95- return true , nil
156+ var paths []string
157+ for _ , e := range entries {
158+ if ! e .IsDir () {
159+ continue
160+ }
161+ name := filepath .Base (f .path ) // usually "seed.txt"
162+ paths = append (paths , filepath .Join ("/mnt" , e .Name (), name ))
163+ }
164+ return paths , nil
96165}
0 commit comments