github.com/johnathanhowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/wallet/persist.go (about) 1 package wallet 2 3 import ( 4 "crypto/rand" 5 "os" 6 "path/filepath" 7 8 "github.com/NebulousLabs/Sia/crypto" 9 "github.com/NebulousLabs/Sia/modules" 10 "github.com/NebulousLabs/Sia/persist" 11 ) 12 13 const ( 14 logFile = modules.WalletDir + ".log" 15 settingsFileSuffix = ".json" 16 settingsFile = modules.WalletDir + settingsFileSuffix 17 18 encryptionVerificationLen = 32 19 ) 20 21 var ( 22 settingsMetadata = persist.Metadata{ 23 Header: "Wallet Settings", 24 Version: "0.4.0", 25 } 26 seedMetadata = persist.Metadata{ 27 Header: "Wallet Seed", 28 Version: "0.4.0", 29 } 30 ) 31 32 // SpendableKeyFile stores an encrypted spendable key on disk. 33 type SpendableKeyFile struct { 34 UID UniqueID 35 EncryptionVerification crypto.Ciphertext 36 SpendableKey crypto.Ciphertext 37 } 38 39 // WalletPersist contains all data that persists on disk during wallet 40 // operation. 41 type WalletPersist struct { 42 // EncryptionVerification is an encrypted string that, when decrypted, is 43 // 32 '0' bytes. The UID is used to prevent leaking information in the 44 // event that the same key gets used for multiple wallets. 45 UID UniqueID 46 EncryptionVerification crypto.Ciphertext 47 48 // The primary seed is used to generate new addresses as they are required. 49 // All addresses are tracked and spendable. Only modules.PublicKeysPerSeed 50 // keys/addresses can be created per seed, after which a new seed will need 51 // to be generated. 52 PrimarySeedFile SeedFile 53 PrimarySeedProgress uint64 54 55 // AuxiliarySeedFiles is a set of seeds that the wallet can spend from, but is 56 // no longer using to generate addresses. The primary use case is loading 57 // backups in the event of lost files or coins. All auxiliary seeds are 58 // encrypted using the primary seed encryption password. 59 AuxiliarySeedFiles []SeedFile 60 61 // UnseededKeys are list of spendable keys that were not generated by a 62 // random seed. 63 UnseededKeys []SpendableKeyFile 64 } 65 66 // loadSettings reads the wallet's settings from the wallet's settings file, 67 // overwriting the settings object in memory. loadSettings should only be 68 // called at startup. 69 func (w *Wallet) loadSettings() error { 70 return persist.LoadFile(settingsMetadata, &w.persist, filepath.Join(w.persistDir, settingsFile)) 71 } 72 73 // saveSettings writes the wallet's settings to the wallet's settings file, 74 // replacing the existing file. 75 func (w *Wallet) saveSettings() error { 76 return persist.SaveFile(settingsMetadata, w.persist, filepath.Join(w.persistDir, settingsFile)) 77 } 78 79 // saveSettingsSync writes the wallet's settings to the wallet's settings file, 80 // replacing the existing file, and then syncs to disk. 81 func (w *Wallet) saveSettingsSync() error { 82 return persist.SaveFileSync(settingsMetadata, w.persist, filepath.Join(w.persistDir, settingsFile)) 83 } 84 85 // initSettings creates the settings object at startup. If a settings file 86 // exists, the settings file will be loaded into memory. If the settings file 87 // does not exist, a new.persist file will be created. 88 func (w *Wallet) initSettings() error { 89 // Check if the settings file exists, if not create it. 90 settingsFilename := filepath.Join(w.persistDir, settingsFile) 91 _, err := os.Stat(settingsFilename) 92 if os.IsNotExist(err) { 93 _, err = rand.Read(w.persist.UID[:]) 94 if err != nil { 95 return err 96 } 97 return w.saveSettings() 98 } else if err != nil { 99 return err 100 } 101 102 // Load the settings file if it does exist. 103 return w.loadSettings() 104 } 105 106 // initPersist loads all of the wallet's persistence files into memory, 107 // creating them if they do not exist. 108 func (w *Wallet) initPersist() error { 109 // Create a directory for the wallet without overwriting an existing 110 // directory. 111 err := os.MkdirAll(w.persistDir, 0700) 112 if err != nil { 113 return err 114 } 115 116 // Start logging. 117 w.log, err = persist.NewFileLogger(filepath.Join(w.persistDir, logFile)) 118 if err != nil { 119 return err 120 } 121 122 // Load the settings file. 123 err = w.initSettings() 124 if err != nil { 125 return err 126 } 127 return nil 128 } 129 130 // createBackup creates a backup file at the desired filepath. 131 func (w *Wallet) createBackup(backupFilepath string) error { 132 return persist.SaveFileSync(settingsMetadata, w.persist, backupFilepath) 133 } 134 135 // CreateBackup creates a backup file at the desired filepath. 136 func (w *Wallet) CreateBackup(backupFilepath string) error { 137 w.mu.Lock() 138 defer w.mu.Unlock() 139 return w.createBackup(backupFilepath) 140 } 141 142 /* 143 // LoadBackup loads a backup file from the provided filepath. The backup file 144 // primary seed is loaded as an auxiliary seed. 145 func (w *Wallet) LoadBackup(masterKey, backupMasterKey crypto.TwofishKey, backupFilepath string) error { 146 lockID := w.mu.Lock() 147 defer w.mu.Unlock(lockID) 148 149 // Load all of the seed files, check for duplicates, re-encrypt them (but 150 // keep the UID), and add them to the WalletPersist object) 151 var backupPersist WalletPersist 152 err := persist.LoadFile(settingsMetadata, &backupPersist, backupFilepath) 153 if err != nil { 154 return err 155 } 156 backupSeeds := append(backupPersist.AuxiliarySeedFiles, backupPersist.PrimarySeedFile) 157 TODO: more 158 } 159 */