github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/account/keystore/keystore.go (about)

     1  // Copyright (C) 2017 go-crystal authors
     2  //
     3  // This file is part of the go-crystal library.
     4  //
     5  // the go-crystal library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-crystal library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-crystal library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package account
    20  
    21  import (
    22  	"errors"
    23  	"fmt"
    24  	"sync"
    25  	"time"
    26  	"github.com/sixexorg/magnetic-ring/crypto"
    27  )
    28  
    29  var (
    30  	// DefaultKS generate a default keystore
    31  	DefaultKS = NewKeystore()
    32  
    33  	// DefaultUnlockDuration default lock 300s
    34  	DefaultUnlockDuration = time.Duration(300 * time.Second)
    35  
    36  	// YearUnlockDuration lock 1 year time
    37  	YearUnlockDuration = time.Duration(365 * 24 * 60 * 60 * time.Second)
    38  )
    39  
    40  var (
    41  	// ErrUninitialized uninitialized provider error.
    42  	ErrUninitialized = errors.New("uninitialized the provider")
    43  
    44  	// ErrNotUnlocked key not unlocked
    45  	ErrNotUnlocked = errors.New("key not unlocked")
    46  
    47  	// ErrInvalidPassphrase invalid passphrase
    48  	ErrInvalidPassphrase = errors.New("passphrase is invalid")
    49  )
    50  
    51  // unlock item
    52  type unlocked struct {
    53  	alias string
    54  
    55  	key crypto.PrivateKey
    56  
    57  	timer *time.Timer
    58  }
    59  
    60  // Keystore class represents a storage facility for cryptographic keys
    61  type Keystore struct {
    62  
    63  	// keystore provider
    64  	p Provider
    65  
    66  	// unlocked items
    67  	unlocked map[string]*unlocked
    68  
    69  	mu sync.RWMutex
    70  }
    71  
    72  // NewKeystore new
    73  func NewKeystore() *Keystore {
    74  	ks := &Keystore{}
    75  
    76  	ks.unlocked = make(map[string]*unlocked)
    77  	ks.p = NewMemoryProvider(1.0)
    78  	return ks
    79  }
    80  
    81  // Aliases lists all the alias names of this keystore.
    82  func (ks *Keystore) Aliases() []string {
    83  	return ks.p.Aliases()
    84  }
    85  
    86  // ContainsAlias checks if the given alias exists in this keystore.
    87  func (ks *Keystore) ContainsAlias(a string) (bool, error) {
    88  	if ks.p == nil {
    89  		return false, ErrUninitialized
    90  	}
    91  
    92  	return ks.p.ContainsAlias(a)
    93  }
    94  
    95  // Unlock unlock key with ProtectionParameter
    96  func (ks *Keystore) Unlock(alias string, passphrase []byte, timeout time.Duration) error {
    97  	ks.mu.Lock()
    98  	defer ks.mu.Unlock()
    99  
   100  	key, err := ks.p.GetKey(alias, passphrase)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	unlockedKey, ok := ks.unlocked[alias]
   106  	if ok == true {
   107  		unlockedKey.key = key
   108  		unlockedKey.timer.Reset(timeout)
   109  	} else {
   110  		u := &unlocked{alias, key, time.NewTimer(timeout)}
   111  		ks.unlocked[alias] = u
   112  		go ks.expire(alias)
   113  	}
   114  	return nil
   115  }
   116  
   117  // Lock lock key
   118  func (ks *Keystore) Lock(alias string) error {
   119  	ks.mu.Lock()
   120  	defer ks.mu.Unlock()
   121  
   122  	if u, ok := ks.unlocked[alias]; ok == true {
   123  		u.timer.Reset(time.Duration(0) * time.Nanosecond)
   124  		return nil
   125  	}
   126  
   127  	return ErrNotUnlocked
   128  }
   129  
   130  func (ks *Keystore) expire(alias string) {
   131  	if u, ok := ks.unlocked[alias]; ok == true {
   132  		defer u.timer.Stop()
   133  		select {
   134  		case <-u.timer.C:
   135  			ks.mu.Lock()
   136  			//u.key.Clear()
   137  			delete(ks.unlocked, alias)
   138  			ks.mu.Unlock()
   139  		}
   140  	}
   141  }
   142  
   143  // GetUnlocked returns a unlocked key
   144  func (ks *Keystore) GetUnlocked(alias string) (crypto.PrivateKey, error) {
   145  	if len(alias) == 0 {
   146  		return nil, ErrNeedAlias
   147  	}
   148  
   149  	ks.mu.RLock()
   150  	defer ks.mu.RUnlock()
   151  
   152  	key, ok := ks.unlocked[alias]
   153  	if ok == false {
   154  		return nil, ErrNotUnlocked
   155  	}
   156  
   157  	return key.key, nil
   158  }
   159  
   160  // SetKey assigns the given key to the given alias, protecting it with the given passphrase.
   161  func (ks *Keystore) SetKey(a string, k crypto.PrivateKey, passphrase []byte) error {
   162  	if ks.p == nil {
   163  		return ErrUninitialized
   164  	}
   165  
   166  	return ks.p.SetKey(a, k, passphrase)
   167  }
   168  
   169  // GetKey returns the key associated with the given alias, using the given
   170  // password to recover it.
   171  func (ks *Keystore) GetKey(a string, passphrase []byte) (crypto.PrivateKey, error) {
   172  	if ks.p == nil {
   173  		fmt.Printf("getkey 001 a=%s\n",a)
   174  		return nil, ErrUninitialized
   175  	}
   176  
   177  	key, err := ks.p.GetKey(a, passphrase)
   178  	if err != nil {
   179  		fmt.Printf("getkey 002 a=%s\n",a)
   180  		return nil, err
   181  	}
   182  	return key, nil
   183  }
   184  
   185  // Delete the entry identified by the given alias from this keystore.
   186  func (ks *Keystore) Delete(a string, passphrase []byte) error {
   187  	if ks.p == nil {
   188  		return ErrUninitialized
   189  	}
   190  
   191  	//key, err := ks.p.GetKey(a, passphrase)
   192  	//if err != nil {
   193  	//	return err
   194  	//}
   195  	//key.Clear()
   196  
   197  	if _, ok := ks.unlocked[a]; ok == true {
   198  		ks.Lock(a)
   199  	}
   200  
   201  	return ks.p.Delete(a)
   202  }