Merge pull request #194 from authorizerdev/feat/webhook

feat: add webhook apis + integrate in events
This commit is contained in:
Lakhan Samani 2022-07-11 19:56:48 +05:30 committed by GitHub
commit 4f5a6c77f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
101 changed files with 4512 additions and 303 deletions

View File

@ -0,0 +1,18 @@
package constants
const (
// UserLoginWebhookEvent name for login event
UserLoginWebhookEvent = `user.login`
// UserCreatedWebhookEvent name for user creation event
// This is triggered when user entry is created but still not verified
UserCreatedWebhookEvent = `user.created`
// UserSignUpWebhookEvent name for signup event
UserSignUpWebhookEvent = `user.signup`
// UserAccessRevokedWebhookEvent name for user access revoke event
UserAccessRevokedWebhookEvent = `user.access_revoked`
// UserAccessEnabledWebhookEvent name for user access enable event
UserAccessEnabledWebhookEvent = `user.access_enabled`
// UserDeletedWebhookEvent name for user deleted event
UserDeletedWebhookEvent = `user.deleted`
)

View File

@ -6,6 +6,8 @@ type CollectionList struct {
VerificationRequest string VerificationRequest string
Session string Session string
Env string Env string
Webhook string
WebhookLog string
} }
var ( var (
@ -17,5 +19,7 @@ var (
VerificationRequest: Prefix + "verification_requests", VerificationRequest: Prefix + "verification_requests",
Session: Prefix + "sessions", Session: Prefix + "sessions",
Env: Prefix + "env", Env: Prefix + "env",
Webhook: Prefix + "webhook",
WebhookLog: Prefix + "webhook_log",
} }
) )

View File

@ -0,0 +1,35 @@
package models
import (
"encoding/json"
"github.com/authorizerdev/authorizer/server/graph/model"
)
// Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation
// Webhook model for db
type Webhook struct {
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name"`
EndPoint string `gorm:"type:text" json:"endpoint" bson:"endpoint" cql:"endpoint"`
Headers string `gorm:"type:text" json:"headers" bson:"headers" cql:"headers"`
Enabled bool `json:"enabled" bson:"enabled" cql:"enabled"`
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
}
func (w *Webhook) AsAPIWebhook() *model.Webhook {
headersMap := make(map[string]interface{})
json.Unmarshal([]byte(w.Headers), &headersMap)
return &model.Webhook{
ID: w.ID,
EventName: &w.EventName,
Endpoint: &w.EndPoint,
Headers: headersMap,
Enabled: &w.Enabled,
CreatedAt: &w.CreatedAt,
UpdatedAt: &w.UpdatedAt,
}
}

View File

@ -0,0 +1,30 @@
package models
import "github.com/authorizerdev/authorizer/server/graph/model"
// Note: any change here should be reflected in providers/casandra/provider.go as it does not have model support in collection creation
// WebhookLog model for db
type WebhookLog struct {
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"`
HttpStatus int64 `json:"http_status" bson:"http_status" cql:"http_status"`
Response string `gorm:"type:text" json:"response" bson:"response" cql:"response"`
Request string `gorm:"type:text" json:"request" bson:"request" cql:"request"`
WebhookID string `gorm:"type:char(36),index:" json:"webhook_id" bson:"webhook_id" cql:"webhook_id"`
Webhook Webhook `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" bson:"-" cql:"-"`
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
}
func (w *WebhookLog) AsAPIWebhookLog() *model.WebhookLog {
return &model.WebhookLog{
ID: w.ID,
HTTPStatus: &w.HttpStatus,
Response: &w.Response,
Request: &w.Request,
WebhookID: &w.WebhookID,
CreatedAt: &w.CreatedAt,
UpdatedAt: &w.UpdatedAt,
}
}

View File

@ -1,6 +1,7 @@
package arangodb package arangodb
import ( import (
"context"
"fmt" "fmt"
"time" "time"
@ -11,15 +12,15 @@ import (
) )
// AddEnv to save environment information in database // AddEnv to save environment information in database
func (p *provider) AddEnv(env models.Env) (models.Env, error) { func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
if env.ID == "" { if env.ID == "" {
env.ID = uuid.New().String() env.ID = uuid.New().String()
} }
env.CreatedAt = time.Now().Unix() env.CreatedAt = time.Now().Unix()
env.UpdatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix()
configCollection, _ := p.db.Collection(nil, models.Collections.Env) configCollection, _ := p.db.Collection(ctx, models.Collections.Env)
meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(nil), env) meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), env)
if err != nil { if err != nil {
return env, err return env, err
} }
@ -29,10 +30,10 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) {
} }
// UpdateEnv to update environment information in database // UpdateEnv to update environment information in database
func (p *provider) UpdateEnv(env models.Env) (models.Env, error) { func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
env.UpdatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix()
collection, _ := p.db.Collection(nil, models.Collections.Env) collection, _ := p.db.Collection(ctx, models.Collections.Env)
meta, err := collection.UpdateDocument(nil, env.Key, env) meta, err := collection.UpdateDocument(ctx, env.Key, env)
if err != nil { if err != nil {
return env, err return env, err
} }
@ -43,11 +44,11 @@ func (p *provider) UpdateEnv(env models.Env) (models.Env, error) {
} }
// GetEnv to get environment information from database // GetEnv to get environment information from database
func (p *provider) GetEnv() (models.Env, error) { func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
var env models.Env var env models.Env
query := fmt.Sprintf("FOR d in %s RETURN d", models.Collections.Env) query := fmt.Sprintf("FOR d in %s RETURN d", models.Collections.Env)
cursor, err := p.db.Query(nil, query, nil) cursor, err := p.db.Query(ctx, query, nil)
if err != nil { if err != nil {
return env, err return env, err
} }
@ -60,7 +61,7 @@ func (p *provider) GetEnv() (models.Env, error) {
} }
break break
} }
_, err := cursor.ReadDocument(nil, &env) _, err := cursor.ReadDocument(ctx, &env)
if err != nil { if err != nil {
return env, err return env, err
} }

View File

@ -107,6 +107,33 @@ func NewProvider() (*provider, error) {
} }
} }
webhookCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Webhook)
if !webhookCollectionExists {
_, err = arangodb.CreateCollection(ctx, models.Collections.Webhook, nil)
if err != nil {
return nil, err
}
}
webhookCollection, _ := arangodb.Collection(nil, models.Collections.Webhook)
webhookCollection.EnsureHashIndex(ctx, []string{"event_name"}, &arangoDriver.EnsureHashIndexOptions{
Unique: true,
Sparse: true,
})
webhookLogCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.WebhookLog)
if !webhookLogCollectionExists {
_, err = arangodb.CreateCollection(ctx, models.Collections.WebhookLog, nil)
if err != nil {
return nil, err
}
}
webhookLogCollection, _ := arangodb.Collection(nil, models.Collections.WebhookLog)
webhookLogCollection.EnsureHashIndex(ctx, []string{"webhook_id"}, &arangoDriver.EnsureHashIndexOptions{
Sparse: true,
})
return &provider{ return &provider{
db: arangodb, db: arangodb,
}, err }, err

View File

@ -1,6 +1,7 @@
package arangodb package arangodb
import ( import (
"context"
"fmt" "fmt"
"time" "time"
@ -9,15 +10,15 @@ import (
) )
// AddSession to save session information in database // AddSession to save session information in database
func (p *provider) AddSession(session models.Session) error { func (p *provider) AddSession(ctx context.Context, session models.Session) error {
if session.ID == "" { if session.ID == "" {
session.ID = uuid.New().String() session.ID = uuid.New().String()
} }
session.CreatedAt = time.Now().Unix() session.CreatedAt = time.Now().Unix()
session.UpdatedAt = time.Now().Unix() session.UpdatedAt = time.Now().Unix()
sessionCollection, _ := p.db.Collection(nil, models.Collections.Session) sessionCollection, _ := p.db.Collection(ctx, models.Collections.Session)
_, err := sessionCollection.CreateDocument(nil, session) _, err := sessionCollection.CreateDocument(ctx, session)
if err != nil { if err != nil {
return err return err
} }
@ -25,12 +26,12 @@ func (p *provider) AddSession(session models.Session) error {
} }
// DeleteSession to delete session information from database // DeleteSession to delete session information from database
func (p *provider) DeleteSession(userId string) error { func (p *provider) DeleteSession(ctx context.Context, 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) 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{}{ bindVars := map[string]interface{}{
"userId": userId, "userId": userId,
} }
cursor, err := p.db.Query(nil, query, bindVars) cursor, err := p.db.Query(ctx, query, bindVars)
if err != nil { if err != nil {
return err return err
} }

View File

@ -15,7 +15,7 @@ import (
) )
// AddUser to save user information in database // AddUser to save user information in database
func (p *provider) AddUser(user models.User) (models.User, error) { func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
if user.ID == "" { if user.ID == "" {
user.ID = uuid.New().String() user.ID = uuid.New().String()
} }
@ -30,8 +30,8 @@ func (p *provider) AddUser(user models.User) (models.User, error) {
user.CreatedAt = time.Now().Unix() user.CreatedAt = time.Now().Unix()
user.UpdatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix()
userCollection, _ := p.db.Collection(nil, models.Collections.User) userCollection, _ := p.db.Collection(ctx, models.Collections.User)
meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(nil), user) meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), user)
if err != nil { if err != nil {
return user, err return user, err
} }
@ -42,10 +42,10 @@ func (p *provider) AddUser(user models.User) (models.User, error) {
} }
// UpdateUser to update user information in database // UpdateUser to update user information in database
func (p *provider) UpdateUser(user models.User) (models.User, error) { func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
user.UpdatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix()
collection, _ := p.db.Collection(nil, models.Collections.User) collection, _ := p.db.Collection(ctx, models.Collections.User)
meta, err := collection.UpdateDocument(nil, user.Key, user) meta, err := collection.UpdateDocument(ctx, user.Key, user)
if err != nil { if err != nil {
return user, err return user, err
} }
@ -56,9 +56,9 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) {
} }
// DeleteUser to delete user information from database // DeleteUser to delete user information from database
func (p *provider) DeleteUser(user models.User) error { func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
collection, _ := p.db.Collection(nil, models.Collections.User) collection, _ := p.db.Collection(ctx, models.Collections.User)
_, err := collection.RemoveDocument(nil, user.Key) _, err := collection.RemoveDocument(ctx, user.Key)
if err != nil { if err != nil {
return err return err
} }
@ -67,13 +67,13 @@ func (p *provider) DeleteUser(user models.User) error {
} }
// ListUsers to get list of users from database // ListUsers to get list of users from database
func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error) { func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
var users []*model.User var users []*model.User
ctx := driver.WithQueryFullCount(context.Background()) sctx := driver.WithQueryFullCount(ctx)
query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.User, pagination.Offset, pagination.Limit) query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.User, pagination.Offset, pagination.Limit)
cursor, err := p.db.Query(ctx, query, nil) cursor, err := p.db.Query(sctx, query, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -84,7 +84,7 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
for { for {
var user models.User var user models.User
meta, err := cursor.ReadDocument(nil, &user) meta, err := cursor.ReadDocument(ctx, &user)
if arangoDriver.IsNoMoreDocuments(err) { if arangoDriver.IsNoMoreDocuments(err) {
break break
@ -104,7 +104,7 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
} }
// GetUserByEmail to get user information from database using email address // GetUserByEmail to get user information from database using email address
func (p *provider) GetUserByEmail(email string) (models.User, error) { func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
var user models.User var user models.User
query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", models.Collections.User) query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", models.Collections.User)
@ -112,7 +112,7 @@ func (p *provider) GetUserByEmail(email string) (models.User, error) {
"email": email, "email": email,
} }
cursor, err := p.db.Query(nil, query, bindVars) cursor, err := p.db.Query(ctx, query, bindVars)
if err != nil { if err != nil {
return user, err return user, err
} }
@ -125,7 +125,7 @@ func (p *provider) GetUserByEmail(email string) (models.User, error) {
} }
break break
} }
_, err := cursor.ReadDocument(nil, &user) _, err := cursor.ReadDocument(ctx, &user)
if err != nil { if err != nil {
return user, err return user, err
} }
@ -135,7 +135,7 @@ func (p *provider) GetUserByEmail(email string) (models.User, error) {
} }
// GetUserByID to get user information from database using user ID // GetUserByID to get user information from database using user ID
func (p *provider) GetUserByID(id string) (models.User, error) { func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
var user models.User var user models.User
query := fmt.Sprintf("FOR d in %s FILTER d._id == @id LIMIT 1 RETURN d", models.Collections.User) query := fmt.Sprintf("FOR d in %s FILTER d._id == @id LIMIT 1 RETURN d", models.Collections.User)
@ -143,7 +143,7 @@ func (p *provider) GetUserByID(id string) (models.User, error) {
"id": id, "id": id,
} }
cursor, err := p.db.Query(nil, query, bindVars) cursor, err := p.db.Query(ctx, query, bindVars)
if err != nil { if err != nil {
return user, err return user, err
} }
@ -156,7 +156,7 @@ func (p *provider) GetUserByID(id string) (models.User, error) {
} }
break break
} }
_, err := cursor.ReadDocument(nil, &user) _, err := cursor.ReadDocument(ctx, &user)
if err != nil { if err != nil {
return user, err return user, err
} }

View File

@ -12,15 +12,15 @@ import (
) )
// AddVerification to save verification request in database // AddVerification to save verification request in database
func (p *provider) AddVerificationRequest(verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
if verificationRequest.ID == "" { if verificationRequest.ID == "" {
verificationRequest.ID = uuid.New().String() verificationRequest.ID = uuid.New().String()
} }
verificationRequest.CreatedAt = time.Now().Unix() verificationRequest.CreatedAt = time.Now().Unix()
verificationRequest.UpdatedAt = time.Now().Unix() verificationRequest.UpdatedAt = time.Now().Unix()
verificationRequestRequestCollection, _ := p.db.Collection(nil, models.Collections.VerificationRequest) verificationRequestRequestCollection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest)
meta, err := verificationRequestRequestCollection.CreateDocument(nil, verificationRequest) meta, err := verificationRequestRequestCollection.CreateDocument(ctx, verificationRequest)
if err != nil { if err != nil {
return verificationRequest, err return verificationRequest, err
} }
@ -31,14 +31,14 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio
} }
// GetVerificationRequestByToken to get verification request from database using token // GetVerificationRequestByToken to get verification request from database using token
func (p *provider) GetVerificationRequestByToken(token string) (models.VerificationRequest, error) { func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
var verificationRequest models.VerificationRequest var verificationRequest models.VerificationRequest
query := fmt.Sprintf("FOR d in %s FILTER d.token == @token LIMIT 1 RETURN d", models.Collections.VerificationRequest) query := fmt.Sprintf("FOR d in %s FILTER d.token == @token LIMIT 1 RETURN d", models.Collections.VerificationRequest)
bindVars := map[string]interface{}{ bindVars := map[string]interface{}{
"token": token, "token": token,
} }
cursor, err := p.db.Query(nil, query, bindVars) cursor, err := p.db.Query(ctx, query, bindVars)
if err != nil { if err != nil {
return verificationRequest, err return verificationRequest, err
} }
@ -51,7 +51,7 @@ func (p *provider) GetVerificationRequestByToken(token string) (models.Verificat
} }
break break
} }
_, err := cursor.ReadDocument(nil, &verificationRequest) _, err := cursor.ReadDocument(ctx, &verificationRequest)
if err != nil { if err != nil {
return verificationRequest, err return verificationRequest, err
} }
@ -61,7 +61,7 @@ func (p *provider) GetVerificationRequestByToken(token string) (models.Verificat
} }
// GetVerificationRequestByEmail to get verification request by email from database // GetVerificationRequestByEmail to get verification request by email from database
func (p *provider) GetVerificationRequestByEmail(email string, identifier string) (models.VerificationRequest, error) { func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
var verificationRequest models.VerificationRequest 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) query := fmt.Sprintf("FOR d in %s FILTER d.email == @email FILTER d.identifier == @identifier LIMIT 1 RETURN d", models.Collections.VerificationRequest)
@ -70,7 +70,7 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string
"identifier": identifier, "identifier": identifier,
} }
cursor, err := p.db.Query(nil, query, bindVars) cursor, err := p.db.Query(ctx, query, bindVars)
if err != nil { if err != nil {
return verificationRequest, err return verificationRequest, err
} }
@ -83,7 +83,7 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string
} }
break break
} }
_, err := cursor.ReadDocument(nil, &verificationRequest) _, err := cursor.ReadDocument(ctx, &verificationRequest)
if err != nil { if err != nil {
return verificationRequest, err return verificationRequest, err
} }
@ -93,12 +93,12 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string
} }
// ListVerificationRequests to get list of verification requests from database // ListVerificationRequests to get list of verification requests from database
func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model.VerificationRequests, error) { func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
var verificationRequests []*model.VerificationRequest var verificationRequests []*model.VerificationRequest
ctx := driver.WithQueryFullCount(context.Background()) sctx := driver.WithQueryFullCount(ctx)
query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.VerificationRequest, pagination.Offset, pagination.Limit) query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.VerificationRequest, pagination.Offset, pagination.Limit)
cursor, err := p.db.Query(ctx, query, nil) cursor, err := p.db.Query(sctx, query, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -109,7 +109,7 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model
for { for {
var verificationRequest models.VerificationRequest var verificationRequest models.VerificationRequest
meta, err := cursor.ReadDocument(nil, &verificationRequest) meta, err := cursor.ReadDocument(ctx, &verificationRequest)
if driver.IsNoMoreDocuments(err) { if driver.IsNoMoreDocuments(err) {
break break
@ -130,7 +130,7 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model
} }
// DeleteVerificationRequest to delete verification request from database // DeleteVerificationRequest to delete verification request from database
func (p *provider) DeleteVerificationRequest(verificationRequest models.VerificationRequest) error { func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
collection, _ := p.db.Collection(nil, models.Collections.VerificationRequest) collection, _ := p.db.Collection(nil, models.Collections.VerificationRequest)
_, err := collection.RemoveDocument(nil, verificationRequest.Key) _, err := collection.RemoveDocument(nil, verificationRequest.Key)
if err != nil { if err != nil {

View File

@ -0,0 +1,161 @@
package arangodb
import (
"context"
"fmt"
"time"
"github.com/arangodb/go-driver"
arangoDriver "github.com/arangodb/go-driver"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/google/uuid"
)
// AddWebhook to add webhook
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
if webhook.ID == "" {
webhook.ID = uuid.New().String()
}
webhook.Key = webhook.ID
webhook.CreatedAt = time.Now().Unix()
webhook.UpdatedAt = time.Now().Unix()
webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook)
_, err := webhookCollection.CreateDocument(ctx, webhook)
if err != nil {
return nil, err
}
return webhook.AsAPIWebhook(), nil
}
// UpdateWebhook to update webhook
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
webhook.UpdatedAt = time.Now().Unix()
webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook)
meta, err := webhookCollection.UpdateDocument(ctx, webhook.Key, webhook)
if err != nil {
return nil, err
}
webhook.Key = meta.Key
webhook.ID = meta.ID.String()
return webhook.AsAPIWebhook(), nil
}
// ListWebhooks to list webhook
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
webhooks := []*model.Webhook{}
query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.Webhook, pagination.Offset, pagination.Limit)
sctx := driver.WithQueryFullCount(ctx)
cursor, err := p.db.Query(sctx, query, nil)
if err != nil {
return nil, err
}
defer cursor.Close()
paginationClone := pagination
paginationClone.Total = cursor.Statistics().FullCount()
for {
var webhook models.Webhook
meta, err := cursor.ReadDocument(ctx, &webhook)
if arangoDriver.IsNoMoreDocuments(err) {
break
} else if err != nil {
return nil, err
}
if meta.Key != "" {
webhooks = append(webhooks, webhook.AsAPIWebhook())
}
}
return &model.Webhooks{
Pagination: &paginationClone,
Webhooks: webhooks,
}, nil
}
// GetWebhookByID to get webhook by id
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
var webhook models.Webhook
query := fmt.Sprintf("FOR d in %s FILTER d._id == @webhook_id RETURN d", models.Collections.Webhook)
bindVars := map[string]interface{}{
"webhook_id": webhookID,
}
cursor, err := p.db.Query(ctx, query, bindVars)
if err != nil {
return nil, err
}
defer cursor.Close()
for {
if !cursor.HasMore() {
if webhook.Key == "" {
return nil, fmt.Errorf("webhook not found")
}
break
}
_, err := cursor.ReadDocument(ctx, &webhook)
if err != nil {
return nil, err
}
}
return webhook.AsAPIWebhook(), nil
}
// GetWebhookByEventName to get webhook by event_name
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
var webhook models.Webhook
query := fmt.Sprintf("FOR d in %s FILTER d.event_name == @event_name RETURN d", models.Collections.Webhook)
bindVars := map[string]interface{}{
"event_name": eventName,
}
cursor, err := p.db.Query(ctx, query, bindVars)
if err != nil {
return nil, err
}
defer cursor.Close()
for {
if !cursor.HasMore() {
if webhook.Key == "" {
return nil, fmt.Errorf("webhook not found")
}
break
}
_, err := cursor.ReadDocument(ctx, &webhook)
if err != nil {
return nil, err
}
}
return webhook.AsAPIWebhook(), nil
}
// DeleteWebhook to delete webhook
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
webhookCollection, _ := p.db.Collection(ctx, models.Collections.Webhook)
_, err := webhookCollection.RemoveDocument(ctx, webhook.ID)
if err != nil {
return err
}
query := fmt.Sprintf("FOR d in %s FILTER d.event_id == @event_id REMOVE { _key: d._key }", models.Collections.WebhookLog)
bindVars := map[string]interface{}{
"event_id": webhook.ID,
}
cursor, err := p.db.Query(ctx, query, bindVars)
if err != nil {
return err
}
defer cursor.Close()
return nil
}

