diff --git a/.env.test b/.env.test index 0df0238..89465a8 100644 --- a/.env.test +++ b/.env.test @@ -1,9 +1,10 @@ ENV=test -DATABASE_URL=test.db -DATABASE_TYPE=sqlite +DATABASE_URL=http://localhost:8000 +DATABASE_TYPE=dynamodb +REGION=us-east-1 CUSTOM_ACCESS_TOKEN_SCRIPT="function(user,tokenPayload){var data = tokenPayload;data.extra = {'x-extra-id': user.id};return data;}" SMTP_HOST=smtp.mailtrap.io SMTP_PORT=2525 SMTP_USERNAME=test SMTP_PASSWORD=test -SENDER_EMAIL="info@authorizer.dev" \ No newline at end of file +SENDER_EMAIL="info@authorizer.dev" \ No newline at end of file diff --git a/server/constants/env.go b/server/constants/env.go index a675dcc..cc1ddfc 100644 --- a/server/constants/env.go +++ b/server/constants/env.go @@ -21,6 +21,12 @@ const ( EnvKeyDatabaseType = "DATABASE_TYPE" // EnvKeyDatabaseURL key for env variable DATABASE_URL EnvKeyDatabaseURL = "DATABASE_URL" + // EnvAwsRegion key for env variable AWS REGION + EnvAwsRegion = "REGION" + // EnvAwsAccessKey key for env variable AWS_ACCESS_KEY + EnvAwsAccessKey = "AWS_ACCESS_KEY" + // EnvAwsAccessKey key for env variable AWS_SECRET_KEY + EnvAwsSecretKey = "AWS_SECRET_KEY" // EnvKeyDatabaseName key for env variable DATABASE_NAME EnvKeyDatabaseName = "DATABASE_NAME" // EnvKeyDatabaseUsername key for env variable DATABASE_USERNAME diff --git a/server/db/models/email_templates.go b/server/db/models/email_templates.go index 95e5891..6608a17 100644 --- a/server/db/models/email_templates.go +++ b/server/db/models/email_templates.go @@ -11,7 +11,7 @@ import ( type EmailTemplate struct { Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` - EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name" dynamo:"event_name"` + EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name" dynamo:"event_name" index:"event_name,hash"` Subject string `gorm:"type:text" json:"subject" bson:"subject" cql:"subject" dynamo:"subject"` Template string `gorm:"type:text" json:"template" bson:"template" cql:"template" dynamo:"template"` Design string `gorm:"type:text" json:"design" bson:"design" cql:"design" dynamo:"design"` diff --git a/server/db/models/otp.go b/server/db/models/otp.go index 8898c95..ac9732b 100644 --- a/server/db/models/otp.go +++ b/server/db/models/otp.go @@ -4,7 +4,7 @@ package models type OTP struct { Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` - Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email"` + Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"` Otp string `json:"otp" bson:"otp" cql:"otp" dynamo:"otp"` ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_at"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` diff --git a/server/db/models/session.go b/server/db/models/session.go index cd98c85..8460c66 100644 --- a/server/db/models/session.go +++ b/server/db/models/session.go @@ -6,7 +6,7 @@ package models type Session struct { Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` - UserID string `gorm:"type:char(36)" json:"user_id" bson:"user_id" cql:"user_id" dynamo:"user_id"` + UserID string `gorm:"type:char(36)" json:"user_id" bson:"user_id" cql:"user_id" dynamo:"user_id" index:"user_id,hash"` UserAgent string `json:"user_agent" bson:"user_agent" cql:"user_agent" dynamo:"user_agent"` IP string `json:"ip" bson:"ip" cql:"ip" dynamo:"ip"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` diff --git a/server/db/models/user.go b/server/db/models/user.go index 7f6b2ae..3b533a3 100644 --- a/server/db/models/user.go +++ b/server/db/models/user.go @@ -15,7 +15,7 @@ type User struct { Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` - Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email"` + Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"` EmailVerifiedAt *int64 `json:"email_verified_at" bson:"email_verified_at" cql:"email_verified_at" dynamo:"email_verified_at"` Password *string `gorm:"type:text" json:"password" bson:"password" cql:"password" dynamo:"password"` SignupMethods string `json:"signup_methods" bson:"signup_methods" cql:"signup_methods" dynamo:"signup_methods"` diff --git a/server/db/models/verification_requests.go b/server/db/models/verification_requests.go index a625ab3..5d4179d 100644 --- a/server/db/models/verification_requests.go +++ b/server/db/models/verification_requests.go @@ -13,7 +13,7 @@ import ( type VerificationRequest struct { Key string `json:"_key,omitempty" bson:"_key" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` - Token string `gorm:"type:text" json:"token" bson:"token" cql:"jwt_token" dynamo:"token"` // token is reserved keyword in cassandra + Token string `gorm:"type:text" json:"token" bson:"token" cql:"jwt_token" dynamo:"token" index:"token,hash"` Identifier string `gorm:"uniqueIndex:idx_email_identifier;type:varchar(64)" json:"identifier" bson:"identifier" cql:"identifier" dynamo:"identifier"` ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_at"` Email string `gorm:"uniqueIndex:idx_email_identifier;type:varchar(256)" json:"email" bson:"email" cql:"email" dynamo:"email"` diff --git a/server/db/models/webhook.go b/server/db/models/webhook.go index a2f8cfb..5f9f8f7 100644 --- a/server/db/models/webhook.go +++ b/server/db/models/webhook.go @@ -14,7 +14,7 @@ import ( type Webhook struct { Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` - EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name" dynamo:"event_name"` + EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name" dynamo:"event_name" index:"event_name,hash"` EndPoint string `gorm:"type:text" json:"endpoint" bson:"endpoint" cql:"endpoint" dynamo:"endpoint"` Headers string `gorm:"type:text" json:"headers" bson:"headers" cql:"headers" dynamo:"headers"` Enabled bool `json:"enabled" bson:"enabled" cql:"enabled" dynamo:"enabled"` diff --git a/server/db/models/webhook_log.go b/server/db/models/webhook_log.go index a74426e..6dda00f 100644 --- a/server/db/models/webhook_log.go +++ b/server/db/models/webhook_log.go @@ -16,7 +16,7 @@ type WebhookLog struct { HttpStatus int64 `json:"http_status" bson:"http_status" cql:"http_status" dynamo:"http_status"` Response string `gorm:"type:text" json:"response" bson:"response" cql:"response" dynamo:"response"` Request string `gorm:"type:text" json:"request" bson:"request" cql:"request" dynamo:"request"` - WebhookID string `gorm:"type:char(36)" json:"webhook_id" bson:"webhook_id" cql:"webhook_id" dynamo:"webhook_id"` + WebhookID string `gorm:"type:char(36)" json:"webhook_id" bson:"webhook_id" cql:"webhook_id" dynamo:"webhook_id" index:"webhook_id,hash"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"` } diff --git a/server/db/providers/dynamodb/email_template.go b/server/db/providers/dynamodb/email_template.go index ae07b00..08745cf 100644 --- a/server/db/providers/dynamodb/email_template.go +++ b/server/db/providers/dynamodb/email_template.go @@ -95,7 +95,7 @@ func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName st var emailTemplates []models.EmailTemplate var emailTemplate models.EmailTemplate - err := collection.Scan().Filter("'event_name' = ?", eventName).Limit(1).AllWithContext(ctx, &emailTemplates) + err := collection.Scan().Index("event_name").Filter("'event_name' = ?", eventName).Limit(1).AllWithContext(ctx, &emailTemplates) if err != nil { return nil, err } diff --git a/server/db/providers/dynamodb/otp.go b/server/db/providers/dynamodb/otp.go index 42e10ab..063f634 100644 --- a/server/db/providers/dynamodb/otp.go +++ b/server/db/providers/dynamodb/otp.go @@ -52,7 +52,7 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod collection := p.db.Table(models.Collections.OTP) - err := collection.Scan().Filter("'email' = ?", emailAddress).Limit(1).AllWithContext(ctx, &otps) + err := collection.Scan().Index("email").Filter("'email' = ?", emailAddress).Limit(1).AllWithContext(ctx, &otps) if err != nil { return nil, err diff --git a/server/db/providers/dynamodb/provider.go b/server/db/providers/dynamodb/provider.go index 9b5efc8..962a222 100644 --- a/server/db/providers/dynamodb/provider.go +++ b/server/db/providers/dynamodb/provider.go @@ -2,51 +2,49 @@ package dynamodb import ( "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/server/memorystore" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/session" "github.com/guregu/dynamo" ) -// TODO change following provider to new db provider type provider struct { db *dynamo.DB } -// NewProvider returns a new SQL provider -// TODO change following provider to new db provider +// NewProvider returns a new Dynamo provider func NewProvider() (*provider, error) { + region := memorystore.RequiredEnvStoreObj.GetRequiredEnv().REGION + dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL + accessKey := memorystore.RequiredEnvStoreObj.GetRequiredEnv().AWS_ACCESS_KEY + secretKey := memorystore.RequiredEnvStoreObj.GetRequiredEnv().AWS_SECRET_KEY config := aws.Config{ - Endpoint: aws.String("http://localhost:8000"), - Region: aws.String("us-east-1"), + Region: aws.String(region), + MaxRetries: aws.Int(3), } - session := session.Must(session.NewSession()) - db := dynamo.New(session, &config) - if err := db.CreateTable(models.Collections.User, models.User{}).Wait(); err != nil { - // fmt.Println(" User", err) - } - if err := db.CreateTable(models.Collections.Session, models.Session{}).Wait(); err != nil { - // fmt.Println("Session error", err) - } - if err := db.CreateTable(models.Collections.EmailTemplate, models.EmailTemplate{}).Wait(); err != nil { - // fmt.Println(" EmailTemplate", err) - } - if err := db.CreateTable(models.Collections.Env, models.Env{}).Wait(); err != nil { - // fmt.Println(" Env", err) - } - if err := db.CreateTable(models.Collections.OTP, models.OTP{}).Wait(); err != nil { - // fmt.Println(" OTP", err) - } - if err := db.CreateTable(models.Collections.VerificationRequest, models.VerificationRequest{}).Wait(); err != nil { - // fmt.Println(" VerificationRequest", err) - } - if err := db.CreateTable(models.Collections.Webhook, models.Webhook{}).Wait(); err != nil { - // fmt.Println(" Webhook", err) - } - if err := db.CreateTable(models.Collections.WebhookLog, models.WebhookLog{}).Wait(); err != nil { - // fmt.Println(" WebhookLog", err) + // custom accessKey, secretkey took first priority, if not then fetch config from aws credentials + if accessKey != "" && secretKey != "" { + config.Credentials = credentials.NewStaticCredentials(accessKey, secretKey, "") + } else if dbURL != "" { + // static config in case of testing or local-setup + config.Credentials = credentials.NewStaticCredentials("key", "key", "") + config.Endpoint = aws.String(dbURL) } + session := session.Must(session.NewSession(&config)) + db := dynamo.New(session) + + db.CreateTable(models.Collections.User, models.User{}).Wait() + db.CreateTable(models.Collections.Session, models.Session{}).Wait() + db.CreateTable(models.Collections.EmailTemplate, models.EmailTemplate{}).Wait() + db.CreateTable(models.Collections.Env, models.Env{}).Wait() + db.CreateTable(models.Collections.OTP, models.OTP{}).Wait() + db.CreateTable(models.Collections.VerificationRequest, models.VerificationRequest{}).Wait() + db.CreateTable(models.Collections.Webhook, models.Webhook{}).Wait() + db.CreateTable(models.Collections.WebhookLog, models.WebhookLog{}).Wait() + return &provider{ db: db, }, nil diff --git a/server/db/providers/dynamodb/user.go b/server/db/providers/dynamodb/user.go index 5617065..ef780b1 100644 --- a/server/db/providers/dynamodb/user.go +++ b/server/db/providers/dynamodb/user.go @@ -131,7 +131,7 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.Use var user models.User collection := p.db.Table(models.Collections.User) - err := collection.Scan().Filter("'email' = ?", email).AllWithContext(ctx, &users) + err := collection.Scan().Index("email").Filter("'email' = ?", email).AllWithContext(ctx, &users) if err != nil { return user, nil diff --git a/server/db/providers/dynamodb/webhook.go b/server/db/providers/dynamodb/webhook.go index 0883418..9cf7ec7 100644 --- a/server/db/providers/dynamodb/webhook.go +++ b/server/db/providers/dynamodb/webhook.go @@ -22,6 +22,7 @@ func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*mod webhook.Key = webhook.ID webhook.CreatedAt = time.Now().Unix() webhook.UpdatedAt = time.Now().Unix() + err := collection.Put(webhook).RunWithContext(ctx) if err != nil { @@ -106,7 +107,7 @@ func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) var webhook models.Webhook collection := p.db.Table(models.Collections.Webhook) - iter := collection.Scan().Filter("'event_name' = ?", eventName).Iter() + iter := collection.Scan().Index("event_name").Filter("'event_name' = ?", eventName).Iter() for iter.NextWithContext(ctx, &webhook) { return webhook.AsAPIWebhook(), nil diff --git a/server/db/providers/dynamodb/webhook_log.go b/server/db/providers/dynamodb/webhook_log.go index e4ca7d5..e9d1dcd 100644 --- a/server/db/providers/dynamodb/webhook_log.go +++ b/server/db/providers/dynamodb/webhook_log.go @@ -44,7 +44,7 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat scanner := collection.Scan() if webhookID != "" { - iter = scanner.Filter("'webhook_id' = ?", webhookID).Iter() + iter = scanner.Index("webhook_id").Filter("'webhook_id' = ?", webhookID).Iter() for iter.NextWithContext(ctx, &webhookLog) { webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog()) } diff --git a/server/memorystore/required_env_store.go b/server/memorystore/required_env_store.go index a5f3a81..2c0139c 100644 --- a/server/memorystore/required_env_store.go +++ b/server/memorystore/required_env_store.go @@ -16,6 +16,9 @@ import ( // RequiredEnv holds information about required envs type RequiredEnv struct { EnvPath string `json:"ENV_PATH"` + REGION string `json:"REGION"` + AWS_ACCESS_KEY string `json:"AWS_ACCESS_KEY"` + AWS_SECRET_KEY string `json:"AWS_SECRET_KEY"` DatabaseURL string `json:"DATABASE_URL"` DatabaseType string `json:"DATABASE_TYPE"` DatabaseName string `json:"DATABASE_NAME"` @@ -73,6 +76,9 @@ func InitRequiredEnv() error { log.Infof("using OS env instead of %s file", envPath) } + region := os.Getenv(constants.EnvAwsRegion) + awsAccessKey := os.Getenv(constants.EnvAwsAccessKey) + awsSecretKey := os.Getenv(constants.EnvAwsSecretKey) dbURL := os.Getenv(constants.EnvKeyDatabaseURL) dbType := os.Getenv(constants.EnvKeyDatabaseType) dbName := os.Getenv(constants.EnvKeyDatabaseName) @@ -127,6 +133,9 @@ func InitRequiredEnv() error { requiredEnv := RequiredEnv{ EnvPath: envPath, + REGION: region, + AWS_ACCESS_KEY: awsAccessKey, + AWS_SECRET_KEY: awsSecretKey, DatabaseURL: dbURL, DatabaseType: dbType, DatabaseName: dbName,