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

Commit

Permalink
Support Private Key Encryption (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
nodiesBlade authored Jan 29, 2024
1 parent dca1b2a commit 996a23d
Show file tree
Hide file tree
Showing 42 changed files with 1,075 additions and 153 deletions.
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 @@ package controllers
// 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
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

0 comments on commit 996a23d

Please sign in to comment.