Skip to content
This repository has been archived by the owner on Aug 25, 2021. It is now read-only.

Commit

Permalink
Merge pull request #5 from eqlabs/latenssi/encryption
Browse files Browse the repository at this point in the history
Data encryption and refactor
  • Loading branch information
nanuuki authored Apr 29, 2021
2 parents df4522f + f1fb1cb commit 25bb86b
Show file tree
Hide file tree
Showing 24 changed files with 574 additions and 475 deletions.
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,24 @@ Run:
# edit .env
go run main.go

_Note:
The emulator creates new account addresses deterministically. This means that deleting the emulators docker volume will cause the emulator to start from the beginning and give the same addresses as before possibly ending in duplicate key errors in database._

## Configuration

### Database

| Config variable | ENV | descrpition | default | examples |
| --------------- | :-----: | ------------------------------------------------------------------------------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| DatabaseType | DB_TYPE | Type of database driver | sqlite | |
| DatabaseDSN | DB_DSN | Data source name ([DSN](https://en.wikipedia.org/wiki/Data_source_name)) for database connection | wallet.db | mysql://john:pass@localhost:3306/my_db<br><br>user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local<br><br>host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai<br><br> For more: https://gorm.io/docs/connecting_to_the_database.html |
| Config variable | ENV | descrpition | default | examples |
| --------------- | :-----: | ------------------------------------------------------------------------------------------------ | --------- | --------- |
| DatabaseType | DB_TYPE | Type of database driver | sqlite | |
| DatabaseDSN | DB_DSN | Data source name ([DSN](https://en.wikipedia.org/wiki/Data_source_name)) for database connection | wallet.db | See below |

Examples of Database DSN

mysql://john:pass@localhost:3306/my_db

user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local

host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai

For more: https://gorm.io/docs/connecting_to_the_database.html
17 changes: 8 additions & 9 deletions pkg/account/account.go → account/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"context"
"fmt"

"github.com/eqlabs/flow-nft-wallet-service/pkg/data"
"github.com/eqlabs/flow-nft-wallet-service/pkg/flow_helpers"
"github.com/eqlabs/flow-nft-wallet-service/pkg/keys"
"github.com/eqlabs/flow-nft-wallet-service/data"
"github.com/eqlabs/flow-nft-wallet-service/flow_helpers"
"github.com/eqlabs/flow-nft-wallet-service/keys"
"github.com/onflow/flow-go-sdk"
"github.com/onflow/flow-go-sdk/client"
"github.com/onflow/flow-go-sdk/templates"
Expand All @@ -15,13 +15,13 @@ import (
func Create(
ctx context.Context,
fc *client.Client,
ks keys.Store,
km keys.Manager,
) (
newAccount data.Account,
newAccountKey data.AccountKey,
newKey keys.Key,
err error,
) {
serviceAuth, err := ks.ServiceAuthorizer(ctx, fc)
serviceAuth, err := km.AdminAuthorizer()
if err != nil {
return
}
Expand All @@ -32,12 +32,12 @@ func Create(
}

// Generate a new key pair
wrapped, err := ks.Generate(ctx, 0, flow.AccountKeyWeightThreshold)
wrapped, err := km.Generate(0, flow.AccountKeyWeightThreshold)
if err != nil {
return
}
publicKey := wrapped.FlowKey
newAccountKey = wrapped.AccountKey
newKey = wrapped.AccountKey

// Setup a transaction to create an account
tx := templates.CreateAccount([]*flow.AccountKey{publicKey}, nil, serviceAuth.Address)
Expand Down Expand Up @@ -82,7 +82,6 @@ func Create(
return
}

newAccountKey.AccountAddress = newAddress
newAccount.Address = newAddress

return
Expand Down
26 changes: 17 additions & 9 deletions pkg/account/service.go → account/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,26 @@ import (
"fmt"
"log"

"github.com/eqlabs/flow-nft-wallet-service/pkg/data"
"github.com/eqlabs/flow-nft-wallet-service/pkg/keys"
"github.com/eqlabs/flow-nft-wallet-service/data"
"github.com/eqlabs/flow-nft-wallet-service/keys"
"github.com/onflow/flow-go-sdk"
"github.com/onflow/flow-go-sdk/client"
)

type Service struct {
l *log.Logger
db data.Store
ks keys.Store
km keys.Manager
fc *client.Client
chainId flow.ChainID // TODO: how do we want to handle different chains?
}

func NewService(
l *log.Logger,
db data.Store,
ks keys.Store,
km keys.Manager,
fc *client.Client) *Service {
return &Service{l, db, ks, fc, flow.Emulator}
return &Service{l, db, km, fc, flow.Emulator}
}

func (s *Service) List(ctx context.Context) (accounts []data.Account, err error) {
Expand All @@ -33,18 +33,18 @@ func (s *Service) List(ctx context.Context) (accounts []data.Account, err error)
}

func (s *Service) Create(ctx context.Context) (account data.Account, err error) {
account, key, err := Create(ctx, s.fc, s.ks)
account, key, err := Create(ctx, s.fc, s.km)
if err != nil {
return
}

// Store the generated key
err = s.ks.Save(key)
accountKey, err := s.km.Save(key)
if err != nil {
return
}
account.Keys = []data.Key{accountKey}

// Store the account
// Store
err = s.db.InsertAccount(account)

return
Expand All @@ -55,7 +55,15 @@ func (s *Service) Details(ctx context.Context, address string) (account data.Acc
if err != nil {
return
}

// keys, err := s.db.AccountKeys(address)
// if err != nil {
// return
// }

account, err = s.db.Account(address)
// account.Keys = keys

return
}

Expand Down
2 changes: 1 addition & 1 deletion api/account.http
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ POST http://localhost:3000/v1/accounts HTTP/1.1
content-type: application/json

###
GET http://localhost:3000/v1/accounts/test HTTP/1.1
GET http://localhost:3000/v1/accounts/0f7025fa05b578e3 HTTP/1.1
content-type: application/json
38 changes: 38 additions & 0 deletions data/gorm/accountstore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package gorm

import (
"github.com/eqlabs/flow-nft-wallet-service/data"
"gorm.io/gorm"
)

type AccountStore struct {
db *gorm.DB
}

func newAccountStore(db *gorm.DB) *AccountStore {
db.AutoMigrate(&data.Account{}, &data.Key{})
return &AccountStore{db}
}

// List all accounts
func (s *AccountStore) Accounts() (accounts []data.Account, err error) {
err = s.db.Select("address").Find(&accounts).Error
return
}

// Insert new account
func (s *AccountStore) InsertAccount(account data.Account) error {
return s.db.Create(&account).Error
}

// Get account details
func (s *AccountStore) Account(address string) (account data.Account, err error) {
err = s.db.Preload("Keys").First(&account, "address = ?", address).Error
return
}

// Get account key with index
func (s *AccountStore) AccountKey(address string, index int) (key data.Key, err error) {
err = s.db.Where("account_address = ? AND index = ?", address, index).First(&key).Error
return
}
20 changes: 20 additions & 0 deletions data/gorm/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package gorm

import (
"github.com/eqlabs/flow-nft-wallet-service/data"
"gorm.io/gorm"
)

type Store struct {
data.AccountStore
}

func NewStore(dialector gorm.Dialector) (*Store, error) {
db, err := gorm.Open(dialector, &gorm.Config{})
if err != nil {
return &Store{}, err
}
return &Store{
AccountStore: newAccountStore(db),
}, nil
}
45 changes: 45 additions & 0 deletions data/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package data

import (
"time"

"gorm.io/gorm"
)

const (
DB_TYPE_POSTGRESQL = "psql"
DB_TYPE_MYSQL = "mysql"
DB_TYPE_SQLITE = "sqlite"
)

type Store interface {
AccountStore
}

type AccountStore interface {
Accounts() ([]Account, error)
InsertAccount(a Account) error
Account(address string) (Account, error)
AccountKey(address string, index int) (Key, error)
}

// Storable account
type Account struct {
Address string `json:"address" gorm:"primaryKey"`
Keys []Key `json:"keys" gorm:"foreignKey:AccountAddress;references:Address;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
}

// Storable account key
type Key struct {
ID int `json:"-" gorm:"primaryKey"`
AccountAddress string `json:"-" gorm:"index"`
Index int `json:"index" gorm:"index"`
Type string `json:"type"`
Value []byte `json:"-"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
}
File renamed without changes.
2 changes: 1 addition & 1 deletion pkg/handlers/accounts.go → handlers/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"log"
"net/http"

"github.com/eqlabs/flow-nft-wallet-service/pkg/account"
"github.com/eqlabs/flow-nft-wallet-service/account"
"github.com/gorilla/mux"
)

Expand Down
10 changes: 5 additions & 5 deletions pkg/handlers/fungible_tokens.go → handlers/fungible_tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"log"
"net/http"

"github.com/eqlabs/flow-nft-wallet-service/pkg/data"
"github.com/eqlabs/flow-nft-wallet-service/pkg/keys"
"github.com/eqlabs/flow-nft-wallet-service/data"
"github.com/eqlabs/flow-nft-wallet-service/keys"
"github.com/gorilla/mux"
"github.com/onflow/flow-go-sdk/client"
)
Expand All @@ -14,15 +14,15 @@ type FungibleTokens struct {
l *log.Logger
c *client.Client
db data.Store
ks keys.Store
km keys.Manager
}

func NewFungibleTokens(
l *log.Logger,
c *client.Client,
db data.Store,
ks keys.Store) *FungibleTokens {
return &FungibleTokens{l, c, db, ks}
km keys.Manager) *FungibleTokens {
return &FungibleTokens{l, c, db, km}
}

func (s *FungibleTokens) Details(rw http.ResponseWriter, r *http.Request) {
Expand Down
10 changes: 5 additions & 5 deletions pkg/handlers/transactions.go → handlers/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@ import (
"log"
"net/http"

"github.com/eqlabs/flow-nft-wallet-service/pkg/data"
"github.com/eqlabs/flow-nft-wallet-service/pkg/keys"
"github.com/eqlabs/flow-nft-wallet-service/data"
"github.com/eqlabs/flow-nft-wallet-service/keys"
"github.com/onflow/flow-go-sdk/client"
)

type Transactions struct {
l *log.Logger
c *client.Client
db data.Store
ks keys.Store
km keys.Manager
}

func NewTransactions(
l *log.Logger,
c *client.Client,
db data.Store,
ks keys.Store) *Transactions {
return &Transactions{l, c, db, ks}
km keys.Manager) *Transactions {
return &Transactions{l, c, db, km}
}

func (s *Transactions) List(rw http.ResponseWriter, r *http.Request) {
Expand Down
58 changes: 58 additions & 0 deletions keys/google/google.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package google

import (
"context"
"fmt"
"strings"

"github.com/onflow/flow-go-sdk/crypto/cloudkms"

kms "cloud.google.com/go/kms/apiv1"
kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
)

// Creates a new asymmetric signing key in Google KMS and returns a cloudkms.Key (the "raw" result isn't needed)
func AsymKey(ctx context.Context, parent, id string) (createdKey cloudkms.Key, err error) {
kmsClient, err := kms.NewKeyManagementClient(ctx)
if err != nil {
return
}

req := &kmspb.CreateCryptoKeyRequest{
Parent: parent,
CryptoKeyId: id,
CryptoKey: &kmspb.CryptoKey{
Purpose: kmspb.CryptoKey_ASYMMETRIC_SIGN,
VersionTemplate: &kmspb.CryptoKeyVersionTemplate{
Algorithm: kmspb.CryptoKeyVersion_EC_SIGN_P256_SHA256,
},
// TODO: Set relevant labels at creation, update post-creation if necessary
Labels: map[string]string{
"service": "flow-nft-wallet-service",
"account_address": "",
"chain_id": "",
"environment": "development",
},
},
}

googleKey, err := kmsClient.CreateCryptoKey(ctx, req)
if err != nil {
return
}

// Append cryptoKeyVersions so that we can utilize the KeyFromResourceID method
createdKey, err = cloudkms.KeyFromResourceID(fmt.Sprintf("%s/cryptoKeyVersions/1", googleKey.Name))
if err != nil {
fmt.Println("Could not create cloudkms.Key from ResourceId:", googleKey.Name)
return
}

// Validate key name
if !strings.HasPrefix(createdKey.ResourceID(), googleKey.Name) {
fmt.Println("WARNING: created Google KMS key name does not match the expected", createdKey.ResourceID(), " vs ", googleKey.Name)
// TODO: Handle scenario
}

return
}
Loading

0 comments on commit 25bb86b

Please sign in to comment.