View File

@ -0,0 +1,74 @@
package arangodb
import (
"context"
"fmt"
"time"
"github.com/arangodb/go-driver"
arangoDriver "github.com/arangodb/go-driver"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/google/uuid"
)
// AddWebhookLog to add webhook log
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
if webhookLog.ID == "" {
webhookLog.ID = uuid.New().String()
}
webhookLog.Key = webhookLog.ID
webhookLog.CreatedAt = time.Now().Unix()
webhookLog.UpdatedAt = time.Now().Unix()
webhookLogCollection, _ := p.db.Collection(ctx, models.Collections.WebhookLog)
_, err := webhookLogCollection.CreateDocument(ctx, webhookLog)
if err != nil {
return nil, err
}
return webhookLog.AsAPIWebhookLog(), nil
}
// ListWebhookLogs to list webhook logs
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
webhookLogs := []*model.WebhookLog{}
bindVariables := map[string]interface{}{}
query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.WebhookLog, pagination.Offset, pagination.Limit)
if webhookID != "" {
query = fmt.Sprintf("FOR d in %s FILTER d.webhook_id == @webhookID SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.WebhookLog, pagination.Offset, pagination.Limit)
bindVariables = map[string]interface{}{
"webhook_id": webhookID,
}
}
sctx := driver.WithQueryFullCount(ctx)
cursor, err := p.db.Query(sctx, query, bindVariables)
if err != nil {
return nil, err
}
defer cursor.Close()
paginationClone := pagination
paginationClone.Total = cursor.Statistics().FullCount()
for {
var webhookLog models.WebhookLog
meta, err := cursor.ReadDocument(ctx, &webhookLog)
if arangoDriver.IsNoMoreDocuments(err) {
break
} else if err != nil {
return nil, err
}
if meta.Key != "" {
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
}
}
return &model.WebhookLogs{
Pagination: &paginationClone,
WebhookLogs: webhookLogs,
}, nil
}

View File

@ -1,6 +1,7 @@
package cassandradb package cassandradb
import ( import (
"context"
"fmt" "fmt"
"time" "time"
@ -10,7 +11,7 @@ import (
) )
// AddEnv to save environment information in database // AddEnv to save environment information in database
func (p *provider) AddEnv(env models.Env) (models.Env, error) { func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
if env.ID == "" { if env.ID == "" {
env.ID = uuid.New().String() env.ID = uuid.New().String()
} }
@ -27,7 +28,7 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) {
} }
// UpdateEnv to update environment information in database // UpdateEnv to update environment information in database
func (p *provider) UpdateEnv(env models.Env) (models.Env, error) { func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
env.UpdatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix()
updateEnvQuery := fmt.Sprintf("UPDATE %s SET env = '%s', updated_at = %d WHERE id = '%s'", KeySpace+"."+models.Collections.Env, env.EnvData, env.UpdatedAt, env.ID) updateEnvQuery := fmt.Sprintf("UPDATE %s SET env = '%s', updated_at = %d WHERE id = '%s'", KeySpace+"."+models.Collections.Env, env.EnvData, env.UpdatedAt, env.ID)
@ -39,7 +40,7 @@ func (p *provider) UpdateEnv(env models.Env) (models.Env, error) {
} }
// GetEnv to get environment information from database // GetEnv to get environment information from database
func (p *provider) GetEnv() (models.Env, error) { func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
var env models.Env var env models.Env
query := fmt.Sprintf("SELECT id, env, hash, created_at, updated_at FROM %s LIMIT 1", KeySpace+"."+models.Collections.Env) query := fmt.Sprintf("SELECT id, env, hash, created_at, updated_at FROM %s LIMIT 1", KeySpace+"."+models.Collections.Env)

View File

@ -177,6 +177,28 @@ func NewProvider() (*provider, error) {
return nil, err return nil, err
} }
webhookCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, event_name text, endpoint text, enabled boolean, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.Webhook)
err = session.Query(webhookCollectionQuery).Exec()
if err != nil {
return nil, err
}
webhookIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_webhook_event_name ON %s.%s (event_name)", KeySpace, models.Collections.Webhook)
err = session.Query(webhookIndexQuery).Exec()
if err != nil {
return nil, err
}
webhookLogCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, http_status bigint, response text, request text, webhook_id text,updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.WebhookLog)
err = session.Query(webhookLogCollectionQuery).Exec()
if err != nil {
return nil, err
}
webhookLogIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_webhook_log_webhook_id ON %s.%s (webhook_id)", KeySpace, models.Collections.WebhookLog)
err = session.Query(webhookLogIndexQuery).Exec()
if err != nil {
return nil, err
}
return &provider{ return &provider{
db: session, db: session,
}, err }, err

View File

@ -1,6 +1,7 @@
package cassandradb package cassandradb
import ( import (
"context"
"fmt" "fmt"
"time" "time"
@ -9,7 +10,7 @@ import (
) )
// AddSession to save session information in database // AddSession to save session information in database
func (p *provider) AddSession(session models.Session) error { func (p *provider) AddSession(ctx context.Context, session models.Session) error {
if session.ID == "" { if session.ID == "" {
session.ID = uuid.New().String() session.ID = uuid.New().String()
} }
@ -26,7 +27,7 @@ func (p *provider) AddSession(session models.Session) error {
} }
// DeleteSession to delete session information from database // DeleteSession to delete session information from database
func (p *provider) DeleteSession(userId string) error { func (p *provider) DeleteSession(ctx context.Context, userId string) error {
deleteSessionQuery := fmt.Sprintf("DELETE FROM %s WHERE user_id = '%s'", KeySpace+"."+models.Collections.Session, userId) deleteSessionQuery := fmt.Sprintf("DELETE FROM %s WHERE user_id = '%s'", KeySpace+"."+models.Collections.Session, userId)
err := p.db.Query(deleteSessionQuery).Exec() err := p.db.Query(deleteSessionQuery).Exec()
if err != nil { if err != nil {

View File

@ -1,6 +1,7 @@
package cassandradb package cassandradb
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect" "reflect"
@ -16,7 +17,7 @@ import (
) )
// AddUser to save user information in database // AddUser to save user information in database
func (p *provider) AddUser(user models.User) (models.User, error) { func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
if user.ID == "" { if user.ID == "" {
user.ID = uuid.New().String() user.ID = uuid.New().String()
} }
@ -79,7 +80,7 @@ func (p *provider) AddUser(user models.User) (models.User, error) {
} }
// UpdateUser to update user information in database // UpdateUser to update user information in database
func (p *provider) UpdateUser(user models.User) (models.User, error) { func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
user.UpdatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix()
bytes, err := json.Marshal(user) bytes, err := json.Marshal(user)
@ -97,9 +98,6 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) {
updateFields := "" updateFields := ""
for key, value := range userMap { for key, value := range userMap {
if value != nil && key != "_id" {
}
if key == "_id" { if key == "_id" {
continue continue
} }
@ -130,14 +128,14 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) {
} }
// DeleteUser to delete user information from database // DeleteUser to delete user information from database
func (p *provider) DeleteUser(user models.User) error { func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.User, user.ID) query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.User, user.ID)
err := p.db.Query(query).Exec() err := p.db.Query(query).Exec()
return err return err
} }
// ListUsers to get list of users from database // ListUsers to get list of users from database
func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error) { func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
responseUsers := []*model.User{} responseUsers := []*model.User{}
paginationClone := pagination paginationClone := pagination
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.User) totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.User)
@ -171,7 +169,7 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
} }
// GetUserByEmail to get user information from database using email address // GetUserByEmail to get user information from database using email address
func (p *provider) GetUserByEmail(email string) (models.User, error) { func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
var user models.User var user models.User
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1", KeySpace+"."+models.Collections.User, email) query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, created_at, updated_at FROM %s WHERE email = '%s' LIMIT 1", KeySpace+"."+models.Collections.User, email)
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.CreatedAt, &user.UpdatedAt) err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.CreatedAt, &user.UpdatedAt)
@ -182,7 +180,7 @@ func (p *provider) GetUserByEmail(email string) (models.User, error) {
} }
// GetUserByID to get user information from database using user ID // GetUserByID to get user information from database using user ID
func (p *provider) GetUserByID(id string) (models.User, error) { func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
var user models.User var user models.User
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1", KeySpace+"."+models.Collections.User, id) query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1", KeySpace+"."+models.Collections.User, id)
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.CreatedAt, &user.UpdatedAt) err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.CreatedAt, &user.UpdatedAt)

View File

@ -1,6 +1,7 @@
package cassandradb package cassandradb
import ( import (
"context"
"fmt" "fmt"
"time" "time"
@ -11,7 +12,7 @@ import (
) )
// AddVerification to save verification request in database // AddVerification to save verification request in database
func (p *provider) AddVerificationRequest(verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
if verificationRequest.ID == "" { if verificationRequest.ID == "" {
verificationRequest.ID = uuid.New().String() verificationRequest.ID = uuid.New().String()
} }
@ -28,7 +29,7 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio
} }
// GetVerificationRequestByToken to get verification request from database using token // GetVerificationRequestByToken to get verification request from database using token
func (p *provider) GetVerificationRequestByToken(token string) (models.VerificationRequest, error) { func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
var verificationRequest models.VerificationRequest var verificationRequest models.VerificationRequest
query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s WHERE jwt_token = '%s' LIMIT 1`, KeySpace+"."+models.Collections.VerificationRequest, token) query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s WHERE jwt_token = '%s' LIMIT 1`, KeySpace+"."+models.Collections.VerificationRequest, token)
@ -40,7 +41,7 @@ func (p *provider) GetVerificationRequestByToken(token string) (models.Verificat
} }
// GetVerificationRequestByEmail to get verification request by email from database // GetVerificationRequestByEmail to get verification request by email from database
func (p *provider) GetVerificationRequestByEmail(email string, identifier string) (models.VerificationRequest, error) { func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
var verificationRequest models.VerificationRequest var verificationRequest models.VerificationRequest
query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s WHERE email = '%s' AND identifier = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.VerificationRequest, email, identifier) query := fmt.Sprintf(`SELECT id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s WHERE email = '%s' AND identifier = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.VerificationRequest, email, identifier)
@ -53,7 +54,7 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string
} }
// ListVerificationRequests to get list of verification requests from database // ListVerificationRequests to get list of verification requests from database
func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model.VerificationRequests, error) { func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
var verificationRequests []*model.VerificationRequest var verificationRequests []*model.VerificationRequest
paginationClone := pagination paginationClone := pagination
@ -89,7 +90,7 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model
} }
// DeleteVerificationRequest to delete verification request from database // DeleteVerificationRequest to delete verification request from database
func (p *provider) DeleteVerificationRequest(verificationRequest models.VerificationRequest) error { func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.VerificationRequest, verificationRequest.ID) query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.VerificationRequest, verificationRequest.ID)
err := p.db.Query(query).Exec() err := p.db.Query(query).Exec()
if err != nil { if err != nil {

View File

@ -0,0 +1,152 @@
package cassandradb
import (
"context"
"encoding/json"
"fmt"
"reflect"
"strings"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/gocql/gocql"
"github.com/google/uuid"
)
// AddWebhook to add webhook
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
if webhook.ID == "" {
webhook.ID = uuid.New().String()
}
webhook.Key = webhook.ID
webhook.CreatedAt = time.Now().Unix()
webhook.UpdatedAt = time.Now().Unix()
insertQuery := fmt.Sprintf("INSERT INTO %s (id, event_name, endpoint, headers, enabled, created_at, updated_at) VALUES ('%s', '%s', '%s', '%s', %t, %d, %d)", KeySpace+"."+models.Collections.Webhook, webhook.ID, webhook.EventName, webhook.EndPoint, webhook.Headers, webhook.Enabled, webhook.CreatedAt, webhook.UpdatedAt)
err := p.db.Query(insertQuery).Exec()
if err != nil {
return nil, err
}
return webhook.AsAPIWebhook(), nil
}
// UpdateWebhook to update webhook
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
webhook.UpdatedAt = time.Now().Unix()
bytes, err := json.Marshal(webhook)
if err != nil {
return nil, err
}
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
decoder.UseNumber()
webhookMap := map[string]interface{}{}
err = decoder.Decode(&webhookMap)
if err != nil {
return nil, err
}
updateFields := ""
for key, value := range webhookMap {
if key == "_id" {
continue
}
if value == nil {
updateFields += fmt.Sprintf("%s = null,", key)
continue
}
valueType := reflect.TypeOf(value)
if valueType.Name() == "string" {
updateFields += fmt.Sprintf("%s = '%s', ", key, value.(string))
} else {
updateFields += fmt.Sprintf("%s = %v, ", key, value)
}
}
updateFields = strings.Trim(updateFields, " ")
updateFields = strings.TrimSuffix(updateFields, ",")
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.Webhook, updateFields, webhook.ID)
err = p.db.Query(query).Exec()
if err != nil {
return nil, err
}
return webhook.AsAPIWebhook(), nil
}
// ListWebhooks to list webhook
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
webhooks := []*model.Webhook{}
paginationClone := pagination
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.Webhook)
err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total)
if err != nil {
return nil, err
}
// there is no offset in cassandra
// so we fetch till limit + offset
// and return the results from offset to limit
query := fmt.Sprintf("SELECT id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.Webhook, pagination.Limit+pagination.Offset)
scanner := p.db.Query(query).Iter().Scanner()
counter := int64(0)
for scanner.Next() {
if counter >= pagination.Offset {
var webhook models.Webhook
err := scanner.Scan(&webhook.ID, &webhook.EventName, &webhook.EndPoint, &webhook.Headers, &webhook.Enabled, &webhook.CreatedAt, &webhook.UpdatedAt)
if err != nil {
return nil, err
}
webhooks = append(webhooks, webhook.AsAPIWebhook())
}
counter++
}
return &model.Webhooks{
Pagination: &paginationClone,
Webhooks: webhooks,
}, nil
}
// GetWebhookByID to get webhook by id
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
var webhook models.Webhook
query := fmt.Sprintf(`SELECT id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1`, KeySpace+"."+models.Collections.Webhook, webhookID)
err := p.db.Query(query).Consistency(gocql.One).Scan(&webhook.ID, &webhook.EventName, &webhook.EndPoint, &webhook.Headers, &webhook.Enabled, &webhook.CreatedAt, &webhook.UpdatedAt)
if err != nil {
return nil, err
}
return webhook.AsAPIWebhook(), nil
}
// GetWebhookByEventName to get webhook by event_name
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
var webhook models.Webhook
query := fmt.Sprintf(`SELECT id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s WHERE event_name = '%s' LIMIT 1`, KeySpace+"."+models.Collections.Webhook, eventName)
err := p.db.Query(query).Consistency(gocql.One).Scan(&webhook.ID, &webhook.EventName, &webhook.EndPoint, &webhook.Headers, &webhook.Enabled, &webhook.CreatedAt, &webhook.UpdatedAt)
if err != nil {
return nil, err
}
return webhook.AsAPIWebhook(), nil
}
// DeleteWebhook to delete webhook
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
query := fmt.Sprintf("DELETE FROM %s WHERE id = '%s'", KeySpace+"."+models.Collections.Webhook, webhook.ID)
err := p.db.Query(query).Exec()
if err != nil {
return err
}
query = fmt.Sprintf("DELETE FROM %s WHERE webhook_id = '%s'", KeySpace+"."+models.Collections.WebhookLog, webhook.ID)
err = p.db.Query(query).Exec()
return err
}

View File

@ -0,0 +1,70 @@
package cassandradb
import (
"context"
"fmt"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/gocql/gocql"
"github.com/google/uuid"
)
// AddWebhookLog to add webhook log
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
if webhookLog.ID == "" {
webhookLog.ID = uuid.New().String()
}
webhookLog.Key = webhookLog.ID
webhookLog.CreatedAt = time.Now().Unix()
webhookLog.UpdatedAt = time.Now().Unix()
insertQuery := fmt.Sprintf("INSERT INTO %s (id, http_status, response, request, webhook_id, created_at, updated_at) VALUES ('%s', %d,'%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.WebhookLog, webhookLog.ID, webhookLog.HttpStatus, webhookLog.Response, webhookLog.Request, webhookLog.WebhookID, webhookLog.CreatedAt, webhookLog.UpdatedAt)
err := p.db.Query(insertQuery).Exec()
if err != nil {
return nil, err
}
return webhookLog.AsAPIWebhookLog(), nil
}
// ListWebhookLogs to list webhook logs
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
webhookLogs := []*model.WebhookLog{}
paginationClone := pagination
totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.WebhookLog)
// there is no offset in cassandra
// so we fetch till limit + offset
// and return the results from offset to limit
query := fmt.Sprintf("SELECT id, http_status, response, request, webhook_id, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.WebhookLog, pagination.Limit+pagination.Offset)
if webhookID != "" {
totalCountQuery = fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE webhook_id='%s'`, KeySpace+"."+models.Collections.WebhookLog, webhookID)
query = fmt.Sprintf("SELECT id, http_status, response, request, webhook_id, created_at, updated_at FROM %s WHERE webhook_id = '%s' LIMIT %d", KeySpace+"."+models.Collections.WebhookLog, webhookID, pagination.Limit+pagination.Offset)
}
err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total)
if err != nil {
return nil, err
}
scanner := p.db.Query(query).Iter().Scanner()
counter := int64(0)
for scanner.Next() {
if counter >= pagination.Offset {
var webhookLog models.WebhookLog
err := scanner.Scan(&webhookLog.ID, &webhookLog.HttpStatus, &webhookLog.Response, &webhookLog.Request, &webhookLog.WebhookID, &webhookLog.CreatedAt, &webhookLog.UpdatedAt)
if err != nil {
return nil, err
}
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
}
counter++
}
return &model.WebhookLogs{
Pagination: &paginationClone,
WebhookLogs: webhookLogs,
}, nil
}

