diff --git a/server/db/db.go b/server/db/db.go index 25d1ddc..ca14e16 100644 --- a/server/db/db.go +++ b/server/db/db.go @@ -3,132 +3,42 @@ package db import ( "log" - arangoDriver "github.com/arangodb/go-driver" "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/db/providers" + "github.com/authorizerdev/authorizer/server/db/providers/arangodb" + "github.com/authorizerdev/authorizer/server/db/providers/mongodb" + "github.com/authorizerdev/authorizer/server/db/providers/sql" "github.com/authorizerdev/authorizer/server/envstore" - "go.mongodb.org/mongo-driver/mongo" - "gorm.io/driver/mysql" - "gorm.io/driver/postgres" - "gorm.io/driver/sqlite" - "gorm.io/driver/sqlserver" - "gorm.io/gorm" - "gorm.io/gorm/schema" ) -type Manager interface { - AddUser(user User) (User, error) - UpdateUser(user User) (User, error) - DeleteUser(user User) error - GetUsers() ([]User, error) - GetUserByEmail(email string) (User, error) - GetUserByID(email string) (User, error) - AddVerification(verification VerificationRequest) (VerificationRequest, error) - GetVerificationByToken(token string) (VerificationRequest, error) - DeleteVerificationRequest(verificationRequest VerificationRequest) error - GetVerificationRequests() ([]VerificationRequest, error) - GetVerificationByEmail(email string, identifier string) (VerificationRequest, error) - AddSession(session Session) error - DeleteUserSession(userId string) error - AddEnv(env Env) (Env, error) - UpdateEnv(env Env) (Env, error) - GetEnv() (Env, error) -} - -type manager struct { - sqlDB *gorm.DB - arangodb arangoDriver.Database - mongodb *mongo.Database -} - -// mainly used by nosql dbs -type CollectionList struct { - User string - VerificationRequest string - Session string - Env string -} - -var ( - IsORMSupported bool - IsArangoDB bool - IsMongoDB bool - Mgr Manager - Prefix = "authorizer_" - Collections = CollectionList{ - User: Prefix + "users", - VerificationRequest: Prefix + "verification_requests", - Session: Prefix + "sessions", - Env: Prefix + "env", - } -) +// Provider returns the current database provider +var Provider providers.Provider func InitDB() { - var sqlDB *gorm.DB var err error - IsORMSupported = envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) != constants.DbTypeArangodb && envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) != constants.DbTypeMongodb - IsArangoDB = envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) == constants.DbTypeArangodb - IsMongoDB = envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) == constants.DbTypeMongodb + isSQL := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) != constants.DbTypeArangodb && envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) != constants.DbTypeMongodb + isArangoDB := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) == constants.DbTypeArangodb + isMongoDB := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) == constants.DbTypeMongodb - // sql db orm config - ormConfig := &gorm.Config{ - NamingStrategy: schema.NamingStrategy{ - TablePrefix: Prefix, - }, - } - - log.Println("db type:", envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType)) - - switch envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) { - case constants.DbTypePostgres: - sqlDB, err = gorm.Open(postgres.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig) - break - case constants.DbTypeSqlite: - sqlDB, err = gorm.Open(sqlite.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig) - break - case constants.DbTypeMysql: - sqlDB, err = gorm.Open(mysql.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig) - break - case constants.DbTypeSqlserver: - sqlDB, err = gorm.Open(sqlserver.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig) - break - case constants.DbTypeArangodb: - arangodb, err := initArangodb() + if isSQL { + Provider, err = sql.NewProvider() if err != nil { - log.Fatal("error initializing arangodb:", err) - } - - Mgr = &manager{ - sqlDB: nil, - arangodb: arangodb, - mongodb: nil, - } - - break - case constants.DbTypeMongodb: - mongodb, err := initMongodb() - if err != nil { - log.Fatal("error initializing mongodb connection:", err) - } - - Mgr = &manager{ - sqlDB: nil, - arangodb: nil, - mongodb: mongodb, + log.Fatal("=> error setting sql provider:", err) } } - // common for all sql dbs that are configured via go-orm - if IsORMSupported { + if isArangoDB { + Provider, err = arangodb.NewProvider() if err != nil { - log.Fatal("Failed to init sqlDB:", err) - } else { - sqlDB.AutoMigrate(&User{}, &VerificationRequest{}, &Session{}, &Env{}) + log.Fatal("=> error setting arangodb provider:", err) } - Mgr = &manager{ - sqlDB: sqlDB, - arangodb: nil, - mongodb: nil, + } + + if isMongoDB { + Provider, err = mongodb.NewProvider() + if err != nil { + log.Fatal("=> error setting arangodb provider:", err) } } } diff --git a/server/db/env.go b/server/db/env.go deleted file mode 100644 index 5d51371..0000000 --- a/server/db/env.go +++ /dev/null @@ -1,161 +0,0 @@ -package db - -import ( - "fmt" - "log" - "time" - - arangoDriver "github.com/arangodb/go-driver" - "github.com/google/uuid" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo/options" -) - -type Env struct { - Key string `json:"_key,omitempty" bson:"_key"` // for arangodb - ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"` - EnvData []byte `gorm:"type:text" json:"env" bson:"env"` - Hash string `gorm:"type:hash" json:"hash" bson:"hash"` - UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` - CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` -} - -// AddEnv function to add env to db -func (mgr *manager) AddEnv(env Env) (Env, error) { - if env.ID == "" { - env.ID = uuid.New().String() - } - - if IsORMSupported { - // copy id as value for fields required for mongodb & arangodb - env.Key = env.ID - result := mgr.sqlDB.Create(&env) - - if result.Error != nil { - log.Println("error adding config:", result.Error) - return env, result.Error - } - } - - if IsArangoDB { - env.CreatedAt = time.Now().Unix() - env.UpdatedAt = time.Now().Unix() - configCollection, _ := mgr.arangodb.Collection(nil, Collections.Env) - meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(nil), env) - if err != nil { - log.Println("error adding config:", err) - return env, err - } - env.Key = meta.Key - env.ID = meta.ID.String() - } - - if IsMongoDB { - env.CreatedAt = time.Now().Unix() - env.UpdatedAt = time.Now().Unix() - env.Key = env.ID - configCollection := mgr.mongodb.Collection(Collections.Env, options.Collection()) - _, err := configCollection.InsertOne(nil, env) - if err != nil { - log.Println("error adding config:", err) - return env, err - } - } - - return env, nil -} - -// UpdateEnv function to update env in db -func (mgr *manager) UpdateEnv(env Env) (Env, error) { - env.UpdatedAt = time.Now().Unix() - - if IsORMSupported { - result := mgr.sqlDB.Save(&env) - - if result.Error != nil { - log.Println("error updating config:", result.Error) - return env, result.Error - } - } - - if IsArangoDB { - collection, _ := mgr.arangodb.Collection(nil, Collections.Env) - meta, err := collection.UpdateDocument(nil, env.Key, env) - if err != nil { - log.Println("error updating config:", err) - return env, err - } - - env.Key = meta.Key - env.ID = meta.ID.String() - } - - if IsMongoDB { - configCollection := mgr.mongodb.Collection(Collections.Env, options.Collection()) - _, err := configCollection.UpdateOne(nil, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions()) - if err != nil { - log.Println("error updating config:", err) - return env, err - } - } - - return env, nil -} - -// GetConfig function to get config -func (mgr *manager) GetEnv() (Env, error) { - var env Env - - if IsORMSupported { - result := mgr.sqlDB.First(&env) - - if result.Error != nil { - return env, result.Error - } - } - - if IsArangoDB { - query := fmt.Sprintf("FOR d in %s RETURN d", Collections.Env) - - cursor, err := mgr.arangodb.Query(nil, query, nil) - if err != nil { - return env, err - } - defer cursor.Close() - - for { - if !cursor.HasMore() { - if env.Key == "" { - return env, fmt.Errorf("config not found") - } - break - } - _, err := cursor.ReadDocument(nil, &env) - if err != nil { - return env, err - } - } - } - - if IsMongoDB { - configCollection := mgr.mongodb.Collection(Collections.Env, options.Collection()) - cursor, err := configCollection.Find(nil, bson.M{}, options.Find()) - if err != nil { - return env, err - } - defer cursor.Close(nil) - - for cursor.Next(nil) { - err := cursor.Decode(&env) - if err != nil { - return env, err - } - } - - if env.ID == "" { - return env, fmt.Errorf("config not found") - } - } - - return env, nil -} diff --git a/server/db/models/env.go b/server/db/models/env.go new file mode 100644 index 0000000..24c6353 --- /dev/null +++ b/server/db/models/env.go @@ -0,0 +1,11 @@ +package models + +// Env model for db +type Env struct { + Key string `json:"_key,omitempty" bson:"_key"` // for arangodb + ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"` + EnvData []byte `gorm:"type:text" json:"env" bson:"env"` + Hash string `gorm:"type:hash" json:"hash" bson:"hash"` + UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` + CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` +} diff --git a/server/db/models/model.go b/server/db/models/model.go new file mode 100644 index 0000000..c9eb0b8 --- /dev/null +++ b/server/db/models/model.go @@ -0,0 +1,21 @@ +package models + +// Collections / Tables available for authorizer in the database +type CollectionList struct { + User string + VerificationRequest string + Session string + Env string +} + +var ( + // Prefix for table name / collection names + Prefix = "authorizer_" + // Collections / Tables available for authorizer in the database (used for dbs other than gorm) + Collections = CollectionList{ + User: Prefix + "users", + VerificationRequest: Prefix + "verification_requests", + Session: Prefix + "sessions", + Env: Prefix + "env", + } +) diff --git a/server/db/models/session.go b/server/db/models/session.go new file mode 100644 index 0000000..c989e8b --- /dev/null +++ b/server/db/models/session.go @@ -0,0 +1,13 @@ +package models + +// Session model for db +type Session struct { + Key string `json:"_key,omitempty" bson:"_key,omitempty"` // for arangodb + ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"` + UserID string `gorm:"type:char(36),index:" json:"user_id" bson:"user_id"` + User User `json:"-" bson:"-"` + UserAgent string `json:"user_agent" bson:"user_agent"` + IP string `json:"ip" bson:"ip"` + CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` + UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` +} diff --git a/server/db/models/user.go b/server/db/models/user.go new file mode 100644 index 0000000..5d45dfe --- /dev/null +++ b/server/db/models/user.go @@ -0,0 +1,24 @@ +package models + +// User model for db +type User struct { + Key string `json:"_key,omitempty" bson:"_key"` // for arangodb + ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"` + + Email string `gorm:"unique" json:"email" bson:"email"` + EmailVerifiedAt *int64 `json:"email_verified_at" bson:"email_verified_at"` + Password *string `gorm:"type:text" json:"password" bson:"password"` + SignupMethods string `json:"signup_methods" bson:"signup_methods"` + GivenName *string `json:"given_name" bson:"given_name"` + FamilyName *string `json:"family_name" bson:"family_name"` + MiddleName *string `json:"middle_name" bson:"middle_name"` + Nickname *string `json:"nickname" bson:"nickname"` + Gender *string `json:"gender" bson:"gender"` + Birthdate *string `json:"birthdate" bson:"birthdate"` + PhoneNumber *string `gorm:"unique" json:"phone_number" bson:"phone_number"` + PhoneNumberVerifiedAt *int64 `json:"phone_number_verified_at" bson:"phone_number_verified_at"` + Picture *string `gorm:"type:text" json:"picture" bson:"picture"` + Roles string `json:"roles" bson:"roles"` + UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` + CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` +} diff --git a/server/db/models/verification_requests.go b/server/db/models/verification_requests.go new file mode 100644 index 0000000..931887f --- /dev/null +++ b/server/db/models/verification_requests.go @@ -0,0 +1,13 @@ +package models + +// VerificationRequest model for db +type VerificationRequest struct { + Key string `json:"_key,omitempty" bson:"_key"` // for arangodb + ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"` + Token string `gorm:"type:text" json:"token" bson:"token"` + Identifier string `gorm:"uniqueIndex:idx_email_identifier" json:"identifier" bson:"identifier"` + ExpiresAt int64 `json:"expires_at" bson:"expires_at"` + CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` + UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` + Email string `gorm:"uniqueIndex:idx_email_identifier" json:"email" bson:"email"` +} diff --git a/server/db/arangodb.go b/server/db/providers/arangodb/arangodb.go similarity index 60% rename from server/db/arangodb.go rename to server/db/providers/arangodb/arangodb.go index 85b33b0..9c9bff8 100644 --- a/server/db/arangodb.go +++ b/server/db/providers/arangodb/arangodb.go @@ -1,4 +1,4 @@ -package db +package arangodb import ( "context" @@ -8,14 +8,20 @@ import ( arangoDriver "github.com/arangodb/go-driver" "github.com/arangodb/go-driver/http" "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/envstore" ) +type provider struct { + db arangoDriver.Database +} + // for this we need arangodb instance up and running // for local testing we can use dockerized version of it // docker run -p 8529:8529 -e ARANGO_ROOT_PASSWORD=root arangodb/arangodb:3.8.4 -func initArangodb() (arangoDriver.Database, error) { +// NewProvider to initialize arangodb connection +func NewProvider() (*provider, error) { ctx := context.Background() conn, err := http.NewConnection(http.ConnectionConfig{ Endpoints: []string{envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)}, @@ -48,16 +54,16 @@ func initArangodb() (arangoDriver.Database, error) { } } - userCollectionExists, err := arangodb.CollectionExists(ctx, Collections.User) + userCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.User) if userCollectionExists { - log.Println(Collections.User + " collection exists already") + log.Println(models.Collections.User + " collection exists already") } else { - _, err = arangodb.CreateCollection(ctx, Collections.User, nil) + _, err = arangodb.CreateCollection(ctx, models.Collections.User, nil) if err != nil { - log.Println("error creating collection("+Collections.User+"):", err) + log.Println("error creating collection("+models.Collections.User+"):", err) } } - userCollection, _ := arangodb.Collection(nil, Collections.User) + userCollection, _ := arangodb.Collection(nil, models.Collections.User) userCollection.EnsureHashIndex(ctx, []string{"email"}, &arangoDriver.EnsureHashIndexOptions{ Unique: true, Sparse: true, @@ -67,17 +73,17 @@ func initArangodb() (arangoDriver.Database, error) { Sparse: true, }) - verificationRequestCollectionExists, err := arangodb.CollectionExists(ctx, Collections.VerificationRequest) + verificationRequestCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.VerificationRequest) if verificationRequestCollectionExists { - log.Println(Collections.VerificationRequest + " collection exists already") + log.Println(models.Collections.VerificationRequest + " collection exists already") } else { - _, err = arangodb.CreateCollection(ctx, Collections.VerificationRequest, nil) + _, err = arangodb.CreateCollection(ctx, models.Collections.VerificationRequest, nil) if err != nil { - log.Println("error creating collection("+Collections.VerificationRequest+"):", err) + log.Println("error creating collection("+models.Collections.VerificationRequest+"):", err) } } - verificationRequestCollection, _ := arangodb.Collection(nil, Collections.VerificationRequest) + verificationRequestCollection, _ := arangodb.Collection(nil, models.Collections.VerificationRequest) verificationRequestCollection.EnsureHashIndex(ctx, []string{"email", "identifier"}, &arangoDriver.EnsureHashIndexOptions{ Unique: true, Sparse: true, @@ -86,30 +92,32 @@ func initArangodb() (arangoDriver.Database, error) { Sparse: true, }) - sessionCollectionExists, err := arangodb.CollectionExists(ctx, Collections.Session) + sessionCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Session) if sessionCollectionExists { - log.Println(Collections.Session + " collection exists already") + log.Println(models.Collections.Session + " collection exists already") } else { - _, err = arangodb.CreateCollection(ctx, Collections.Session, nil) + _, err = arangodb.CreateCollection(ctx, models.Collections.Session, nil) if err != nil { - log.Println("error creating collection("+Collections.Session+"):", err) + log.Println("error creating collection("+models.Collections.Session+"):", err) } } - sessionCollection, _ := arangodb.Collection(nil, Collections.Session) + sessionCollection, _ := arangodb.Collection(nil, models.Collections.Session) sessionCollection.EnsureHashIndex(ctx, []string{"user_id"}, &arangoDriver.EnsureHashIndexOptions{ Sparse: true, }) - configCollectionExists, err := arangodb.CollectionExists(ctx, Collections.Env) + configCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Env) if configCollectionExists { - log.Println(Collections.Env + " collection exists already") + log.Println(models.Collections.Env + " collection exists already") } else { - _, err = arangodb.CreateCollection(ctx, Collections.Env, nil) + _, err = arangodb.CreateCollection(ctx, models.Collections.Env, nil) if err != nil { - log.Println("error creating collection("+Collections.Env+"):", err) + log.Println("error creating collection("+models.Collections.Env+"):", err) } } - return arangodb, err + return &provider{ + db: arangodb, + }, err } diff --git a/server/db/providers/arangodb/env.go b/server/db/providers/arangodb/env.go new file mode 100644 index 0000000..c2d866f --- /dev/null +++ b/server/db/providers/arangodb/env.go @@ -0,0 +1,73 @@ +package arangodb + +import ( + "fmt" + "log" + "time" + + arangoDriver "github.com/arangodb/go-driver" + "github.com/google/uuid" + + "github.com/authorizerdev/authorizer/server/db/models" +) + +// AddEnv to save environment information in database +func (p *provider) AddEnv(env models.Env) (models.Env, error) { + if env.ID == "" { + env.ID = uuid.New().String() + } + + env.CreatedAt = time.Now().Unix() + env.UpdatedAt = time.Now().Unix() + configCollection, _ := p.db.Collection(nil, models.Collections.Env) + meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(nil), env) + if err != nil { + log.Println("error adding config:", err) + return env, err + } + env.Key = meta.Key + env.ID = meta.ID.String() + return env, nil +} + +// UpdateEnv to update environment information in database +func (p *provider) UpdateEnv(env models.Env) (models.Env, error) { + env.UpdatedAt = time.Now().Unix() + collection, _ := p.db.Collection(nil, models.Collections.Env) + meta, err := collection.UpdateDocument(nil, env.Key, env) + if err != nil { + log.Println("error updating config:", err) + return env, err + } + + env.Key = meta.Key + env.ID = meta.ID.String() + return env, nil +} + +// GetEnv to get environment information from database +func (p *provider) GetEnv() (models.Env, error) { + var env models.Env + query := fmt.Sprintf("FOR d in %s RETURN d", models.Collections.Env) + + cursor, err := p.db.Query(nil, query, nil) + if err != nil { + return env, err + } + defer cursor.Close() + + for { + if !cursor.HasMore() { + if env.Key == "" { + return env, fmt.Errorf("config not found") + } + break + } + _, err := cursor.ReadDocument(nil, &env) + if err != nil { + return env, err + } + } + + return env, nil +} diff --git a/server/db/providers/arangodb/session.go b/server/db/providers/arangodb/session.go new file mode 100644 index 0000000..9cfc8be --- /dev/null +++ b/server/db/providers/arangodb/session.go @@ -0,0 +1,42 @@ +package arangodb + +import ( + "fmt" + "log" + "time" + + "github.com/authorizerdev/authorizer/server/db/models" + "github.com/google/uuid" +) + +// AddSession to save session information in database +func (p *provider) AddSession(session models.Session) error { + if session.ID == "" { + session.ID = uuid.New().String() + } + + session.CreatedAt = time.Now().Unix() + session.UpdatedAt = time.Now().Unix() + sessionCollection, _ := p.db.Collection(nil, models.Collections.Session) + _, err := sessionCollection.CreateDocument(nil, session) + if err != nil { + log.Println(`error saving session`, err) + return err + } + return nil +} + +// DeleteSession to delete session information from database +func (p *provider) DeleteSession(userId string) error { + query := fmt.Sprintf(`FOR d IN %s FILTER d.user_id == @userId REMOVE { _key: d._key } IN %s`, models.Collections.Session, models.Collections.Session) + bindVars := map[string]interface{}{ + "userId": userId, + } + cursor, err := p.db.Query(nil, query, bindVars) + if err != nil { + log.Println("=> error deleting arangodb session:", err) + return err + } + defer cursor.Close() + return nil +} diff --git a/server/db/providers/arangodb/user.go b/server/db/providers/arangodb/user.go new file mode 100644 index 0000000..055bd52 --- /dev/null +++ b/server/db/providers/arangodb/user.go @@ -0,0 +1,157 @@ +package arangodb + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/arangodb/go-driver" + arangoDriver "github.com/arangodb/go-driver" + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/server/envstore" + "github.com/google/uuid" +) + +// AddUser to save user information in database +func (p *provider) AddUser(user models.User) (models.User, error) { + if user.ID == "" { + user.ID = uuid.New().String() + } + + if user.Roles == "" { + user.Roles = strings.Join(envstore.EnvInMemoryStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles), ",") + } + + user.CreatedAt = time.Now().Unix() + user.UpdatedAt = time.Now().Unix() + userCollection, _ := p.db.Collection(nil, models.Collections.User) + meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(nil), user) + if err != nil { + log.Println("error adding user:", err) + return user, err + } + user.Key = meta.Key + user.ID = meta.ID.String() + + return user, nil +} + +// UpdateUser to update user information in database +func (p *provider) UpdateUser(user models.User) (models.User, error) { + user.UpdatedAt = time.Now().Unix() + collection, _ := p.db.Collection(nil, models.Collections.User) + meta, err := collection.UpdateDocument(nil, user.Key, user) + if err != nil { + log.Println("error updating user:", err) + return user, err + } + + user.Key = meta.Key + user.ID = meta.ID.String() + return user, nil +} + +// DeleteUser to delete user information from database +func (p *provider) DeleteUser(user models.User) error { + collection, _ := p.db.Collection(nil, models.Collections.User) + _, err := collection.RemoveDocument(nil, user.Key) + if err != nil { + log.Println(`error deleting user:`, err) + return err + } + + return nil +} + +// ListUsers to get list of users from database +func (p *provider) ListUsers() ([]models.User, error) { + var users []models.User + query := fmt.Sprintf("FOR d in %s RETURN d", models.Collections.User) + + cursor, err := p.db.Query(nil, query, nil) + if err != nil { + return users, err + } + defer cursor.Close() + + for { + var user models.User + meta, err := cursor.ReadDocument(nil, &user) + + if driver.IsNoMoreDocuments(err) { + break + } else if err != nil { + return users, err + } + + if meta.Key != "" { + users = append(users, user) + } + } + + return users, nil +} + +// GetUserByEmail to get user information from database using email address +func (p *provider) GetUserByEmail(email string) (models.User, error) { + var user models.User + + query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", models.Collections.User) + bindVars := map[string]interface{}{ + "email": email, + } + + cursor, err := p.db.Query(nil, query, bindVars) + if err != nil { + return user, err + } + defer cursor.Close() + + for { + if !cursor.HasMore() { + if user.Key == "" { + return user, fmt.Errorf("user not found") + } + break + } + _, err := cursor.ReadDocument(nil, &user) + if err != nil { + return user, err + } + } + + return user, nil +} + +// GetUserByID to get user information from database using user ID +func (p *provider) GetUserByID(id string) (models.User, error) { + var user models.User + + query := fmt.Sprintf("FOR d in %s FILTER d._id == @id LIMIT 1 RETURN d", models.Collections.User) + bindVars := map[string]interface{}{ + "id": id, + } + + cursor, err := p.db.Query(nil, query, bindVars) + if err != nil { + return user, err + } + defer cursor.Close() + + for { + if !cursor.HasMore() { + if user.Key == "" { + return user, fmt.Errorf("user not found") + } + break + } + _, err := cursor.ReadDocument(nil, &user) + if err != nil { + return user, err + } + } + + return user, nil +} diff --git a/server/db/providers/arangodb/verification_requests.go b/server/db/providers/arangodb/verification_requests.go new file mode 100644 index 0000000..ab7eee6 --- /dev/null +++ b/server/db/providers/arangodb/verification_requests.go @@ -0,0 +1,135 @@ +package arangodb + +import ( + "fmt" + "log" + "time" + + "github.com/arangodb/go-driver" + "github.com/authorizerdev/authorizer/server/db/models" + "github.com/google/uuid" +) + +// AddVerification to save verification request in database +func (p *provider) AddVerificationRequest(verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { + if verificationRequest.ID == "" { + verificationRequest.ID = uuid.New().String() + } + + verificationRequest.CreatedAt = time.Now().Unix() + verificationRequest.UpdatedAt = time.Now().Unix() + verificationRequestRequestCollection, _ := p.db.Collection(nil, models.Collections.VerificationRequest) + meta, err := verificationRequestRequestCollection.CreateDocument(nil, verificationRequest) + if err != nil { + log.Println("error saving verificationRequest record:", err) + return verificationRequest, err + } + verificationRequest.Key = meta.Key + verificationRequest.ID = meta.ID.String() + + return verificationRequest, nil +} + +// GetVerificationRequestByToken to get verification request from database using token +func (p *provider) GetVerificationRequestByToken(token string) (models.VerificationRequest, error) { + var verificationRequest models.VerificationRequest + query := fmt.Sprintf("FOR d in %s FILTER d.token == @token LIMIT 1 RETURN d", models.Collections.VerificationRequest) + bindVars := map[string]interface{}{ + "token": token, + } + + cursor, err := p.db.Query(nil, query, bindVars) + if err != nil { + return verificationRequest, err + } + defer cursor.Close() + + for { + if !cursor.HasMore() { + if verificationRequest.Key == "" { + return verificationRequest, fmt.Errorf("verification request not found") + } + break + } + _, err := cursor.ReadDocument(nil, &verificationRequest) + if err != nil { + return verificationRequest, err + } + } + + return verificationRequest, nil +} + +// GetVerificationRequestByEmail to get verification request by email from database +func (p *provider) GetVerificationRequestByEmail(email string, identifier string) (models.VerificationRequest, error) { + var verificationRequest models.VerificationRequest + + query := fmt.Sprintf("FOR d in %s FILTER d.email == @email FILTER d.identifier == @identifier LIMIT 1 RETURN d", models.Collections.VerificationRequest) + bindVars := map[string]interface{}{ + "email": email, + "identifier": identifier, + } + + cursor, err := p.db.Query(nil, query, bindVars) + if err != nil { + return verificationRequest, err + } + defer cursor.Close() + + for { + if !cursor.HasMore() { + if verificationRequest.Key == "" { + return verificationRequest, fmt.Errorf("verification request not found") + } + break + } + _, err := cursor.ReadDocument(nil, &verificationRequest) + if err != nil { + return verificationRequest, err + } + } + + return verificationRequest, nil +} + +// ListVerificationRequests to get list of verification requests from database +func (p *provider) ListVerificationRequests() ([]models.VerificationRequest, error) { + var verificationRequests []models.VerificationRequest + + query := fmt.Sprintf("FOR d in %s RETURN d", models.Collections.VerificationRequest) + + cursor, err := p.db.Query(nil, query, nil) + if err != nil { + return verificationRequests, err + } + defer cursor.Close() + + for { + var verificationRequest models.VerificationRequest + meta, err := cursor.ReadDocument(nil, &verificationRequest) + + if driver.IsNoMoreDocuments(err) { + break + } else if err != nil { + return verificationRequests, err + } + + if meta.Key != "" { + verificationRequests = append(verificationRequests, verificationRequest) + } + + } + + return verificationRequests, nil +} + +// DeleteVerificationRequest to delete verification request from database +func (p *provider) DeleteVerificationRequest(verificationRequest models.VerificationRequest) error { + collection, _ := p.db.Collection(nil, models.Collections.VerificationRequest) + _, err := collection.RemoveDocument(nil, verificationRequest.Key) + if err != nil { + log.Println(`error deleting verification request:`, err) + return err + } + return nil +} diff --git a/server/db/providers/mongodb/env.go b/server/db/providers/mongodb/env.go new file mode 100644 index 0000000..0d144e6 --- /dev/null +++ b/server/db/providers/mongodb/env.go @@ -0,0 +1,66 @@ +package mongodb + +import ( + "fmt" + "log" + "time" + + "github.com/authorizerdev/authorizer/server/db/models" + "github.com/google/uuid" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo/options" +) + +// AddEnv to save environment information in database +func (p *provider) AddEnv(env models.Env) (models.Env, error) { + if env.ID == "" { + env.ID = uuid.New().String() + } + + env.CreatedAt = time.Now().Unix() + env.UpdatedAt = time.Now().Unix() + env.Key = env.ID + configCollection := p.db.Collection(models.Collections.Env, options.Collection()) + _, err := configCollection.InsertOne(nil, env) + if err != nil { + log.Println("error adding config:", err) + return env, err + } + return env, nil +} + +// UpdateEnv to update environment information in database +func (p *provider) UpdateEnv(env models.Env) (models.Env, error) { + env.UpdatedAt = time.Now().Unix() + configCollection := p.db.Collection(models.Collections.Env, options.Collection()) + _, err := configCollection.UpdateOne(nil, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions()) + if err != nil { + log.Println("error updating config:", err) + return env, err + } + return env, nil +} + +// GetEnv to get environment information from database +func (p *provider) GetEnv() (models.Env, error) { + var env models.Env + configCollection := p.db.Collection(models.Collections.Env, options.Collection()) + cursor, err := configCollection.Find(nil, bson.M{}, options.Find()) + if err != nil { + return env, err + } + defer cursor.Close(nil) + + for cursor.Next(nil) { + err := cursor.Decode(&env) + if err != nil { + return env, err + } + } + + if env.ID == "" { + return env, fmt.Errorf("config not found") + } + + return env, nil +} diff --git a/server/db/mongodb.go b/server/db/providers/mongodb/mongodb.go similarity index 70% rename from server/db/mongodb.go rename to server/db/providers/mongodb/mongodb.go index 1480bd6..b53b276 100644 --- a/server/db/mongodb.go +++ b/server/db/providers/mongodb/mongodb.go @@ -1,10 +1,11 @@ -package db +package mongodb import ( "context" "time" "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/envstore" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" @@ -12,7 +13,12 @@ import ( "go.mongodb.org/mongo-driver/mongo/readpref" ) -func initMongodb() (*mongo.Database, error) { +type provider struct { + db *mongo.Database +} + +// NewProvider to initialize mongodb connection +func NewProvider() (*provider, error) { mongodbOptions := options.Client().ApplyURI(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)) maxWait := time.Duration(5 * time.Second) mongodbOptions.ConnectTimeout = &maxWait @@ -33,8 +39,8 @@ func initMongodb() (*mongo.Database, error) { mongodb := mongoClient.Database(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseName), options.Database()) - mongodb.CreateCollection(ctx, Collections.User, options.CreateCollection()) - userCollection := mongodb.Collection(Collections.User, options.Collection()) + mongodb.CreateCollection(ctx, models.Collections.User, options.CreateCollection()) + userCollection := mongodb.Collection(models.Collections.User, options.Collection()) userCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ mongo.IndexModel{ Keys: bson.M{"email": 1}, @@ -50,8 +56,8 @@ func initMongodb() (*mongo.Database, error) { }, }, options.CreateIndexes()) - mongodb.CreateCollection(ctx, Collections.VerificationRequest, options.CreateCollection()) - verificationRequestCollection := mongodb.Collection(Collections.VerificationRequest, options.Collection()) + mongodb.CreateCollection(ctx, models.Collections.VerificationRequest, options.CreateCollection()) + verificationRequestCollection := mongodb.Collection(models.Collections.VerificationRequest, options.Collection()) verificationRequestCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ mongo.IndexModel{ Keys: bson.M{"email": 1, "identifier": 1}, @@ -65,8 +71,8 @@ func initMongodb() (*mongo.Database, error) { }, }, options.CreateIndexes()) - mongodb.CreateCollection(ctx, Collections.Session, options.CreateCollection()) - sessionCollection := mongodb.Collection(Collections.Session, options.Collection()) + mongodb.CreateCollection(ctx, models.Collections.Session, options.CreateCollection()) + sessionCollection := mongodb.Collection(models.Collections.Session, options.Collection()) sessionCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{ mongo.IndexModel{ Keys: bson.M{"user_id": 1}, @@ -74,7 +80,9 @@ func initMongodb() (*mongo.Database, error) { }, }, options.CreateIndexes()) - mongodb.CreateCollection(ctx, Collections.Env, options.CreateCollection()) + mongodb.CreateCollection(ctx, models.Collections.Env, options.CreateCollection()) - return mongodb, nil + return &provider{ + db: mongodb, + }, nil } diff --git a/server/db/providers/mongodb/session.go b/server/db/providers/mongodb/session.go new file mode 100644 index 0000000..88c492f --- /dev/null +++ b/server/db/providers/mongodb/session.go @@ -0,0 +1,40 @@ +package mongodb + +import ( + "log" + "time" + + "github.com/authorizerdev/authorizer/server/db/models" + "github.com/google/uuid" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo/options" +) + +// AddSession to save session information in database +func (p *provider) AddSession(session models.Session) error { + if session.ID == "" { + session.ID = uuid.New().String() + } + + session.Key = session.ID + session.CreatedAt = time.Now().Unix() + session.UpdatedAt = time.Now().Unix() + sessionCollection := p.db.Collection(models.Collections.Session, options.Collection()) + _, err := sessionCollection.InsertOne(nil, session) + if err != nil { + log.Println(`error saving session`, err) + return err + } + return nil +} + +// DeleteSession to delete session information from database +func (p *provider) DeleteSession(userId string) error { + sessionCollection := p.db.Collection(models.Collections.Session, options.Collection()) + _, err := sessionCollection.DeleteMany(nil, bson.M{"user_id": userId}, options.Delete()) + if err != nil { + log.Println("error deleting session:", err) + return err + } + return nil +} diff --git a/server/db/providers/mongodb/user.go b/server/db/providers/mongodb/user.go new file mode 100644 index 0000000..e62107e --- /dev/null +++ b/server/db/providers/mongodb/user.go @@ -0,0 +1,108 @@ +package mongodb + +import ( + "log" + "strings" + "time" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/server/envstore" + "github.com/google/uuid" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo/options" +) + +// AddUser to save user information in database +func (p *provider) AddUser(user models.User) (models.User, error) { + if user.ID == "" { + user.ID = uuid.New().String() + } + + if user.Roles == "" { + user.Roles = strings.Join(envstore.EnvInMemoryStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles), ",") + } + user.CreatedAt = time.Now().Unix() + user.UpdatedAt = time.Now().Unix() + user.Key = user.ID + userCollection := p.db.Collection(models.Collections.User, options.Collection()) + _, err := userCollection.InsertOne(nil, user) + if err != nil { + log.Println("error adding user:", err) + return user, err + } + + return user, nil +} + +// UpdateUser to update user information in database +func (p *provider) UpdateUser(user models.User) (models.User, error) { + user.UpdatedAt = time.Now().Unix() + userCollection := p.db.Collection(models.Collections.User, options.Collection()) + _, err := userCollection.UpdateOne(nil, bson.M{"_id": bson.M{"$eq": user.ID}}, bson.M{"$set": user}, options.MergeUpdateOptions()) + if err != nil { + log.Println("error updating user:", err) + return user, err + } + return user, nil +} + +// DeleteUser to delete user information from database +func (p *provider) DeleteUser(user models.User) error { + userCollection := p.db.Collection(models.Collections.User, options.Collection()) + _, err := userCollection.DeleteOne(nil, bson.M{"_id": user.ID}, options.Delete()) + if err != nil { + log.Println("error deleting user:", err) + return err + } + + return nil +} + +// ListUsers to get list of users from database +func (p *provider) ListUsers() ([]models.User, error) { + var users []models.User + userCollection := p.db.Collection(models.Collections.User, options.Collection()) + cursor, err := userCollection.Find(nil, bson.M{}, options.Find()) + if err != nil { + log.Println("error getting users:", err) + return users, err + } + defer cursor.Close(nil) + + for cursor.Next(nil) { + var user models.User + err := cursor.Decode(&user) + if err != nil { + return users, err + } + users = append(users, user) + } + + return users, nil +} + +// GetUserByEmail to get user information from database using email address +func (p *provider) GetUserByEmail(email string) (models.User, error) { + var user models.User + userCollection := p.db.Collection(models.Collections.User, options.Collection()) + err := userCollection.FindOne(nil, bson.M{"email": email}).Decode(&user) + if err != nil { + return user, err + } + + return user, nil +} + +// GetUserByID to get user information from database using user ID +func (p *provider) GetUserByID(id string) (models.User, error) { + var user models.User + + userCollection := p.db.Collection(models.Collections.User, options.Collection()) + err := userCollection.FindOne(nil, bson.M{"_id": id}).Decode(&user) + if err != nil { + return user, err + } + + return user, nil +} diff --git a/server/db/providers/mongodb/verification_requests.go b/server/db/providers/mongodb/verification_requests.go new file mode 100644 index 0000000..7e86745 --- /dev/null +++ b/server/db/providers/mongodb/verification_requests.go @@ -0,0 +1,91 @@ +package mongodb + +import ( + "log" + "time" + + "github.com/authorizerdev/authorizer/server/db/models" + "github.com/google/uuid" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo/options" +) + +// AddVerification to save verification request in database +func (p *provider) AddVerificationRequest(verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { + if verificationRequest.ID == "" { + verificationRequest.ID = uuid.New().String() + + verificationRequest.CreatedAt = time.Now().Unix() + verificationRequest.UpdatedAt = time.Now().Unix() + verificationRequest.Key = verificationRequest.ID + verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) + _, err := verificationRequestCollection.InsertOne(nil, verificationRequest) + if err != nil { + log.Println("error saving verification record:", err) + return verificationRequest, err + } + } + + return verificationRequest, nil +} + +// GetVerificationRequestByToken to get verification request from database using token +func (p *provider) GetVerificationRequestByToken(token string) (models.VerificationRequest, error) { + var verificationRequest models.VerificationRequest + + verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) + err := verificationRequestCollection.FindOne(nil, bson.M{"token": token}).Decode(&verificationRequest) + if err != nil { + return verificationRequest, err + } + + return verificationRequest, nil +} + +// GetVerificationRequestByEmail to get verification request by email from database +func (p *provider) GetVerificationRequestByEmail(email string, identifier string) (models.VerificationRequest, error) { + var verificationRequest models.VerificationRequest + + verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) + err := verificationRequestCollection.FindOne(nil, bson.M{"email": email, "identifier": identifier}).Decode(&verificationRequest) + if err != nil { + return verificationRequest, err + } + + return verificationRequest, nil +} + +// ListVerificationRequests to get list of verification requests from database +func (p *provider) ListVerificationRequests() ([]models.VerificationRequest, error) { + var verificationRequests []models.VerificationRequest + verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) + cursor, err := verificationRequestCollection.Find(nil, bson.M{}, options.Find()) + if err != nil { + log.Println("error getting verification requests:", err) + return verificationRequests, err + } + defer cursor.Close(nil) + + for cursor.Next(nil) { + var verificationRequest models.VerificationRequest + err := cursor.Decode(&verificationRequest) + if err != nil { + return verificationRequests, err + } + verificationRequests = append(verificationRequests, verificationRequest) + } + + return verificationRequests, nil +} + +// DeleteVerificationRequest to delete verification request from database +func (p *provider) DeleteVerificationRequest(verificationRequest models.VerificationRequest) error { + verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) + _, err := verificationRequestCollection.DeleteOne(nil, bson.M{"_id": verificationRequest.ID}, options.Delete()) + if err != nil { + log.Println("error deleting verification request::", err) + return err + } + + return nil +} diff --git a/server/db/providers/providers.go b/server/db/providers/providers.go new file mode 100644 index 0000000..da4e5f7 --- /dev/null +++ b/server/db/providers/providers.go @@ -0,0 +1,41 @@ +package providers + +import "github.com/authorizerdev/authorizer/server/db/models" + +type Provider interface { + // AddUser to save user information in database + AddUser(user models.User) (models.User, error) + // UpdateUser to update user information in database + UpdateUser(user models.User) (models.User, error) + // DeleteUser to delete user information from database + DeleteUser(user models.User) error + // ListUsers to get list of users from database + ListUsers() ([]models.User, error) + // GetUserByEmail to get user information from database using email address + GetUserByEmail(email string) (models.User, error) + // GetUserByID to get user information from database using user ID + GetUserByID(id string) (models.User, error) + + // AddVerification to save verification request in database + AddVerificationRequest(verificationRequest models.VerificationRequest) (models.VerificationRequest, error) + // GetVerificationRequestByToken to get verification request from database using token + GetVerificationRequestByToken(token string) (models.VerificationRequest, error) + // GetVerificationRequestByEmail to get verification request by email from database + GetVerificationRequestByEmail(email string, identifier string) (models.VerificationRequest, error) + // ListVerificationRequests to get list of verification requests from database + ListVerificationRequests() ([]models.VerificationRequest, error) + // DeleteVerificationRequest to delete verification request from database + DeleteVerificationRequest(verificationRequest models.VerificationRequest) error + + // AddSession to save session information in database + AddSession(session models.Session) error + // DeleteSession to delete session information from database + DeleteSession(userId string) error + + // AddEnv to save environment information in database + AddEnv(env models.Env) (models.Env, error) + // UpdateEnv to update environment information in database + UpdateEnv(env models.Env) (models.Env, error) + // GetEnv to get environment information from database + GetEnv() (models.Env, error) +} diff --git a/server/db/providers/sql/env.go b/server/db/providers/sql/env.go new file mode 100644 index 0000000..489fa8d --- /dev/null +++ b/server/db/providers/sql/env.go @@ -0,0 +1,49 @@ +package sql + +import ( + "log" + "time" + + "github.com/authorizerdev/authorizer/server/db/models" + "github.com/google/uuid" +) + +// AddEnv to save environment information in database +func (p *provider) AddEnv(env models.Env) (models.Env, error) { + if env.ID == "" { + env.ID = uuid.New().String() + } + + env.Key = env.ID + result := p.db.Create(&env) + + if result.Error != nil { + log.Println("error adding config:", result.Error) + return env, result.Error + } + return env, nil +} + +// UpdateEnv to update environment information in database +func (p *provider) UpdateEnv(env models.Env) (models.Env, error) { + env.UpdatedAt = time.Now().Unix() + result := p.db.Save(&env) + + if result.Error != nil { + log.Println("error updating config:", result.Error) + return env, result.Error + } + return env, nil +} + +// GetEnv to get environment information from database +func (p *provider) GetEnv() (models.Env, error) { + var env models.Env + result := p.db.First(&env) + + if result.Error != nil { + return env, result.Error + } + + return env, nil +} diff --git a/server/db/providers/sql/session.go b/server/db/providers/sql/session.go new file mode 100644 index 0000000..28230b5 --- /dev/null +++ b/server/db/providers/sql/session.go @@ -0,0 +1,38 @@ +package sql + +import ( + "log" + + "github.com/authorizerdev/authorizer/server/db/models" + "github.com/google/uuid" + "gorm.io/gorm/clause" +) + +// AddSession to save session information in database +func (p *provider) AddSession(session models.Session) error { + if session.ID == "" { + session.ID = uuid.New().String() + } + + session.Key = session.ID + res := p.db.Clauses( + clause.OnConflict{ + DoNothing: true, + }).Create(&session) + if res.Error != nil { + log.Println(`error saving session`, res.Error) + return res.Error + } + return nil +} + +// DeleteSession to delete session information from database +func (p *provider) DeleteSession(userId string) error { + result := p.db.Where("user_id = ?", userId).Delete(&models.Session{}) + + if result.Error != nil { + log.Println(`error deleting session:`, result.Error) + return result.Error + } + return nil +} diff --git a/server/db/providers/sql/sql.go b/server/db/providers/sql/sql.go new file mode 100644 index 0000000..ccc1c2c --- /dev/null +++ b/server/db/providers/sql/sql.go @@ -0,0 +1,53 @@ +package sql + +import ( + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/server/envstore" + "gorm.io/driver/mysql" + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/driver/sqlserver" + "gorm.io/gorm" + "gorm.io/gorm/schema" +) + +type provider struct { + db *gorm.DB +} + +// NewProvider returns a new SQL provider +func NewProvider() (*provider, error) { + var sqlDB *gorm.DB + var err error + + ormConfig := &gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + TablePrefix: models.Prefix, + }, + } + + switch envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) { + case constants.DbTypePostgres: + sqlDB, err = gorm.Open(postgres.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig) + break + case constants.DbTypeSqlite: + sqlDB, err = gorm.Open(sqlite.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig) + break + case constants.DbTypeMysql: + sqlDB, err = gorm.Open(mysql.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig) + break + case constants.DbTypeSqlserver: + sqlDB, err = gorm.Open(sqlserver.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig) + break + } + + if err != nil { + return nil, err + } + + sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}) + return &provider{ + db: sqlDB, + }, nil +} diff --git a/server/db/providers/sql/user.go b/server/db/providers/sql/user.go new file mode 100644 index 0000000..ad91b59 --- /dev/null +++ b/server/db/providers/sql/user.go @@ -0,0 +1,101 @@ +package sql + +import ( + "log" + "strings" + "time" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/db/models" + "github.com/authorizerdev/authorizer/server/envstore" + "github.com/google/uuid" + "gorm.io/gorm/clause" +) + +// AddUser to save user information in database +func (p *provider) AddUser(user models.User) (models.User, error) { + if user.ID == "" { + user.ID = uuid.New().String() + } + + if user.Roles == "" { + user.Roles = strings.Join(envstore.EnvInMemoryStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles), ",") + } + + user.Key = user.ID + result := p.db.Clauses( + clause.OnConflict{ + UpdateAll: true, + Columns: []clause.Column{{Name: "email"}}, + }).Create(&user) + + if result.Error != nil { + log.Println("error adding user:", result.Error) + return user, result.Error + } + + return user, nil +} + +// UpdateUser to update user information in database +func (p *provider) UpdateUser(user models.User) (models.User, error) { + user.UpdatedAt = time.Now().Unix() + + result := p.db.Save(&user) + + if result.Error != nil { + log.Println("error updating user:", result.Error) + return user, result.Error + } + + return user, nil +} + +// DeleteUser to delete user information from database +func (p *provider) DeleteUser(user models.User) error { + result := p.db.Delete(&user) + + if result.Error != nil { + log.Println(`error deleting user:`, result.Error) + return result.Error + } + + return nil +} + +// ListUsers to get list of users from database +func (p *provider) ListUsers() ([]models.User, error) { + var users []models.User + result := p.db.Find(&users) + if result.Error != nil { + log.Println("error getting users:", result.Error) + return users, result.Error + } + + return users, nil +} + +// GetUserByEmail to get user information from database using email address +func (p *provider) GetUserByEmail(email string) (models.User, error) { + var user models.User + result := p.db.Where("email = ?", email).First(&user) + + if result.Error != nil { + return user, result.Error + } + + return user, nil +} + +// GetUserByID to get user information from database using user ID +func (p *provider) GetUserByID(id string) (models.User, error) { + var user models.User + + result := p.db.Where("id = ?", id).First(&user) + + if result.Error != nil { + return user, result.Error + } + + return user, nil +} diff --git a/server/db/providers/sql/verification_requests.go b/server/db/providers/sql/verification_requests.go new file mode 100644 index 0000000..df21c7c --- /dev/null +++ b/server/db/providers/sql/verification_requests.go @@ -0,0 +1,80 @@ +package sql + +import ( + "log" + + "github.com/authorizerdev/authorizer/server/db/models" + "github.com/google/uuid" + "gorm.io/gorm/clause" +) + +// AddVerification to save verification request in database +func (p *provider) AddVerificationRequest(verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { + if verificationRequest.ID == "" { + verificationRequest.ID = uuid.New().String() + } + + verificationRequest.Key = verificationRequest.ID + result := p.db.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "email"}, {Name: "identifier"}}, + DoUpdates: clause.AssignmentColumns([]string{"token", "expires_at"}), + }).Create(&verificationRequest) + + if result.Error != nil { + log.Println(`error saving verification request record`, result.Error) + return verificationRequest, result.Error + } + + return verificationRequest, nil +} + +// GetVerificationRequestByToken to get verification request from database using token +func (p *provider) GetVerificationRequestByToken(token string) (models.VerificationRequest, error) { + var verificationRequest models.VerificationRequest + result := p.db.Where("token = ?", token).First(&verificationRequest) + + if result.Error != nil { + log.Println(`error getting verification request:`, result.Error) + return verificationRequest, result.Error + } + + return verificationRequest, nil +} + +// GetVerificationRequestByEmail to get verification request by email from database +func (p *provider) GetVerificationRequestByEmail(email string, identifier string) (models.VerificationRequest, error) { + var verificationRequest models.VerificationRequest + + result := p.db.Where("email = ? AND identifier = ?", email, identifier).First(&verificationRequest) + + if result.Error != nil { + log.Println(`error getting verification token:`, result.Error) + return verificationRequest, result.Error + } + + return verificationRequest, nil +} + +// ListVerificationRequests to get list of verification requests from database +func (p *provider) ListVerificationRequests() ([]models.VerificationRequest, error) { + var verificationRequests []models.VerificationRequest + + result := p.db.Find(&verificationRequests) + if result.Error != nil { + log.Println("error getting verification requests:", result.Error) + return verificationRequests, result.Error + } + return verificationRequests, nil +} + +// DeleteVerificationRequest to delete verification request from database +func (p *provider) DeleteVerificationRequest(verificationRequest models.VerificationRequest) error { + result := p.db.Delete(&verificationRequest) + + if result.Error != nil { + log.Println(`error deleting verification request:`, result.Error) + return result.Error + } + + return nil +} diff --git a/server/db/session.go b/server/db/session.go deleted file mode 100644 index 47b31aa..0000000 --- a/server/db/session.go +++ /dev/null @@ -1,102 +0,0 @@ -package db - -import ( - "fmt" - "log" - "time" - - "github.com/google/uuid" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo/options" - "gorm.io/gorm/clause" -) - -type Session struct { - Key string `json:"_key,omitempty" bson:"_key,omitempty"` // for arangodb - ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"` - UserID string `gorm:"type:char(36),index:" json:"user_id" bson:"user_id"` - User User `json:"-" bson:"-"` - UserAgent string `json:"user_agent" bson:"user_agent"` - IP string `json:"ip" bson:"ip"` - CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` - UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` -} - -// AddSession function to save user sessiosn -func (mgr *manager) AddSession(session Session) error { - if session.ID == "" { - session.ID = uuid.New().String() - } - - if IsORMSupported { - session.Key = session.ID - res := mgr.sqlDB.Clauses( - clause.OnConflict{ - DoNothing: true, - }).Create(&session) - if res.Error != nil { - log.Println(`error saving session`, res.Error) - return res.Error - } - } - - if IsArangoDB { - session.CreatedAt = time.Now().Unix() - session.UpdatedAt = time.Now().Unix() - sessionCollection, _ := mgr.arangodb.Collection(nil, Collections.Session) - _, err := sessionCollection.CreateDocument(nil, session) - if err != nil { - log.Println(`error saving session`, err) - return err - } - } - - if IsMongoDB { - session.Key = session.ID - session.CreatedAt = time.Now().Unix() - session.UpdatedAt = time.Now().Unix() - sessionCollection := mgr.mongodb.Collection(Collections.Session, options.Collection()) - _, err := sessionCollection.InsertOne(nil, session) - if err != nil { - log.Println(`error saving session`, err) - return err - } - } - - return nil -} - -func (mgr *manager) DeleteUserSession(userId string) error { - if IsORMSupported { - result := mgr.sqlDB.Where("user_id = ?", userId).Delete(&Session{}) - - if result.Error != nil { - log.Println(`error deleting session:`, result.Error) - return result.Error - } - } - - if IsArangoDB { - query := fmt.Sprintf(`FOR d IN %s FILTER d.user_id == @userId REMOVE { _key: d._key } IN %s`, Collections.Session, Collections.Session) - bindVars := map[string]interface{}{ - "userId": userId, - } - cursor, err := mgr.arangodb.Query(nil, query, bindVars) - if err != nil { - log.Println("=> error deleting arangodb session:", err) - return err - } - defer cursor.Close() - } - - if IsMongoDB { - sessionCollection := mgr.mongodb.Collection(Collections.Session, options.Collection()) - _, err := sessionCollection.DeleteMany(nil, bson.M{"user_id": userId}, options.Delete()) - if err != nil { - log.Println("error deleting session:", err) - return err - } - } - - return nil -} diff --git a/server/db/user.go b/server/db/user.go deleted file mode 100644 index 3ab2def..0000000 --- a/server/db/user.go +++ /dev/null @@ -1,318 +0,0 @@ -package db - -import ( - "fmt" - "log" - "strings" - "time" - - "github.com/arangodb/go-driver" - arangoDriver "github.com/arangodb/go-driver" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/envstore" - "github.com/google/uuid" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo/options" - "gorm.io/gorm/clause" -) - -type User struct { - Key string `json:"_key,omitempty" bson:"_key"` // for arangodb - ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"` - - Email string `gorm:"unique" json:"email" bson:"email"` - EmailVerifiedAt *int64 `json:"email_verified_at" bson:"email_verified_at"` - Password *string `gorm:"type:text" json:"password" bson:"password"` - SignupMethods string `json:"signup_methods" bson:"signup_methods"` - GivenName *string `json:"given_name" bson:"given_name"` - FamilyName *string `json:"family_name" bson:"family_name"` - MiddleName *string `json:"middle_name" bson:"middle_name"` - Nickname *string `json:"nickname" bson:"nickname"` - Gender *string `json:"gender" bson:"gender"` - Birthdate *string `json:"birthdate" bson:"birthdate"` - PhoneNumber *string `gorm:"unique" json:"phone_number" bson:"phone_number"` - PhoneNumberVerifiedAt *int64 `json:"phone_number_verified_at" bson:"phone_number_verified_at"` - Picture *string `gorm:"type:text" json:"picture" bson:"picture"` - Roles string `json:"roles" bson:"roles"` - UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` - CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` -} - -// AddUser function to add user even with email conflict -func (mgr *manager) AddUser(user User) (User, error) { - if user.ID == "" { - user.ID = uuid.New().String() - } - - if user.Roles == "" { - user.Roles = strings.Join(envstore.EnvInMemoryStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles), ",") - } - - if IsORMSupported { - // copy id as value for fields required for mongodb & arangodb - user.Key = user.ID - result := mgr.sqlDB.Clauses( - clause.OnConflict{ - UpdateAll: true, - Columns: []clause.Column{{Name: "email"}}, - }).Create(&user) - - if result.Error != nil { - log.Println("error adding user:", result.Error) - return user, result.Error - } - } - - if IsArangoDB { - user.CreatedAt = time.Now().Unix() - user.UpdatedAt = time.Now().Unix() - userCollection, _ := mgr.arangodb.Collection(nil, Collections.User) - meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(nil), user) - if err != nil { - log.Println("error adding user:", err) - return user, err - } - user.Key = meta.Key - user.ID = meta.ID.String() - } - - if IsMongoDB { - user.CreatedAt = time.Now().Unix() - user.UpdatedAt = time.Now().Unix() - user.Key = user.ID - userCollection := mgr.mongodb.Collection(Collections.User, options.Collection()) - _, err := userCollection.InsertOne(nil, user) - if err != nil { - log.Println("error adding user:", err) - return user, err - } - } - - return user, nil -} - -// UpdateUser function to update user with ID conflict -func (mgr *manager) UpdateUser(user User) (User, error) { - user.UpdatedAt = time.Now().Unix() - - if IsORMSupported { - result := mgr.sqlDB.Save(&user) - - if result.Error != nil { - log.Println("error updating user:", result.Error) - return user, result.Error - } - } - - if IsArangoDB { - collection, _ := mgr.arangodb.Collection(nil, Collections.User) - meta, err := collection.UpdateDocument(nil, user.Key, user) - if err != nil { - log.Println("error updating user:", err) - return user, err - } - - user.Key = meta.Key - user.ID = meta.ID.String() - } - - if IsMongoDB { - userCollection := mgr.mongodb.Collection(Collections.User, options.Collection()) - _, err := userCollection.UpdateOne(nil, bson.M{"_id": bson.M{"$eq": user.ID}}, bson.M{"$set": user}, options.MergeUpdateOptions()) - if err != nil { - log.Println("error updating user:", err) - return user, err - } - } - - return user, nil -} - -// GetUsers function to get all users -func (mgr *manager) GetUsers() ([]User, error) { - var users []User - - if IsORMSupported { - result := mgr.sqlDB.Find(&users) - if result.Error != nil { - log.Println("error getting users:", result.Error) - return users, result.Error - } - } - - if IsArangoDB { - query := fmt.Sprintf("FOR d in %s RETURN d", Collections.User) - - cursor, err := mgr.arangodb.Query(nil, query, nil) - if err != nil { - return users, err - } - defer cursor.Close() - - for { - var user User - meta, err := cursor.ReadDocument(nil, &user) - - if driver.IsNoMoreDocuments(err) { - break - } else if err != nil { - return users, err - } - - if meta.Key != "" { - users = append(users, user) - } - } - } - - if IsMongoDB { - userCollection := mgr.mongodb.Collection(Collections.User, options.Collection()) - cursor, err := userCollection.Find(nil, bson.M{}, options.Find()) - if err != nil { - log.Println("error getting users:", err) - return users, err - } - defer cursor.Close(nil) - - for cursor.Next(nil) { - var user User - err := cursor.Decode(&user) - if err != nil { - return users, err - } - users = append(users, user) - } - } - - return users, nil -} - -// GetUserByEmail function to get user by email -func (mgr *manager) GetUserByEmail(email string) (User, error) { - var user User - - if IsORMSupported { - result := mgr.sqlDB.Where("email = ?", email).First(&user) - - if result.Error != nil { - return user, result.Error - } - } - - if IsArangoDB { - query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", Collections.User) - bindVars := map[string]interface{}{ - "email": email, - } - - cursor, err := mgr.arangodb.Query(nil, query, bindVars) - if err != nil { - return user, err - } - defer cursor.Close() - - for { - if !cursor.HasMore() { - if user.Key == "" { - return user, fmt.Errorf("user not found") - } - break - } - _, err := cursor.ReadDocument(nil, &user) - if err != nil { - return user, err - } - } - } - - if IsMongoDB { - userCollection := mgr.mongodb.Collection(Collections.User, options.Collection()) - err := userCollection.FindOne(nil, bson.M{"email": email}).Decode(&user) - if err != nil { - return user, err - } - } - - return user, nil -} - -// GetUserByID function to get user by ID -func (mgr *manager) GetUserByID(id string) (User, error) { - var user User - - if IsORMSupported { - result := mgr.sqlDB.Where("id = ?", id).First(&user) - - if result.Error != nil { - return user, result.Error - } - } - - if IsArangoDB { - query := fmt.Sprintf("FOR d in %s FILTER d._id == @id LIMIT 1 RETURN d", Collections.User) - bindVars := map[string]interface{}{ - "id": id, - } - - cursor, err := mgr.arangodb.Query(nil, query, bindVars) - if err != nil { - return user, err - } - defer cursor.Close() - - for { - if !cursor.HasMore() { - if user.Key == "" { - return user, fmt.Errorf("user not found") - } - break - } - _, err := cursor.ReadDocument(nil, &user) - if err != nil { - return user, err - } - } - } - - if IsMongoDB { - userCollection := mgr.mongodb.Collection(Collections.User, options.Collection()) - err := userCollection.FindOne(nil, bson.M{"_id": id}).Decode(&user) - if err != nil { - return user, err - } - } - - return user, nil -} - -// DeleteUser function to delete user -func (mgr *manager) DeleteUser(user User) error { - if IsORMSupported { - result := mgr.sqlDB.Delete(&user) - - if result.Error != nil { - log.Println(`error deleting user:`, result.Error) - return result.Error - } - } - - if IsArangoDB { - collection, _ := mgr.arangodb.Collection(nil, Collections.User) - _, err := collection.RemoveDocument(nil, user.Key) - if err != nil { - log.Println(`error deleting user:`, err) - return err - } - } - - if IsMongoDB { - userCollection := mgr.mongodb.Collection(Collections.User, options.Collection()) - _, err := userCollection.DeleteOne(nil, bson.M{"_id": user.ID}, options.Delete()) - if err != nil { - log.Println("error deleting user:", err) - return err - } - } - - return nil -} diff --git a/server/db/verification_requests.go b/server/db/verification_requests.go deleted file mode 100644 index 45b5de0..0000000 --- a/server/db/verification_requests.go +++ /dev/null @@ -1,260 +0,0 @@ -package db - -import ( - "fmt" - "log" - "time" - - "github.com/arangodb/go-driver" - "github.com/google/uuid" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo/options" - "gorm.io/gorm/clause" -) - -type VerificationRequest struct { - Key string `json:"_key,omitempty" bson:"_key"` // for arangodb - ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"` - Token string `gorm:"type:text" json:"token" bson:"token"` - Identifier string `gorm:"uniqueIndex:idx_email_identifier" json:"identifier" bson:"identifier"` - ExpiresAt int64 `json:"expires_at" bson:"expires_at"` - CreatedAt int64 `gorm:"autoCreateTime" json:"created_at" bson:"created_at"` - UpdatedAt int64 `gorm:"autoUpdateTime" json:"updated_at" bson:"updated_at"` - Email string `gorm:"uniqueIndex:idx_email_identifier" json:"email" bson:"email"` -} - -// AddVerification function to add verification record -func (mgr *manager) AddVerification(verification VerificationRequest) (VerificationRequest, error) { - if verification.ID == "" { - verification.ID = uuid.New().String() - } - if IsORMSupported { - // copy id as value for fields required for mongodb & arangodb - verification.Key = verification.ID - result := mgr.sqlDB.Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "email"}, {Name: "identifier"}}, - DoUpdates: clause.AssignmentColumns([]string{"token", "expires_at"}), - }).Create(&verification) - - if result.Error != nil { - log.Println(`error saving verification record`, result.Error) - return verification, result.Error - } - } - - if IsArangoDB { - verification.CreatedAt = time.Now().Unix() - verification.UpdatedAt = time.Now().Unix() - verificationRequestCollection, _ := mgr.arangodb.Collection(nil, Collections.VerificationRequest) - meta, err := verificationRequestCollection.CreateDocument(nil, verification) - if err != nil { - log.Println("error saving verification record:", err) - return verification, err - } - verification.Key = meta.Key - verification.ID = meta.ID.String() - } - - if IsMongoDB { - verification.CreatedAt = time.Now().Unix() - verification.UpdatedAt = time.Now().Unix() - verification.Key = verification.ID - verificationRequestCollection := mgr.mongodb.Collection(Collections.VerificationRequest, options.Collection()) - _, err := verificationRequestCollection.InsertOne(nil, verification) - if err != nil { - log.Println("error saving verification record:", err) - return verification, err - } - } - - return verification, nil -} - -// GetVerificationRequests function to get all verification requests -func (mgr *manager) GetVerificationRequests() ([]VerificationRequest, error) { - var verificationRequests []VerificationRequest - - if IsORMSupported { - result := mgr.sqlDB.Find(&verificationRequests) - if result.Error != nil { - log.Println("error getting verification requests:", result.Error) - return verificationRequests, result.Error - } - } - - if IsArangoDB { - query := fmt.Sprintf("FOR d in %s RETURN d", Collections.VerificationRequest) - - cursor, err := mgr.arangodb.Query(nil, query, nil) - if err != nil { - return verificationRequests, err - } - defer cursor.Close() - - for { - var verificationRequest VerificationRequest - meta, err := cursor.ReadDocument(nil, &verificationRequest) - - if driver.IsNoMoreDocuments(err) { - break - } else if err != nil { - return verificationRequests, err - } - - if meta.Key != "" { - verificationRequests = append(verificationRequests, verificationRequest) - } - - } - } - - if IsMongoDB { - verificationRequestCollection := mgr.mongodb.Collection(Collections.VerificationRequest, options.Collection()) - cursor, err := verificationRequestCollection.Find(nil, bson.M{}, options.Find()) - if err != nil { - log.Println("error getting verification requests:", err) - return verificationRequests, err - } - defer cursor.Close(nil) - - for cursor.Next(nil) { - var verificationRequest VerificationRequest - err := cursor.Decode(&verificationRequest) - if err != nil { - return verificationRequests, err - } - verificationRequests = append(verificationRequests, verificationRequest) - } - } - - return verificationRequests, nil -} - -func (mgr *manager) GetVerificationByToken(token string) (VerificationRequest, error) { - var verification VerificationRequest - - if IsORMSupported { - result := mgr.sqlDB.Where("token = ?", token).First(&verification) - - if result.Error != nil { - log.Println(`error getting verification request:`, result.Error) - return verification, result.Error - } - } - - if IsArangoDB { - query := fmt.Sprintf("FOR d in %s FILTER d.token == @token LIMIT 1 RETURN d", Collections.VerificationRequest) - bindVars := map[string]interface{}{ - "token": token, - } - - cursor, err := mgr.arangodb.Query(nil, query, bindVars) - if err != nil { - return verification, err - } - defer cursor.Close() - - for { - if !cursor.HasMore() { - if verification.Key == "" { - return verification, fmt.Errorf("verification request not found") - } - break - } - _, err := cursor.ReadDocument(nil, &verification) - if err != nil { - return verification, err - } - } - } - - if IsMongoDB { - verificationRequestCollection := mgr.mongodb.Collection(Collections.VerificationRequest, options.Collection()) - err := verificationRequestCollection.FindOne(nil, bson.M{"token": token}).Decode(&verification) - if err != nil { - return verification, err - } - } - - return verification, nil -} - -func (mgr *manager) GetVerificationByEmail(email string, identifier string) (VerificationRequest, error) { - var verification VerificationRequest - if IsORMSupported { - result := mgr.sqlDB.Where("email = ? AND identifier = ?", email, identifier).First(&verification) - - if result.Error != nil { - log.Println(`error getting verification token:`, result.Error) - return verification, result.Error - } - } - - if IsArangoDB { - query := fmt.Sprintf("FOR d in %s FILTER d.email == @email FILTER d.identifier == @identifier LIMIT 1 RETURN d", Collections.VerificationRequest) - bindVars := map[string]interface{}{ - "email": email, - "identifier": identifier, - } - - cursor, err := mgr.arangodb.Query(nil, query, bindVars) - if err != nil { - return verification, err - } - defer cursor.Close() - - for { - if !cursor.HasMore() { - if verification.Key == "" { - return verification, fmt.Errorf("verification request not found") - } - break - } - _, err := cursor.ReadDocument(nil, &verification) - if err != nil { - return verification, err - } - } - } - - if IsMongoDB { - verificationRequestCollection := mgr.mongodb.Collection(Collections.VerificationRequest, options.Collection()) - err := verificationRequestCollection.FindOne(nil, bson.M{"email": email, "identifier": identifier}).Decode(&verification) - if err != nil { - return verification, err - } - } - - return verification, nil -} - -func (mgr *manager) DeleteVerificationRequest(verificationRequest VerificationRequest) error { - if IsORMSupported { - result := mgr.sqlDB.Delete(&verificationRequest) - - if result.Error != nil { - log.Println(`error deleting verification request:`, result.Error) - return result.Error - } - } - - if IsArangoDB { - collection, _ := mgr.arangodb.Collection(nil, Collections.VerificationRequest) - _, err := collection.RemoveDocument(nil, verificationRequest.Key) - if err != nil { - log.Println(`error deleting verification request:`, err) - return err - } - } - - if IsMongoDB { - verificationRequestCollection := mgr.mongodb.Collection(Collections.VerificationRequest, options.Collection()) - _, err := verificationRequestCollection.DeleteOne(nil, bson.M{"_id": verificationRequest.ID}, options.Delete()) - if err != nil { - log.Println("error deleting verification request::", err) - return err - } - } - - return nil -} diff --git a/server/env/persist_env.go b/server/env/persist_env.go index 6e04c43..b887973 100644 --- a/server/env/persist_env.go +++ b/server/env/persist_env.go @@ -9,6 +9,7 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/utils" "github.com/google/uuid" @@ -16,7 +17,7 @@ import ( // PersistEnv persists the environment variables to the database func PersistEnv() error { - env, err := db.Mgr.GetEnv() + env, err := db.Provider.GetEnv() // config not found in db if err != nil { // AES encryption needs 32 bit key only, so we chop off last 4 characters from 36 bit uuid @@ -34,12 +35,12 @@ func PersistEnv() error { return err } - env = db.Env{ + env = models.Env{ Hash: encodedHash, EnvData: encryptedConfig, } - db.Mgr.AddEnv(env) + db.Provider.AddEnv(env) } else { // decrypt the config data from db // decryption can be done using the hash stored in db @@ -131,7 +132,7 @@ func PersistEnv() error { } env.EnvData = encryptedConfig - _, err = db.Mgr.UpdateEnv(env) + _, err = db.Provider.UpdateEnv(env) if err != nil { log.Println("error updating config:", err) return err diff --git a/server/handlers/oauth_callback.go b/server/handlers/oauth_callback.go index 36c7a80..eb8c3f9 100644 --- a/server/handlers/oauth_callback.go +++ b/server/handlers/oauth_callback.go @@ -12,6 +12,7 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/oauth" "github.com/authorizerdev/authorizer/server/session" @@ -45,7 +46,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { redirectURL := sessionSplit[1] var err error - user := db.User{} + user := models.User{} code := c.Request.FormValue("code") switch provider { case constants.SignupMethodGoogle: @@ -63,7 +64,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { return } - existingUser, err := db.Mgr.GetUserByEmail(user.Email) + existingUser, err := db.Provider.GetUserByEmail(user.Email) if err != nil { // user not registered, register user and generate session token @@ -84,7 +85,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { user.Roles = strings.Join(inputRoles, ",") now := time.Now().Unix() user.EmailVerifiedAt = &now - user, _ = db.Mgr.AddUser(user) + user, _ = db.Provider.AddUser(user) } else { // user exists in db, check if method was google // if not append google to existing signup method and save it @@ -130,10 +131,10 @@ func OAuthCallbackHandler() gin.HandlerFunc { } user.Key = existingUser.Key user.ID = existingUser.ID - user, err = db.Mgr.UpdateUser(user) + user, err = db.Provider.UpdateUser(user) } - user, _ = db.Mgr.GetUserByEmail(user.Email) + user, _ = db.Provider.GetUserByEmail(user.Email) userIdStr := fmt.Sprintf("%v", user.ID) refreshToken, _, _ := utils.CreateAuthToken(user, constants.TokenTypeRefreshToken, inputRoles) @@ -146,8 +147,8 @@ func OAuthCallbackHandler() gin.HandlerFunc { } } -func processGoogleUserInfo(code string) (db.User, error) { - user := db.User{} +func processGoogleUserInfo(code string) (models.User, error) { + user := models.User{} ctx := context.Background() oauth2Token, err := oauth.OAuthProviders.GoogleConfig.Exchange(ctx, code) if err != nil { @@ -175,8 +176,8 @@ func processGoogleUserInfo(code string) (db.User, error) { return user, nil } -func processGithubUserInfo(code string) (db.User, error) { - user := db.User{} +func processGithubUserInfo(code string) (models.User, error) { + user := models.User{} token, err := oauth.OAuthProviders.GithubConfig.Exchange(oauth2.NoContext, code) if err != nil { return user, fmt.Errorf("invalid github exchange code: %s", err.Error()) @@ -216,7 +217,7 @@ func processGithubUserInfo(code string) (db.User, error) { picture := userRawData["avatar_url"] - user = db.User{ + user = models.User{ GivenName: &firstName, FamilyName: &lastName, Picture: &picture, @@ -226,8 +227,8 @@ func processGithubUserInfo(code string) (db.User, error) { return user, nil } -func processFacebookUserInfo(code string) (db.User, error) { - user := db.User{} +func processFacebookUserInfo(code string) (models.User, error) { + user := models.User{} token, err := oauth.OAuthProviders.FacebookConfig.Exchange(oauth2.NoContext, code) if err != nil { return user, fmt.Errorf("invalid facebook exchange code: %s", err.Error()) @@ -261,7 +262,7 @@ func processFacebookUserInfo(code string) (db.User, error) { lastName := fmt.Sprintf("%v", userRawData["last_name"]) picture := fmt.Sprintf("%v", picDataObject["url"]) - user = db.User{ + user = models.User{ GivenName: &firstName, FamilyName: &lastName, Picture: &picture, diff --git a/server/handlers/verify_email.go b/server/handlers/verify_email.go index 3a80541..1306d2c 100644 --- a/server/handlers/verify_email.go +++ b/server/handlers/verify_email.go @@ -25,7 +25,7 @@ func VerifyEmailHandler() gin.HandlerFunc { return } - verificationRequest, err := db.Mgr.GetVerificationByToken(token) + verificationRequest, err := db.Provider.GetVerificationRequestByToken(token) if err != nil { c.JSON(400, errorRes) return @@ -38,7 +38,7 @@ func VerifyEmailHandler() gin.HandlerFunc { return } - user, err := db.Mgr.GetUserByEmail(claim.Email) + user, err := db.Provider.GetUserByEmail(claim.Email) if err != nil { c.JSON(400, gin.H{ "message": err.Error(), @@ -50,10 +50,10 @@ func VerifyEmailHandler() gin.HandlerFunc { if user.EmailVerifiedAt == nil { now := time.Now().Unix() user.EmailVerifiedAt = &now - db.Mgr.UpdateUser(user) + db.Provider.UpdateUser(user) } // delete from verification table - db.Mgr.DeleteVerificationRequest(verificationRequest) + db.Provider.DeleteVerificationRequest(verificationRequest) roles := strings.Split(user.Roles, ",") refreshToken, _, _ := utils.CreateAuthToken(user, constants.TokenTypeRefreshToken, roles) diff --git a/server/resolvers/admin_signup.go b/server/resolvers/admin_signup.go index f553ac2..cb8802b 100644 --- a/server/resolvers/admin_signup.go +++ b/server/resolvers/admin_signup.go @@ -52,7 +52,7 @@ func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*m return res, err } - env, err := db.Mgr.GetEnv() + env, err := db.Provider.GetEnv() if err != nil { return res, err } @@ -63,7 +63,7 @@ func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*m } env.EnvData = envData - if _, err := db.Mgr.UpdateEnv(env); err != nil { + if _, err := db.Provider.UpdateEnv(env); err != nil { return res, err } diff --git a/server/resolvers/delete_user.go b/server/resolvers/delete_user.go index db1a31f..92b4472 100644 --- a/server/resolvers/delete_user.go +++ b/server/resolvers/delete_user.go @@ -23,14 +23,14 @@ func DeleteUserResolver(ctx context.Context, params model.DeleteUserInput) (*mod return res, fmt.Errorf("unauthorized") } - user, err := db.Mgr.GetUserByEmail(params.Email) + user, err := db.Provider.GetUserByEmail(params.Email) if err != nil { return res, err } session.DeleteAllUserSession(fmt.Sprintf("%x", user.ID)) - err = db.Mgr.DeleteUser(user) + err = db.Provider.DeleteUser(user) if err != nil { log.Println("error deleting user:", err) return res, err diff --git a/server/resolvers/forgot_password.go b/server/resolvers/forgot_password.go index 7bd5338..2c035df 100644 --- a/server/resolvers/forgot_password.go +++ b/server/resolvers/forgot_password.go @@ -9,6 +9,7 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/graph/model" @@ -32,7 +33,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu return res, fmt.Errorf("invalid email") } - _, err = db.Mgr.GetUserByEmail(params.Email) + _, err = db.Provider.GetUserByEmail(params.Email) if err != nil { return res, fmt.Errorf(`user with this email not found`) } @@ -41,7 +42,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu if err != nil { log.Println(`error generating token`, err) } - db.Mgr.AddVerification(db.VerificationRequest{ + db.Provider.AddVerificationRequest(models.VerificationRequest{ Token: token, Identifier: constants.VerificationTypeForgotPassword, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), diff --git a/server/resolvers/login.go b/server/resolvers/login.go index 9af7f95..ee54e1a 100644 --- a/server/resolvers/login.go +++ b/server/resolvers/login.go @@ -28,7 +28,7 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes } params.Email = strings.ToLower(params.Email) - user, err := db.Mgr.GetUserByEmail(params.Email) + user, err := db.Provider.GetUserByEmail(params.Email) if err != nil { return res, fmt.Errorf(`user with this email not found`) } diff --git a/server/resolvers/magic_link_login.go b/server/resolvers/magic_link_login.go index b9a2318..8b2aef2 100644 --- a/server/resolvers/magic_link_login.go +++ b/server/resolvers/magic_link_login.go @@ -9,6 +9,7 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/graph/model" @@ -31,12 +32,12 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu inputRoles := []string{} - user := db.User{ + user := models.User{ Email: params.Email, } // find user with email - existingUser, err := db.Mgr.GetUserByEmail(params.Email) + existingUser, err := db.Provider.GetUserByEmail(params.Email) if err != nil { user.SignupMethods = constants.SignupMethodMagicLinkLogin @@ -53,7 +54,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu } user.Roles = strings.Join(inputRoles, ",") - user, _ = db.Mgr.AddUser(user) + user, _ = db.Provider.AddUser(user) } else { user = existingUser // There multiple scenarios with roles here in magic link login @@ -94,7 +95,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu } user.SignupMethods = signupMethod - user, _ = db.Mgr.UpdateUser(user) + user, _ = db.Provider.UpdateUser(user) if err != nil { log.Println("error updating user:", err) } @@ -107,7 +108,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu if err != nil { log.Println(`error generating token`, err) } - db.Mgr.AddVerification(db.VerificationRequest{ + db.Provider.AddVerificationRequest(models.VerificationRequest{ Token: token, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), diff --git a/server/resolvers/profile.go b/server/resolvers/profile.go index 1861527..c17d775 100644 --- a/server/resolvers/profile.go +++ b/server/resolvers/profile.go @@ -36,7 +36,7 @@ func ProfileResolver(ctx context.Context) (*model.User, error) { return res, fmt.Errorf(`unauthorized`) } - user, err := db.Mgr.GetUserByEmail(email) + user, err := db.Provider.GetUserByEmail(email) if err != nil { return res, err } diff --git a/server/resolvers/resend_verify_email.go b/server/resolvers/resend_verify_email.go index 1636434..3540282 100644 --- a/server/resolvers/resend_verify_email.go +++ b/server/resolvers/resend_verify_email.go @@ -8,6 +8,7 @@ import ( "time" "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/utils" @@ -26,13 +27,13 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma return res, fmt.Errorf("invalid identifier") } - verificationRequest, err := db.Mgr.GetVerificationByEmail(params.Email, params.Identifier) + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(params.Email, params.Identifier) if err != nil { return res, fmt.Errorf(`verification request not found`) } // delete current verification and create new one - err = db.Mgr.DeleteVerificationRequest(verificationRequest) + err = db.Provider.DeleteVerificationRequest(verificationRequest) if err != nil { log.Println("error deleting verification request:", err) } @@ -41,7 +42,7 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma if err != nil { log.Println(`error generating token`, err) } - db.Mgr.AddVerification(db.VerificationRequest{ + db.Provider.AddVerificationRequest(models.VerificationRequest{ Token: token, Identifier: params.Identifier, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), diff --git a/server/resolvers/reset_password.go b/server/resolvers/reset_password.go index fd20b85..1ac223f 100644 --- a/server/resolvers/reset_password.go +++ b/server/resolvers/reset_password.go @@ -20,7 +20,7 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput) return res, fmt.Errorf(`basic authentication is disabled for this instance`) } - verificationRequest, err := db.Mgr.GetVerificationByToken(params.Token) + verificationRequest, err := db.Provider.GetVerificationRequestByToken(params.Token) if err != nil { return res, fmt.Errorf(`invalid token`) } @@ -35,7 +35,7 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput) return res, fmt.Errorf(`invalid token`) } - user, err := db.Mgr.GetUserByEmail(claim.Email) + user, err := db.Provider.GetUserByEmail(claim.Email) if err != nil { return res, err } @@ -56,8 +56,8 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput) } // delete from verification table - db.Mgr.DeleteVerificationRequest(verificationRequest) - db.Mgr.UpdateUser(user) + db.Provider.DeleteVerificationRequest(verificationRequest) + db.Provider.UpdateUser(user) res = &model.Response{ Message: `Password updated successfully.`, diff --git a/server/resolvers/session.go b/server/resolvers/session.go index 896d63a..6b33ed2 100644 --- a/server/resolvers/session.go +++ b/server/resolvers/session.go @@ -30,7 +30,7 @@ func SessionResolver(ctx context.Context, roles []string) (*model.AuthResponse, expiresAt := claim["exp"].(int64) email := fmt.Sprintf("%v", claim["email"]) - user, err := db.Mgr.GetUserByEmail(email) + user, err := db.Provider.GetUserByEmail(email) if err != nil { return res, err } diff --git a/server/resolvers/signup.go b/server/resolvers/signup.go index 5dee56c..30f0e95 100644 --- a/server/resolvers/signup.go +++ b/server/resolvers/signup.go @@ -9,6 +9,7 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/graph/model" @@ -38,7 +39,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR } // find user with email - existingUser, err := db.Mgr.GetUserByEmail(params.Email) + existingUser, err := db.Provider.GetUserByEmail(params.Email) if err != nil { log.Println("user with email " + params.Email + " not found") } @@ -63,7 +64,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR inputRoles = envstore.EnvInMemoryStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles) } - user := db.User{ + user := models.User{ Email: params.Email, } @@ -109,7 +110,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR now := time.Now().Unix() user.EmailVerifiedAt = &now } - user, err = db.Mgr.AddUser(user) + user, err = db.Provider.AddUser(user) if err != nil { return res, err } @@ -124,7 +125,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR if err != nil { log.Println(`error generating token`, err) } - db.Mgr.AddVerification(db.VerificationRequest{ + db.Provider.AddVerificationRequest(models.VerificationRequest{ Token: token, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), diff --git a/server/resolvers/update_env.go b/server/resolvers/update_env.go index c933dcf..5e83d9e 100644 --- a/server/resolvers/update_env.go +++ b/server/resolvers/update_env.go @@ -78,7 +78,7 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model envstore.EnvInMemoryStoreObj.UpdateEnvStore(updatedData) // Fetch the current db store and update it - env, err := db.Mgr.GetEnv() + env, err := db.Provider.GetEnv() if err != nil { return res, err } @@ -112,7 +112,7 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model } env.EnvData = encryptedConfig - _, err = db.Mgr.UpdateEnv(env) + _, err = db.Provider.UpdateEnv(env) if err != nil { log.Println("error updating config:", err) return res, err diff --git a/server/resolvers/update_profile.go b/server/resolvers/update_profile.go index c077aca..2617861 100644 --- a/server/resolvers/update_profile.go +++ b/server/resolvers/update_profile.go @@ -9,6 +9,7 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/session" @@ -47,7 +48,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) } userEmail := fmt.Sprintf("%v", claim["email"]) - user, err := db.Mgr.GetUserByEmail(userEmail) + user, err := db.Provider.GetUserByEmail(userEmail) if err != nil { return res, err } @@ -115,7 +116,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) } newEmail := strings.ToLower(*params.Email) // check if user with new email exists - _, err := db.Mgr.GetUserByEmail(newEmail) + _, err := db.Provider.GetUserByEmail(newEmail) // err = nil means user exists if err == nil { @@ -134,7 +135,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) if err != nil { log.Println(`error generating token`, err) } - db.Mgr.AddVerification(db.VerificationRequest{ + db.Provider.AddVerificationRequest(models.VerificationRequest{ Token: token, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), @@ -147,7 +148,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) }() } - _, err = db.Mgr.UpdateUser(user) + _, err = db.Provider.UpdateUser(user) if err != nil { log.Println("error updating user:", err) return res, err diff --git a/server/resolvers/update_user.go b/server/resolvers/update_user.go index ae7e97b..79aa110 100644 --- a/server/resolvers/update_user.go +++ b/server/resolvers/update_user.go @@ -9,6 +9,7 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/email" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/graph/model" @@ -33,7 +34,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod return res, fmt.Errorf("please enter atleast one param to update") } - user, err := db.Mgr.GetUserByID(params.ID) + user, err := db.Provider.GetUserByID(params.ID) if err != nil { return res, fmt.Errorf(`User not found`) } @@ -86,7 +87,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod } newEmail := strings.ToLower(*params.Email) // check if user with new email exists - _, err = db.Mgr.GetUserByEmail(newEmail) + _, err = db.Provider.GetUserByEmail(newEmail) // err = nil means user exists if err == nil { return res, fmt.Errorf("user with this email address already exists") @@ -103,7 +104,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod if err != nil { log.Println(`error generating token`, err) } - db.Mgr.AddVerification(db.VerificationRequest{ + db.Provider.AddVerificationRequest(models.VerificationRequest{ Token: token, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), @@ -140,7 +141,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod user.Roles = rolesToSave } - user, err = db.Mgr.UpdateUser(user) + user, err = db.Provider.UpdateUser(user) if err != nil { log.Println("error updating user:", err) return res, err diff --git a/server/resolvers/users.go b/server/resolvers/users.go index d5fd5f1..a74bac1 100644 --- a/server/resolvers/users.go +++ b/server/resolvers/users.go @@ -22,7 +22,7 @@ func UsersResolver(ctx context.Context) ([]*model.User, error) { return res, fmt.Errorf("unauthorized") } - users, err := db.Mgr.GetUsers() + users, err := db.Provider.ListUsers() if err != nil { return res, err } diff --git a/server/resolvers/verification_requests.go b/server/resolvers/verification_requests.go index e21d827..39b8f59 100644 --- a/server/resolvers/verification_requests.go +++ b/server/resolvers/verification_requests.go @@ -22,7 +22,7 @@ func VerificationRequestsResolver(ctx context.Context) ([]*model.VerificationReq return res, fmt.Errorf("unauthorized") } - verificationRequests, err := db.Mgr.GetVerificationRequests() + verificationRequests, err := db.Provider.ListVerificationRequests() if err != nil { return res, err } diff --git a/server/resolvers/verify_email.go b/server/resolvers/verify_email.go index 6a53190..16df15d 100644 --- a/server/resolvers/verify_email.go +++ b/server/resolvers/verify_email.go @@ -21,7 +21,7 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m return res, err } - verificationRequest, err := db.Mgr.GetVerificationByToken(params.Token) + verificationRequest, err := db.Provider.GetVerificationRequestByToken(params.Token) if err != nil { return res, fmt.Errorf(`invalid token`) } @@ -32,7 +32,7 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m return res, fmt.Errorf(`invalid token`) } - user, err := db.Mgr.GetUserByEmail(claim.Email) + user, err := db.Provider.GetUserByEmail(claim.Email) if err != nil { return res, err } @@ -40,9 +40,9 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m // update email_verified_at in users table now := time.Now().Unix() user.EmailVerifiedAt = &now - db.Mgr.UpdateUser(user) + db.Provider.UpdateUser(user) // delete from verification table - db.Mgr.DeleteVerificationRequest(verificationRequest) + db.Provider.DeleteVerificationRequest(verificationRequest) roles := strings.Split(user.Roles, ",") refreshToken, _, _ := utils.CreateAuthToken(user, constants.TokenTypeRefreshToken, roles) diff --git a/server/test/admin_session_test.go b/server/test/admin_session_test.go index d859e98..8b28cdf 100644 --- a/server/test/admin_session_test.go +++ b/server/test/admin_session_test.go @@ -2,7 +2,6 @@ package test import ( "fmt" - "log" "testing" "github.com/authorizerdev/authorizer/server/constants" @@ -17,7 +16,6 @@ func adminSessionTests(t *testing.T, s TestSetup) { t.Run(`should get admin session`, func(t *testing.T) { req, ctx := createContext(s) _, err := resolvers.AdminSessionResolver(ctx) - log.Println("error:", err) assert.NotNil(t, err) h, err := utils.EncryptPassword(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)) diff --git a/server/test/env_test.go b/server/test/env_test.go index 3160e67..9505251 100644 --- a/server/test/env_test.go +++ b/server/test/env_test.go @@ -2,7 +2,6 @@ package test import ( "fmt" - "log" "testing" "github.com/authorizerdev/authorizer/server/constants" @@ -17,7 +16,6 @@ func envTests(t *testing.T, s TestSetup) { t.Run(`should get envs`, func(t *testing.T) { req, ctx := createContext(s) _, err := resolvers.EnvResolver(ctx) - log.Println("error:", err) assert.NotNil(t, err) h, err := utils.EncryptPassword(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)) diff --git a/server/test/forgot_password_test.go b/server/test/forgot_password_test.go index e181b0e..1479cc9 100644 --- a/server/test/forgot_password_test.go +++ b/server/test/forgot_password_test.go @@ -26,7 +26,7 @@ func forgotPasswordTest(t *testing.T, s TestSetup) { }) assert.Nil(t, err, "no errors for forgot password") - verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeForgotPassword) + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeForgotPassword) assert.Nil(t, err) assert.Equal(t, verificationRequest.Identifier, constants.VerificationTypeForgotPassword) diff --git a/server/test/login_test.go b/server/test/login_test.go index 1c40a50..4efb76b 100644 --- a/server/test/login_test.go +++ b/server/test/login_test.go @@ -28,7 +28,7 @@ func loginTests(t *testing.T, s TestSetup) { assert.NotNil(t, err, "should fail because email is not verified") - verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup) + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ Token: verificationRequest.Token, }) diff --git a/server/test/logout_test.go b/server/test/logout_test.go index da390bd..2705997 100644 --- a/server/test/logout_test.go +++ b/server/test/logout_test.go @@ -22,7 +22,7 @@ func logoutTests(t *testing.T, s TestSetup) { Email: email, }) - verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeMagicLinkLogin) + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeMagicLinkLogin) verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ Token: verificationRequest.Token, }) diff --git a/server/test/magic_link_login_test.go b/server/test/magic_link_login_test.go index 9615194..063bc90 100644 --- a/server/test/magic_link_login_test.go +++ b/server/test/magic_link_login_test.go @@ -23,7 +23,7 @@ func magicLinkLoginTests(t *testing.T, s TestSetup) { }) assert.Nil(t, err) - verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeMagicLinkLogin) + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeMagicLinkLogin) verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ Token: verificationRequest.Token, }) diff --git a/server/test/profile_test.go b/server/test/profile_test.go index 6450b37..af6ee2c 100644 --- a/server/test/profile_test.go +++ b/server/test/profile_test.go @@ -27,7 +27,7 @@ func profileTests(t *testing.T, s TestSetup) { _, err := resolvers.ProfileResolver(ctx) assert.NotNil(t, err, "unauthorized") - verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup) + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ Token: verificationRequest.Token, }) diff --git a/server/test/reset_password_test.go b/server/test/reset_password_test.go index 3aaccbc..6d0ce20 100644 --- a/server/test/reset_password_test.go +++ b/server/test/reset_password_test.go @@ -26,7 +26,7 @@ func resetPasswordTest(t *testing.T, s TestSetup) { }) assert.Nil(t, err, "no errors for forgot password") - verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeForgotPassword) + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeForgotPassword) assert.Nil(t, err, "should get forgot password request") _, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{ diff --git a/server/test/resolvers_test.go b/server/test/resolvers_test.go index 0d6a3db..ea82bc2 100644 --- a/server/test/resolvers_test.go +++ b/server/test/resolvers_test.go @@ -11,9 +11,9 @@ import ( func TestResolvers(t *testing.T) { databases := map[string]string{ - constants.DbTypeSqlite: "../../data.db", - // constants.DbTypeArangodb: "http://localhost:8529", - // constants.DbTypeMongodb: "mongodb://localhost:27017", + constants.DbTypeSqlite: "../../data.db", + constants.DbTypeArangodb: "http://localhost:8529", + constants.DbTypeMongodb: "mongodb://localhost:27017", } envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyVersion, "test") for dbType, dbURL := range databases { @@ -24,10 +24,10 @@ func TestResolvers(t *testing.T) { db.InitDB() // clean the persisted config for test to use fresh config - envData, err := db.Mgr.GetEnv() + envData, err := db.Provider.GetEnv() if err == nil { envData.EnvData = []byte{} - db.Mgr.UpdateEnv(envData) + db.Provider.UpdateEnv(envData) } env.PersistEnv() diff --git a/server/test/session_test.go b/server/test/session_test.go index 40a6510..167418d 100644 --- a/server/test/session_test.go +++ b/server/test/session_test.go @@ -27,7 +27,7 @@ func sessionTests(t *testing.T, s TestSetup) { _, err := resolvers.SessionResolver(ctx, []string{}) assert.NotNil(t, err, "unauthorized") - verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup) + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ Token: verificationRequest.Token, }) diff --git a/server/test/signup_test.go b/server/test/signup_test.go index 92ec18f..60af8eb 100644 --- a/server/test/signup_test.go +++ b/server/test/signup_test.go @@ -40,7 +40,7 @@ func signupTests(t *testing.T, s TestSetup) { assert.NotNil(t, err, "should throw duplicate email error") - verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup) + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) assert.Nil(t, err) assert.Equal(t, email, verificationRequest.Email) cleanData(email) diff --git a/server/test/test.go b/server/test/test.go index 42f4406..aae0018 100644 --- a/server/test/test.go +++ b/server/test/test.go @@ -3,7 +3,6 @@ package test import ( "context" "fmt" - "log" "net/http" "net/http/httptest" "time" @@ -33,25 +32,25 @@ type TestSetup struct { } func cleanData(email string) { - verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup) + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) if err == nil { - err = db.Mgr.DeleteVerificationRequest(verificationRequest) + err = db.Provider.DeleteVerificationRequest(verificationRequest) } - verificationRequest, err = db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeForgotPassword) + verificationRequest, err = db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeForgotPassword) if err == nil { - err = db.Mgr.DeleteVerificationRequest(verificationRequest) + err = db.Provider.DeleteVerificationRequest(verificationRequest) } - verificationRequest, err = db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeUpdateEmail) + verificationRequest, err = db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeUpdateEmail) if err == nil { - err = db.Mgr.DeleteVerificationRequest(verificationRequest) + err = db.Provider.DeleteVerificationRequest(verificationRequest) } - dbUser, err := db.Mgr.GetUserByEmail(email) + dbUser, err := db.Provider.GetUserByEmail(email) if err == nil { - db.Mgr.DeleteUser(dbUser) - db.Mgr.DeleteUserSession(dbUser.ID) + db.Provider.DeleteUser(dbUser) + db.Provider.DeleteSession(dbUser.ID) } } @@ -74,7 +73,7 @@ func testSetup() TestSetup { } envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyEnvPath, "../../.env.sample") - log.Println("envstore", envstore.EnvInMemoryStoreObj.GetEnvStoreClone()) + env.InitEnv() session.InitSession() diff --git a/server/test/update_env_test.go b/server/test/update_env_test.go index 7a7b65d..3aca3fd 100644 --- a/server/test/update_env_test.go +++ b/server/test/update_env_test.go @@ -2,7 +2,6 @@ package test import ( "fmt" - "log" "testing" "github.com/authorizerdev/authorizer/server/constants" @@ -21,7 +20,7 @@ func updateEnvTests(t *testing.T, s TestSetup) { data := model.UpdateEnvInput{} _, err := resolvers.UpdateEnvResolver(ctx, data) - log.Println("error:", err) + assert.NotNil(t, err) h, err := utils.EncryptPassword(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)) diff --git a/server/test/update_profile_test.go b/server/test/update_profile_test.go index c7de158..029f266 100644 --- a/server/test/update_profile_test.go +++ b/server/test/update_profile_test.go @@ -30,7 +30,7 @@ func updateProfileTests(t *testing.T, s TestSetup) { }) assert.NotNil(t, err, "unauthorized") - verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup) + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ Token: verificationRequest.Token, }) diff --git a/server/test/verify_email_test.go b/server/test/verify_email_test.go index 67affae..9cb4583 100644 --- a/server/test/verify_email_test.go +++ b/server/test/verify_email_test.go @@ -24,7 +24,7 @@ func verifyEmailTest(t *testing.T, s TestSetup) { user := *res.User assert.Equal(t, email, user.Email) assert.Nil(t, res.AccessToken, "access token should be nil") - verificationRequest, err := db.Mgr.GetVerificationByEmail(email, constants.VerificationTypeBasicAuthSignup) + verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) assert.Nil(t, err) assert.Equal(t, email, verificationRequest.Email) diff --git a/server/utils/auth_token.go b/server/utils/auth_token.go index c907bfe..cb364bb 100644 --- a/server/utils/auth_token.go +++ b/server/utils/auth_token.go @@ -10,7 +10,7 @@ import ( "time" "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/envstore" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt" @@ -20,7 +20,7 @@ import ( // CreateAuthToken util to create JWT token, based on // user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT -func CreateAuthToken(user db.User, tokenType string, roles []string) (string, int64, error) { +func CreateAuthToken(user models.User, tokenType string, roles []string) (string, int64, error) { t := jwt.New(jwt.GetSigningMethod(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType))) expiryBound := time.Hour if tokenType == constants.TokenTypeRefreshToken { diff --git a/server/utils/common.go b/server/utils/common.go index 52348bf..338fc30 100644 --- a/server/utils/common.go +++ b/server/utils/common.go @@ -1,7 +1,10 @@ package utils import ( + "log" + "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/gin-gonic/gin" ) @@ -16,13 +19,18 @@ func StringSliceContains(s []string, e string) bool { } // SaveSessionInDB saves sessions generated for a given user with meta information -// Not store token here as that could be security breach +// Do not store token here as that could be security breach func SaveSessionInDB(userId string, c *gin.Context) { - sessionData := db.Session{ + sessionData := models.Session{ UserID: userId, UserAgent: GetUserAgent(c.Request), IP: GetIP(c.Request), } - db.Mgr.AddSession(sessionData) + err := db.Provider.AddSession(sessionData) + if err != nil { + log.Println("=> error saving session in db:", err) + } else { + log.Println("=> session saved in db:", sessionData) + } } diff --git a/server/utils/get_response_user_data.go b/server/utils/get_response_user_data.go index ed3a8f2..1e6c360 100644 --- a/server/utils/get_response_user_data.go +++ b/server/utils/get_response_user_data.go @@ -3,14 +3,14 @@ package utils import ( "strings" - "github.com/authorizerdev/authorizer/server/db" + "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/graph/model" ) // TODO move this to provider // rename it to AsAPIUser -func GetResponseUserData(user db.User) *model.User { +func GetResponseUserData(user models.User) *model.User { isEmailVerified := user.EmailVerifiedAt != nil isPhoneVerified := user.PhoneNumberVerifiedAt != nil return &model.User{