2021-12-04 16:42:11 +00:00
|
|
|
// Copyright 2017-2021 DERO Project. All rights reserved.
|
|
|
|
// Use of this source code in any form is governed by RESEARCH license.
|
|
|
|
// license can be found in the LICENSE file.
|
|
|
|
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
|
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
|
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
package walletapi
|
|
|
|
|
|
|
|
import "os"
|
|
|
|
import "fmt"
|
|
|
|
import "time"
|
|
|
|
import "sync"
|
|
|
|
import "io/ioutil"
|
|
|
|
|
|
|
|
import "github.com/deroproject/derohe/cryptography/crypto"
|
|
|
|
import "github.com/deroproject/derohe/walletapi/mnemonics"
|
|
|
|
|
|
|
|
// this is stored in disk in encrypted form
|
|
|
|
type Wallet_Disk struct {
|
|
|
|
*Wallet_Memory
|
|
|
|
filename string
|
|
|
|
sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
// when smart contracts are implemented, each will have it's own universe to track and maintain transactions
|
|
|
|
|
|
|
|
// this file implements the encrypted data store at rest
|
|
|
|
func Create_Encrypted_Wallet(filename string, password string, seed *crypto.BNRed) (wd *Wallet_Disk, err error) {
|
|
|
|
|
|
|
|
if _, err = os.Stat(filename); err == nil {
|
|
|
|
err = fmt.Errorf("File '%s' already exists", filename)
|
|
|
|
return
|
|
|
|
|
|
|
|
} else if os.IsNotExist(err) {
|
|
|
|
// path/to/whatever does *not* exist
|
|
|
|
// err = fmt.Errorf("path does not exists '%s'", filename)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
wd = &Wallet_Disk{filename: filename}
|
|
|
|
|
|
|
|
// generate account keys
|
|
|
|
if wd.Wallet_Memory, err = Create_Encrypted_Wallet_Memory(password, seed); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
wd.Wallet_Memory.wallet_disk = wd
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// create an encrypted wallet using electrum recovery words
|
|
|
|
func Create_Encrypted_Wallet_From_Recovery_Words(filename string, password string, electrum_seed string) (wd *Wallet_Disk, err error) {
|
|
|
|
wd = &Wallet_Disk{filename: filename}
|
|
|
|
|
|
|
|
language, seed, err := mnemonics.Words_To_Key(electrum_seed)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if wd.Wallet_Memory, err = Create_Encrypted_Wallet_Memory(password, crypto.GetBNRed(seed)); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
wd.Wallet_Memory.account.SeedLanguage = language
|
|
|
|
wd.Wallet_Memory.wallet_disk = wd
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// create an encrypted wallet using using random data
|
|
|
|
func Create_Encrypted_Wallet_Random(filename string, password string) (wd *Wallet_Disk, err error) {
|
|
|
|
wd = &Wallet_Disk{filename: filename}
|
|
|
|
if wd.Wallet_Memory, err = Create_Encrypted_Wallet_Memory(password, crypto.RandomScalarBNRed()); err == nil {
|
|
|
|
return wd, nil
|
|
|
|
}
|
|
|
|
wd.Wallet_Memory.wallet_disk = wd
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// wallet must already be open
|
|
|
|
func (w *Wallet_Disk) Set_Encrypted_Wallet_Password(password string) (err error) {
|
|
|
|
if w != nil {
|
|
|
|
w.Wallet_Memory.Set_Encrypted_Wallet_Password(password)
|
|
|
|
w.Save_Wallet() // save wallet data
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func Open_Encrypted_Wallet(filename string, password string) (wd *Wallet_Disk, err error) {
|
|
|
|
wd = &Wallet_Disk{filename: filename}
|
|
|
|
var filedata []byte
|
|
|
|
|
|
|
|
if _, err = os.Stat(filename); os.IsNotExist(err) {
|
|
|
|
err = fmt.Errorf("File '%s' does NOT exists", filename)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if filedata, err = ioutil.ReadFile(filename); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if wd.Wallet_Memory, err = Open_Encrypted_Wallet_Memory(password, filedata); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
wd.Wallet_Memory.wallet_disk = wd
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// check whether the already opened wallet can use this password
|
|
|
|
func (w *Wallet_Disk) Check_Password(password string) bool {
|
|
|
|
w.Lock()
|
|
|
|
defer w.Unlock()
|
|
|
|
|
|
|
|
return w.Wallet_Memory.Check_Password(password)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// save updated copy of wallet
|
|
|
|
func (w *Wallet_Disk) Save_Wallet() (err error) {
|
|
|
|
if w == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
w.Lock()
|
|
|
|
defer w.Unlock()
|
|
|
|
|
|
|
|
if err = w.Wallet_Memory.Save_Wallet(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-10 11:15:46 +00:00
|
|
|
// attempt to protect atleast one backup copy
|
|
|
|
os.Remove(w.filename + ".bak")
|
|
|
|
os.Rename(w.filename, w.filename+".bak") // renames are atomic, thus more chances of retention
|
|
|
|
|
2021-12-04 16:42:11 +00:00
|
|
|
return ioutil.WriteFile(w.filename, w.Wallet_Memory.db_memory, 0600)
|
|
|
|
}
|
|
|
|
|
|
|
|
// close the wallet
|
|
|
|
func (w *Wallet_Disk) Close_Encrypted_Wallet() {
|
|
|
|
time.Sleep(time.Second) // give goroutines some time to quit
|
|
|
|
w.Save_Wallet()
|
|
|
|
w.Wallet_Memory.wallet_disk = nil
|
|
|
|
w.Wallet_Memory.Close_Encrypted_Wallet()
|
|
|
|
}
|