View File

@ -1,6 +1,7 @@
package mongodb package mongodb
import ( import (
"context"
"fmt" "fmt"
"time" "time"
@ -11,7 +12,7 @@ import (
) )
// AddEnv to save environment information in database // AddEnv to save environment information in database
func (p *provider) AddEnv(env models.Env) (models.Env, error) { func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
if env.ID == "" { if env.ID == "" {
env.ID = uuid.New().String() env.ID = uuid.New().String()
} }
@ -20,7 +21,7 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) {
env.UpdatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix()
env.Key = env.ID env.Key = env.ID
configCollection := p.db.Collection(models.Collections.Env, options.Collection()) configCollection := p.db.Collection(models.Collections.Env, options.Collection())
_, err := configCollection.InsertOne(nil, env) _, err := configCollection.InsertOne(ctx, env)
if err != nil { if err != nil {
return env, err return env, err
} }
@ -28,10 +29,10 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) {
} }
// UpdateEnv to update environment information in database // UpdateEnv to update environment information in database
func (p *provider) UpdateEnv(env models.Env) (models.Env, error) { func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
env.UpdatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix()
configCollection := p.db.Collection(models.Collections.Env, options.Collection()) 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()) _, err := configCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions())
if err != nil { if err != nil {
return env, err return env, err
} }
@ -39,14 +40,14 @@ func (p *provider) UpdateEnv(env models.Env) (models.Env, error) {
} }
// GetEnv to get environment information from database // GetEnv to get environment information from database
func (p *provider) GetEnv() (models.Env, error) { func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
var env models.Env var env models.Env
configCollection := p.db.Collection(models.Collections.Env, options.Collection()) configCollection := p.db.Collection(models.Collections.Env, options.Collection())
cursor, err := configCollection.Find(nil, bson.M{}, options.Find()) cursor, err := configCollection.Find(ctx, bson.M{}, options.Find())
if err != nil { if err != nil {
return env, err return env, err
} }
defer cursor.Close(nil) defer cursor.Close(ctx)
for cursor.Next(nil) { for cursor.Next(nil) {
err := cursor.Decode(&env) err := cursor.Decode(&env)

View File

@ -83,6 +83,24 @@ func NewProvider() (*provider, error) {
mongodb.CreateCollection(ctx, models.Collections.Env, options.CreateCollection()) mongodb.CreateCollection(ctx, models.Collections.Env, options.CreateCollection())
mongodb.CreateCollection(ctx, models.Collections.Webhook, options.CreateCollection())
webhookCollection := mongodb.Collection(models.Collections.Webhook, options.Collection())
webhookCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
{
Keys: bson.M{"event_name": 1},
Options: options.Index().SetUnique(true).SetSparse(true),
},
}, options.CreateIndexes())
mongodb.CreateCollection(ctx, models.Collections.WebhookLog, options.CreateCollection())
webhookLogCollection := mongodb.Collection(models.Collections.WebhookLog, options.Collection())
webhookLogCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
{
Keys: bson.M{"webhook_id": 1},
Options: options.Index().SetSparse(true),
},
}, options.CreateIndexes())
return &provider{ return &provider{
db: mongodb, db: mongodb,
}, nil }, nil

View File

@ -1,6 +1,7 @@
package mongodb package mongodb
import ( import (
"context"
"time" "time"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
@ -10,7 +11,7 @@ import (
) )
// AddSession to save session information in database // AddSession to save session information in database
func (p *provider) AddSession(session models.Session) error { func (p *provider) AddSession(ctx context.Context, session models.Session) error {
if session.ID == "" { if session.ID == "" {
session.ID = uuid.New().String() session.ID = uuid.New().String()
} }
@ -19,7 +20,7 @@ func (p *provider) AddSession(session models.Session) error {
session.CreatedAt = time.Now().Unix() session.CreatedAt = time.Now().Unix()
session.UpdatedAt = time.Now().Unix() session.UpdatedAt = time.Now().Unix()
sessionCollection := p.db.Collection(models.Collections.Session, options.Collection()) sessionCollection := p.db.Collection(models.Collections.Session, options.Collection())
_, err := sessionCollection.InsertOne(nil, session) _, err := sessionCollection.InsertOne(ctx, session)
if err != nil { if err != nil {
return err return err
} }
@ -27,9 +28,9 @@ func (p *provider) AddSession(session models.Session) error {
} }
// DeleteSession to delete session information from database // DeleteSession to delete session information from database
func (p *provider) DeleteSession(userId string) error { func (p *provider) DeleteSession(ctx context.Context, userId string) error {
sessionCollection := p.db.Collection(models.Collections.Session, options.Collection()) sessionCollection := p.db.Collection(models.Collections.Session, options.Collection())
_, err := sessionCollection.DeleteMany(nil, bson.M{"user_id": userId}, options.Delete()) _, err := sessionCollection.DeleteMany(ctx, bson.M{"user_id": userId}, options.Delete())
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,6 +1,7 @@
package mongodb package mongodb
import ( import (
"context"
"time" "time"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
@ -13,7 +14,7 @@ import (
) )
// AddUser to save user information in database // AddUser to save user information in database
func (p *provider) AddUser(user models.User) (models.User, error) { func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
if user.ID == "" { if user.ID == "" {
user.ID = uuid.New().String() user.ID = uuid.New().String()
} }
@ -29,7 +30,7 @@ func (p *provider) AddUser(user models.User) (models.User, error) {
user.UpdatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix()
user.Key = user.ID user.Key = user.ID
userCollection := p.db.Collection(models.Collections.User, options.Collection()) userCollection := p.db.Collection(models.Collections.User, options.Collection())
_, err := userCollection.InsertOne(nil, user) _, err := userCollection.InsertOne(ctx, user)
if err != nil { if err != nil {
return user, err return user, err
} }
@ -38,10 +39,10 @@ func (p *provider) AddUser(user models.User) (models.User, error) {
} }
// UpdateUser to update user information in database // UpdateUser to update user information in database
func (p *provider) UpdateUser(user models.User) (models.User, error) { func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
user.UpdatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix()
userCollection := p.db.Collection(models.Collections.User, options.Collection()) 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()) _, err := userCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": user.ID}}, bson.M{"$set": user}, options.MergeUpdateOptions())
if err != nil { if err != nil {
return user, err return user, err
} }
@ -49,9 +50,9 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) {
} }
// DeleteUser to delete user information from database // DeleteUser to delete user information from database
func (p *provider) DeleteUser(user models.User) error { func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
userCollection := p.db.Collection(models.Collections.User, options.Collection()) userCollection := p.db.Collection(models.Collections.User, options.Collection())
_, err := userCollection.DeleteOne(nil, bson.M{"_id": user.ID}, options.Delete()) _, err := userCollection.DeleteOne(ctx, bson.M{"_id": user.ID}, options.Delete())
if err != nil { if err != nil {
return err return err
} }
@ -60,7 +61,7 @@ func (p *provider) DeleteUser(user models.User) error {
} }
// ListUsers to get list of users from database // ListUsers to get list of users from database
func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error) { func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
var users []*model.User var users []*model.User
opts := options.Find() opts := options.Find()
opts.SetLimit(pagination.Limit) opts.SetLimit(pagination.Limit)
@ -70,20 +71,20 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
paginationClone := pagination paginationClone := pagination
userCollection := p.db.Collection(models.Collections.User, options.Collection()) userCollection := p.db.Collection(models.Collections.User, options.Collection())
count, err := userCollection.CountDocuments(nil, bson.M{}, options.Count()) count, err := userCollection.CountDocuments(ctx, bson.M{}, options.Count())
if err != nil { if err != nil {
return nil, err return nil, err
} }
paginationClone.Total = count paginationClone.Total = count
cursor, err := userCollection.Find(nil, bson.M{}, opts) cursor, err := userCollection.Find(ctx, bson.M{}, opts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer cursor.Close(nil) defer cursor.Close(ctx)
for cursor.Next(nil) { for cursor.Next(ctx) {
var user models.User var user models.User
err := cursor.Decode(&user) err := cursor.Decode(&user)
if err != nil { if err != nil {
@ -99,10 +100,10 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
} }
// GetUserByEmail to get user information from database using email address // GetUserByEmail to get user information from database using email address
func (p *provider) GetUserByEmail(email string) (models.User, error) { func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
var user models.User var user models.User
userCollection := p.db.Collection(models.Collections.User, options.Collection()) userCollection := p.db.Collection(models.Collections.User, options.Collection())
err := userCollection.FindOne(nil, bson.M{"email": email}).Decode(&user) err := userCollection.FindOne(ctx, bson.M{"email": email}).Decode(&user)
if err != nil { if err != nil {
return user, err return user, err
} }
@ -111,11 +112,11 @@ func (p *provider) GetUserByEmail(email string) (models.User, error) {
} }
// GetUserByID to get user information from database using user ID // GetUserByID to get user information from database using user ID
func (p *provider) GetUserByID(id string) (models.User, error) { func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
var user models.User var user models.User
userCollection := p.db.Collection(models.Collections.User, options.Collection()) userCollection := p.db.Collection(models.Collections.User, options.Collection())
err := userCollection.FindOne(nil, bson.M{"_id": id}).Decode(&user) err := userCollection.FindOne(ctx, bson.M{"_id": id}).Decode(&user)
if err != nil { if err != nil {
return user, err return user, err
} }

View File

@ -1,6 +1,7 @@
package mongodb package mongodb
import ( import (
"context"
"time" "time"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
@ -11,7 +12,7 @@ import (
) )
// AddVerification to save verification request in database // AddVerification to save verification request in database
func (p *provider) AddVerificationRequest(verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
if verificationRequest.ID == "" { if verificationRequest.ID == "" {
verificationRequest.ID = uuid.New().String() verificationRequest.ID = uuid.New().String()
@ -19,7 +20,7 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio
verificationRequest.UpdatedAt = time.Now().Unix() verificationRequest.UpdatedAt = time.Now().Unix()
verificationRequest.Key = verificationRequest.ID verificationRequest.Key = verificationRequest.ID
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
_, err := verificationRequestCollection.InsertOne(nil, verificationRequest) _, err := verificationRequestCollection.InsertOne(ctx, verificationRequest)
if err != nil { if err != nil {
return verificationRequest, err return verificationRequest, err
} }
@ -29,11 +30,11 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio
} }
// GetVerificationRequestByToken to get verification request from database using token // GetVerificationRequestByToken to get verification request from database using token
func (p *provider) GetVerificationRequestByToken(token string) (models.VerificationRequest, error) { func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
var verificationRequest models.VerificationRequest var verificationRequest models.VerificationRequest
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
err := verificationRequestCollection.FindOne(nil, bson.M{"token": token}).Decode(&verificationRequest) err := verificationRequestCollection.FindOne(ctx, bson.M{"token": token}).Decode(&verificationRequest)
if err != nil { if err != nil {
return verificationRequest, err return verificationRequest, err
} }
@ -42,11 +43,11 @@ func (p *provider) GetVerificationRequestByToken(token string) (models.Verificat
} }
// GetVerificationRequestByEmail to get verification request by email from database // GetVerificationRequestByEmail to get verification request by email from database
func (p *provider) GetVerificationRequestByEmail(email string, identifier string) (models.VerificationRequest, error) { func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
var verificationRequest models.VerificationRequest var verificationRequest models.VerificationRequest
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
err := verificationRequestCollection.FindOne(nil, bson.M{"email": email, "identifier": identifier}).Decode(&verificationRequest) err := verificationRequestCollection.FindOne(ctx, bson.M{"email": email, "identifier": identifier}).Decode(&verificationRequest)
if err != nil { if err != nil {
return verificationRequest, err return verificationRequest, err
} }
@ -55,7 +56,7 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string
} }
// ListVerificationRequests to get list of verification requests from database // ListVerificationRequests to get list of verification requests from database
func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model.VerificationRequests, error) { func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
var verificationRequests []*model.VerificationRequest var verificationRequests []*model.VerificationRequest
opts := options.Find() opts := options.Find()
@ -65,17 +66,17 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
verificationRequestCollectionCount, err := verificationRequestCollection.CountDocuments(nil, bson.M{}) verificationRequestCollectionCount, err := verificationRequestCollection.CountDocuments(ctx, bson.M{})
paginationClone := pagination paginationClone := pagination
paginationClone.Total = verificationRequestCollectionCount paginationClone.Total = verificationRequestCollectionCount
cursor, err := verificationRequestCollection.Find(nil, bson.M{}, opts) cursor, err := verificationRequestCollection.Find(ctx, bson.M{}, opts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer cursor.Close(nil) defer cursor.Close(ctx)
for cursor.Next(nil) { for cursor.Next(ctx) {
var verificationRequest models.VerificationRequest var verificationRequest models.VerificationRequest
err := cursor.Decode(&verificationRequest) err := cursor.Decode(&verificationRequest)
if err != nil { if err != nil {
@ -91,9 +92,9 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model
} }
// DeleteVerificationRequest to delete verification request from database // DeleteVerificationRequest to delete verification request from database
func (p *provider) DeleteVerificationRequest(verificationRequest models.VerificationRequest) error { func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
_, err := verificationRequestCollection.DeleteOne(nil, bson.M{"_id": verificationRequest.ID}, options.Delete()) _, err := verificationRequestCollection.DeleteOne(ctx, bson.M{"_id": verificationRequest.ID}, options.Delete())
if err != nil { if err != nil {
return err return err
} }

View File

@ -0,0 +1,120 @@
package mongodb
import (
"context"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/google/uuid"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
)
// AddWebhook to add webhook
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
if webhook.ID == "" {
webhook.ID = uuid.New().String()
}
webhook.Key = webhook.ID
webhook.CreatedAt = time.Now().Unix()
webhook.UpdatedAt = time.Now().Unix()
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
_, err := webhookCollection.InsertOne(ctx, webhook)
if err != nil {
return nil, err
}
return webhook.AsAPIWebhook(), nil
}
// UpdateWebhook to update webhook
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
webhook.UpdatedAt = time.Now().Unix()
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
_, err := webhookCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": webhook.ID}}, bson.M{"$set": webhook}, options.MergeUpdateOptions())
if err != nil {
return nil, err
}
return webhook.AsAPIWebhook(), nil
}
// ListWebhooks to list webhook
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
var webhooks []*model.Webhook
opts := options.Find()
opts.SetLimit(pagination.Limit)
opts.SetSkip(pagination.Offset)
opts.SetSort(bson.M{"created_at": -1})
paginationClone := pagination
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
count, err := webhookCollection.CountDocuments(ctx, bson.M{}, options.Count())
if err != nil {
return nil, err
}
paginationClone.Total = count
cursor, err := webhookCollection.Find(ctx, bson.M{}, opts)
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
for cursor.Next(ctx) {
var webhook models.Webhook
err := cursor.Decode(&webhook)
if err != nil {
return nil, err
}
webhooks = append(webhooks, webhook.AsAPIWebhook())
}
return &model.Webhooks{
Pagination: &paginationClone,
Webhooks: webhooks,
}, nil
}
// GetWebhookByID to get webhook by id
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
var webhook models.Webhook
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
err := webhookCollection.FindOne(ctx, bson.M{"_id": webhookID}).Decode(&webhook)
if err != nil {
return nil, err
}
return webhook.AsAPIWebhook(), nil
}
// GetWebhookByEventName to get webhook by event_name
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
var webhook models.Webhook
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
err := webhookCollection.FindOne(ctx, bson.M{"event_name": eventName}).Decode(&webhook)
if err != nil {
return nil, err
}
return webhook.AsAPIWebhook(), nil
}
// DeleteWebhook to delete webhook
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
webhookCollection := p.db.Collection(models.Collections.Webhook, options.Collection())
_, err := webhookCollection.DeleteOne(nil, bson.M{"_id": webhook.ID}, options.Delete())
if err != nil {
return err
}
webhookLogCollection := p.db.Collection(models.Collections.WebhookLog, options.Collection())
_, err = webhookLogCollection.DeleteOne(nil, bson.M{"webhook_id": webhook.ID}, options.Delete())
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,74 @@
package mongodb
import (
"context"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/google/uuid"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
)
// AddWebhookLog to add webhook log
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
if webhookLog.ID == "" {
webhookLog.ID = uuid.New().String()
}
webhookLog.Key = webhookLog.ID
webhookLog.CreatedAt = time.Now().Unix()
webhookLog.UpdatedAt = time.Now().Unix()
webhookLogCollection := p.db.Collection(models.Collections.WebhookLog, options.Collection())
_, err := webhookLogCollection.InsertOne(ctx, webhookLog)
if err != nil {
return nil, err
}
return webhookLog.AsAPIWebhookLog(), nil
}
// ListWebhookLogs to list webhook logs
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
webhookLogs := []*model.WebhookLog{}
opts := options.Find()
opts.SetLimit(pagination.Limit)
opts.SetSkip(pagination.Offset)
opts.SetSort(bson.M{"created_at": -1})
paginationClone := pagination
query := bson.M{}
if webhookID != "" {
query = bson.M{"webhook_id": webhookID}
}
webhookLogCollection := p.db.Collection(models.Collections.WebhookLog, options.Collection())
count, err := webhookLogCollection.CountDocuments(ctx, query, options.Count())
if err != nil {
return nil, err
}
paginationClone.Total = count
cursor, err := webhookLogCollection.Find(ctx, query, opts)
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
for cursor.Next(ctx) {
var webhookLog models.WebhookLog
err := cursor.Decode(&webhookLog)
if err != nil {
return nil, err
}
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
}
return &model.WebhookLogs{
Pagination: &paginationClone,
WebhookLogs: webhookLogs,
}, nil
}

View File

@ -1,6 +1,7 @@
package provider_template package provider_template
import ( import (
"context"
"time" "time"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
@ -8,7 +9,7 @@ import (
) )
// AddEnv to save environment information in database // AddEnv to save environment information in database
func (p *provider) AddEnv(env models.Env) (models.Env, error) { func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
if env.ID == "" { if env.ID == "" {
env.ID = uuid.New().String() env.ID = uuid.New().String()
} }
@ -19,13 +20,13 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) {
} }
// UpdateEnv to update environment information in database // UpdateEnv to update environment information in database
func (p *provider) UpdateEnv(env models.Env) (models.Env, error) { func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
env.UpdatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix()
return env, nil return env, nil
} }
// GetEnv to get environment information from database // GetEnv to get environment information from database
func (p *provider) GetEnv() (models.Env, error) { func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
var env models.Env var env models.Env
return env, nil return env, nil

View File

@ -1,6 +1,7 @@
package provider_template package provider_template
import ( import (
"context"
"time" "time"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
@ -8,7 +9,7 @@ import (
) )
// AddSession to save session information in database // AddSession to save session information in database
func (p *provider) AddSession(session models.Session) error { func (p *provider) AddSession(ctx context.Context, session models.Session) error {
if session.ID == "" { if session.ID == "" {
session.ID = uuid.New().String() session.ID = uuid.New().String()
} }
@ -19,6 +20,6 @@ func (p *provider) AddSession(session models.Session) error {
} }
// DeleteSession to delete session information from database // DeleteSession to delete session information from database
func (p *provider) DeleteSession(userId string) error { func (p *provider) DeleteSession(ctx context.Context, userId string) error {
return nil return nil
} }

View File

@ -1,6 +1,7 @@
package provider_template package provider_template
import ( import (
"context"
"time" "time"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
@ -11,7 +12,7 @@ import (
) )
// AddUser to save user information in database // AddUser to save user information in database
func (p *provider) AddUser(user models.User) (models.User, error) { func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
if user.ID == "" { if user.ID == "" {
user.ID = uuid.New().String() user.ID = uuid.New().String()
} }
@ -31,30 +32,30 @@ func (p *provider) AddUser(user models.User) (models.User, error) {
} }
// UpdateUser to update user information in database // UpdateUser to update user information in database
func (p *provider) UpdateUser(user models.User) (models.User, error) { func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
user.UpdatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix()
return user, nil return user, nil
} }
// DeleteUser to delete user information from database // DeleteUser to delete user information from database
func (p *provider) DeleteUser(user models.User) error { func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
return nil return nil
} }
// ListUsers to get list of users from database // ListUsers to get list of users from database
func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error) { func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
return nil, nil return nil, nil
} }
// GetUserByEmail to get user information from database using email address // GetUserByEmail to get user information from database using email address
func (p *provider) GetUserByEmail(email string) (models.User, error) { func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
var user models.User var user models.User
return user, nil return user, nil
} }
// GetUserByID to get user information from database using user ID // GetUserByID to get user information from database using user ID
func (p *provider) GetUserByID(id string) (models.User, error) { func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
var user models.User var user models.User
return user, nil return user, nil

View File

@ -1,6 +1,7 @@
package provider_template package provider_template
import ( import (
"context"
"time" "time"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
@ -9,7 +10,7 @@ import (
) )
// AddVerification to save verification request in database // AddVerification to save verification request in database
func (p *provider) AddVerificationRequest(verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
if verificationRequest.ID == "" { if verificationRequest.ID == "" {
verificationRequest.ID = uuid.New().String() verificationRequest.ID = uuid.New().String()
} }
@ -21,25 +22,25 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio
} }
// GetVerificationRequestByToken to get verification request from database using token // GetVerificationRequestByToken to get verification request from database using token
func (p *provider) GetVerificationRequestByToken(token string) (models.VerificationRequest, error) { func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
var verificationRequest models.VerificationRequest var verificationRequest models.VerificationRequest
return verificationRequest, nil return verificationRequest, nil
} }
// GetVerificationRequestByEmail to get verification request by email from database // GetVerificationRequestByEmail to get verification request by email from database
func (p *provider) GetVerificationRequestByEmail(email string, identifier string) (models.VerificationRequest, error) { func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
var verificationRequest models.VerificationRequest var verificationRequest models.VerificationRequest
return verificationRequest, nil return verificationRequest, nil
} }
// ListVerificationRequests to get list of verification requests from database // ListVerificationRequests to get list of verification requests from database
func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model.VerificationRequests, error) { func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
return nil, nil return nil, nil
} }
// DeleteVerificationRequest to delete verification request from database // DeleteVerificationRequest to delete verification request from database
func (p *provider) DeleteVerificationRequest(verificationRequest models.VerificationRequest) error { func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
return nil return nil
} }

View File

@ -0,0 +1,49 @@
package provider_template
import (
"context"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/google/uuid"
)
// AddWebhook to add webhook
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
if webhook.ID == "" {
webhook.ID = uuid.New().String()
}
webhook.Key = webhook.ID
webhook.CreatedAt = time.Now().Unix()
webhook.UpdatedAt = time.Now().Unix()
return webhook.AsAPIWebhook(), nil
}
// UpdateWebhook to update webhook
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
webhook.UpdatedAt = time.Now().Unix()
return webhook.AsAPIWebhook(), nil
}
// ListWebhooks to list webhook
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
return nil, nil
}
// GetWebhookByID to get webhook by id
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
return nil, nil
}
// GetWebhookByEventName to get webhook by event_name
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
return nil, nil
}
// DeleteWebhook to delete webhook
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
// Also delete webhook logs for given webhook id
return nil
}

