Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Database Errors on Sunrise #254

Merged
merged 1 commit into from
Jan 11, 2025
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
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
Loading