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 #7 from eqlabs/latenssi/refactor-params
Browse files Browse the repository at this point in the history
Refactor param passing and keys package structure
  • Loading branch information
latenssi authored Apr 30, 2021
2 parents 25bb86b + c5bda00 commit 371e5bd
Show file tree
Hide file tree
Showing 11 changed files with 319 additions and 219 deletions.
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
SERVICE_ACC_ADDRESS=
SERVICE_ACC_KEY_VALUE=
ADMIN_ACC_ADDRESS=
ADMIN_ACC_KEY_VALUE=
DEFAULT_KEY_MANAGER=
GOOGLE_APPLICATION_CREDENTIALS=
GOOGLE_KMS_PROJECT_ID=
Expand Down
2 changes: 1 addition & 1 deletion account/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (s *Service) Details(ctx context.Context, address string) (account data.Acc
func (s *Service) ValidateAddress(address string) (err error) {
flowAddress := flow.HexToAddress(address)
if !flowAddress.IsValid(s.chainId) {
err = fmt.Errorf("'address': %s is not a valid address in '%s' chain", address, s.chainId)
err = fmt.Errorf("'%s' is not a valid address in '%s' chain", address, s.chainId)
}
return
}
7 changes: 5 additions & 2 deletions data/gorm/accountstore.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package gorm

import (
"log"

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

type AccountStore struct {
l *log.Logger
db *gorm.DB
}

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

// List all accounts
Expand Down
43 changes: 38 additions & 5 deletions data/gorm/store.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,53 @@
package gorm

import (
"fmt"
"log"

"github.com/caarlos0/env/v6"
"github.com/eqlabs/flow-nft-wallet-service/data"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)

type Store struct {
data.AccountStore
}

func NewStore(dialector gorm.Dialector) (*Store, error) {
type Config struct {
DatabaseDSN string `env:"DB_DSN" envDefault:"wallet.db"`
DatabaseType string `env:"DB_TYPE" envDefault:"sqlite"`
}

func NewStore(l *log.Logger) (store *Store, err error) {
cfg := Config{}
if err = env.Parse(&cfg); err != nil {
return
}

var dialector gorm.Dialector
switch cfg.DatabaseType {
case data.DB_TYPE_POSTGRESQL:
dialector = postgres.Open(cfg.DatabaseDSN)
case data.DB_TYPE_MYSQL:
dialector = mysql.Open(cfg.DatabaseDSN)
case data.DB_TYPE_SQLITE:
dialector = sqlite.Open(cfg.DatabaseDSN)
default:
err = fmt.Errorf("database type '%s' not supported", cfg.DatabaseType)
return
}

db, err := gorm.Open(dialector, &gorm.Config{})
if err != nil {
return &Store{}, err
return
}
return &Store{
AccountStore: newAccountStore(db),
}, nil

store = &Store{
AccountStore: newAccountStore(l, db),
}

return
}
6 changes: 3 additions & 3 deletions handlers/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (s *Accounts) List(rw http.ResponseWriter, r *http.Request) {
s.l.Println("List accounts")
accounts, err := s.as.List(context.Background())
if err != nil {
s.l.Printf("Error: %s\n", err)
s.l.Printf("Error: %v\n", err)
rw.WriteHeader(http.StatusInternalServerError)
rw.Write([]byte("Error"))
return
Expand All @@ -37,7 +37,7 @@ func (s *Accounts) Create(rw http.ResponseWriter, r *http.Request) {
s.l.Println("Create account")
account, err := s.as.Create(context.Background())
if err != nil {
s.l.Printf("Error: %s\n", err)
s.l.Printf("Error: %v\n", err)
rw.WriteHeader(http.StatusInternalServerError)
rw.Write([]byte("Error"))
return
Expand All @@ -52,7 +52,7 @@ func (s *Accounts) Details(rw http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
account, err := s.as.Details(context.Background(), vars["address"])
if err != nil {
s.l.Printf("Error: %s\n", err)
s.l.Printf("Error: %v\n", err)
rw.WriteHeader(http.StatusInternalServerError)
rw.Write([]byte("Error"))
return
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package simple
package encryption

import (
"crypto/aes"
Expand Down
93 changes: 62 additions & 31 deletions keys/google/google.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,87 @@ package google
import (
"context"
"fmt"
"strings"

"github.com/eqlabs/flow-nft-wallet-service/keys"
"github.com/google/uuid"
"github.com/onflow/flow-go-sdk"
"github.com/onflow/flow-go-sdk/crypto"
"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)
type Config struct {
ProjectID string `env:"GOOGLE_KMS_PROJECT_ID"`
LocationID string `env:"GOOGLE_KMS_LOCATION_ID"`
KeyRingID string `env:"GOOGLE_KMS_KEYRING_ID"`
}

func Generate(
projectId, locationId, KeyRingId string,
keyIndex, weight int,
) (result keys.Wrapped, err error) {
ctx := context.Background()

keyUUID := uuid.New()

// Create the new key in Google KMS
createdKey, err := AsymKey(
ctx,
fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", projectId, locationId, KeyRingId),
fmt.Sprintf("flow-wallet-account-key-%s", keyUUID.String()),
)
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",
},
},
client, err := cloudkms.NewClient(ctx)
if err != nil {
return
}

googleKey, err := kmsClient.CreateCryptoKey(ctx, req)
// Get the public key (using flow-go-sdk's cloudkms.Client)
publicKey, hashAlgorithm, err := client.GetPublicKey(ctx, createdKey)
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))
key := keys.Key{
Index: keyIndex,
Type: keys.ACCOUNT_KEY_TYPE_GOOGLE_KMS,
Value: createdKey.ResourceID(),
}

flowKey := flow.NewAccountKey().
SetPublicKey(publicKey).
SetHashAlgo(hashAlgorithm).
SetWeight(weight)
flowKey.Index = keyIndex

result.AccountKey = key
result.FlowKey = flowKey

return
}

func Signer(
ctx context.Context,
address string,
key keys.Key,
) (result crypto.Signer, err error) {
kmsClient, err := cloudkms.NewClient(ctx)
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
kmsKey, err := cloudkms.KeyFromResourceID(key.Value)
if err != nil {
return
}

result, err = kmsClient.SignerForKey(
ctx,
flow.HexToAddress(address),
kmsKey,
)

return
}
58 changes: 58 additions & 0 deletions keys/google/helpers.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
}
57 changes: 57 additions & 0 deletions keys/local/local.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package local

import (
"crypto/rand"

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

func Generate(
signAlgo crypto.SignatureAlgorithm,
hashAlgo crypto.HashAlgorithm,
keyIndex, weight int,
) (result keys.Wrapped, err error) {
seed := make([]byte, crypto.MinSeedLength)
_, err = rand.Read(seed)
if err != nil {
return
}

privateKey, err := crypto.GeneratePrivateKey(signAlgo, seed)
if err != nil {
return
}

flowKey := flow.NewAccountKey().
FromPrivateKey(privateKey).
SetHashAlgo(hashAlgo).
SetWeight(weight)

flowKey.Index = keyIndex

key := keys.Key{
Index: keyIndex,
Type: keys.ACCOUNT_KEY_TYPE_LOCAL,
Value: privateKey.String(),
}

result.AccountKey = key
result.FlowKey = flowKey

return
}

func Signer(
signAlgo crypto.SignatureAlgorithm,
hashAlgo crypto.HashAlgorithm,
key keys.Key,
) (result crypto.Signer, err error) {
pk, err := crypto.DecodePrivateKeyHex(signAlgo, key.Value)
if err != nil {
return
}
result = crypto.NewInMemorySigner(pk, hashAlgo)
return
}
Loading

0 comments on commit 371e5bd

Please sign in to comment.