View File

@ -0,0 +1,27 @@
package provider_template
import (
"context"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/google/uuid"
)
// AddWebhookLog to add webhook log
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
if webhookLog.ID == "" {
webhookLog.ID = uuid.New().String()
}
webhookLog.Key = webhookLog.ID
webhookLog.CreatedAt = time.Now().Unix()
webhookLog.UpdatedAt = time.Now().Unix()
return webhookLog.AsAPIWebhookLog(), nil
}
// ListWebhookLogs to list webhook logs
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
return nil, nil
}

View File

@ -1,44 +1,64 @@
package providers package providers
import ( import (
"context"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
) )
type Provider interface { type Provider interface {
// AddUser to save user information in database // AddUser to save user information in database
AddUser(user models.User) (models.User, error) AddUser(ctx context.Context, user models.User) (models.User, error)
// UpdateUser to update user information in database // UpdateUser to update user information in database
UpdateUser(user models.User) (models.User, error) UpdateUser(ctx context.Context, user models.User) (models.User, error)
// DeleteUser to delete user information from database // DeleteUser to delete user information from database
DeleteUser(user models.User) error DeleteUser(ctx context.Context, user models.User) error
// ListUsers to get list of users from database // ListUsers to get list of users from database
ListUsers(pagination model.Pagination) (*model.Users, error) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error)
// GetUserByEmail to get user information from database using email address // GetUserByEmail to get user information from database using email address
GetUserByEmail(email string) (models.User, error) GetUserByEmail(ctx context.Context, email string) (models.User, error)
// GetUserByID to get user information from database using user ID // GetUserByID to get user information from database using user ID
GetUserByID(id string) (models.User, error) GetUserByID(ctx context.Context, id string) (models.User, error)
// AddVerification to save verification request in database // AddVerification to save verification request in database
AddVerificationRequest(verificationRequest models.VerificationRequest) (models.VerificationRequest, error) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error)
// GetVerificationRequestByToken to get verification request from database using token // GetVerificationRequestByToken to get verification request from database using token
GetVerificationRequestByToken(token string) (models.VerificationRequest, error) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error)
// GetVerificationRequestByEmail to get verification request by email from database // GetVerificationRequestByEmail to get verification request by email from database
GetVerificationRequestByEmail(email string, identifier string) (models.VerificationRequest, error) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error)
// ListVerificationRequests to get list of verification requests from database // ListVerificationRequests to get list of verification requests from database
ListVerificationRequests(pagination model.Pagination) (*model.VerificationRequests, error) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error)
// DeleteVerificationRequest to delete verification request from database // DeleteVerificationRequest to delete verification request from database
DeleteVerificationRequest(verificationRequest models.VerificationRequest) error DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error
// AddSession to save session information in database // AddSession to save session information in database
AddSession(session models.Session) error AddSession(ctx context.Context, session models.Session) error
// DeleteSession to delete session information from database // DeleteSession to delete session information from database
DeleteSession(userId string) error DeleteSession(ctx context.Context, userId string) error
// AddEnv to save environment information in database // AddEnv to save environment information in database
AddEnv(env models.Env) (models.Env, error) AddEnv(ctx context.Context, env models.Env) (models.Env, error)
// UpdateEnv to update environment information in database // UpdateEnv to update environment information in database
UpdateEnv(env models.Env) (models.Env, error) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error)
// GetEnv to get environment information from database // GetEnv to get environment information from database
GetEnv() (models.Env, error) GetEnv(ctx context.Context) (models.Env, error)
// AddWebhook to add webhook
AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error)
// UpdateWebhook to update webhook
UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error)
// ListWebhooks to list webhook
ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error)
// GetWebhookByID to get webhook by id
GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error)
// GetWebhookByEventName to get webhook by event_name
GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error)
// DeleteWebhook to delete webhook
DeleteWebhook(ctx context.Context, webhook *model.Webhook) error
// AddWebhookLog to add webhook log
AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error)
// ListWebhookLogs to list webhook logs
ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error)
} }

View File

