key_store_plain.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Copyright 2014 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package crypto
  17. import (
  18. "encoding/hex"
  19. "encoding/json"
  20. "fmt"
  21. "io"
  22. "io/ioutil"
  23. "os"
  24. "path/filepath"
  25. "time"
  26. "github.com/ethereum/go-ethereum/common"
  27. )
  28. type KeyStore interface {
  29. // create new key using io.Reader entropy source and optionally using auth string
  30. GenerateNewKey(io.Reader, string) (*Key, error)
  31. GetKey(common.Address, string) (*Key, error) // get key from addr and auth string
  32. GetKeyAddresses() ([]common.Address, error) // get all addresses
  33. StoreKey(*Key, string) error // store key optionally using auth string
  34. DeleteKey(common.Address, string) error // delete key by addr and auth string
  35. Cleanup(keyAddr common.Address) (err error)
  36. }
  37. type keyStorePlain struct {
  38. keysDirPath string
  39. }
  40. func NewKeyStorePlain(path string) KeyStore {
  41. return &keyStorePlain{path}
  42. }
  43. func (ks keyStorePlain) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) {
  44. return GenerateNewKeyDefault(ks, rand, auth)
  45. }
  46. func GenerateNewKeyDefault(ks KeyStore, rand io.Reader, auth string) (key *Key, err error) {
  47. defer func() {
  48. if r := recover(); r != nil {
  49. err = fmt.Errorf("GenerateNewKey error: %v", r)
  50. }
  51. }()
  52. key = NewKey(rand)
  53. err = ks.StoreKey(key, auth)
  54. return key, err
  55. }
  56. func (ks keyStorePlain) GetKey(keyAddr common.Address, auth string) (key *Key, err error) {
  57. key = new(Key)
  58. err = getKey(ks.keysDirPath, keyAddr, key)
  59. return
  60. }
  61. func getKey(keysDirPath string, keyAddr common.Address, content interface{}) (err error) {
  62. fileContent, err := getKeyFile(keysDirPath, keyAddr)
  63. if err != nil {
  64. return
  65. }
  66. return json.Unmarshal(fileContent, content)
  67. }
  68. func (ks keyStorePlain) GetKeyAddresses() (addresses []common.Address, err error) {
  69. return getKeyAddresses(ks.keysDirPath)
  70. }
  71. func (ks keyStorePlain) Cleanup(keyAddr common.Address) (err error) {
  72. return cleanup(ks.keysDirPath, keyAddr)
  73. }
  74. func (ks keyStorePlain) StoreKey(key *Key, auth string) (err error) {
  75. keyJSON, err := json.Marshal(key)
  76. if err != nil {
  77. return
  78. }
  79. err = writeKeyFile(key.Address, ks.keysDirPath, keyJSON)
  80. return
  81. }
  82. func (ks keyStorePlain) DeleteKey(keyAddr common.Address, auth string) (err error) {
  83. return deleteKey(ks.keysDirPath, keyAddr)
  84. }
  85. func deleteKey(keysDirPath string, keyAddr common.Address) (err error) {
  86. var path string
  87. path, err = getKeyFilePath(keysDirPath, keyAddr)
  88. if err == nil {
  89. addrHex := hex.EncodeToString(keyAddr[:])
  90. if path == filepath.Join(keysDirPath, addrHex, addrHex) {
  91. path = filepath.Join(keysDirPath, addrHex)
  92. }
  93. err = os.RemoveAll(path)
  94. }
  95. return
  96. }
  97. func getKeyFilePath(keysDirPath string, keyAddr common.Address) (keyFilePath string, err error) {
  98. addrHex := hex.EncodeToString(keyAddr[:])
  99. matches, err := filepath.Glob(filepath.Join(keysDirPath, fmt.Sprintf("*--%s", addrHex)))
  100. if len(matches) > 0 {
  101. if err == nil {
  102. keyFilePath = matches[len(matches)-1]
  103. }
  104. return
  105. }
  106. keyFilePath = filepath.Join(keysDirPath, addrHex, addrHex)
  107. _, err = os.Stat(keyFilePath)
  108. return
  109. }
  110. func cleanup(keysDirPath string, keyAddr common.Address) (err error) {
  111. fileInfos, err := ioutil.ReadDir(keysDirPath)
  112. if err != nil {
  113. return
  114. }
  115. var paths []string
  116. account := hex.EncodeToString(keyAddr[:])
  117. for _, fileInfo := range fileInfos {
  118. path := filepath.Join(keysDirPath, fileInfo.Name())
  119. if len(path) >= 40 {
  120. addr := path[len(path)-40 : len(path)]
  121. if addr == account {
  122. if path == filepath.Join(keysDirPath, addr, addr) {
  123. path = filepath.Join(keysDirPath, addr)
  124. }
  125. paths = append(paths, path)
  126. }
  127. }
  128. }
  129. if len(paths) > 1 {
  130. for i := 0; err == nil && i < len(paths)-1; i++ {
  131. err = os.RemoveAll(paths[i])
  132. if err != nil {
  133. break
  134. }
  135. }
  136. }
  137. return
  138. }
  139. func getKeyFile(keysDirPath string, keyAddr common.Address) (fileContent []byte, err error) {
  140. var keyFilePath string
  141. keyFilePath, err = getKeyFilePath(keysDirPath, keyAddr)
  142. if err == nil {
  143. fileContent, err = ioutil.ReadFile(keyFilePath)
  144. }
  145. return
  146. }
  147. func writeKeyFile(addr common.Address, keysDirPath string, content []byte) (err error) {
  148. filename := keyFileName(addr)
  149. // read, write and dir search for user
  150. err = os.MkdirAll(keysDirPath, 0700)
  151. if err != nil {
  152. return err
  153. }
  154. // read, write for user
  155. return ioutil.WriteFile(filepath.Join(keysDirPath, filename), content, 0600)
  156. }
  157. // keyFilePath implements the naming convention for keyfiles:
  158. // UTC--<created_at UTC ISO8601>-<address hex>
  159. func keyFileName(keyAddr common.Address) string {
  160. ts := time.Now().UTC()
  161. return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(keyAddr[:]))
  162. }
  163. func toISO8601(t time.Time) string {
  164. var tz string
  165. name, offset := t.Zone()
  166. if name == "UTC" {
  167. tz = "Z"
  168. } else {
  169. tz = fmt.Sprintf("%03d00", offset/3600)
  170. }
  171. return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz)
  172. }
  173. func getKeyAddresses(keysDirPath string) (addresses []common.Address, err error) {
  174. fileInfos, err := ioutil.ReadDir(keysDirPath)
  175. if err != nil {
  176. return nil, err
  177. }
  178. for _, fileInfo := range fileInfos {
  179. filename := fileInfo.Name()
  180. if len(filename) >= 40 {
  181. addr := filename[len(filename)-40 : len(filename)]
  182. address, err := hex.DecodeString(addr)
  183. if err == nil {
  184. addresses = append(addresses, common.BytesToAddress(address))
  185. }
  186. }
  187. }
  188. return addresses, err
  189. }