Skip to content

Commit

Permalink
Fix Database Errors on Sunrise (#254)
Browse files Browse the repository at this point in the history
  • Loading branch information
bbengfort authored Jan 11, 2025
1 parent e38b171 commit 73ef401
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 13 deletions.
21 changes: 20 additions & 1 deletion .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,23 @@ TRISA_TRP_ENABLED=true
TRISA_TRP_BIND_ADDR=:8200
TRISA_TRP_USE_MTLS=false
TRISA_TRP_POOL=.secret/localhost.pem.gz
TRISA_TRP_CERTS=.secret/server.pem.gz
TRISA_TRP_CERTS=.secret/server.pem.gz

TRISA_TRP_IDENTITY_VASP_NAME="Alice VASP"
TRISA_TRP_IDENTITY_LEI="254900OPPU84GM83MG36"

# If Sunrise is enabled an email configuration must be specified
TRISA_SUNRISE_ENABLED=true

# Email configuration
TRISA_EMAIL_SENDER="AliceVASP Compliance <compliance@alice.us>"

# Specify either SendGrid or SMTP
# SendGrid configuration
TRISA_EMAIL_SENDGRID_API_KEY=""

# SMTP Configuration
TRISA_EMAIL_SMTP_HOST="smtp.alice.us"
TRISA_EMAIL_SMTP_PORT=587
TRISA_EMAIL_SMTP_USERNAME="admin"
TRISA_EMAIL_SMTP_PASSWORD="password"
8 changes: 7 additions & 1 deletion pkg/emails/emails.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,14 @@ const (
initialInterval = 2500 * time.Millisecond
)

// Configure the package to start sending emails.
// Configure the package to start sending emails. If there is no valid email
// configuration available then configuration is gracefully ignored without error.
func Configure(conf Config) (err error) {
// Do not configure email if it is not available but also do not return an error.
if !conf.Available() {
return nil
}

if err = conf.Validate(); err != nil {
return err
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/trisacrypto/envoy/pkg/config"
"github.com/trisacrypto/envoy/pkg/directory"
"github.com/trisacrypto/envoy/pkg/emails"
"github.com/trisacrypto/envoy/pkg/logger"
"github.com/trisacrypto/envoy/pkg/metrics"
"github.com/trisacrypto/envoy/pkg/store"
Expand Down Expand Up @@ -81,6 +82,11 @@ func New(conf config.Config) (node *Node, err error) {
node.webhook = webhook.New(conf.Webhook())
}

// Configure email if it's available
if err = emails.Configure(conf.Email); err != nil {
return nil, err
}

// Create the TRISA management system
if node.network, err = network.New(conf.Node); err != nil {
return nil, err
Expand Down
2 changes: 2 additions & 0 deletions pkg/store/models/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ type PreparedTransaction interface {
Update(*Transaction) error // Update the transaction with new information; e.g. data from decryption
AddCounterparty(*Counterparty) error // Add counterparty by database ULID, counterparty name, or registered directory ID; if the counterparty doesn't exist, it is created
AddEnvelope(*SecureEnvelope) error // Associate a secure envelope with the prepared transaction
CreateSunrise(*Sunrise) error // Create a sunrise message sent to the counterparty for the transaction
UpdateSunrise(*Sunrise) error // Update the sunrise message
Rollback() error // Rollback the prepared transaction and conclude it
Commit() error // Commit the prepared transaction and conclude it
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/store/sqlite/migrations/0005_sunrise_tokens.sql
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ CREATE TABLE IF NOT EXISTS sunrise (
envelope_id TEXT NOT NULL,
email TEXT NOT NULL,
expiration DATETIME NOT NULL,
signature BLOB NOT NULL,
signature BLOB DEFAULT NULL,
status TEXT NOT NULL,
sent_on DATETIME DEFAULT NULL,
verified_on DATETIME DEFAULT NULL,
Expand Down
43 changes: 36 additions & 7 deletions pkg/store/sqlite/sunrise.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ const createSunriseSQL = "INSERT INTO sunrise (id, envelope_id, email, expiratio
// Create a sunrise message in the database.
func (s *Store) CreateSunrise(ctx context.Context, msg *models.Sunrise) (err error) {
// Basic validation
// Note: this is duplicated in updateSunrise but better to check before starting a
// transaction that will take up system resources.
if !ulids.IsZero(msg.ID) {
return dberr.ErrNoIDOnCreate
}
Expand All @@ -69,6 +71,22 @@ func (s *Store) CreateSunrise(ctx context.Context, msg *models.Sunrise) (err err
}
defer tx.Rollback()

if err = createSunrise(tx, msg); err != nil {
return err
}

if err = tx.Commit(); err != nil {
return err
}
return nil
}

func createSunrise(tx *sql.Tx, msg *models.Sunrise) (err error) {
// Basic validation
if !ulids.IsZero(msg.ID) {
return dberr.ErrNoIDOnCreate
}

// Create IDs and model metadata, updating the sunrise message in place.
msg.ID = ulids.New()
msg.Created = time.Now()
Expand All @@ -79,10 +97,6 @@ func (s *Store) CreateSunrise(ctx context.Context, msg *models.Sunrise) (err err
// TODO: handle constraint violations
return err
}

if err = tx.Commit(); err != nil {
return err
}
return nil
}

Expand Down Expand Up @@ -120,6 +134,8 @@ const updateSunriseSQL = "UPDATE sunrise SET envelope_id=:envelopeID, email=:ema
// Update sunrise message information.
func (s *Store) UpdateSunrise(ctx context.Context, msg *models.Sunrise) (err error) {
// Basic validation
// Note: this is duplicated in updateSunrise but better to check before starting a
// transaction that will take up system resources.
if ulids.IsZero(msg.ID) {
return dberr.ErrMissingID
}
Expand All @@ -130,6 +146,22 @@ func (s *Store) UpdateSunrise(ctx context.Context, msg *models.Sunrise) (err err
}
defer tx.Rollback()

if err = updateSunrise(tx, msg); err != nil {
return err
}

if err = tx.Commit(); err != nil {
return err
}
return nil
}

func updateSunrise(tx *sql.Tx, msg *models.Sunrise) (err error) {
// Basic validation
if ulids.IsZero(msg.ID) {
return dberr.ErrMissingID
}

// Update modified timestamp (in place).
msg.Modified = time.Now()

Expand All @@ -142,9 +174,6 @@ func (s *Store) UpdateSunrise(ctx context.Context, msg *models.Sunrise) (err err
return dberr.ErrNotFound
}

if err = tx.Commit(); err != nil {
return err
}
return nil
}

Expand Down
8 changes: 8 additions & 0 deletions pkg/store/sqlite/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,14 @@ func (p *PreparedTransaction) AddEnvelope(in *models.SecureEnvelope) (err error)
return nil
}

func (p *PreparedTransaction) CreateSunrise(in *models.Sunrise) error {
return createSunrise(p.tx, in)
}

func (p *PreparedTransaction) UpdateSunrise(in *models.Sunrise) error {
return updateSunrise(p.tx, in)
}

func (p *PreparedTransaction) Rollback() error {
return p.tx.Rollback()
}
Expand Down
7 changes: 7 additions & 0 deletions pkg/web/api/v1/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ const (
colorUnspecified = "text-gray-500"
tooltipUnspecified = "The transfer state is unknown or purposefully not specified."

colorDraft = "text-gray-500"
tooltipDraft = "The TRISA exchange is in a draft state and has not been sent."

colorPending = "text-yellow-700"
tooltipPending = "Action is required by the sending party, await a following RPC."

Expand Down Expand Up @@ -272,6 +275,8 @@ func (c *Transaction) ColorStatus() string {
switch c.Status {
case models.StatusUnspecified, "":
return colorUnspecified
case models.StatusDraft:
return colorDraft
case models.StatusPending:
return colorPending
case models.StatusReview:
Expand All @@ -293,6 +298,8 @@ func (c *Transaction) TooltipStatus() string {
switch c.Status {
case models.StatusUnspecified, "":
return tooltipUnspecified
case models.StatusDraft:
return tooltipDraft
case models.StatusPending:
return tooltipPending
case models.StatusReview:
Expand Down
5 changes: 4 additions & 1 deletion pkg/web/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ func (s *Server) Serve(errc chan<- error) (err error) {
}
}()

log.Info().Str("url", s.URL()).Msg("compliance and admin web user interface started")
log.Info().
Str("url", s.URL()).
Bool("sunrise", s.conf.Sunrise.Enabled && s.conf.Email.Available()).
Msg("compliance and admin web user interface started")
return nil
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/web/sunrise.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func (s *Server) SendSunrise(c *gin.Context) {
}

// This method will create the ID on the sunrise record
if err = s.store.CreateSunrise(ctx, record); err != nil {
if err = packet.DB.CreateSunrise(record); err != nil {
c.Error(err)
c.JSON(http.StatusInternalServerError, api.Error("could not complete sunrise request"))
return
Expand Down Expand Up @@ -170,7 +170,7 @@ func (s *Server) SendSunrise(c *gin.Context) {

// Update the sunrise record in the database with the token and sent on timestamp
record.SentOn = sql.NullTime{Valid: true, Time: time.Now()}
if err = s.store.UpdateSunrise(ctx, record); err != nil {
if err = packet.DB.UpdateSunrise(record); err != nil {
c.Error(err)
c.JSON(http.StatusInternalServerError, api.Error("could not complete sunrise request"))
return
Expand Down

0 comments on commit 73ef401

Please sign in to comment.