@ -1,6 +1,7 @@
package sql package sql
import ( import (
"context"
"time" "time"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
@ -8,7 +9,7 @@ import (
) )
// AddEnv to save environment information in database // AddEnv to save environment information in database
func (p *provider) AddEnv(env models.Env) (models.Env, error) { func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
if env.ID == "" { if env.ID == "" {
env.ID = uuid.New().String() env.ID = uuid.New().String()
} }
@ -25,7 +26,7 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) {
} }
// UpdateEnv to update environment information in database // UpdateEnv to update environment information in database
func (p *provider) UpdateEnv(env models.Env) (models.Env, error) { func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
env.UpdatedAt = time.Now().Unix() env.UpdatedAt = time.Now().Unix()
result := p.db.Save(&env) result := p.db.Save(&env)
@ -36,7 +37,7 @@ func (p *provider) UpdateEnv(env models.Env) (models.Env, error) {
} }
// GetEnv to get environment information from database // GetEnv to get environment information from database
func (p *provider) GetEnv() (models.Env, error) { func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
var env models.Env var env models.Env
result := p.db.First(&env) result := p.db.First(&env)

View File

@ -60,7 +60,7 @@ func NewProvider() (*provider, error) {
return nil, err return nil, err
} }
err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}) err = sqlDB.AutoMigrate(&models.User{}, &models.VerificationRequest{}, &models.Session{}, &models.Env{}, &models.Webhook{}, models.WebhookLog{})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,6 +1,7 @@
package sql package sql
import ( import (
"context"
"time" "time"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
@ -9,7 +10,7 @@ import (
) )
// AddSession to save session information in database // AddSession to save session information in database
func (p *provider) AddSession(session models.Session) error { func (p *provider) AddSession(ctx context.Context, session models.Session) error {
if session.ID == "" { if session.ID == "" {
session.ID = uuid.New().String() session.ID = uuid.New().String()
} }
@ -28,7 +29,7 @@ func (p *provider) AddSession(session models.Session) error {
} }
// DeleteSession to delete session information from database // DeleteSession to delete session information from database
func (p *provider) DeleteSession(userId string) error { func (p *provider) DeleteSession(ctx context.Context, userId string) error {
result := p.db.Where("user_id = ?", userId).Delete(&models.Session{}) result := p.db.Where("user_id = ?", userId).Delete(&models.Session{})
if result.Error != nil { if result.Error != nil {

View File

@ -1,6 +1,7 @@
package sql package sql
import ( import (
"context"
"time" "time"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
@ -12,7 +13,7 @@ import (
) )
// AddUser to save user information in database // AddUser to save user information in database
func (p *provider) AddUser(user models.User) (models.User, error) { func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
if user.ID == "" { if user.ID == "" {
user.ID = uuid.New().String() user.ID = uuid.New().String()
} }
@ -42,7 +43,7 @@ func (p *provider) AddUser(user models.User) (models.User, error) {
} }
// UpdateUser to update user information in database // UpdateUser to update user information in database
func (p *provider) UpdateUser(user models.User) (models.User, error) { func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
user.UpdatedAt = time.Now().Unix() user.UpdatedAt = time.Now().Unix()
result := p.db.Save(&user) result := p.db.Save(&user)
@ -55,7 +56,7 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) {
} }
// DeleteUser to delete user information from database // DeleteUser to delete user information from database
func (p *provider) DeleteUser(user models.User) error { func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
result := p.db.Delete(&user) result := p.db.Delete(&user)
if result.Error != nil { if result.Error != nil {
@ -66,7 +67,7 @@ func (p *provider) DeleteUser(user models.User) error {
} }
// ListUsers to get list of users from database // ListUsers to get list of users from database
func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error) { func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
var users []models.User var users []models.User
result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&users) result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&users)
if result.Error != nil { if result.Error != nil {
@ -94,7 +95,7 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
} }
// GetUserByEmail to get user information from database using email address // GetUserByEmail to get user information from database using email address
func (p *provider) GetUserByEmail(email string) (models.User, error) { func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
var user models.User var user models.User
result := p.db.Where("email = ?", email).First(&user) result := p.db.Where("email = ?", email).First(&user)
if result.Error != nil { if result.Error != nil {
@ -105,7 +106,7 @@ func (p *provider) GetUserByEmail(email string) (models.User, error) {
} }
// GetUserByID to get user information from database using user ID // GetUserByID to get user information from database using user ID
func (p *provider) GetUserByID(id string) (models.User, error) { func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
var user models.User var user models.User
result := p.db.Where("id = ?", id).First(&user) result := p.db.Where("id = ?", id).First(&user)

View File

@ -1,6 +1,7 @@
package sql package sql
import ( import (
"context"
"time" "time"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
@ -10,7 +11,7 @@ import (
) )
// AddVerification to save verification request in database // AddVerification to save verification request in database
func (p *provider) AddVerificationRequest(verificationRequest models.VerificationRequest) (models.VerificationRequest, error) { func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
if verificationRequest.ID == "" { if verificationRequest.ID == "" {
verificationRequest.ID = uuid.New().String() verificationRequest.ID = uuid.New().String()
} }
@ -31,7 +32,7 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio
} }
// GetVerificationRequestByToken to get verification request from database using token // GetVerificationRequestByToken to get verification request from database using token
func (p *provider) GetVerificationRequestByToken(token string) (models.VerificationRequest, error) { func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
var verificationRequest models.VerificationRequest var verificationRequest models.VerificationRequest
result := p.db.Where("token = ?", token).First(&verificationRequest) result := p.db.Where("token = ?", token).First(&verificationRequest)
@ -43,7 +44,7 @@ func (p *provider) GetVerificationRequestByToken(token string) (models.Verificat
} }
// GetVerificationRequestByEmail to get verification request by email from database // GetVerificationRequestByEmail to get verification request by email from database
func (p *provider) GetVerificationRequestByEmail(email string, identifier string) (models.VerificationRequest, error) { func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
var verificationRequest models.VerificationRequest var verificationRequest models.VerificationRequest
result := p.db.Where("email = ? AND identifier = ?", email, identifier).First(&verificationRequest) result := p.db.Where("email = ? AND identifier = ?", email, identifier).First(&verificationRequest)
@ -56,7 +57,7 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string
} }
// ListVerificationRequests to get list of verification requests from database // ListVerificationRequests to get list of verification requests from database
func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model.VerificationRequests, error) { func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
var verificationRequests []models.VerificationRequest var verificationRequests []models.VerificationRequest
result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&verificationRequests) result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&verificationRequests)
@ -85,7 +86,7 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model
} }
// DeleteVerificationRequest to delete verification request from database // DeleteVerificationRequest to delete verification request from database
func (p *provider) DeleteVerificationRequest(verificationRequest models.VerificationRequest) error { func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
result := p.db.Delete(&verificationRequest) result := p.db.Delete(&verificationRequest)
if result.Error != nil { if result.Error != nil {

View File

@ -0,0 +1,104 @@
package sql
import (
"context"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/google/uuid"
)
// AddWebhook to add webhook
func (p *provider) AddWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
if webhook.ID == "" {
webhook.ID = uuid.New().String()
}
webhook.Key = webhook.ID
webhook.CreatedAt = time.Now().Unix()
webhook.UpdatedAt = time.Now().Unix()
res := p.db.Create(&webhook)
if res.Error != nil {
return nil, res.Error
}
return webhook.AsAPIWebhook(), nil
}
// UpdateWebhook to update webhook
func (p *provider) UpdateWebhook(ctx context.Context, webhook models.Webhook) (*model.Webhook, error) {
webhook.UpdatedAt = time.Now().Unix()
result := p.db.Save(&webhook)
if result.Error != nil {
return nil, result.Error
}
return webhook.AsAPIWebhook(), nil
}
// ListWebhooks to list webhook
func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination) (*model.Webhooks, error) {
var webhooks []models.Webhook
result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&webhooks)
if result.Error != nil {
return nil, result.Error
}
var total int64
totalRes := p.db.Model(&models.Webhook{}).Count(&total)
if totalRes.Error != nil {
return nil, totalRes.Error
}
paginationClone := pagination
paginationClone.Total = total
responseWebhooks := []*model.Webhook{}
for _, w := range webhooks {
responseWebhooks = append(responseWebhooks, w.AsAPIWebhook())
}
return &model.Webhooks{
Pagination: &paginationClone,
Webhooks: responseWebhooks,
}, nil
}
// GetWebhookByID to get webhook by id
func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model.Webhook, error) {
var webhook models.Webhook
result := p.db.Where("id = ?", webhookID).First(&webhook)
if result.Error != nil {
return nil, result.Error
}
return webhook.AsAPIWebhook(), nil
}
// GetWebhookByEventName to get webhook by event_name
func (p *provider) GetWebhookByEventName(ctx context.Context, eventName string) (*model.Webhook, error) {
var webhook models.Webhook
result := p.db.Where("event_name = ?", eventName).First(&webhook)
if result.Error != nil {
return nil, result.Error
}
return webhook.AsAPIWebhook(), nil
}
// DeleteWebhook to delete webhook
func (p *provider) DeleteWebhook(ctx context.Context, webhook *model.Webhook) error {
result := p.db.Delete(&models.Webhook{
ID: webhook.ID,
})
if result.Error != nil {
return result.Error
}
result = p.db.Where("webhook_id = ?", webhook.ID).Delete(&models.WebhookLog{})
if result.Error != nil {
return result.Error
}
return nil
}

View File

@ -0,0 +1,68 @@
package sql
import (
"context"
"time"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/google/uuid"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
// AddWebhookLog to add webhook log
func (p *provider) AddWebhookLog(ctx context.Context, webhookLog models.WebhookLog) (*model.WebhookLog, error) {
if webhookLog.ID == "" {
webhookLog.ID = uuid.New().String()
}
webhookLog.Key = webhookLog.ID
webhookLog.CreatedAt = time.Now().Unix()
webhookLog.UpdatedAt = time.Now().Unix()
res := p.db.Clauses(
clause.OnConflict{
DoNothing: true,
}).Create(&webhookLog)
if res.Error != nil {
return nil, res.Error
}
return webhookLog.AsAPIWebhookLog(), nil
}
// ListWebhookLogs to list webhook logs
func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Pagination, webhookID string) (*model.WebhookLogs, error) {
var webhookLogs []models.WebhookLog
var result *gorm.DB
var totalRes *gorm.DB
var total int64
if webhookID != "" {
result = p.db.Where("webhook_id = ?", webhookID).Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&webhookLogs)
totalRes = p.db.Where("webhook_id = ?", webhookID).Model(&models.WebhookLog{}).Count(&total)
} else {
result = p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&webhookLogs)
totalRes = p.db.Model(&models.WebhookLog{}).Count(&total)
}
if result.Error != nil {
return nil, result.Error
}
if totalRes.Error != nil {
return nil, totalRes.Error
}
paginationClone := pagination
paginationClone.Total = total
responseWebhookLogs := []*model.WebhookLog{}
for _, w := range webhookLogs {
responseWebhookLogs = append(responseWebhookLogs, w.AsAPIWebhookLog())
}
return &model.WebhookLogs{
WebhookLogs: responseWebhookLogs,
Pagination: &paginationClone,
}, nil
}

View File

@ -1,6 +1,7 @@
package env package env
import ( import (
"context"
"encoding/json" "encoding/json"
"os" "os"
"reflect" "reflect"
@ -58,7 +59,8 @@ func fixBackwardCompatibility(data map[string]interface{}) (bool, map[string]int
// GetEnvData returns the env data from database // GetEnvData returns the env data from database
func GetEnvData() (map[string]interface{}, error) { func GetEnvData() (map[string]interface{}, error) {
var result map[string]interface{} var result map[string]interface{}
env, err := db.Provider.GetEnv() ctx := context.Background()
env, err := db.Provider.GetEnv(ctx)
// config not found in db // config not found in db
if err != nil { if err != nil {
log.Debug("Error while getting env data from db: ", err) log.Debug("Error while getting env data from db: ", err)
@ -108,7 +110,8 @@ func GetEnvData() (map[string]interface{}, error) {
// PersistEnv persists the environment variables to the database // PersistEnv persists the environment variables to the database
func PersistEnv() error { func PersistEnv() error {
env, err := db.Provider.GetEnv() ctx := context.Background()
env, err := db.Provider.GetEnv(ctx)
// config not found in db // config not found in db
if err != nil { if err != nil {
// AES encryption needs 32 bit key only, so we chop off last 4 characters from 36 bit uuid // AES encryption needs 32 bit key only, so we chop off last 4 characters from 36 bit uuid
@ -137,7 +140,7 @@ func PersistEnv() error {
EnvData: encryptedConfig, EnvData: encryptedConfig,
} }
env, err = db.Provider.AddEnv(env) env, err = db.Provider.AddEnv(ctx, env)
if err != nil { if err != nil {
log.Debug("Error while persisting env data to db: ", err) log.Debug("Error while persisting env data to db: ", err)
return err return err
@ -251,7 +254,7 @@ func PersistEnv() error {
} }
env.EnvData = encryptedConfig env.EnvData = encryptedConfig
_, err = db.Provider.UpdateEnv(env) _, err = db.Provider.UpdateEnv(ctx, env)
if err != nil { if err != nil {
log.Debug("Failed to Update Config: ", err) log.Debug("Failed to Update Config: ", err)
return err return err

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,13 @@
package model package model
type AddWebhookRequest struct {
EventName string `json:"event_name"`
Endpoint string `json:"endpoint"`
Enabled bool `json:"enabled"`
Headers map[string]interface{} `json:"headers"`
}
type AdminLoginInput struct { type AdminLoginInput struct {
AdminSecret string `json:"admin_secret"` AdminSecret string `json:"admin_secret"`
} }
@ -100,6 +107,11 @@ type InviteMemberInput struct {
RedirectURI *string `json:"redirect_uri"` RedirectURI *string `json:"redirect_uri"`
} }
type ListWebhookLogRequest struct {
Pagination *PaginationInput `json:"pagination"`
WebhookID *string `json:"webhook_id"`
}
type LoginInput struct { type LoginInput struct {
Email string `json:"email"` Email string `json:"email"`
Password string `json:"password"` Password string `json:"password"`
@ -187,6 +199,17 @@ type SignUpInput struct {
RedirectURI *string `json:"redirect_uri"` RedirectURI *string `json:"redirect_uri"`
} }
type TestEndpointRequest struct {
Endpoint string `json:"endpoint"`
EventName string `json:"event_name"`
Headers map[string]interface{} `json:"headers"`
}
type TestEndpointResponse struct {
HTTPStatus *int64 `json:"http_status"`
Response map[string]interface{} `json:"response"`
}
type UpdateAccessInput struct { type UpdateAccessInput struct {
UserID string `json:"user_id"` UserID string `json:"user_id"`
} }
@ -263,6 +286,14 @@ type UpdateUserInput struct {
Roles []*string `json:"roles"` Roles []*string `json:"roles"`
} }
type UpdateWebhookRequest struct {
ID string `json:"id"`
EventName *string `json:"event_name"`
Endpoint *string `json:"endpoint"`
Enabled *bool `json:"enabled"`
Headers map[string]interface{} `json:"headers"`
}
type User struct { type User struct {
ID string `json:"id"` ID string `json:"id"`
Email string `json:"email"` Email string `json:"email"`
@ -319,3 +350,37 @@ type VerificationRequests struct {
type VerifyEmailInput struct { type VerifyEmailInput struct {
Token string `json:"token"` Token string `json:"token"`
} }
type Webhook struct {
ID string `json:"id"`
EventName *string `json:"event_name"`
Endpoint *string `json:"endpoint"`
Enabled *bool `json:"enabled"`
Headers map[string]interface{} `json:"headers"`
CreatedAt *int64 `json:"created_at"`
UpdatedAt *int64 `json:"updated_at"`
}
type WebhookLog struct {
ID string `json:"id"`
HTTPStatus *int64 `json:"http_status"`
Response *string `json:"response"`
Request *string `json:"request"`
WebhookID *string `json:"webhook_id"`
CreatedAt *int64 `json:"created_at"`
UpdatedAt *int64 `json:"updated_at"`
}
type WebhookLogs struct {
Pagination *Pagination `json:"pagination"`
WebhookLogs []*WebhookLog `json:"webhook_logs"`
}
type WebhookRequest struct {
ID string `json:"id"`
}
type Webhooks struct {
Pagination *Pagination `json:"pagination"`
Webhooks []*Webhook `json:"webhooks"`
}

View File

@ -324,6 +324,71 @@ input GenerateJWTKeysInput {
type: String! type: String!
} }
type Webhook {
id: ID!
event_name: String
endpoint: String
enabled: Boolean
headers: Map
created_at: Int64
updated_at: Int64
}
type Webhooks {
pagination: Pagination!
webhooks: [Webhook!]!
}
type WebhookLog {
id: ID!
http_status: Int64
response: String
request: String
webhook_id: ID
created_at: Int64
updated_at: Int64
}
type TestEndpointResponse {
http_status: Int64
response: Map
}
input ListWebhookLogRequest {
pagination: PaginationInput!
webhook_id: String
}
input AddWebhookRequest {
event_name: String!
endpoint: String!
enabled: Boolean!
headers: Map
}
input UpdateWebhookRequest {
id: ID!
event_name: String
endpoint: String
enabled: Boolean
headers: Map
}
input WebhookRequest {
id: ID!
}
input TestEndpointRequest {
endpoint: String!
event_name: String!
headers: Map
}
type WebhookLogs {
pagination: Pagination!
webhook_logs: [WebhookLog!]!
}
type Mutation { type Mutation {
signup(params: SignUpInput!): AuthResponse! signup(params: SignUpInput!): AuthResponse!
login(params: LoginInput!): AuthResponse! login(params: LoginInput!): AuthResponse!
@ -346,6 +411,10 @@ type Mutation {
_revoke_access(param: UpdateAccessInput!): Response! _revoke_access(param: UpdateAccessInput!): Response!
_enable_access(param: UpdateAccessInput!): Response! _enable_access(param: UpdateAccessInput!): Response!
_generate_jwt_keys(params: GenerateJWTKeysInput!): GenerateJWTKeysResponse! _generate_jwt_keys(params: GenerateJWTKeysInput!): GenerateJWTKeysResponse!
_add_webhook(params: AddWebhookRequest!): Response!
_update_webhook(params: UpdateWebhookRequest!): Response!
_delete_webhook(params: WebhookRequest!): Response!
_test_endpoint(params: TestEndpointRequest!): TestEndpointResponse!
} }
type Query { type Query {
@ -358,4 +427,7 @@ type Query {
_verification_requests(params: PaginatedInput): VerificationRequests! _verification_requests(params: PaginatedInput): VerificationRequests!
_admin_session: Response! _admin_session: Response!
_env: Env! _env: Env!
_webhook(params: WebhookRequest!): Webhook!
_webhooks(params: PaginatedInput): Webhooks!
_webhook_logs(params: ListWebhookLogRequest!): WebhookLogs!
} }

View File

@ -91,6 +91,22 @@ func (r *mutationResolver) GenerateJwtKeys(ctx context.Context, params model.Gen
return resolvers.GenerateJWTKeysResolver(ctx, params) return resolvers.GenerateJWTKeysResolver(ctx, params)
} }
func (r *mutationResolver) AddWebhook(ctx context.Context, params model.AddWebhookRequest) (*model.Response, error) {
return resolvers.AddWebhookResolver(ctx, params)
}
func (r *mutationResolver) UpdateWebhook(ctx context.Context, params model.UpdateWebhookRequest) (*model.Response, error) {
return resolvers.UpdateWebhookResolver(ctx, params)
}
func (r *mutationResolver) DeleteWebhook(ctx context.Context, params model.WebhookRequest) (*model.Response, error) {
return resolvers.DeleteWebhookResolver(ctx, params)
}
func (r *mutationResolver) TestEndpoint(ctx context.Context, params model.TestEndpointRequest) (*model.TestEndpointResponse, error) {
return resolvers.TestEndpointResolver(ctx, params)
}
func (r *queryResolver) Meta(ctx context.Context) (*model.Meta, error) { func (r *queryResolver) Meta(ctx context.Context) (*model.Meta, error) {
return resolvers.MetaResolver(ctx) return resolvers.MetaResolver(ctx)
} }
@ -123,6 +139,18 @@ func (r *queryResolver) Env(ctx context.Context) (*model.Env, error) {
return resolvers.EnvResolver(ctx) return resolvers.EnvResolver(ctx)
} }
func (r *queryResolver) Webhook(ctx context.Context, params model.WebhookRequest) (*model.Webhook, error) {
return resolvers.WebhookResolver(ctx, params)
}
func (r *queryResolver) Webhooks(ctx context.Context, params *model.PaginatedInput) (*model.Webhooks, error) {
return resolvers.WebhooksResolver(ctx, params)
}
func (r *queryResolver) WebhookLogs(ctx context.Context, params model.ListWebhookLogRequest) (*model.WebhookLogs, error) {
return resolvers.WebhookLogsResolver(ctx, params)
}
// Mutation returns generated.MutationResolver implementation. // Mutation returns generated.MutationResolver implementation.
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} } func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }

View File

@ -199,7 +199,7 @@ func AuthorizeHandler() gin.HandlerFunc {
return return
} }
userID := claims.Subject userID := claims.Subject
user, err := db.Provider.GetUserByID(userID) user, err := db.Provider.GetUserByID(gc, userID)
if err != nil { if err != nil {
if isQuery { if isQuery {
gc.Redirect(http.StatusFound, loginURL) gc.Redirect(http.StatusFound, loginURL)

View File

@ -28,21 +28,21 @@ import (
// OAuthCallbackHandler handles the OAuth callback for various oauth providers // OAuthCallbackHandler handles the OAuth callback for various oauth providers
func OAuthCallbackHandler() gin.HandlerFunc { func OAuthCallbackHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(ctx *gin.Context) {
provider := c.Param("oauth_provider") provider := ctx.Param("oauth_provider")
state := c.Request.FormValue("state") state := ctx.Request.FormValue("state")
sessionState, err := memorystore.Provider.GetState(state) sessionState, err := memorystore.Provider.GetState(state)
if sessionState == "" || err != nil { if sessionState == "" || err != nil {
log.Debug("Invalid oauth state: ", state) log.Debug("Invalid oauth state: ", state)
c.JSON(400, gin.H{"error": "invalid oauth state"}) ctx.JSON(400, gin.H{"error": "invalid oauth state"})
} }
// contains random token, redirect url, role // contains random token, redirect url, role
sessionSplit := strings.Split(state, "___") sessionSplit := strings.Split(state, "___")
if len(sessionSplit) < 3 { if len(sessionSplit) < 3 {
log.Debug("Unable to get redirect url from state: ", state) log.Debug("Unable to get redirect url from state: ", state)
c.JSON(400, gin.H{"error": "invalid redirect url"}) ctx.JSON(400, gin.H{"error": "invalid redirect url"})
return return
} }
@ -55,7 +55,7 @@ func OAuthCallbackHandler() gin.HandlerFunc {
scopes := strings.Split(sessionSplit[3], ",") scopes := strings.Split(sessionSplit[3], ",")
user := models.User{} user := models.User{}
code := c.Request.FormValue("code") code := ctx.Request.FormValue("code")
switch provider { switch provider {
case constants.AuthRecipeMethodGoogle: case constants.AuthRecipeMethodGoogle:
user, err = processGoogleUserInfo(code) user, err = processGoogleUserInfo(code)
@ -74,23 +74,24 @@ func OAuthCallbackHandler() gin.HandlerFunc {
if err != nil { if err != nil {
log.Debug("Failed to process user info: ", err) log.Debug("Failed to process user info: ", err)
c.JSON(400, gin.H{"error": err.Error()}) ctx.JSON(400, gin.H{"error": err.Error()})
return return
} }
existingUser, err := db.Provider.GetUserByEmail(user.Email) existingUser, err := db.Provider.GetUserByEmail(ctx, user.Email)
log := log.WithField("user", user.Email) log := log.WithField("user", user.Email)
isSignUp := false
if err != nil { if err != nil {
isSignupDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp) isSignupDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp)
if err != nil { if err != nil {
log.Debug("Failed to get signup disabled env variable: ", err) log.Debug("Failed to get signup disabled env variable: ", err)
c.JSON(400, gin.H{"error": err.Error()}) ctx.JSON(400, gin.H{"error": err.Error()})
return return
} }
if isSignupDisabled { if isSignupDisabled {
log.Debug("Failed to signup as disabled") log.Debug("Failed to signup as disabled")
c.JSON(400, gin.H{"error": "signup is disabled for this instance"}) ctx.JSON(400, gin.H{"error": "signup is disabled for this instance"})
return return
} }
// user not registered, register user and generate session token // user not registered, register user and generate session token
@ -113,19 +114,20 @@ func OAuthCallbackHandler() gin.HandlerFunc {
if hasProtectedRole { if hasProtectedRole {
log.Debug("Signup is not allowed with protected roles:", inputRoles) log.Debug("Signup is not allowed with protected roles:", inputRoles)
c.JSON(400, gin.H{"error": "invalid role"}) ctx.JSON(400, gin.H{"error": "invalid role"})
return return
} }
user.Roles = strings.Join(inputRoles, ",") user.Roles = strings.Join(inputRoles, ",")
now := time.Now().Unix() now := time.Now().Unix()
user.EmailVerifiedAt = &now user.EmailVerifiedAt = &now
user, _ = db.Provider.AddUser(user) user, _ = db.Provider.AddUser(ctx, user)
isSignUp = true
} else { } else {
user = existingUser user = existingUser
if user.RevokedTimestamp != nil { if user.RevokedTimestamp != nil {
log.Debug("User access revoked at: ", user.RevokedTimestamp) log.Debug("User access revoked at: ", user.RevokedTimestamp)
c.JSON(400, gin.H{"error": "user access has been revoked"}) ctx.JSON(400, gin.H{"error": "user access has been revoked"})
return return
} }
@ -175,7 +177,7 @@ func OAuthCallbackHandler() gin.HandlerFunc {
if hasProtectedRole { if hasProtectedRole {
log.Debug("Invalid role. User is using protected unassigned role") log.Debug("Invalid role. User is using protected unassigned role")
c.JSON(400, gin.H{"error": "invalid role"}) ctx.JSON(400, gin.H{"error": "invalid role"})
return return
} else { } else {
user.Roles = existingUser.Roles + "," + strings.Join(unasignedRoles, ",") user.Roles = existingUser.Roles + "," + strings.Join(unasignedRoles, ",")
@ -184,18 +186,18 @@ func OAuthCallbackHandler() gin.HandlerFunc {
user.Roles = existingUser.Roles user.Roles = existingUser.Roles
} }
user, err = db.Provider.UpdateUser(user) user, err = db.Provider.UpdateUser(ctx, user)
if err != nil { if err != nil {
log.Debug("Failed to update user: ", err) log.Debug("Failed to update user: ", err)
c.JSON(500, gin.H{"error": err.Error()}) ctx.JSON(500, gin.H{"error": err.Error()})
return return
} }
} }
authToken, err := token.CreateAuthToken(c, user, inputRoles, scopes, provider) authToken, err := token.CreateAuthToken(ctx, user, inputRoles, scopes, provider)
if err != nil { if err != nil {
log.Debug("Failed to create auth token: ", err) log.Debug("Failed to create auth token: ", err)
c.JSON(500, gin.H{"error": err.Error()}) ctx.JSON(500, gin.H{"error": err.Error()})
} }
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
@ -206,7 +208,7 @@ func OAuthCallbackHandler() gin.HandlerFunc {
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token
sessionKey := provider + ":" + user.ID sessionKey := provider + ":" + user.ID
cookie.SetSession(c, authToken.FingerPrintHash) cookie.SetSession(ctx, authToken.FingerPrintHash)
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
@ -215,18 +217,25 @@ func OAuthCallbackHandler() gin.HandlerFunc {
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
} }
go db.Provider.AddSession(models.Session{ go func() {
UserID: user.ID, if isSignUp {
UserAgent: utils.GetUserAgent(c.Request), utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, provider, user)
IP: utils.GetIP(c.Request), } else {
}) utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, provider, user)
}
db.Provider.AddSession(ctx, models.Session{
UserID: user.ID,
UserAgent: utils.GetUserAgent(ctx.Request),
IP: utils.GetIP(ctx.Request),
})
}()
if strings.Contains(redirectURL, "?") { if strings.Contains(redirectURL, "?") {
redirectURL = redirectURL + "&" + params redirectURL = redirectURL + "&" + params
} else { } else {
redirectURL = redirectURL + "?" + strings.TrimPrefix(params, "&") redirectURL = redirectURL + "?" + strings.TrimPrefix(params, "&")
} }
c.Redirect(http.StatusFound, redirectURL) ctx.Redirect(http.StatusFound, redirectURL)
} }
} }

View File

@ -12,8 +12,8 @@ import (
"github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/token"
) )
// Revoke handler to revoke refresh token // RevokeRefreshTokenHandler handler to revoke refresh token
func RevokeHandler() gin.HandlerFunc { func RevokeRefreshTokenHandler() gin.HandlerFunc {
return func(gc *gin.Context) { return func(gc *gin.Context) {
var reqBody map[string]string var reqBody map[string]string
if err := gc.BindJSON(&reqBody); err != nil { if err := gc.BindJSON(&reqBody); err != nil {

View File

@ -190,7 +190,7 @@ func TokenHandler() gin.HandlerFunc {
return return
} }
user, err := db.Provider.GetUserByID(userID) user, err := db.Provider.GetUserByID(gc, userID)
if err != nil { if err != nil {
log.Debug("Error getting user: ", err) log.Debug("Error getting user: ", err)
gc.JSON(http.StatusUnauthorized, gin.H{ gc.JSON(http.StatusUnauthorized, gin.H{

View File

@ -31,7 +31,7 @@ func UserInfoHandler() gin.HandlerFunc {
} }
userID := claims["sub"].(string) userID := claims["sub"].(string)
user, err := db.Provider.GetUserByID(userID) user, err := db.Provider.GetUserByID(gc, userID)
if err != nil { if err != nil {
log.Debug("Error getting user: ", err) log.Debug("Error getting user: ", err)
gc.JSON(http.StatusUnauthorized, gin.H{ gc.JSON(http.StatusUnauthorized, gin.H{

View File

@ -33,7 +33,7 @@ func VerifyEmailHandler() gin.HandlerFunc {
return return
} }
verificationRequest, err := db.Provider.GetVerificationRequestByToken(tokenInQuery) verificationRequest, err := db.Provider.GetVerificationRequestByToken(c, tokenInQuery)
if err != nil { if err != nil {
log.Debug("Error getting verification request: ", err) log.Debug("Error getting verification request: ", err)
errorRes["error_description"] = err.Error() errorRes["error_description"] = err.Error()
@ -58,7 +58,7 @@ func VerifyEmailHandler() gin.HandlerFunc {
return return
} }
user, err := db.Provider.GetUserByEmail(verificationRequest.Email) user, err := db.Provider.GetUserByEmail(c, verificationRequest.Email)
if err != nil { if err != nil {
log.Debug("Error getting user: ", err) log.Debug("Error getting user: ", err)
errorRes["error_description"] = err.Error() errorRes["error_description"] = err.Error()
@ -66,14 +66,16 @@ func VerifyEmailHandler() gin.HandlerFunc {
return return
} }
isSignUp := false
// update email_verified_at in users table // update email_verified_at in users table
if user.EmailVerifiedAt == nil { if user.EmailVerifiedAt == nil {
now := time.Now().Unix() now := time.Now().Unix()
user.EmailVerifiedAt = &now user.EmailVerifiedAt = &now
db.Provider.UpdateUser(user) isSignUp = true
db.Provider.UpdateUser(c, user)
} }
// delete from verification table // delete from verification table
db.Provider.DeleteVerificationRequest(verificationRequest) db.Provider.DeleteVerificationRequest(c, verificationRequest)
state := strings.TrimSpace(c.Query("state")) state := strings.TrimSpace(c.Query("state"))
redirectURL := strings.TrimSpace(c.Query("redirect_uri")) redirectURL := strings.TrimSpace(c.Query("redirect_uri"))
@ -131,11 +133,19 @@ func VerifyEmailHandler() gin.HandlerFunc {
redirectURL = redirectURL + "?" + strings.TrimPrefix(params, "&") redirectURL = redirectURL + "?" + strings.TrimPrefix(params, "&")
} }
go db.Provider.AddSession(models.Session{ go func() {
UserID: user.ID, if isSignUp {
UserAgent: utils.GetUserAgent(c.Request), utils.RegisterEvent(c, constants.UserSignUpWebhookEvent, loginMethod, user)
IP: utils.GetIP(c.Request), } else {
}) utils.RegisterEvent(c, constants.UserLoginWebhookEvent, loginMethod, user)
}
db.Provider.AddSession(c, models.Session{
UserID: user.ID,
UserAgent: utils.GetUserAgent(c.Request),
IP: utils.GetIP(c.Request),
})
}()
c.Redirect(http.StatusTemporaryRedirect, redirectURL) c.Redirect(http.StatusTemporaryRedirect, redirectURL)
} }

View File

@ -0,0 +1,54 @@
package resolvers
import (
"context"
"encoding/json"
"fmt"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/authorizerdev/authorizer/server/validators"
log "github.com/sirupsen/logrus"
)
// AddWebhookResolver resolver for add webhook mutation
func AddWebhookResolver(ctx context.Context, params model.AddWebhookRequest) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx)
if err != nil {
log.Debug("Failed to get GinContext: ", err)
return nil, err
}
if !token.IsSuperAdmin(gc) {
log.Debug("Not logged in as super admin")
return nil, fmt.Errorf("unauthorized")
}
if !validators.IsValidWebhookEventName(params.EventName) {
log.Debug("Invalid Event Name: ", params.EventName)
return nil, fmt.Errorf("invalid event name %s", params.EventName)
}
headerBytes, err := json.Marshal(params.Headers)
if err != nil {
return nil, err
}
_, err = db.Provider.AddWebhook(ctx, models.Webhook{
EventName: params.EventName,
EndPoint: params.Endpoint,
Enabled: params.Enabled,
Headers: string(headerBytes),
})
if err != nil {
log.Debug("Failed to add webhook: ", err)
return nil, err
}
return &model.Response{
Message: `Webhook added successfully`,
}, nil
}

View File

@ -58,7 +58,7 @@ func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*m
return res, err return res, err
} }
env, err := db.Provider.GetEnv() env, err := db.Provider.GetEnv(ctx)
if err != nil { if err != nil {
log.Debug("Failed to get env: ", err) log.Debug("Failed to get env: ", err)
return res, err return res, err
@ -71,7 +71,7 @@ func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*m
} }
env.EnvData = envData env.EnvData = envData
if _, err := db.Provider.UpdateEnv(env); err != nil { if _, err := db.Provider.UpdateEnv(ctx, env); err != nil {
log.Debug("Failed to update env: ", err) log.Debug("Failed to update env: ", err)
return res, err return res, err
} }

View File

@ -6,6 +6,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/memorystore"
@ -32,15 +33,13 @@ func DeleteUserResolver(ctx context.Context, params model.DeleteUserInput) (*mod
"email": params.Email, "email": params.Email,
}) })
user, err := db.Provider.GetUserByEmail(params.Email) user, err := db.Provider.GetUserByEmail(ctx, params.Email)
if err != nil { if err != nil {
log.Debug("Failed to get user from DB: ", err) log.Debug("Failed to get user from DB: ", err)
return res, err return res, err
} }
go memorystore.Provider.DeleteAllUserSessions(user.ID) err = db.Provider.DeleteUser(ctx, user)
err = db.Provider.DeleteUser(user)
if err != nil { if err != nil {
log.Debug("Failed to delete user: ", err) log.Debug("Failed to delete user: ", err)
return res, err return res, err
@ -50,5 +49,10 @@ func DeleteUserResolver(ctx context.Context, params model.DeleteUserInput) (*mod
Message: `user deleted successfully`, Message: `user deleted successfully`,
} }
go func() {
memorystore.Provider.DeleteAllUserSessions(user.ID)
utils.RegisterEvent(ctx, constants.UserDeletedWebhookEvent, "", user)
}()
return res, nil return res, nil
} }

View File

@ -0,0 +1,49 @@
package resolvers
import (
"context"
"fmt"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils"
log "github.com/sirupsen/logrus"
)
// DeleteWebhookResolver resolver to delete webhook and its relevant logs
func DeleteWebhookResolver(ctx context.Context, params model.WebhookRequest) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx)
if err != nil {
log.Debug("Failed to get GinContext: ", err)
return nil, err
}
if !token.IsSuperAdmin(gc) {
log.Debug("Not logged in as super admin")
return nil, fmt.Errorf("unauthorized")
}
if params.ID == "" {
log.Debug("webhookID is required")
return nil, fmt.Errorf("webhook ID required")
}
log := log.WithField("webhook_id", params.ID)
webhook, err := db.Provider.GetWebhookByID(ctx, params.ID)
if err != nil {
log.Debug("failed to get webhook: ", err)
return nil, err
}
err = db.Provider.DeleteWebhook(ctx, webhook)
if err != nil {
log.Debug("failed to delete webhook: ", err)
return nil, err
}
return &model.Response{
Message: "Webhook deleted successfully",
}, nil
}

View File

@ -6,6 +6,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/token"
@ -31,7 +32,7 @@ func EnableAccessResolver(ctx context.Context, params model.UpdateAccessInput) (
"user_id": params.UserID, "user_id": params.UserID,
}) })
user, err := db.Provider.GetUserByID(params.UserID) user, err := db.Provider.GetUserByID(ctx, params.UserID)
if err != nil { if err != nil {
log.Debug("Failed to get user from DB: ", err) log.Debug("Failed to get user from DB: ", err)
return res, err return res, err
@ -39,7 +40,7 @@ func EnableAccessResolver(ctx context.Context, params model.UpdateAccessInput) (
user.RevokedTimestamp = nil user.RevokedTimestamp = nil
user, err = db.Provider.UpdateUser(user) user, err = db.Provider.UpdateUser(ctx, user)
if err != nil { if err != nil {
log.Debug("Failed to update user: ", err) log.Debug("Failed to update user: ", err)
return res, err return res, err
@ -49,5 +50,7 @@ func EnableAccessResolver(ctx context.Context, params model.UpdateAccessInput) (
Message: `user access enabled successfully`, Message: `user access enabled successfully`,
} }
go utils.RegisterEvent(ctx, constants.UserAccessEnabledWebhookEvent, "", user)
return res, nil return res, nil
} }

View File

@ -49,7 +49,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
log := log.WithFields(log.Fields{ log := log.WithFields(log.Fields{
"email": params.Email, "email": params.Email,
}) })
_, err = db.Provider.GetUserByEmail(params.Email) _, err = db.Provider.GetUserByEmail(ctx, params.Email)
if err != nil { if err != nil {
log.Debug("User not found: ", err) log.Debug("User not found: ", err)
return res, fmt.Errorf(`user with this email not found`) return res, fmt.Errorf(`user with this email not found`)
@ -71,7 +71,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
log.Debug("Failed to create verification token", err) log.Debug("Failed to create verification token", err)
return res, err return res, err
} }
_, err = db.Provider.AddVerificationRequest(models.VerificationRequest{ _, err = db.Provider.AddVerificationRequest(ctx, models.VerificationRequest{
Token: verificationToken, Token: verificationToken,
Identifier: constants.VerificationTypeForgotPassword, Identifier: constants.VerificationTypeForgotPassword,
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),

View File

@ -70,7 +70,7 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput)
// for each emails check if emails exists in db // for each emails check if emails exists in db
newEmails := []string{} newEmails := []string{}
for _, email := range emails { for _, email := range emails {
_, err := db.Provider.GetUserByEmail(email) _, err := db.Provider.GetUserByEmail(ctx, email)
if err != nil { if err != nil {
log.Debugf("User with %s email not found, so inviting user", email) log.Debugf("User with %s email not found, so inviting user", email)
newEmails = append(newEmails, email) newEmails = append(newEmails, email)
@ -140,13 +140,13 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput)
} }
user, err = db.Provider.AddUser(user) user, err = db.Provider.AddUser(ctx, user)
if err != nil { if err != nil {
log.Debugf("Error adding user: %s, err: %v", email, err) log.Debugf("Error adding user: %s, err: %v", email, err)
return nil, err return nil, err
} }
_, err = db.Provider.AddVerificationRequest(verificationRequest) _, err = db.Provider.AddVerificationRequest(ctx, verificationRequest)
if err != nil { if err != nil {
log.Debugf("Error adding verification request: %s, err: %v", email, err) log.Debugf("Error adding verification request: %s, err: %v", email, err)
return nil, err return nil, err

View File

@ -45,7 +45,7 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
"email": params.Email, "email": params.Email,
}) })
params.Email = strings.ToLower(params.Email) params.Email = strings.ToLower(params.Email)
user, err := db.Provider.GetUserByEmail(params.Email) user, err := db.Provider.GetUserByEmail(ctx, params.Email)
if err != nil { if err != nil {
log.Debug("Failed to get user by email: ", err) log.Debug("Failed to get user by email: ", err)
return res, fmt.Errorf(`user with this email not found`) return res, fmt.Errorf(`user with this email not found`)
@ -126,11 +126,14 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token) memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
} }
go db.Provider.AddSession(models.Session{ go func() {
UserID: user.ID, utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user)
UserAgent: utils.GetUserAgent(gc.Request), db.Provider.AddSession(ctx, models.Session{
IP: utils.GetIP(gc.Request), UserID: user.ID,
}) UserAgent: utils.GetUserAgent(gc.Request),
IP: utils.GetIP(gc.Request),
})
}()
return res, nil return res, nil
} }

View File

@ -59,7 +59,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu
} }
// find user with email // find user with email
existingUser, err := db.Provider.GetUserByEmail(params.Email) existingUser, err := db.Provider.GetUserByEmail(ctx, params.Email)
if err != nil { if err != nil {
isSignupDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp) isSignupDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp)
if err != nil { if err != nil {
@ -99,7 +99,8 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu
} }
user.Roles = strings.Join(inputRoles, ",") user.Roles = strings.Join(inputRoles, ",")
user, _ = db.Provider.AddUser(user) user, _ = db.Provider.AddUser(ctx, user)
go utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodMagicLinkLogin, user)
} else { } else {
user = existingUser user = existingUser
// There multiple scenarios with roles here in magic link login // There multiple scenarios with roles here in magic link login
@ -163,7 +164,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu
} }
user.SignupMethods = signupMethod user.SignupMethods = signupMethod
user, _ = db.Provider.UpdateUser(user) user, _ = db.Provider.UpdateUser(ctx, user)
if err != nil { if err != nil {
log.Debug("Failed to update user: ", err) log.Debug("Failed to update user: ", err)
} }
@ -205,7 +206,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu
if err != nil { if err != nil {
log.Debug("Failed to create verification token: ", err) log.Debug("Failed to create verification token: ", err)
} }
_, err = db.Provider.AddVerificationRequest(models.VerificationRequest{ _, err = db.Provider.AddVerificationRequest(ctx, models.VerificationRequest{
Token: verificationToken, Token: verificationToken,
Identifier: verificationType, Identifier: verificationType,
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),

View File

@ -38,7 +38,7 @@ func ProfileResolver(ctx context.Context) (*model.User, error) {
log := log.WithFields(log.Fields{ log := log.WithFields(log.Fields{
"user_id": userID, "user_id": userID,
}) })
user, err := db.Provider.GetUserByID(userID) user, err := db.Provider.GetUserByID(ctx, userID)
if err != nil { if err != nil {
log.Debug("Failed to get user: ", err) log.Debug("Failed to get user: ", err)
return res, err return res, err

View File

@ -39,14 +39,14 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma
return res, fmt.Errorf("invalid identifier") return res, fmt.Errorf("invalid identifier")
} }
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(params.Email, params.Identifier) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, params.Email, params.Identifier)
if err != nil { if err != nil {
log.Debug("Failed to get verification request: ", err) log.Debug("Failed to get verification request: ", err)
return res, fmt.Errorf(`verification request not found`) return res, fmt.Errorf(`verification request not found`)
} }
// delete current verification and create new one // delete current verification and create new one
err = db.Provider.DeleteVerificationRequest(verificationRequest) err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest)
if err != nil { if err != nil {
log.Debug("Failed to delete verification request: ", err) log.Debug("Failed to delete verification request: ", err)
} }
@ -62,7 +62,7 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma
if err != nil { if err != nil {
log.Debug("Failed to create verification token: ", err) log.Debug("Failed to create verification token: ", err)
} }
_, err = db.Provider.AddVerificationRequest(models.VerificationRequest{ _, err = db.Provider.AddVerificationRequest(ctx, models.VerificationRequest{
Token: verificationToken, Token: verificationToken,
Identifier: params.Identifier, Identifier: params.Identifier,
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),

View File

@ -39,7 +39,7 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput)
return res, fmt.Errorf(`basic authentication is disabled for this instance`) return res, fmt.Errorf(`basic authentication is disabled for this instance`)
} }
verificationRequest, err := db.Provider.GetVerificationRequestByToken(params.Token) verificationRequest, err := db.Provider.GetVerificationRequestByToken(ctx, params.Token)
if err != nil { if err != nil {
log.Debug("Failed to get verification request: ", err) log.Debug("Failed to get verification request: ", err)
return res, fmt.Errorf(`invalid token`) return res, fmt.Errorf(`invalid token`)
@ -72,7 +72,7 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput)
log := log.WithFields(log.Fields{ log := log.WithFields(log.Fields{
"email": email, "email": email,
}) })
user, err := db.Provider.GetUserByEmail(email) user, err := db.Provider.GetUserByEmail(ctx, email)
if err != nil { if err != nil {
log.Debug("Failed to get user: ", err) log.Debug("Failed to get user: ", err)
return res, err return res, err
@ -94,13 +94,13 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput)
} }
// delete from verification table // delete from verification table
err = db.Provider.DeleteVerificationRequest(verificationRequest) err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest)
if err != nil { if err != nil {
log.Debug("Failed to delete verification request: ", err) log.Debug("Failed to delete verification request: ", err)
return res, err return res, err
} }
_, err = db.Provider.UpdateUser(user) _, err = db.Provider.UpdateUser(ctx, user)
if err != nil { if err != nil {
log.Debug("Failed to update user: ", err) log.Debug("Failed to update user: ", err)
return res, err return res, err

View File

@ -7,6 +7,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/memorystore"
@ -32,7 +33,7 @@ func RevokeAccessResolver(ctx context.Context, params model.UpdateAccessInput) (
log := log.WithFields(log.Fields{ log := log.WithFields(log.Fields{
"user_id": params.UserID, "user_id": params.UserID,
}) })
user, err := db.Provider.GetUserByID(params.UserID) user, err := db.Provider.GetUserByID(ctx, params.UserID)
if err != nil { if err != nil {
log.Debug("Failed to get user by ID: ", err) log.Debug("Failed to get user by ID: ", err)
return res, err return res, err
@ -41,13 +42,16 @@ func RevokeAccessResolver(ctx context.Context, params model.UpdateAccessInput) (
now := time.Now().Unix() now := time.Now().Unix()
user.RevokedTimestamp = &now user.RevokedTimestamp = &now
user, err = db.Provider.UpdateUser(user) user, err = db.Provider.UpdateUser(ctx, user)
if err != nil { if err != nil {
log.Debug("Failed to update user: ", err) log.Debug("Failed to update user: ", err)
return res, err return res, err
} }
go memorystore.Provider.DeleteAllUserSessions(user.ID) go func() {
memorystore.Provider.DeleteAllUserSessions(user.ID)
utils.RegisterEvent(ctx, constants.UserAccessRevokedWebhookEvent, "", user)
}()
res = &model.Response{ res = &model.Response{
Message: `user access revoked successfully`, Message: `user access revoked successfully`,

View File

@ -46,7 +46,7 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
"user_id": userID, "user_id": userID,
}) })
user, err := db.Provider.GetUserByID(userID) user, err := db.Provider.GetUserByID(ctx, userID)
if err != nil { if err != nil {
return res, err return res, err
} }

View File

@ -74,7 +74,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
"email": params.Email, "email": params.Email,
}) })
// find user with email // find user with email
existingUser, err := db.Provider.GetUserByEmail(params.Email) existingUser, err := db.Provider.GetUserByEmail(ctx, params.Email)
if err != nil { if err != nil {
log.Debug("Failed to get user by email: ", err) log.Debug("Failed to get user by email: ", err)
} }
@ -167,7 +167,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
now := time.Now().Unix() now := time.Now().Unix()
user.EmailVerifiedAt = &now user.EmailVerifiedAt = &now
} }
user, err = db.Provider.AddUser(user) user, err = db.Provider.AddUser(ctx, user)
if err != nil { if err != nil {
log.Debug("Failed to add user: ", err) log.Debug("Failed to add user: ", err)
return res, err return res, err
@ -193,7 +193,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
log.Debug("Failed to create verification token: ", err) log.Debug("Failed to create verification token: ", err)
return res, err return res, err
} }
_, err = db.Provider.AddVerificationRequest(models.VerificationRequest{ _, err = db.Provider.AddVerificationRequest(ctx, models.VerificationRequest{
Token: verificationToken, Token: verificationToken,
Identifier: verificationType, Identifier: verificationType,
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
@ -207,7 +207,10 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
} }
// exec it as go routin so that we can reduce the api latency // exec it as go routin so that we can reduce the api latency
go email.SendVerificationMail(params.Email, verificationToken, hostname) go func() {
email.SendVerificationMail(params.Email, verificationToken, hostname)
utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodBasicAuth, user)
}()
res = &model.AuthResponse{ res = &model.AuthResponse{
Message: `Verification email has been sent. Please check your inbox`, Message: `Verification email has been sent. Please check your inbox`,
@ -225,12 +228,6 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
return res, err return res, err
} }
go db.Provider.AddSession(models.Session{
UserID: user.ID,
UserAgent: utils.GetUserAgent(gc.Request),
IP: utils.GetIP(gc.Request),
})
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 { if expiresIn <= 0 {
expiresIn = 1 expiresIn = 1
@ -252,6 +249,15 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
res.RefreshToken = &authToken.RefreshToken.Token res.RefreshToken = &authToken.RefreshToken.Token
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
} }
go func() {
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodBasicAuth, user)
db.Provider.AddSession(ctx, models.Session{
UserID: user.ID,
UserAgent: utils.GetUserAgent(gc.Request),
IP: utils.GetIP(gc.Request),
})
}()
} }
return res, nil return res, nil

View File

@ -0,0 +1,109 @@
package resolvers
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/authorizerdev/authorizer/server/validators"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
)
// TestEndpointResolver resolver to test webhook endpoints
func TestEndpointResolver(ctx context.Context, params model.TestEndpointRequest) (*model.TestEndpointResponse, error) {
gc, err := utils.GinContextFromContext(ctx)
if err != nil {
log.Debug("Failed to get GinContext: ", err)
return nil, err
}
if !token.IsSuperAdmin(gc) {
log.Debug("Not logged in as super admin")
return nil, fmt.Errorf("unauthorized")
}
if !validators.IsValidWebhookEventName(params.EventName) {
log.Debug("Invalid event name: ", params.EventName)
return nil, fmt.Errorf("invalid event_name %s", params.EventName)
}
user := model.User{
ID: uuid.NewString(),
Email: "test_endpoint@foo.com",
EmailVerified: true,
SignupMethods: constants.AuthRecipeMethodMagicLinkLogin,
GivenName: utils.NewStringRef("Foo"),
FamilyName: utils.NewStringRef("Bar"),
}
userBytes, err := json.Marshal(user)
if err != nil {
log.Debug("error marshalling user obj: ", err)
return nil, err
}
userMap := map[string]interface{}{}
err = json.Unmarshal(userBytes, &userMap)
if err != nil {
log.Debug("error un-marshalling user obj: ", err)
return nil, err
}
reqBody := map[string]interface{}{
"event_name": constants.UserLoginWebhookEvent,
"user": userMap,
}
if params.EventName == constants.UserLoginWebhookEvent {
reqBody["auth_recipe"] = constants.AuthRecipeMethodMagicLinkLogin
}
requestBody, err := json.Marshal(reqBody)
if err != nil {
log.Debug("error marshalling requestBody obj: ", err)
return nil, err
}
req, err := http.NewRequest("POST", params.Endpoint, bytes.NewBuffer(requestBody))
if err != nil {
log.Debug("error creating post request: ", err)
return nil, err
}
req.Header.Set("Content-Type", "application/json")
for key, val := range params.Headers {
req.Header.Set(key, val.(string))
}
client := &http.Client{Timeout: time.Second * 30}
resp, err := client.Do(req)
if err != nil {
log.Debug("error making request: ", err)
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Debug("error reading response: ", err)
return nil, err
}
response := map[string]interface{}{}
if err := json.Unmarshal(body, &response); err != nil {
log.Debug("error un-marshalling response: ", err)
return nil, err
}
statusCode := int64(resp.StatusCode)
return &model.TestEndpointResponse{
HTTPStatus: &statusCode,
Response: response,
}, nil
}

View File

@ -287,7 +287,7 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
} }
// Fetch the current db store and update it // Fetch the current db store and update it
env, err := db.Provider.GetEnv() env, err := db.Provider.GetEnv(ctx)
if err != nil { if err != nil {
log.Debug("Failed to get env: ", err) log.Debug("Failed to get env: ", err)
return res, err return res, err
@ -314,7 +314,7 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
} }
env.EnvData = encryptedConfig env.EnvData = encryptedConfig
_, err = db.Provider.UpdateEnv(env) _, err = db.Provider.UpdateEnv(ctx, env)
if err != nil { if err != nil {
log.Debug("Failed to update env: ", err) log.Debug("Failed to update env: ", err)
return res, err return res, err

View File

@ -55,7 +55,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
"user_id": userID, "user_id": userID,
}) })
user, err := db.Provider.GetUserByID(userID) user, err := db.Provider.GetUserByID(ctx, userID)
if err != nil { if err != nil {
log.Debug("Failed to get user by id: ", err) log.Debug("Failed to get user by id: ", err)
return res, err return res, err
@ -135,7 +135,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
return res, fmt.Errorf("invalid new email address") return res, fmt.Errorf("invalid new email address")
} }
// check if user with new email exists // check if user with new email exists
_, err := db.Provider.GetUserByEmail(newEmail) _, err := db.Provider.GetUserByEmail(ctx, newEmail)
// err = nil means user exists // err = nil means user exists
if err == nil { if err == nil {
log.Debug("Failed to get user by email: ", newEmail) log.Debug("Failed to get user by email: ", newEmail)
@ -168,7 +168,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
log.Debug("Failed to create verification token: ", err) log.Debug("Failed to create verification token: ", err)
return res, err return res, err
} }
_, err = db.Provider.AddVerificationRequest(models.VerificationRequest{ _, err = db.Provider.AddVerificationRequest(ctx, models.VerificationRequest{
Token: verificationToken, Token: verificationToken,
Identifier: verificationType, Identifier: verificationType,
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
@ -186,7 +186,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
} }
} }
_, err = db.Provider.UpdateUser(user) _, err = db.Provider.UpdateUser(ctx, user)
if err != nil { if err != nil {
log.Debug("Failed to update user: ", err) log.Debug("Failed to update user: ", err)
return res, err return res, err

View File

@ -50,7 +50,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
return res, fmt.Errorf("please enter atleast one param to update") return res, fmt.Errorf("please enter atleast one param to update")
} }
user, err := db.Provider.GetUserByID(params.ID) user, err := db.Provider.GetUserByID(ctx, params.ID)
if err != nil { if err != nil {
log.Debug("Failed to get user by id: ", err) log.Debug("Failed to get user by id: ", err)
return res, fmt.Errorf(`User not found`) return res, fmt.Errorf(`User not found`)
@ -105,7 +105,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
} }
newEmail := strings.ToLower(*params.Email) newEmail := strings.ToLower(*params.Email)
// check if user with new email exists // check if user with new email exists
_, err = db.Provider.GetUserByEmail(newEmail) _, err = db.Provider.GetUserByEmail(ctx, newEmail)
// err = nil means user exists // err = nil means user exists
if err == nil { if err == nil {
log.Debug("User with email already exists: ", newEmail) log.Debug("User with email already exists: ", newEmail)
@ -130,7 +130,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
if err != nil { if err != nil {
log.Debug("Failed to create verification token: ", err) log.Debug("Failed to create verification token: ", err)
} }
_, err = db.Provider.AddVerificationRequest(models.VerificationRequest{ _, err = db.Provider.AddVerificationRequest(ctx, models.VerificationRequest{
Token: verificationToken, Token: verificationToken,
Identifier: verificationType, Identifier: verificationType,
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
@ -189,7 +189,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
user.Roles = rolesToSave user.Roles = rolesToSave
} }
user, err = db.Provider.UpdateUser(user) user, err = db.Provider.UpdateUser(ctx, user)
if err != nil { if err != nil {
log.Debug("Failed to update user: ", err) log.Debug("Failed to update user: ", err)
return res, err return res, err

View File

@ -0,0 +1,93 @@
package resolvers
import (
"context"
"encoding/json"
"fmt"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/authorizerdev/authorizer/server/validators"
log "github.com/sirupsen/logrus"
)
// UpdateWebhookResolver resolver for update webhook mutation
func UpdateWebhookResolver(ctx context.Context, params model.UpdateWebhookRequest) (*model.Response, error) {
gc, err := utils.GinContextFromContext(ctx)
if err != nil {
log.Debug("Failed to get GinContext: ", err)
return nil, err
}
if !token.IsSuperAdmin(gc) {
log.Debug("Not logged in as super admin")
return nil, fmt.Errorf("unauthorized")
}
webhook, err := db.Provider.GetWebhookByID(ctx, params.ID)
if err != nil {
log.Debug("failed to get webhook: ", err)
return nil, err
}
headersString := ""
if webhook.Headers != nil {
headerBytes, err := json.Marshal(webhook.Headers)
if err != nil {
log.Debug("failed to marshall source headers: ", err)
}
headersString = string(headerBytes)
}
webhookDetails := models.Webhook{
ID: webhook.ID,
Key: webhook.ID,
EventName: utils.StringValue(webhook.EventName),
EndPoint: utils.StringValue(webhook.Endpoint),
Enabled: utils.BoolValue(webhook.Enabled),
Headers: headersString,
CreatedAt: *webhook.CreatedAt,
}
if params.EventName != nil && webhookDetails.EventName != utils.StringValue(params.EventName) {
if isValid := validators.IsValidWebhookEventName(utils.StringValue(params.EventName)); !isValid {
log.Debug("invalid event name: ", utils.StringValue(params.EventName))
return nil, fmt.Errorf("invalid event name %s", utils.StringValue(params.EventName))
}
webhookDetails.EventName = utils.StringValue(params.EventName)
}
if params.Endpoint != nil && webhookDetails.EndPoint != utils.StringValue(params.Endpoint) {
webhookDetails.EventName = utils.StringValue(params.EventName)
}
if params.Enabled != nil && webhookDetails.Enabled != utils.BoolValue(params.Enabled) {
webhookDetails.Enabled = utils.BoolValue(params.Enabled)
}
if params.Headers != nil {
for key, val := range params.Headers {
webhook.Headers[key] = val
}
headerBytes, err := json.Marshal(webhook.Headers)
if err != nil {
log.Debug("failed to marshall headers: ", err)
return nil, err
}
webhookDetails.Headers = string(headerBytes)
}
_, err = db.Provider.UpdateWebhook(ctx, webhookDetails)
if err != nil {
return nil, err
}
return &model.Response{
Message: `Webhook updated successfully.`,
}, nil
}

View File

@ -28,7 +28,7 @@ func UsersResolver(ctx context.Context, params *model.PaginatedInput) (*model.Us
pagination := utils.GetPagination(params) pagination := utils.GetPagination(params)
res, err := db.Provider.ListUsers(pagination) res, err := db.Provider.ListUsers(ctx, pagination)
if err != nil { if err != nil {
log.Debug("Failed to get users: ", err) log.Debug("Failed to get users: ", err)
return nil, err return nil, err

View File

@ -28,7 +28,7 @@ func VerificationRequestsResolver(ctx context.Context, params *model.PaginatedIn
pagination := utils.GetPagination(params) pagination := utils.GetPagination(params)
res, err := db.Provider.ListVerificationRequests(pagination) res, err := db.Provider.ListVerificationRequests(ctx, pagination)
if err != nil { if err != nil {
log.Debug("Failed to get verification requests: ", err) log.Debug("Failed to get verification requests: ", err)
return nil, err return nil, err

View File

@ -29,7 +29,7 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
return res, err return res, err
} }
verificationRequest, err := db.Provider.GetVerificationRequestByToken(params.Token) verificationRequest, err := db.Provider.GetVerificationRequestByToken(ctx, params.Token)
if err != nil { if err != nil {
log.Debug("Failed to get verification request by token: ", err) log.Debug("Failed to get verification request by token: ", err)
return res, fmt.Errorf(`invalid token: %s`, err.Error()) return res, fmt.Errorf(`invalid token: %s`, err.Error())
@ -52,22 +52,26 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
log := log.WithFields(log.Fields{ log := log.WithFields(log.Fields{
"email": email, "email": email,
}) })
user, err := db.Provider.GetUserByEmail(email) user, err := db.Provider.GetUserByEmail(ctx, email)
if err != nil { if err != nil {
log.Debug("Failed to get user by email: ", err) log.Debug("Failed to get user by email: ", err)
return res, err return res, err
} }
// update email_verified_at in users table isSignUp := false
now := time.Now().Unix() if user.EmailVerifiedAt == nil {
user.EmailVerifiedAt = &now isSignUp = true
user, err = db.Provider.UpdateUser(user) // update email_verified_at in users table
if err != nil { now := time.Now().Unix()
log.Debug("Failed to update user: ", err) user.EmailVerifiedAt = &now
return res, err user, err = db.Provider.UpdateUser(ctx, user)
if err != nil {
log.Debug("Failed to update user: ", err)
return res, err
}
} }
// delete from verification table // delete from verification table
err = db.Provider.DeleteVerificationRequest(verificationRequest) err = db.Provider.DeleteVerificationRequest(gc, verificationRequest)
if err != nil { if err != nil {
log.Debug("Failed to delete verification request: ", err) log.Debug("Failed to delete verification request: ", err)
return res, err return res, err
@ -86,12 +90,19 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
return res, err return res, err
} }
go db.Provider.AddSession(models.Session{ go func() {
UserID: user.ID, if isSignUp {
UserAgent: utils.GetUserAgent(gc.Request), utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user)
IP: utils.GetIP(gc.Request), } else {
}) utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user)
}
db.Provider.AddSession(ctx, models.Session{
UserID: user.ID,
UserAgent: utils.GetUserAgent(gc.Request),
IP: utils.GetIP(gc.Request),
})
}()
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 { if expiresIn <= 0 {
expiresIn = 1 expiresIn = 1

View File

@ -0,0 +1,33 @@
package resolvers
import (
"context"
"fmt"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils"
log "github.com/sirupsen/logrus"
)
// WebhookResolver resolver for getting webhook by identifier
func WebhookResolver(ctx context.Context, params model.WebhookRequest) (*model.Webhook, error) {
gc, err := utils.GinContextFromContext(ctx)
if err != nil {
log.Debug("Failed to get GinContext: ", err)
return nil, err
}
if !token.IsSuperAdmin(gc) {
log.Debug("Not logged in as super admin")
return nil, fmt.Errorf("unauthorized")
}
webhook, err := db.Provider.GetWebhookByID(ctx, params.ID)
if err != nil {
log.Debug("error getting webhook: ", err)
return nil, err
}
return webhook, nil
}

View File

@ -0,0 +1,37 @@
package resolvers
import (
"context"
"fmt"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils"
log "github.com/sirupsen/logrus"
)
// WebhookLogsResolver resolver for getting the list of webhook_logs based on pagination & webhook identifier
func WebhookLogsResolver(ctx context.Context, params model.ListWebhookLogRequest) (*model.WebhookLogs, error) {
gc, err := utils.GinContextFromContext(ctx)
if err != nil {
log.Debug("Failed to get GinContext: ", err)
return nil, err
}
if !token.IsSuperAdmin(gc) {
log.Debug("Not logged in as super admin")
return nil, fmt.Errorf("unauthorized")
}
pagination := utils.GetPagination(&model.PaginatedInput{
Pagination: params.Pagination,
})
webhookLogs, err := db.Provider.ListWebhookLogs(ctx, pagination, utils.StringValue(params.WebhookID))
if err != nil {
log.Debug("failed to get webhook logs: ", err)
return nil, err
}
return webhookLogs, nil
}

View File

@ -0,0 +1,35 @@
package resolvers
import (
"context"
"fmt"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils"
log "github.com/sirupsen/logrus"
)
// WebhooksResolver resolver for getting the list of webhooks based on pagination
func WebhooksResolver(ctx context.Context, params *model.PaginatedInput) (*model.Webhooks, error) {
gc, err := utils.GinContextFromContext(ctx)
if err != nil {
log.Debug("Failed to get GinContext: ", err)
return nil, err
}
if !token.IsSuperAdmin(gc) {
log.Debug("Not logged in as super admin")
return nil, fmt.Errorf("unauthorized")
}
pagination := utils.GetPagination(params)
webhooks, err := db.Provider.ListWebhook(ctx, pagination)
if err != nil {
log.Debug("failed to get webhook logs: ", err)
return nil, err
}
return webhooks, nil
}

View File

@ -32,7 +32,7 @@ func InitRouter(log *logrus.Logger) *gin.Engine {
router.GET("/userinfo", handlers.UserInfoHandler()) router.GET("/userinfo", handlers.UserInfoHandler())
router.GET("/logout", handlers.LogoutHandler()) router.GET("/logout", handlers.LogoutHandler())
router.POST("/oauth/token", handlers.TokenHandler()) router.POST("/oauth/token", handlers.TokenHandler())
router.POST("/oauth/revoke", handlers.RevokeHandler()) router.POST("/oauth/revoke", handlers.RevokeRefreshTokenHandler())
router.LoadHTMLGlob("templates/*") router.LoadHTMLGlob("templates/*")
// login page app related routes. // login page app related routes.

View File

@ -0,0 +1,39 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert"
)
func addWebhookTest(t *testing.T, s TestSetup) {
t.Helper()
t.Run("should add webhook", func(t *testing.T) {
req, ctx := createContext(s)
adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)
assert.NoError(t, err)
h, err := crypto.EncryptPassword(adminSecret)
assert.NoError(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h))
for _, eventType := range s.TestInfo.TestEventTypes {
webhook, err := resolvers.AddWebhookResolver(ctx, model.AddWebhookRequest{
EventName: eventType,
Endpoint: s.TestInfo.WebhookEndpoint,
Enabled: true,
Headers: map[string]interface{}{
"x-test": "foo",
},
})
assert.NoError(t, err)
assert.NotNil(t, webhook)
assert.NotEmpty(t, webhook.Message)
}
})
}

View File

@ -0,0 +1,50 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert"
)
func deleteWebhookTest(t *testing.T, s TestSetup) {
t.Helper()
t.Run("should delete webhook", func(t *testing.T) {
req, ctx := createContext(s)
adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)
assert.NoError(t, err)
h, err := crypto.EncryptPassword(adminSecret)
assert.NoError(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h))
// get all webhooks
webhooks, err := db.Provider.ListWebhook(ctx, model.Pagination{})
assert.NoError(t, err)
for _, w := range webhooks.Webhooks {
res, err := resolvers.DeleteWebhookResolver(ctx, model.WebhookRequest{
ID: w.ID,
})
assert.NoError(t, err)
assert.NotNil(t, res)
assert.NotEmpty(t, res.Message)
}
webhooks, err = db.Provider.ListWebhook(ctx, model.Pagination{})
assert.NoError(t, err)
assert.Len(t, webhooks.Webhooks, 0)
webhookLogs, err := db.Provider.ListWebhookLogs(ctx, model.Pagination{
Limit: 10,
}, "")
assert.NoError(t, err)
assert.Len(t, webhookLogs.WebhookLogs, 0)
})
}

View File

@ -22,7 +22,7 @@ func enableAccessTest(t *testing.T, s TestSetup) {
Email: email, Email: email,
}) })
assert.NoError(t, err) assert.NoError(t, err)
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeMagicLinkLogin) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin)
verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })

View File

@ -26,7 +26,7 @@ func forgotPasswordTest(t *testing.T, s TestSetup) {
}) })
assert.Nil(t, err, "no errors for forgot password") assert.Nil(t, err, "no errors for forgot password")
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeForgotPassword) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeForgotPassword)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, verificationRequest.Identifier, constants.VerificationTypeForgotPassword) assert.Equal(t, verificationRequest.Identifier, constants.VerificationTypeForgotPassword)

