signer/storage creaate new db_storage and related tests

This commit is contained in:
Huiyi Li 2020-01-24 22:53:43 -08:00
parent 1ffab783a5
commit bee2249e21
4 changed files with 254 additions and 0 deletions

3
go.mod
View file

@ -23,6 +23,7 @@ require (
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-ole/go-ole v1.2.1 // indirect
github.com/go-sql-driver/mysql v1.5.0
github.com/go-stack/stack v1.8.0 github.com/go-stack/stack v1.8.0
github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c
github.com/golang/snappy v0.0.1 github.com/golang/snappy v0.0.1
@ -37,8 +38,10 @@ require (
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356
github.com/kr/pretty v0.1.0 // indirect github.com/kr/pretty v0.1.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect
github.com/lib/pq v1.3.0
github.com/mattn/go-colorable v0.1.0 github.com/mattn/go-colorable v0.1.0
github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035 github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035
github.com/mattn/go-sqlite3 v2.0.2+incompatible
github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/go-stringutil v0.1.0 // indirect
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416
github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c

6
go.sum
View file

@ -77,6 +77,8 @@ github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2i
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -116,6 +118,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-colorable v0.1.0 h1:v2XXALHHh6zHfYTJ+cSkwtyffnaOyR1MXaA91mTrb8o= github.com/mattn/go-colorable v0.1.0 h1:v2XXALHHh6zHfYTJ+cSkwtyffnaOyR1MXaA91mTrb8o=
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
@ -126,6 +130,8 @@ github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXT
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v2.0.2+incompatible h1:qzw9c2GNT8UFrgWNDhCTqRqYUSmu/Dav/9Z58LGpk7U=
github.com/mattn/go-sqlite3 v2.0.2+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks= github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=

View file

@ -0,0 +1,173 @@
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package storage
import (
"database/sql"
"encoding/json"
"fmt"
"github.com/ethereum/go-ethereum/log"
// here we are adding multiple default supported db drivers
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
)
// DBStorage is a storage type which is backed by a general purpose database
type DBStorage struct {
driverName string
dataSourceName string
db *sql.DB
key []byte
}
// KPS is the structure to hold a row of our credentials database
type KPS struct {
id int
address string
json string
}
// NewDBStorage create new database backed storage
func NewDBStorage(key []byte, driverName, dataSourceName string) (*DBStorage, error) {
// sql.Open only validates the input, but didn't create a connection
db, err := sql.Open(driverName, dataSourceName)
if err != nil {
log.Error("failed to validate driver: #{driverName}, #{dataSourceName}")
db.Close()
return nil, err
}
// Connects to the database and make sure it is ok, connection will be closed shortly since default MaxIdle is 0
err = db.Ping()
if err != nil {
log.Error("failed to connect to database: #{dataSourceName}")
db.Close()
return nil, err
}
// set connection limits
db.SetMaxOpenConns(5)
return &DBStorage{
driverName: driverName,
dataSourceName: dataSourceName,
db: db,
key: key,
}, nil
}
// Put stores a value by key. 0-length keys results in noop.
func (s *DBStorage) Put(key, value string) {
if len(key) == 0 {
return
}
ciphertext, iv, err := Encrypt(s.key, []byte(value), []byte(key))
if err != nil {
log.Warn("Failed to encrypt entry", "err", err)
return
}
creds := StoredCredential{Iv: iv, CipherText: ciphertext}
_, exist, err := s.queryRow("SELECT * FROM kps WHERE address = ?", key)
if err != nil {
log.Warn("Failed to execute SQL", "err", err)
return
}
raw, err := json.Marshal(creds)
if err != nil {
log.Warn("Failed to marshal StoredCredential data")
return
}
if !exist {
s.exec("INSERT INTO kps (address, json) VALUES (?, ?)", key, raw)
} else {
s.exec("UPDATE kps SET json = ? WHERE address = ?", raw, key)
}
}
// Get returns the previously stored value, or an error if it does not exist or
// key is of 0-length.
func (s *DBStorage) Get(key string) (string, error) {
kps, exist, err := s.queryRow("SELECT * FROM kps WHERE address = ?", key)
if err != nil {
log.Warn("Failed to execute SQL", "err", err)
return "", err
}
if !exist {
log.Warn("Key does not exist", "key", key)
return "", ErrNotFound
}
cred := StoredCredential{}
if err = json.Unmarshal([]byte(kps.json), &cred); err != nil {
log.Warn("Failed to unmarshall stored json", "err", err)
return "", err
}
entry, err := Decrypt(s.key, cred.Iv, cred.CipherText, []byte(key))
if err != nil {
log.Warn("Failed to decrypt key", "key", key)
return "", err
}
return string(entry), nil
}
// Del removes a key-value pair. If the key doesn't exist, the method is a noop.
func (s *DBStorage) Del(key string) {
s.exec("DELETE FROM kps WHERE address = ?", key)
}
func (s *DBStorage) exec(query string, args ...interface{}) {
_, err := s.db.Exec(query, args...)
if err != nil {
log.Warn("Failed to execute sql", query, args)
}
}
func (s *DBStorage) queryRow(query string, args ...interface{}) (*KPS, bool, error) {
kps := KPS{}
err := s.db.QueryRow(query, args...).Scan(&kps.id, &kps.address, &kps.json)
if err != nil && err != sql.ErrNoRows {
return nil, false, err
}
if kps.id == 0 {
return nil, false, nil
}
return &kps, true, nil
}
// Close sql.DB
func (s *DBStorage) Close() {
s.db.Close()
}
func main() {
// "root:900406.mysql@tcp(localhost:3306)/adv_database"
db, err := sql.Open("mysql", "server=localhost;user id=root;password=900406.mysql;port=3306;database=adv_database")
if err != nil {
fmt.Println("failure")
panic(err)
}
fmt.Println("success")
defer db.Close()
}

View file

@ -0,0 +1,72 @@
package storage
import (
"fmt"
"io/ioutil"
"path/filepath"
"testing"
_ "github.com/mattn/go-sqlite3"
)
var (
ds *DBStorage
key string
)
func init() {
key = "AES256Key-32Characters1234567890"
tmpDir, _ := ioutil.TempDir("", "eth-encrypted-db-storge-test")
fmt.Println(tmpDir)
ds, _ = NewDBStorage([]byte(key), "sqlite3", filepath.Join(tmpDir, "test.db"))
ds.exec("CREATE TABLE IF NOT EXISTS kps (id INTEGER PRIMARY KEY, address TEXT, json TEXT)")
}
func TestDBStorage(t *testing.T) {
// test Put
k1, v1 := "k1", "v1"
ds.Put(k1, v1)
// test Get
ret, err := ds.Get(k1)
if err != nil || ret != v1 {
t.Fatal("Get didn't return correct result")
}
// test Put when there's duplicate
v2 := "v2"
ds.Put(k1, v2)
ret, err = ds.Get(k1)
if err != nil || ret != v2 {
t.Fatal("Get didn't return correct result")
}
// test Del
ds.Del(k1)
ret, err = ds.Get(k1)
if err != ErrNotFound {
t.Fatal("Del didn't work as expected")
}
}
func TestSwappedKeysForDBStorage(t *testing.T) {
ds.Put("k1", "v1")
ds.Put("k2", "v2")
// now make a modified copy
swap := func() {
creds1, _, _ := ds.queryRow("SELECT * FROM kps WHERE address = 'k1'")
creds2, _, _ := ds.queryRow("SELECT * FROM kps WHERE address = 'k2'")
ds.exec("UPDATE kps SET json = ? WHERE address = ?", creds1.json, "k2")
ds.exec("UPDATE kps SET json = ? WHERE address = ?", creds2.json, "k1")
}
swap()
if v, _ := ds.Get("k1"); v != "" {
t.Errorf("swapped value should return empty")
}
swap()
if v, _ := ds.Get("k1"); v != "v1" {
t.Errorf(v)
t.Errorf("double-swapped value should work fine")
}
}