Skip to content
This repository has been archived by the owner on Nov 13, 2024. It is now read-only.

Support Private Key Encryption #20

Merged
merged 1 commit into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ POKT_RPC_FULL_HOST=
HTTP_SERVER_PORT=8080
POKT_RPC_TIMEOUT=5s
ENVIRONMENT_STAGE=development
APPSTAKE_PRIVATE_KEYS=
POKT_APPLICATIONS_ENCRYPTION_KEY=
SESSION_CACHE_TTL=75m
DB_CONNECTION_URL=postgres://postgres:mypassword@localhost:5432/postgres?sslmode=disable
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,23 @@ Learn more about the vision and overall architecture [overview](docs%2Foverview.
```
3. Run the binary `./main`

## Creating a DB Migration
Migrations are like version control for your database, allowing your team to define and share the application's database schema definition.
Before running a migration make sure to install the go lang migration cli on your machine.
https://github.com/golang-migrate/migrate/tree/master/cmd/migrate
```sh
./scripts/migration.sh -n {migration_name}
```
This command will generate a up and down migration in `db_migrations`

## Applying a DB Migration
DB Migrations are applied upon server start, but as well, it can be applied manually through:
```sh
./scripts/migration.sh {--down or --up} {number_of_times}
./scripts/migration.sh -d 1
./scripts/migration.sh -u 1
```

## Running Tests
Before running any tests make sure to have the mock files in placed at `./mocks` folder.
You can generate the mock files through:
Expand Down
115 changes: 46 additions & 69 deletions cmd/gateway_server/internal/config/dot_env_config_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,50 @@ import (
"fmt"
"github.com/joho/godotenv"
"os"
"os-gateway/internal/config"
"os-gateway/pkg/pokt/pokt_v0/models"
"pokt_gateway_server/internal/config"
"strconv"
"strings"
"time"
)

// Environment variable names
const (
poktRPCFullHostEnv = "POKT_RPC_FULL_HOST"
httpServerPortEnv = "HTTP_SERVER_PORT"
poktRPCTimeoutEnv = "POKT_RPC_TIMEOUT"
environmentStageEnv = "ENVIRONMENT_STAGE"
// TODO: Use an encrypted key file or move over to a encrypted DB. (@Blade)
appStakesPrivateKeyEnv = "APPSTAKE_PRIVATE_KEYS"
poktRPCFullHostEnv = "POKT_RPC_FULL_HOST"
httpServerPortEnv = "HTTP_SERVER_PORT"
poktRPCTimeoutEnv = "POKT_RPC_TIMEOUT"
dbConnectionUrlEnv = "DB_CONNECTION_URL"
sessionCacheTTLEnv = "SESSION_CACHE_TTL"
environmentStageEnv = "ENVIRONMENT_STAGE"
poktApplicationsEncryptionKeyEnv = "POKT_APPLICATIONS_ENCRYPTION_KEY"
)

// DotEnvConfigProvider implements the GatewayServerProvider interface.
type DotEnvConfigProvider struct {
poktRPCFullHost string
httpServerPort uint
poktRPCTimeout time.Duration
environmentStage config.EnvironmentStage
appStakes []*models.Ed25519Account
poktRPCFullHost string
httpServerPort uint
poktRPCTimeout time.Duration
sessionCacheTTL time.Duration
environmentStage config.EnvironmentStage
poktApplicationsEncryptionKey string
databaseConnectionUrl string
}

// GetPoktRPCFullHost returns the PoktRPCFullHost value.
func (c *DotEnvConfigProvider) GetPoktRPCFullHost() string {
func (c DotEnvConfigProvider) GetPoktRPCFullHost() string {
return c.poktRPCFullHost
}

// GetHTTPServerPort returns the HTTPServerPort value.
func (c *DotEnvConfigProvider) GetHTTPServerPort() uint {
func (c DotEnvConfigProvider) GetHTTPServerPort() uint {
return c.httpServerPort
}

// GetPoktRPCTimeout returns the PoktRPCTimeout value.
func (c *DotEnvConfigProvider) GetPoktRPCTimeout() time.Duration {
func (c DotEnvConfigProvider) GetPoktRPCTimeout() time.Duration {
return c.poktRPCTimeout
}

// GetSessionCacheTTL returns the time value for session to expire in cache.
func (c DotEnvConfigProvider) GetSessionCacheTTL() time.Duration {
return c.poktRPCTimeout
}

Expand All @@ -50,9 +56,14 @@ func (c DotEnvConfigProvider) GetEnvironmentStage() config.EnvironmentStage {
return c.environmentStage
}

// GetAppStakes returns the app stakes for sending a relay
func (c *DotEnvConfigProvider) GetAppStakes() []*models.Ed25519Account {
return c.appStakes
// GetPoktApplicationsEncryptionKey: Key used to decrypt pokt applications private key.
func (c DotEnvConfigProvider) GetPoktApplicationsEncryptionKey() string {
return c.poktApplicationsEncryptionKey
}

// GetDatabaseConnectionUrl returns the PoktRPCFullHost value.
func (c DotEnvConfigProvider) GetDatabaseConnectionUrl() string {
return c.databaseConnectionUrl
}

// NewDotEnvConfigProvider creates a new instance of DotEnvConfigProvider.
Expand All @@ -62,71 +73,37 @@ func NewDotEnvConfigProvider() *DotEnvConfigProvider {
panic(fmt.Sprintf("Error loading .env file: %s", err))
}

poktRPCFullHost, err := getEnvVar(poktRPCFullHostEnv)
if err != nil {
panic(fmt.Sprintf("Error getting %s: %s", poktRPCFullHostEnv, err))
}

httpServerPortStr, err := getEnvVar(httpServerPortEnv)
if err != nil {
panic(fmt.Sprintf("Error getting %s: %s", httpServerPortEnv, err))
}

poktRPCTimeoutStr, err := getEnvVar(poktRPCTimeoutEnv)
if err != nil {
panic(fmt.Sprintf("Error getting %s: %s", poktRPCTimeoutEnv, err))
}

environmentStage, err := getEnvVar(environmentStageEnv)
poktRPCTimeout, err := time.ParseDuration(getEnvVar(poktRPCTimeoutEnv))
if err != nil {
panic(fmt.Sprintf("Error getting %s: %s", environmentStageEnv, err))
panic(fmt.Sprintf("Error parsing %s: %s", poktRPCTimeoutEnv, err))
}

httpServerPort, err := strconv.ParseUint(httpServerPortStr, 10, 64)
httpServerPort, err := strconv.ParseUint(getEnvVar(httpServerPortEnv), 10, 64)
if err != nil {
panic(fmt.Sprintf("Error parsing %s: %s", httpServerPortEnv, err))
}

poktRPCTimeout, err := time.ParseDuration(poktRPCTimeoutStr)
sessionCacheTTLDuration, err := time.ParseDuration(getEnvVar(sessionCacheTTLEnv))
if err != nil {
panic(fmt.Sprintf("Error parsing %s: %s", poktRPCTimeoutEnv, err))
panic(fmt.Sprintf("Error parsing %s: %s", sessionCacheTTLDuration, err))
}

return &DotEnvConfigProvider{
poktRPCFullHost: poktRPCFullHost,
httpServerPort: uint(httpServerPort),
poktRPCTimeout: poktRPCTimeout,
environmentStage: config.EnvironmentStage(environmentStage),
appStakes: getAppStakesFromEnv(),
poktRPCFullHost: getEnvVar(poktRPCFullHostEnv),
httpServerPort: uint(httpServerPort),
poktRPCTimeout: poktRPCTimeout,
sessionCacheTTL: sessionCacheTTLDuration,
databaseConnectionUrl: getEnvVar(dbConnectionUrlEnv),
environmentStage: config.EnvironmentStage(getEnvVar(environmentStageEnv)),
poktApplicationsEncryptionKey: getEnvVar(poktApplicationsEncryptionKeyEnv),
}
}

// getEnvVar retrieves the value of the environment variable with error handling.
func getEnvVar(name string) (string, error) {
func getEnvVar(name string) string {
value, exists := os.LookupEnv(name)
if !exists {
return "", fmt.Errorf("%s not set", name)
}
return value, nil
}

func getAppStakesFromEnv() []*models.Ed25519Account {
privateKeys, err := getEnvVar(appStakesPrivateKeyEnv)
if err != nil {
panic(fmt.Sprintf("Error parsing %s", appStakesPrivateKeyEnv))
}
var appStakePrivateKeys []*models.Ed25519Account
for _, key := range strings.Split(privateKeys, ",") {
appStake, err := models.NewAccount(key)
if err != nil {
panic("Failed to parse appstake key")
}
appStakePrivateKeys = append(appStakePrivateKeys, appStake)
panic(fmt.Errorf("%s not set", name))
}

if len(appStakePrivateKeys) == 0 {
panic("app stakes were not provided or unable to parse successfully")
}

return appStakePrivateKeys
return value
}
10 changes: 4 additions & 6 deletions cmd/gateway_server/internal/config/provider.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package config

import (
"os-gateway/internal/config"
"os-gateway/pkg/pokt/pokt_v0/models"
"time"
"pokt_gateway_server/internal/config"
)

type GatewayServerProvider interface {
GetPoktRPCFullHost() string
GetHTTPServerPort() uint
GetPoktRPCTimeout() time.Duration
GetAppStakes() []*models.Ed25519Account
config.DBCredentialsProvider
config.PoktNodeConfigProvider
config.SecretProvider
config.EnvironmentProvider
}
44 changes: 44 additions & 0 deletions cmd/gateway_server/internal/controllers/pokt_apps.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package controllers

import (
"github.com/pquerna/ffjson/ffjson"
"github.com/valyala/fasthttp"
"go.uber.org/zap"
"pokt_gateway_server/cmd/gateway_server/internal/models"
"pokt_gateway_server/cmd/gateway_server/internal/transform"
"pokt_gateway_server/internal/pokt_applications_registry"
"pokt_gateway_server/pkg/pokt/pokt_v0"
)

// RelayController handles relay requests for a specific chain.
type PoktAppsController struct {
logger *zap.Logger
poktClient pokt_v0.PocketService
appRegistry pokt_applications_registry.Service
}

// NewRelayController creates a new instance of RelayController.
func NewPoktAppsController(appRegistry pokt_applications_registry.Service, logger *zap.Logger) *PoktAppsController {
return &PoktAppsController{appRegistry: appRegistry, logger: logger}
}

// GetAllPoktApps is the path for relay requests.
const GetAllPoktApps = "/poktapps"

// HandleRelay handles incoming relay requests.
func (c *PoktAppsController) GetAll(ctx *fasthttp.RequestCtx) {
applications := c.appRegistry.GetApplications()
appsPublic := []*models.PoktApplication{}
for _, app := range applications {
appsPublic = append(appsPublic, transform.ToPoktApplication(app))
}
result, err := ffjson.Marshal(appsPublic)
if err != nil {
ctx.Response.SetStatusCode(fasthttp.StatusInternalServerError)
return
}
// Send a successful response back to the client.
ctx.Response.SetStatusCode(fasthttp.StatusOK)
ctx.Response.Header.Set("Content-Type", "application/json")
ctx.Response.SetBody(result)
}
33 changes: 21 additions & 12 deletions cmd/gateway_server/internal/controllers/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package controllers

import (
"errors"
"fmt"
"github.com/valyala/fasthttp"
"go.uber.org/zap"
"os-gateway/cmd/gateway_server/internal/common"
slice_common "os-gateway/pkg/common"
"os-gateway/pkg/pokt/pokt_v0"
"os-gateway/pkg/pokt/pokt_v0/models"
"pokt_gateway_server/cmd/gateway_server/internal/common"
"pokt_gateway_server/internal/pokt_applications_registry"
slice_common "pokt_gateway_server/pkg/common"
"pokt_gateway_server/pkg/pokt/pokt_v0"
"pokt_gateway_server/pkg/pokt/pokt_v0/models"
"strings"
"sync"
)
Expand All @@ -16,14 +18,14 @@ var ErrRelayChannelClosed = errors.New("concurrent relay channel closed")

// RelayController handles relay requests for a specific chain.
type RelayController struct {
logger *zap.Logger
poktClient pokt_v0.PocketService
appStakes []*models.Ed25519Account
logger *zap.Logger
poktClient pokt_v0.PocketService
appRegistry pokt_applications_registry.Service
}

// NewRelayController creates a new instance of RelayController.
func NewRelayController(poktClient pokt_v0.PocketService, appStakes []*models.Ed25519Account, logger *zap.Logger) *RelayController {
return &RelayController{poktClient: poktClient, appStakes: appStakes, logger: logger}
func NewRelayController(poktClient pokt_v0.PocketService, appRegistry pokt_applications_registry.Service, logger *zap.Logger) *RelayController {
return &RelayController{poktClient: poktClient, appRegistry: appRegistry, logger: logger}
}

// RelayHandlerPath is the path for relay requests.
Expand All @@ -43,15 +45,22 @@ func (c *RelayController) HandleRelay(ctx *fasthttp.RequestCtx) {
return
}

applications, ok := c.appRegistry.GetApplicationsByChainId(chainID)

if !ok {
common.JSONError(ctx, fmt.Sprintf("%s chainId not supported with existing application registry", chainID), fasthttp.StatusBadRequest)
return
}

// Get a random app stake from the available list.
appStake := slice_common.GetRandomElement(c.appStakes)
appStake := slice_common.GetRandomElement(applications)
if appStake == nil {
common.JSONError(ctx, "App stake not provided", fasthttp.StatusInternalServerError)
return
}

sessionResp, err := c.poktClient.GetSession(&models.GetSessionRequest{
AppPubKey: appStake.PublicKey,
AppPubKey: appStake.Ed25519Account.PublicKey,
Chain: chainID,
})

Expand All @@ -67,7 +76,7 @@ func (c *RelayController) HandleRelay(ctx *fasthttp.RequestCtx) {
Method: string(ctx.Method()),
Path: path,
},
Signer: appStake,
Signer: appStake.Ed25519Account,
Chain: chainID,
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/gateway_server/internal/controllers/relay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// Basic imports
import (
"errors"
"os-gateway/mocks"
"os-gateway/pkg/pokt/pokt_v0/models"
"pokt_gateway_server/mocks"
"pokt_gateway_server/pkg/pokt/pokt_v0/models"
"testing"

"github.com/stretchr/testify/suite"
Expand Down Expand Up @@ -70,7 +70,7 @@
{
name: "EmptyChainID",
setupMocks: func(ctx *fasthttp.RequestCtx) {
suite.mockRelayController = NewRelayController(suite.mockPocketService, suite.mockAppStakePrivateKeys, zap.NewNop())

Check failure on line 73 in cmd/gateway_server/internal/controllers/relay_test.go

View workflow job for this annotation

GitHub Actions / build

cannot use suite.mockPocketService (variable of type *mocks.PocketService) as pokt_v0.PocketService value in argument to NewRelayController: *mocks.PocketService does not implement pokt_v0.PocketService (missing method GetLatestStakedApplications)

Check failure on line 73 in cmd/gateway_server/internal/controllers/relay_test.go

View workflow job for this annotation

GitHub Actions / build

cannot use suite.mockAppStakePrivateKeys (variable of type []*"pokt_gateway_server/pkg/pokt/pokt_v0/models".Ed25519Account) as pokt_applications_registry.Service value in argument to NewRelayController: []*"pokt_gateway_server/pkg/pokt/pokt_v0/models".Ed25519Account does not implement pokt_applications_registry.Service (missing method GetApplications)
},
path: "/relay/",
expectedSatus: fasthttp.StatusBadRequest,
Expand All @@ -79,7 +79,7 @@
{
name: "AppStakeNotProvided",
setupMocks: func(ctx *fasthttp.RequestCtx) {
suite.mockRelayController = NewRelayController(suite.mockPocketService, []*models.Ed25519Account{}, zap.NewNop())

Check failure on line 82 in cmd/gateway_server/internal/controllers/relay_test.go

View workflow job for this annotation

GitHub Actions / build

cannot use suite.mockPocketService (variable of type *mocks.PocketService) as pokt_v0.PocketService value in argument to NewRelayController: *mocks.PocketService does not implement pokt_v0.PocketService (missing method GetLatestStakedApplications)

Check failure on line 82 in cmd/gateway_server/internal/controllers/relay_test.go

View workflow job for this annotation

GitHub Actions / build

cannot use []*models.Ed25519Account{} (value of type []*"pokt_gateway_server/pkg/pokt/pokt_v0/models".Ed25519Account) as pokt_applications_registry.Service value in argument to NewRelayController: []*"pokt_gateway_server/pkg/pokt/pokt_v0/models".Ed25519Account does not implement pokt_applications_registry.Service (missing method GetApplications)
},
path: "/relay/1234",
expectedSatus: fasthttp.StatusInternalServerError,
Expand All @@ -91,7 +91,7 @@

chainID, _ := getPathSegmented(ctx.Path())

suite.mockRelayController = NewRelayController(suite.mockPocketService, suite.mockAppStakePrivateKeys, zap.NewNop())

Check failure on line 94 in cmd/gateway_server/internal/controllers/relay_test.go

View workflow job for this annotation

GitHub Actions / build

cannot use suite.mockPocketService (variable of type *mocks.PocketService) as pokt_v0.PocketService value in argument to NewRelayController: *mocks.PocketService does not implement pokt_v0.PocketService (missing method GetLatestStakedApplications)

Check failure on line 94 in cmd/gateway_server/internal/controllers/relay_test.go

View workflow job for this annotation

GitHub Actions / build

cannot use suite.mockAppStakePrivateKeys (variable of type []*"pokt_gateway_server/pkg/pokt/pokt_v0/models".Ed25519Account) as pokt_applications_registry.Service value in argument to NewRelayController: []*"pokt_gateway_server/pkg/pokt/pokt_v0/models".Ed25519Account does not implement pokt_applications_registry.Service (missing method GetApplications)

suite.mockPocketService.EXPECT().GetSession(&models.GetSessionRequest{
AppPubKey: suite.mockAppStakePrivateKeys[0].PublicKey,
Expand All @@ -109,7 +109,7 @@

chainID, _ := getPathSegmented(ctx.Path())

suite.mockRelayController = NewRelayController(suite.mockPocketService, suite.mockAppStakePrivateKeys, zap.NewNop())

Check failure on line 112 in cmd/gateway_server/internal/controllers/relay_test.go

View workflow job for this annotation

GitHub Actions / build

cannot use suite.mockPocketService (variable of type *mocks.PocketService) as pokt_v0.PocketService value in argument to NewRelayController: *mocks.PocketService does not implement pokt_v0.PocketService (missing method GetLatestStakedApplications)

Check failure on line 112 in cmd/gateway_server/internal/controllers/relay_test.go

View workflow job for this annotation

GitHub Actions / build

cannot use suite.mockAppStakePrivateKeys (variable of type []*"pokt_gateway_server/pkg/pokt/pokt_v0/models".Ed25519Account) as pokt_applications_registry.Service value in argument to NewRelayController: []*"pokt_gateway_server/pkg/pokt/pokt_v0/models".Ed25519Account does not implement pokt_applications_registry.Service (missing method GetApplications)

suite.mockPocketService.EXPECT().GetSession(&models.GetSessionRequest{
AppPubKey: suite.mockAppStakePrivateKeys[0].PublicKey,
Expand Down Expand Up @@ -141,7 +141,7 @@

chainID, _ := getPathSegmented(ctx.Path())

suite.mockRelayController = NewRelayController(suite.mockPocketService, suite.mockAppStakePrivateKeys, zap.NewNop())

Check failure on line 144 in cmd/gateway_server/internal/controllers/relay_test.go

View workflow job for this annotation

GitHub Actions / build

cannot use suite.mockPocketService (variable of type *mocks.PocketService) as pokt_v0.PocketService value in argument to NewRelayController: *mocks.PocketService does not implement pokt_v0.PocketService (missing method GetLatestStakedApplications)

Check failure on line 144 in cmd/gateway_server/internal/controllers/relay_test.go

View workflow job for this annotation

GitHub Actions / build

cannot use suite.mockAppStakePrivateKeys (variable of type []*"pokt_gateway_server/pkg/pokt/pokt_v0/models".Ed25519Account) as pokt_applications_registry.Service value in argument to NewRelayController: []*"pokt_gateway_server/pkg/pokt/pokt_v0/models".Ed25519Account does not implement pokt_applications_registry.Service (missing method GetApplications)

suite.mockPocketService.EXPECT().GetSession(&models.GetSessionRequest{
AppPubKey: suite.mockAppStakePrivateKeys[0].PublicKey,
Expand Down
8 changes: 8 additions & 0 deletions cmd/gateway_server/internal/models/pokt_application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package models

type PoktApplication struct {
ID string `json:"id"`
MaxRelays int `json:"max_relays"`
Chains []string `json:"chain"`
Address string `json:"address"`
}
15 changes: 15 additions & 0 deletions cmd/gateway_server/internal/transform/pokt_application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package transform

import (
"pokt_gateway_server/cmd/gateway_server/internal/models"
internal_model "pokt_gateway_server/internal/pokt_applications_registry/models"
)

func ToPoktApplication(signer *internal_model.PoktApplicationSigner) *models.PoktApplication {
return &models.PoktApplication{
ID: signer.ID,
MaxRelays: int(signer.MaxRelays),
Chains: signer.Chains,
Address: signer.PoktApplication.Address,
}
}
Loading
Loading