View File

@ -29,7 +29,7 @@ func loginTests(t *testing.T, s TestSetup) {
assert.NotNil(t, err, "should fail because email is not verified") assert.NotNil(t, err, "should fail because email is not verified")
assert.Nil(t, res) assert.Nil(t, res)
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
n, err := utils.EncryptNonce(verificationRequest.Nonce) n, err := utils.EncryptNonce(verificationRequest.Nonce)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotEmpty(t, n) assert.NotEmpty(t, n)

View File

@ -24,7 +24,7 @@ func logoutTests(t *testing.T, s TestSetup) {
Email: email, Email: email,
}) })
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeMagicLinkLogin) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin)
verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })

View File

@ -29,7 +29,7 @@ func magicLinkLoginTests(t *testing.T, s TestSetup) {
}) })
assert.Nil(t, err, "signup should be successful") assert.Nil(t, err, "signup should be successful")
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeMagicLinkLogin) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin)
verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })

View File

@ -26,7 +26,7 @@ func profileTests(t *testing.T, s TestSetup) {
_, err := resolvers.ProfileResolver(ctx) _, err := resolvers.ProfileResolver(ctx)
assert.NotNil(t, err, "unauthorized") assert.NotNil(t, err, "unauthorized")
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })

View File

@ -26,7 +26,7 @@ func resetPasswordTest(t *testing.T, s TestSetup) {
}) })
assert.Nil(t, err, "no errors for forgot password") assert.Nil(t, err, "no errors for forgot password")
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeForgotPassword) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeForgotPassword)
assert.Nil(t, err, "should get forgot password request") assert.Nil(t, err, "should get forgot password request")
_, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{ _, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{

View File

@ -1,7 +1,9 @@
package test package test
import ( import (
"context"
"testing" "testing"
"time"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
@ -12,14 +14,15 @@ import (
func TestResolvers(t *testing.T) { func TestResolvers(t *testing.T) {
databases := map[string]string{ databases := map[string]string{
constants.DbTypeSqlite: "../../data.db", constants.DbTypeSqlite: "../../data.db",
// constants.DbTypeArangodb: "http://localhost:8529", // constants.DbTypeArangodb: "http://localhost:8529",
// constants.DbTypeMongodb: "mongodb://localhost:27017", // constants.DbTypeMongodb: "mongodb://localhost:27017",
// constants.DbTypeCassandraDB: "127.0.0.1:9042", // constants.DbTypeCassandraDB: "127.0.0.1:9042",
} }
for dbType, dbURL := range databases { for dbType, dbURL := range databases {
s := testSetup() s := testSetup()
defer s.Server.Close() defer s.Server.Close()
ctx := context.Background()
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseURL, dbURL) memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseURL, dbURL)
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseType, dbType) memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseType, dbType)
@ -29,19 +32,24 @@ func TestResolvers(t *testing.T) {
} }
// clean the persisted config for test to use fresh config // clean the persisted config for test to use fresh config
envData, err := db.Provider.GetEnv() envData, err := db.Provider.GetEnv(ctx)
if err == nil { if err == nil {
envData.EnvData = "" envData.EnvData = ""
db.Provider.UpdateEnv(envData) db.Provider.UpdateEnv(ctx, envData)
} }
env.PersistEnv() env.PersistEnv()
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEnv, "test") memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEnv, "test")
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyIsProd, false) memorystore.Provider.UpdateEnvVariable(constants.EnvKeyIsProd, false)
t.Run("should pass tests for "+dbType, func(t *testing.T) { t.Run("should pass tests for "+dbType, func(t *testing.T) {
// admin tests // admin resolvers tests
adminSignupTests(t, s) adminSignupTests(t, s)
addWebhookTest(t, s) // add webhooks for all the system events
testEndpointTest(t, s)
verificationRequestsTest(t, s) verificationRequestsTest(t, s)
updateWebhookTest(t, s)
webhookTest(t, s)
webhooksTest(t, s)
usersTest(t, s) usersTest(t, s)
deleteUserTest(t, s) deleteUserTest(t, s)
updateUserTest(t, s) updateUserTest(t, s)
@ -54,7 +62,7 @@ func TestResolvers(t *testing.T) {
enableAccessTest(t, s) enableAccessTest(t, s)
generateJWTkeyTest(t, s) generateJWTkeyTest(t, s)
// user tests // user resolvers tests
loginTests(t, s) loginTests(t, s)
signupTests(t, s) signupTests(t, s)
forgotPasswordTest(t, s) forgotPasswordTest(t, s)
@ -69,6 +77,10 @@ func TestResolvers(t *testing.T) {
metaTests(t, s) metaTests(t, s)
inviteUserTest(t, s) inviteUserTest(t, s)
validateJwtTokenTest(t, s) validateJwtTokenTest(t, s)
time.Sleep(5 * time.Second) // add sleep for webhooklogs to get generated as they are async
webhookLogsTest(t, s) // get logs after above resolver tests are done
deleteWebhookTest(t, s) // delete webhooks (admin resolver)
}) })
} }
} }

View File

@ -22,7 +22,7 @@ func revokeAccessTest(t *testing.T, s TestSetup) {
Email: email, Email: email,
}) })
assert.NoError(t, err) assert.NoError(t, err)
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeMagicLinkLogin) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin)
verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })

View File

@ -29,7 +29,7 @@ func sessionTests(t *testing.T, s TestSetup) {
_, err := resolvers.SessionResolver(ctx, &model.SessionQueryInput{}) _, err := resolvers.SessionResolver(ctx, &model.SessionQueryInput{})
assert.NotNil(t, err, "unauthorized") assert.NotNil(t, err, "unauthorized")
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })

View File

@ -57,7 +57,7 @@ func signupTests(t *testing.T, s TestSetup) {
assert.NotNil(t, err, "should throw duplicate email error") assert.NotNil(t, err, "should throw duplicate email error")
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, email, verificationRequest.Email) assert.Equal(t, email, verificationRequest.Email)
cleanData(email) cleanData(email)

View File

@ -21,8 +21,10 @@ import (
// common user data to share across tests // common user data to share across tests
type TestData struct { type TestData struct {
Email string Email string
Password string Password string
WebhookEndpoint string
TestEventTypes []string
} }
type TestSetup struct { type TestSetup struct {
@ -33,30 +35,31 @@ type TestSetup struct {
} }
func cleanData(email string) { func cleanData(email string) {
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) ctx := context.Background()
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
if err == nil { if err == nil {
err = db.Provider.DeleteVerificationRequest(verificationRequest) err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest)
} }
verificationRequest, err = db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeForgotPassword) verificationRequest, err = db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeForgotPassword)
if err == nil { if err == nil {
err = db.Provider.DeleteVerificationRequest(verificationRequest) err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest)
} }
verificationRequest, err = db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeUpdateEmail) verificationRequest, err = db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeUpdateEmail)
if err == nil { if err == nil {
err = db.Provider.DeleteVerificationRequest(verificationRequest) err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest)
} }
verificationRequest, err = db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeMagicLinkLogin) verificationRequest, err = db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeMagicLinkLogin)
if err == nil { if err == nil {
err = db.Provider.DeleteVerificationRequest(verificationRequest) err = db.Provider.DeleteVerificationRequest(ctx, verificationRequest)
} }
dbUser, err := db.Provider.GetUserByEmail(email) dbUser, err := db.Provider.GetUserByEmail(ctx, email)
if err == nil { if err == nil {
db.Provider.DeleteUser(dbUser) db.Provider.DeleteUser(ctx, dbUser)
db.Provider.DeleteSession(dbUser.ID) db.Provider.DeleteSession(ctx, dbUser.ID)
} }
} }
@ -74,8 +77,10 @@ func createContext(s TestSetup) (*http.Request, context.Context) {
func testSetup() TestSetup { func testSetup() TestSetup {
testData := TestData{ testData := TestData{
Email: fmt.Sprintf("%d_authorizer_tester@yopmail.com", time.Now().Unix()), Email: fmt.Sprintf("%d_authorizer_tester@yopmail.com", time.Now().Unix()),
Password: "Test@123", Password: "Test@123",
WebhookEndpoint: "https://62cbc6738042b16aa7c22df2.mockapi.io/api/v1/webhook",
TestEventTypes: []string{constants.UserAccessEnabledWebhookEvent, constants.UserAccessRevokedWebhookEvent, constants.UserCreatedWebhookEvent, constants.UserDeletedWebhookEvent, constants.UserLoginWebhookEvent, constants.UserSignUpWebhookEvent},
} }
err := os.Setenv(constants.EnvKeyEnvPath, "../../.env.test") err := os.Setenv(constants.EnvKeyEnvPath, "../../.env.test")

View File

@ -0,0 +1,37 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert"
)
func testEndpointTest(t *testing.T, s TestSetup) {
t.Helper()
t.Run("should test endpoint", func(t *testing.T) {
req, ctx := createContext(s)
adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)
assert.NoError(t, err)
h, err := crypto.EncryptPassword(adminSecret)
assert.NoError(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h))
res, err := resolvers.TestEndpointResolver(ctx, model.TestEndpointRequest{
Endpoint: s.TestInfo.WebhookEndpoint,
EventName: constants.UserLoginWebhookEvent,
Headers: map[string]interface{}{
"x-test": "test",
},
})
assert.NoError(t, err)
assert.NotNil(t, res)
assert.GreaterOrEqual(t, int64(201), *res.HTTPStatus)
assert.NotEmpty(t, res.Response)
})
}

View File

@ -29,7 +29,7 @@ func updateProfileTests(t *testing.T, s TestSetup) {
}) })
assert.NotNil(t, err, "unauthorized") assert.NotNil(t, err, "unauthorized")
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{ verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
Token: verificationRequest.Token, Token: verificationRequest.Token,
}) })

View File

@ -0,0 +1,60 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
func updateWebhookTest(t *testing.T, s TestSetup) {
t.Helper()
t.Run("should update webhook", func(t *testing.T) {
req, ctx := createContext(s)
adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)
assert.NoError(t, err)
h, err := crypto.EncryptPassword(adminSecret)
assert.NoError(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h))
// get webhook
webhook, err := db.Provider.GetWebhookByEventName(ctx, constants.UserDeletedWebhookEvent)
assert.NoError(t, err)
assert.NotNil(t, webhook)
webhook.Headers["x-new-test"] = "new-test"
res, err := resolvers.UpdateWebhookResolver(ctx, model.UpdateWebhookRequest{
ID: webhook.ID,
Headers: webhook.Headers,
Enabled: utils.NewBoolRef(false),
})
assert.NoError(t, err)
assert.NotEmpty(t, res)
assert.NotEmpty(t, res.Message)
updatedWebhook, err := db.Provider.GetWebhookByEventName(ctx, constants.UserDeletedWebhookEvent)
assert.NoError(t, err)
assert.NotNil(t, updatedWebhook)
assert.Equal(t, webhook.ID, updatedWebhook.ID)
assert.Equal(t, utils.StringValue(webhook.EventName), utils.StringValue(updatedWebhook.EventName))
assert.Equal(t, utils.StringValue(webhook.Endpoint), utils.StringValue(updatedWebhook.Endpoint))
assert.Len(t, updatedWebhook.Headers, 2)
assert.False(t, utils.BoolValue(updatedWebhook.Enabled))
res, err = resolvers.UpdateWebhookResolver(ctx, model.UpdateWebhookRequest{
ID: webhook.ID,
Headers: webhook.Headers,
Enabled: utils.NewBoolRef(true),
})
assert.NoError(t, err)
assert.NotEmpty(t, res)
assert.NotEmpty(t, res.Message)
})
}

View File

@ -24,7 +24,7 @@ func verifyEmailTest(t *testing.T, s TestSetup) {
user := *res.User user := *res.User
assert.Equal(t, email, user.Email) assert.Equal(t, email, user.Email)
assert.Nil(t, res.AccessToken, "access token should be nil") assert.Nil(t, res.AccessToken, "access token should be nil")
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeBasicAuthSignup) verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, email, verificationRequest.Email) assert.Equal(t, email, verificationRequest.Email)

View File

@ -0,0 +1,45 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
func webhookLogsTest(t *testing.T, s TestSetup) {
t.Helper()
t.Run("should get webhook logs", func(t *testing.T) {
req, ctx := createContext(s)
adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)
assert.NoError(t, err)
h, err := crypto.EncryptPassword(adminSecret)
assert.NoError(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h))
webhooks, err := resolvers.WebhooksResolver(ctx, nil)
assert.NoError(t, err)
assert.NotEmpty(t, webhooks)
webhookLogs, err := resolvers.WebhookLogsResolver(ctx, model.ListWebhookLogRequest{})
assert.NoError(t, err)
assert.Greater(t, len(webhookLogs.WebhookLogs), 1)
for _, w := range webhooks.Webhooks {
webhookLogs, err := resolvers.WebhookLogsResolver(ctx, model.ListWebhookLogRequest{
WebhookID: &w.ID,
})
assert.NoError(t, err)
assert.GreaterOrEqual(t, len(webhookLogs.WebhookLogs), 1)
for _, wl := range webhookLogs.WebhookLogs {
assert.Equal(t, utils.StringValue(wl.WebhookID), w.ID)
}
}
})
}

View File

@ -0,0 +1,42 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/stretchr/testify/assert"
)
func webhookTest(t *testing.T, s TestSetup) {
t.Helper()
t.Run("should get webhook", func(t *testing.T) {
req, ctx := createContext(s)
adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)
assert.NoError(t, err)
h, err := crypto.EncryptPassword(adminSecret)
assert.NoError(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h))
// get webhook by event name
webhook, err := db.Provider.GetWebhookByEventName(ctx, constants.UserCreatedWebhookEvent)
assert.NoError(t, err)
assert.NotNil(t, webhook)
res, err := resolvers.WebhookResolver(ctx, model.WebhookRequest{
ID: webhook.ID,
})
assert.NoError(t, err)
assert.Equal(t, res.ID, webhook.ID)
assert.Equal(t, utils.StringValue(res.Endpoint), utils.StringValue(webhook.Endpoint))
assert.Equal(t, utils.StringValue(res.EventName), utils.StringValue(webhook.EventName))
assert.Equal(t, utils.BoolValue(res.Enabled), utils.BoolValue(webhook.Enabled))
assert.Len(t, res.Headers, len(webhook.Headers))
})
}

View File

@ -0,0 +1,29 @@
package test
import (
"fmt"
"testing"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert"
)
func webhooksTest(t *testing.T, s TestSetup) {
t.Helper()
t.Run("should get webhooks", func(t *testing.T) {
req, ctx := createContext(s)
adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)
assert.NoError(t, err)
h, err := crypto.EncryptPassword(adminSecret)
assert.NoError(t, err)
req.Header.Set("Cookie", fmt.Sprintf("%s=%s", constants.AdminCookieName, h))
webhooks, err := resolvers.WebhooksResolver(ctx, nil)
assert.NoError(t, err)
assert.NotEmpty(t, webhooks)
assert.Len(t, webhooks.Webhooks, len(s.TestInfo.TestEventTypes))
})
}

View File

@ -4,3 +4,27 @@ package utils
func NewStringRef(v string) *string { func NewStringRef(v string) *string {
return &v return &v
} }
// StringValue returns the value of the given string ref
func StringValue(r *string, defaultValue ...string) string {
if r != nil {
return *r
}
if len(defaultValue) > 0 {
return defaultValue[0]
}
return ""
}
// NewBoolRef returns a reference to a bool with given value
func NewBoolRef(v bool) *bool {
return &v
}
// BoolValue returns the value of the given bool ref
func BoolValue(r *bool) bool {
if r == nil {
return false
}
return *r
}

96
server/utils/webhook.go Normal file
View File

@ -0,0 +1,96 @@
package utils
import (
"bytes"
"context"
"encoding/json"
"io/ioutil"
"net/http"
"time"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/db/models"
log "github.com/sirupsen/logrus"
)
func RegisterEvent(ctx context.Context, eventName string, authRecipe string, user models.User) error {
webhook, err := db.Provider.GetWebhookByEventName(ctx, eventName)
if err != nil {
return err
}
if !BoolValue(webhook.Enabled) {
return nil
}
userBytes, err := json.Marshal(user.AsAPIUser())
if err != nil {
log.Debug("error marshalling user obj: ", err)
return err
}
userMap := map[string]interface{}{}
err = json.Unmarshal(userBytes, &userMap)
if err != nil {
log.Debug("error un-marshalling user obj: ", err)
return err
}
reqBody := map[string]interface{}{
"event_name": eventName,
"user": userMap,
}
if eventName == constants.UserLoginWebhookEvent || eventName == constants.UserSignUpWebhookEvent {
reqBody["auth_recipe"] = authRecipe
}
requestBody, err := json.Marshal(reqBody)
if err != nil {
log.Debug("error marshalling requestBody obj: ", err)
return err
}
requestBytesBuffer := bytes.NewBuffer(requestBody)
req, err := http.NewRequest("POST", StringValue(webhook.Endpoint), requestBytesBuffer)
if err != nil {
log.Debug("error creating webhook post request: ", err)
return err
}
req.Header.Set("Content-Type", "application/json")
if webhook.Headers != nil {
for key, val := range webhook.Headers {
req.Header.Set(key, val.(string))
}
}
client := &http.Client{Timeout: time.Second * 30}
resp, err := client.Do(req)
if err != nil {
log.Debug("error making request: ", err)
return err
}
defer resp.Body.Close()
responseBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Debug("error reading response: ", err)
return err
}
statusCode := int64(resp.StatusCode)
_, err = db.Provider.AddWebhookLog(ctx, models.WebhookLog{
HttpStatus: statusCode,
Request: string(requestBody),
Response: string(responseBytes),
WebhookID: webhook.ID,
})
if err != nil {
log.Debug("failed to add webhook log: ", err)
return err
}
return nil
}

Some files were not shown because too many files have changed in this diff Show More