Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
330f35f2fc | ||
![]() |
70242debe1 | ||
![]() |
4018da6697 | ||
![]() |
a73c6ee49e | ||
![]() |
c23fb1bb32 | ||
![]() |
270853a6a3 | ||
![]() |
2d0346ff23 | ||
![]() |
4b26e1ce85 | ||
![]() |
8212e81023 | ||
![]() |
642581eefd | ||
![]() |
b7357dde21 | ||
![]() |
a1df2ce31f | ||
![]() |
748761926d | ||
![]() |
d632195ba5 | ||
![]() |
25970f80e1 | ||
![]() |
a52b7c86e7 | ||
![]() |
504d0f34d7 | ||
![]() |
44879f1a8f |
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.19.1-alpine as go-builder
|
||||
FROM golang:1.19.5-alpine as go-builder
|
||||
WORKDIR /authorizer
|
||||
COPY server server
|
||||
COPY Makefile .
|
||||
|
14
Makefile
14
Makefile
@@ -26,23 +26,31 @@ test-scylladb:
|
||||
cd server && go clean --testcache && TEST_DBS="scylladb" go test -p 1 -v ./test
|
||||
docker rm -vf authorizer_scylla_db
|
||||
test-arangodb:
|
||||
docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.8.4
|
||||
docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.10.3
|
||||
cd server && go clean --testcache && TEST_DBS="arangodb" go test -p 1 -v ./test
|
||||
docker rm -vf authorizer_arangodb
|
||||
test-dynamodb:
|
||||
docker run -d --name dynamodb-local-test -p 8000:8000 amazon/dynamodb-local:latest
|
||||
cd server && go clean --testcache && TEST_DBS="dynamodb" go test -p 1 -v ./test
|
||||
docker rm -vf dynamodb-local-test
|
||||
test-couchbase:
|
||||
docker run -d --name couchbase-local-test -p 8091-8097:8091-8097 -p 11210:11210 -p 11207:11207 -p 18091-18095:18091-18095 -p 18096:18096 -p 18097:18097 couchbase:latest
|
||||
sh scripts/couchbase-test.sh
|
||||
cd server && go clean --testcache && TEST_DBS="couchbase" go test -p 1 -v ./test
|
||||
docker rm -vf couchbase-local-test
|
||||
test-all-db:
|
||||
rm -rf server/test/test.db server/test/test.db-shm server/test/test.db-wal && rm -rf test.db test.db-shm test.db-wal
|
||||
docker run -d --name authorizer_scylla_db -p 9042:9042 scylladb/scylla
|
||||
docker run -d --name authorizer_mongodb_db -p 27017:27017 mongo:4.4.15
|
||||
docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.8.4
|
||||
docker run -d --name dynamodb-local-test -p 8000:8000 amazon/dynamodb-local:latest
|
||||
docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.10.3
|
||||
docker run -d --name dynamodb-local-test -p 8000:8000 amazon/dynamodb-local:latest
|
||||
docker run -d --name couchbase-local-test -p 8091-8097:8091-8097 -p 11210:11210 -p 11207:11207 -p 18091-18095:18091-18095 -p 18096:18096 -p 18097:18097 couchbase:latest
|
||||
sh scripts/couchbase-test.sh
|
||||
cd server && go clean --testcache && TEST_DBS="sqlite,mongodb,arangodb,scylladb,dynamodb" go test -p 1 -v ./test
|
||||
docker rm -vf authorizer_scylla_db
|
||||
docker rm -vf authorizer_mongodb_db
|
||||
docker rm -vf authorizer_arangodb
|
||||
docker rm -vf dynamodb-local-test
|
||||
# docker rm -vf couchbase-local-test
|
||||
generate:
|
||||
cd server && go run github.com/99designs/gqlgen generate && go mod tidy
|
||||
|
14
app/package-lock.json
generated
14
app/package-lock.json
generated
@@ -9,7 +9,7 @@
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-react": "^1.1.4",
|
||||
"@authorizerdev/authorizer-react": "^1.1.7",
|
||||
"@types/react": "^17.0.15",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"esbuild": "^0.12.17",
|
||||
@@ -38,9 +38,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@authorizerdev/authorizer-react": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.4.tgz",
|
||||
"integrity": "sha512-FBH2igXFM8+TdA2hl1S/HMzt1+OL5wWUow3+Zyiq+IkG9nIjWFlM7ebo4D0zJd875IJiabYFnXqstRABo0ysIQ==",
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.7.tgz",
|
||||
"integrity": "sha512-JYwwOjlKjKx8RX0RLcXIhWacugBE241BDmKq4z20B2hq8xTy3cPbKC+UY3lkp+IiMtrIvHZJ9es26UR9NTUlXA==",
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-js": "^1.1.2"
|
||||
},
|
||||
@@ -842,9 +842,9 @@
|
||||
}
|
||||
},
|
||||
"@authorizerdev/authorizer-react": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.4.tgz",
|
||||
"integrity": "sha512-FBH2igXFM8+TdA2hl1S/HMzt1+OL5wWUow3+Zyiq+IkG9nIjWFlM7ebo4D0zJd875IJiabYFnXqstRABo0ysIQ==",
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.7.tgz",
|
||||
"integrity": "sha512-JYwwOjlKjKx8RX0RLcXIhWacugBE241BDmKq4z20B2hq8xTy3cPbKC+UY3lkp+IiMtrIvHZJ9es26UR9NTUlXA==",
|
||||
"requires": {
|
||||
"@authorizerdev/authorizer-js": "^1.1.2"
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@
|
||||
"author": "Lakhan Samani",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-react": "^1.1.4",
|
||||
"@authorizerdev/authorizer-react": "^1.1.7",
|
||||
"@types/react": "^17.0.15",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"esbuild": "^0.12.17",
|
||||
|
39
scripts/couchbase-test.sh
Normal file
39
scripts/couchbase-test.sh
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -x
|
||||
set -m
|
||||
|
||||
sleep 15
|
||||
|
||||
# Setup index and memory quota
|
||||
# curl -v -X POST http://127.0.0.1:8091/pools/default -d memoryQuota=300 -d indexMemoryQuota=300
|
||||
|
||||
# Setup services
|
||||
curl -v http://127.0.0.1:8091/node/controller/setupServices -d services=kv%2Cn1ql%2Cindex
|
||||
|
||||
# Setup credentials
|
||||
curl -v http://127.0.0.1:8091/settings/web -d port=8091 -d username=Administrator -d password=password
|
||||
|
||||
# Setup Memory Optimized Indexes
|
||||
curl -i -u Administrator:password -X POST http://127.0.0.1:8091/settings/indexes -d 'storageMode=memory_optimized'
|
||||
|
||||
# Load travel-sample bucket
|
||||
#curl -v -u Administrator:password -X POST http://127.0.0.1:8091/sampleBuckets/install -d '["travel-sample"]'
|
||||
|
||||
echo "Type: $TYPE"
|
||||
|
||||
if [ "$TYPE" = "WORKER" ]; then
|
||||
echo "Sleeping ..."
|
||||
sleep 15
|
||||
|
||||
#IP=`hostname -s`
|
||||
IP=`hostname -I | cut -d ' ' -f1`
|
||||
echo "IP: " $IP
|
||||
|
||||
echo "Auto Rebalance: $AUTO_REBALANCE"
|
||||
if [ "$AUTO_REBALANCE" = "true" ]; then
|
||||
couchbase-cli rebalance --cluster=$COUCHBASE_MASTER:8091 --user=Administrator --password=password --server-add=$IP --server-add-username=Administrator --server-add-password=password
|
||||
else
|
||||
couchbase-cli server-add --cluster=$COUCHBASE_MASTER:8091 --user=Administrator --password=password --server-add=$IP --server-add-username=Administrator --server-add-password=password
|
||||
fi;
|
||||
fi;
|
@@ -27,4 +27,6 @@ const (
|
||||
DbTypePlanetScaleDB = "planetscale"
|
||||
// DbTypeDynamoDB is the Dynamo database type
|
||||
DbTypeDynamoDB = "dynamodb"
|
||||
// DbTypeCouchbaseDB is the Couchbase database type
|
||||
DbTypeCouchbaseDB = "couchbase"
|
||||
)
|
||||
|
@@ -43,6 +43,13 @@ const (
|
||||
EnvKeyDatabaseCertKey = "DATABASE_CERT_KEY"
|
||||
// EnvKeyDatabaseCACert key for env variable DATABASE_CA_CERT
|
||||
EnvKeyDatabaseCACert = "DATABASE_CA_CERT"
|
||||
// EnvCouchbaseBucket key for env variable COUCHBASE_BUCKET
|
||||
EnvCouchbaseBucket = "COUCHBASE_BUCKET"
|
||||
// EnvCouchbaseBucketRAMQuotaMB key for env variable COUCHBASE_BUCKET_RAM_QUOTA
|
||||
// This value should be parsed as number
|
||||
EnvCouchbaseBucketRAMQuotaMB = "COUCHBASE_BUCKET_RAM_QUOTA"
|
||||
// EnvCouchbaseBucket key for env variable COUCHBASE_SCOPE
|
||||
EnvCouchbaseScope = "COUCHBASE_SCOPE"
|
||||
// EnvKeySmtpHost key for env variable SMTP_HOST
|
||||
EnvKeySmtpHost = "SMTP_HOST"
|
||||
// EnvKeySmtpPort key for env variable SMTP_PORT
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/authorizerdev/authorizer/server/db/providers"
|
||||
"github.com/authorizerdev/authorizer/server/db/providers/arangodb"
|
||||
"github.com/authorizerdev/authorizer/server/db/providers/cassandradb"
|
||||
"github.com/authorizerdev/authorizer/server/db/providers/couchbase"
|
||||
"github.com/authorizerdev/authorizer/server/db/providers/dynamodb"
|
||||
"github.com/authorizerdev/authorizer/server/db/providers/mongodb"
|
||||
"github.com/authorizerdev/authorizer/server/db/providers/sql"
|
||||
@@ -21,11 +22,12 @@ func InitDB() error {
|
||||
|
||||
envs := memorystore.RequiredEnvStoreObj.GetRequiredEnv()
|
||||
|
||||
isSQL := envs.DatabaseType != constants.DbTypeArangodb && envs.DatabaseType != constants.DbTypeMongodb && envs.DatabaseType != constants.DbTypeCassandraDB && envs.DatabaseType != constants.DbTypeScyllaDB && envs.DatabaseType != constants.DbTypeDynamoDB
|
||||
isSQL := envs.DatabaseType != constants.DbTypeArangodb && envs.DatabaseType != constants.DbTypeMongodb && envs.DatabaseType != constants.DbTypeCassandraDB && envs.DatabaseType != constants.DbTypeScyllaDB && envs.DatabaseType != constants.DbTypeDynamoDB && envs.DatabaseType != constants.DbTypeCouchbaseDB
|
||||
isArangoDB := envs.DatabaseType == constants.DbTypeArangodb
|
||||
isMongoDB := envs.DatabaseType == constants.DbTypeMongodb
|
||||
isCassandra := envs.DatabaseType == constants.DbTypeCassandraDB || envs.DatabaseType == constants.DbTypeScyllaDB
|
||||
isDynamoDB := envs.DatabaseType == constants.DbTypeDynamoDB
|
||||
isCouchbaseDB := envs.DatabaseType == constants.DbTypeCouchbaseDB
|
||||
|
||||
if isSQL {
|
||||
log.Info("Initializing SQL Driver for: ", envs.DatabaseType)
|
||||
@@ -72,5 +74,14 @@ func InitDB() error {
|
||||
}
|
||||
}
|
||||
|
||||
if isCouchbaseDB {
|
||||
log.Info("Initializing CouchbaseDB Driver for: ", envs.DatabaseType)
|
||||
Provider, err = couchbase.NewProvider()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to initialize Couchbase driver: ", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -4,10 +4,11 @@ package models
|
||||
|
||||
// Env model for db
|
||||
type Env struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||
EnvData string `json:"env" bson:"env" cql:"env" dynamo:"env"`
|
||||
Hash string `json:"hash" bson:"hash" cql:"hash" dynamo:"hash"`
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||
EnvData string `json:"env" bson:"env" cql:"env" dynamo:"env"`
|
||||
Hash string `json:"hash" bson:"hash" cql:"hash" dynamo:"hash"`
|
||||
EncryptionKey string `json:"encryption_key" bson:"encryption_key" cql:"encryption_key" dynamo:"encryption_key"` // couchbase has "hash" as reserved keyword so we cannot use it. This will be empty for other dbs.
|
||||
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"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"
|
||||
@@ -52,7 +51,7 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin
|
||||
|
||||
query := fmt.Sprintf("FOR d in %s SORT d.created_at DESC LIMIT %d, %d RETURN d", models.Collections.EmailTemplate, pagination.Offset, pagination.Limit)
|
||||
|
||||
sctx := driver.WithQueryFullCount(ctx)
|
||||
sctx := arangoDriver.WithQueryFullCount(ctx)
|
||||
cursor, err := p.db.Query(sctx, query, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -2,8 +2,11 @@ package arangodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
arangoDriver "github.com/arangodb/go-driver"
|
||||
"github.com/arangodb/go-driver/http"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
@@ -22,44 +25,75 @@ type provider struct {
|
||||
func NewProvider() (*provider, error) {
|
||||
ctx := context.Background()
|
||||
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
||||
conn, err := http.NewConnection(http.ConnectionConfig{
|
||||
dbUsername := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseUsername
|
||||
dbPassword := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePassword
|
||||
dbCACertificate := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseCACert
|
||||
httpConfig := http.ConnectionConfig{
|
||||
Endpoints: []string{dbURL},
|
||||
})
|
||||
}
|
||||
// If ca certificate if present, create tls config
|
||||
if dbCACertificate != "" {
|
||||
caCert, err := base64.StdEncoding.DecodeString(dbCACertificate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Prepare TLS Config
|
||||
tlsConfig := &tls.Config{}
|
||||
certPool := x509.NewCertPool()
|
||||
if success := certPool.AppendCertsFromPEM(caCert); !success {
|
||||
return nil, fmt.Errorf("invalid certificate")
|
||||
}
|
||||
tlsConfig.RootCAs = certPool
|
||||
httpConfig.TLSConfig = tlsConfig
|
||||
}
|
||||
// Create new http connection
|
||||
conn, err := http.NewConnection(httpConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
arangoClient, err := arangoDriver.NewClient(arangoDriver.ClientConfig{
|
||||
clientConfig := arangoDriver.ClientConfig{
|
||||
Connection: conn,
|
||||
})
|
||||
}
|
||||
if dbUsername != "" && dbPassword != "" {
|
||||
clientConfig.Authentication = arangoDriver.BasicAuthentication(dbUsername, dbPassword)
|
||||
}
|
||||
arangoClient, err := arangoDriver.NewClient(clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var arangodb driver.Database
|
||||
var arangodb arangoDriver.Database
|
||||
dbName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseName
|
||||
arangodb_exists, err := arangoClient.DatabaseExists(nil, dbName)
|
||||
|
||||
arangodb_exists, err := arangoClient.DatabaseExists(ctx, dbName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if arangodb_exists {
|
||||
arangodb, err = arangoClient.Database(nil, dbName)
|
||||
arangodb, err = arangoClient.Database(ctx, dbName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
arangodb, err = arangoClient.CreateDatabase(nil, dbName, nil)
|
||||
arangodb, err = arangoClient.CreateDatabase(ctx, dbName, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
userCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.User)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !userCollectionExists {
|
||||
_, err = arangodb.CreateCollection(ctx, models.Collections.User, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
userCollection, _ := arangodb.Collection(nil, models.Collections.User)
|
||||
userCollection, err := arangodb.Collection(ctx, models.Collections.User)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userCollection.EnsureHashIndex(ctx, []string{"email"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
Sparse: true,
|
||||
@@ -70,6 +104,9 @@ func NewProvider() (*provider, error) {
|
||||
})
|
||||
|
||||
verificationRequestCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.VerificationRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !verificationRequestCollectionExists {
|
||||
_, err = arangodb.CreateCollection(ctx, models.Collections.VerificationRequest, nil)
|
||||
if err != nil {
|
||||
@@ -77,7 +114,10 @@ func NewProvider() (*provider, error) {
|
||||
}
|
||||
}
|
||||
|
||||
verificationRequestCollection, _ := arangodb.Collection(nil, models.Collections.VerificationRequest)
|
||||
verificationRequestCollection, err := arangodb.Collection(ctx, models.Collections.VerificationRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
verificationRequestCollection.EnsureHashIndex(ctx, []string{"email", "identifier"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
Sparse: true,
|
||||
@@ -87,6 +127,9 @@ func NewProvider() (*provider, error) {
|
||||
})
|
||||
|
||||
sessionCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !sessionCollectionExists {
|
||||
_, err = arangodb.CreateCollection(ctx, models.Collections.Session, nil)
|
||||
if err != nil {
|
||||
@@ -94,13 +137,19 @@ func NewProvider() (*provider, error) {
|
||||
}
|
||||
}
|
||||
|
||||
sessionCollection, _ := arangodb.Collection(nil, models.Collections.Session)
|
||||
sessionCollection, err := arangodb.Collection(ctx, models.Collections.Session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sessionCollection.EnsureHashIndex(ctx, []string{"user_id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
configCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Env)
|
||||
if !configCollectionExists {
|
||||
envCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !envCollectionExists {
|
||||
_, err = arangodb.CreateCollection(ctx, models.Collections.Env, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -108,6 +157,9 @@ func NewProvider() (*provider, error) {
|
||||
}
|
||||
|
||||
webhookCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Webhook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !webhookCollectionExists {
|
||||
_, err = arangodb.CreateCollection(ctx, models.Collections.Webhook, nil)
|
||||
if err != nil {
|
||||
@@ -115,13 +167,19 @@ func NewProvider() (*provider, error) {
|
||||
}
|
||||
}
|
||||
|
||||
webhookCollection, _ := arangodb.Collection(nil, models.Collections.Webhook)
|
||||
webhookCollection, err := arangodb.Collection(ctx, models.Collections.Webhook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhookCollection.EnsureHashIndex(ctx, []string{"event_name"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
webhookLogCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.WebhookLog)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !webhookLogCollectionExists {
|
||||
_, err = arangodb.CreateCollection(ctx, models.Collections.WebhookLog, nil)
|
||||
if err != nil {
|
||||
@@ -129,12 +187,18 @@ func NewProvider() (*provider, error) {
|
||||
}
|
||||
}
|
||||
|
||||
webhookLogCollection, _ := arangodb.Collection(nil, models.Collections.WebhookLog)
|
||||
webhookLogCollection, err := arangodb.Collection(ctx, models.Collections.WebhookLog)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhookLogCollection.EnsureHashIndex(ctx, []string{"webhook_id"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
emailTemplateCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.EmailTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !emailTemplateCollectionExists {
|
||||
_, err = arangodb.CreateCollection(ctx, models.Collections.EmailTemplate, nil)
|
||||
if err != nil {
|
||||
@@ -142,13 +206,19 @@ func NewProvider() (*provider, error) {
|
||||
}
|
||||
}
|
||||
|
||||
emailTemplateCollection, _ := arangodb.Collection(nil, models.Collections.EmailTemplate)
|
||||
emailTemplateCollection, err := arangodb.Collection(ctx, models.Collections.EmailTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
emailTemplateCollection.EnsureHashIndex(ctx, []string{"event_name"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
Sparse: true,
|
||||
})
|
||||
|
||||
otpCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.OTP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !otpCollectionExists {
|
||||
_, err = arangodb.CreateCollection(ctx, models.Collections.OTP, nil)
|
||||
if err != nil {
|
||||
@@ -156,7 +226,10 @@ func NewProvider() (*provider, error) {
|
||||
}
|
||||
}
|
||||
|
||||
otpCollection, _ := arangodb.Collection(nil, models.Collections.OTP)
|
||||
otpCollection, err := arangodb.Collection(ctx, models.Collections.OTP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
otpCollection.EnsureHashIndex(ctx, []string{"email"}, &arangoDriver.EnsureHashIndexOptions{
|
||||
Unique: true,
|
||||
Sparse: true,
|
||||
|
@@ -7,7 +7,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
arangoDriver "github.com/arangodb/go-driver"
|
||||
"github.com/google/uuid"
|
||||
|
||||
@@ -91,7 +90,7 @@ func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
||||
// ListUsers to get list of users from database
|
||||
func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
|
||||
var users []*model.User
|
||||
sctx := driver.WithQueryFullCount(ctx)
|
||||
sctx := arangoDriver.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)
|
||||
|
||||
@@ -199,7 +198,7 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||
}
|
||||
|
||||
query := ""
|
||||
if ids != nil && len(ids) > 0 {
|
||||
if len(ids) > 0 {
|
||||
keysArray := ""
|
||||
for _, id := range ids {
|
||||
keysArray += fmt.Sprintf("'%s', ", id)
|
||||
@@ -212,7 +211,6 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||
}
|
||||
|
||||
_, err = p.db.Query(ctx, query, nil)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"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"
|
||||
@@ -96,7 +96,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
||||
// ListVerificationRequests to get list of verification requests from database
|
||||
func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
|
||||
var verificationRequests []*model.VerificationRequest
|
||||
sctx := driver.WithQueryFullCount(ctx)
|
||||
sctx := arangoDriver.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)
|
||||
|
||||
cursor, err := p.db.Query(sctx, query, nil)
|
||||
@@ -112,7 +112,7 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode
|
||||
var verificationRequest models.VerificationRequest
|
||||
meta, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||
|
||||
if driver.IsNoMoreDocuments(err) {
|
||||
if arangoDriver.IsNoMoreDocuments(err) {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
@@ -132,8 +132,8 @@ func (p *provider) ListVerificationRequests(ctx context.Context, pagination mode
|
||||
|
||||
// DeleteVerificationRequest to delete verification request from database
|
||||
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
|
||||
collection, _ := p.db.Collection(nil, models.Collections.VerificationRequest)
|
||||
_, err := collection.RemoveDocument(nil, verificationRequest.Key)
|
||||
collection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest)
|
||||
_, err := collection.RemoveDocument(ctx, verificationRequest.Key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"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"
|
||||
@@ -50,7 +49,7 @@ func (p *provider) ListWebhook(ctx context.Context, pagination model.Pagination)
|
||||
|
||||
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)
|
||||
sctx := arangoDriver.WithQueryFullCount(ctx)
|
||||
cursor, err := p.db.Query(sctx, query, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"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"
|
||||
@@ -44,7 +43,7 @@ func (p *provider) ListWebhookLogs(ctx context.Context, pagination model.Paginat
|
||||
}
|
||||
}
|
||||
|
||||
sctx := driver.WithQueryFullCount(ctx)
|
||||
sctx := arangoDriver.WithQueryFullCount(ctx)
|
||||
cursor, err := p.db.Query(sctx, query, bindVariables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
166
server/db/providers/couchbase/email_template.go
Normal file
166
server/db/providers/couchbase/email_template.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package couchbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/couchbase/gocb/v2"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddEmailTemplate to add EmailTemplate
|
||||
func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||
|
||||
if emailTemplate.ID == "" {
|
||||
emailTemplate.ID = uuid.New().String()
|
||||
}
|
||||
|
||||
emailTemplate.Key = emailTemplate.ID
|
||||
emailTemplate.CreatedAt = time.Now().Unix()
|
||||
emailTemplate.UpdatedAt = time.Now().Unix()
|
||||
insertOpt := gocb.InsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
|
||||
_, err := p.db.Collection(models.Collections.EmailTemplate).Insert(emailTemplate.ID, emailTemplate, &insertOpt)
|
||||
if err != nil {
|
||||
return emailTemplate.AsAPIEmailTemplate(), err
|
||||
}
|
||||
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// UpdateEmailTemplate to update EmailTemplate
|
||||
func (p *provider) UpdateEmailTemplate(ctx context.Context, emailTemplate models.EmailTemplate) (*model.EmailTemplate, error) {
|
||||
bytes, err := json.Marshal(emailTemplate)
|
||||
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()
|
||||
emailTemplateMap := map[string]interface{}{}
|
||||
err = decoder.Decode(&emailTemplateMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updateFields, params := GetSetFields(emailTemplateMap)
|
||||
params["emailId"] = emailTemplate.ID
|
||||
|
||||
query := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = $emailId", p.scopeName, models.Collections.EmailTemplate, updateFields)
|
||||
|
||||
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
NamedParameters: params,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// ListEmailTemplates to list EmailTemplate
|
||||
func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagination) (*model.EmailTemplates, error) {
|
||||
emailTemplates := []*model.EmailTemplate{}
|
||||
paginationClone := pagination
|
||||
total, err := p.GetTotalDocs(ctx, models.Collections.EmailTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paginationClone.Total = total
|
||||
userQuery := fmt.Sprintf("SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s ORDER BY _id OFFSET $1 LIMIT $2", p.scopeName, models.Collections.EmailTemplate)
|
||||
|
||||
queryResult, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
PositionalParameters: []interface{}{paginationClone.Offset, paginationClone.Limit},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for queryResult.Next() {
|
||||
emailTemplate := models.EmailTemplate{}
|
||||
err := queryResult.Row(&emailTemplate)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
emailTemplates = append(emailTemplates, emailTemplate.AsAPIEmailTemplate())
|
||||
}
|
||||
|
||||
if err := queryResult.Err(); err != nil {
|
||||
return nil, err
|
||||
|
||||
}
|
||||
|
||||
return &model.EmailTemplates{
|
||||
Pagination: &paginationClone,
|
||||
EmailTemplates: emailTemplates,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetEmailTemplateByID to get EmailTemplate by id
|
||||
func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) {
|
||||
emailTemplate := models.EmailTemplate{}
|
||||
|
||||
query := fmt.Sprintf(`SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1`, p.scopeName, models.Collections.EmailTemplate)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
PositionalParameters: []interface{}{emailTemplateID},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = q.One(&emailTemplate)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// GetEmailTemplateByEventName to get EmailTemplate by event_name
|
||||
func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) {
|
||||
emailTemplate := models.EmailTemplate{}
|
||||
|
||||
query := fmt.Sprintf("SELECT _id, event_name, subject, design, template, created_at, updated_at FROM %s.%s WHERE event_name=$1 LIMIT 1", p.scopeName, models.Collections.EmailTemplate)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
PositionalParameters: []interface{}{eventName},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = q.One(&emailTemplate)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return emailTemplate.AsAPIEmailTemplate(), nil
|
||||
}
|
||||
|
||||
// DeleteEmailTemplate to delete EmailTemplate
|
||||
func (p *provider) DeleteEmailTemplate(ctx context.Context, emailTemplate *model.EmailTemplate) error {
|
||||
removeOpt := gocb.RemoveOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.EmailTemplate).Remove(emailTemplate.ID, &removeOpt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
70
server/db/providers/couchbase/env.go
Normal file
70
server/db/providers/couchbase/env.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package couchbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/couchbase/gocb/v2"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddEnv to save environment information in database
|
||||
func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
||||
if env.ID == "" {
|
||||
env.ID = uuid.New().String()
|
||||
}
|
||||
env.CreatedAt = time.Now().Unix()
|
||||
env.UpdatedAt = time.Now().Unix()
|
||||
env.Key = env.ID
|
||||
env.EncryptionKey = env.Hash
|
||||
|
||||
insertOpt := gocb.InsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.Env).Insert(env.ID, env, &insertOpt)
|
||||
if err != nil {
|
||||
return env, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
||||
// UpdateEnv to update environment information in database
|
||||
func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
||||
env.UpdatedAt = time.Now().Unix()
|
||||
env.EncryptionKey = env.Hash
|
||||
|
||||
updateEnvQuery := fmt.Sprintf("UPDATE %s.%s SET env = $1, updated_at = $2 WHERE _id = $3", p.scopeName, models.Collections.Env)
|
||||
_, err := p.db.Query(updateEnvQuery, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
PositionalParameters: []interface{}{env.EnvData, env.UpdatedAt, env.UpdatedAt, env.ID},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return env, err
|
||||
}
|
||||
|
||||
return env, nil
|
||||
}
|
||||
|
||||
// GetEnv to get environment information from database
|
||||
func (p *provider) GetEnv(ctx context.Context) (models.Env, error) {
|
||||
var env models.Env
|
||||
|
||||
query := fmt.Sprintf("SELECT _id, env, encryption_key, created_at, updated_at FROM %s.%s LIMIT 1", p.scopeName, models.Collections.Env)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
})
|
||||
if err != nil {
|
||||
return env, err
|
||||
}
|
||||
err = q.One(&env)
|
||||
|
||||
if err != nil {
|
||||
return env, err
|
||||
}
|
||||
env.Hash = env.EncryptionKey
|
||||
return env, nil
|
||||
}
|
84
server/db/providers/couchbase/otp.go
Normal file
84
server/db/providers/couchbase/otp.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package couchbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/couchbase/gocb/v2"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// UpsertOTP to add or update otp
|
||||
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
|
||||
|
||||
shouldCreate := false
|
||||
if otp == nil {
|
||||
shouldCreate = true
|
||||
otp = &models.OTP{
|
||||
ID: uuid.NewString(),
|
||||
Otp: otpParam.Otp,
|
||||
Email: otpParam.Email,
|
||||
ExpiresAt: otpParam.ExpiresAt,
|
||||
CreatedAt: time.Now().Unix(),
|
||||
UpdatedAt: time.Now().Unix(),
|
||||
}
|
||||
} else {
|
||||
otp.Otp = otpParam.Otp
|
||||
otp.ExpiresAt = otpParam.ExpiresAt
|
||||
}
|
||||
|
||||
otp.UpdatedAt = time.Now().Unix()
|
||||
if shouldCreate {
|
||||
insertOpt := gocb.InsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.OTP).Insert(otp.ID, otp, &insertOpt)
|
||||
if err != nil {
|
||||
return otp, err
|
||||
}
|
||||
} else {
|
||||
query := fmt.Sprintf(`UPDATE %s.%s SET otp=$1, expires_at=$2, updated_at=$3 WHERE _id=$4`, p.scopeName, models.Collections.OTP)
|
||||
_, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
PositionalParameters: []interface{}{otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID},
|
||||
})
|
||||
if err != nil {
|
||||
return otp, err
|
||||
}
|
||||
}
|
||||
return otp, nil
|
||||
}
|
||||
|
||||
// GetOTPByEmail to get otp for a given email address
|
||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||
otp := models.OTP{}
|
||||
query := fmt.Sprintf(`SELECT _id, email, otp, expires_at, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1`, p.scopeName, models.Collections.OTP)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
PositionalParameters: []interface{}{emailAddress},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = q.One(&otp)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &otp, nil
|
||||
}
|
||||
|
||||
// DeleteOTP to delete otp
|
||||
func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error {
|
||||
removeOpt := gocb.RemoveOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.OTP).Remove(otp.ID, &removeOpt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
170
server/db/providers/couchbase/provider.go
Normal file
170
server/db/providers/couchbase/provider.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package couchbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/couchbase/gocb/v2"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultBucketName = "authorizer"
|
||||
defaultScope = "_default"
|
||||
)
|
||||
|
||||
type provider struct {
|
||||
db *gocb.Scope
|
||||
scopeName string
|
||||
}
|
||||
|
||||
// NewProvider returns a new Couchbase provider
|
||||
func NewProvider() (*provider, error) {
|
||||
bucketName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().CouchbaseBucket
|
||||
scopeName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().CouchbaseScope
|
||||
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
||||
userName := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseUsername
|
||||
password := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePassword
|
||||
opts := gocb.ClusterOptions{
|
||||
Username: userName,
|
||||
Password: password,
|
||||
}
|
||||
if bucketName == "" {
|
||||
bucketName = defaultBucketName
|
||||
}
|
||||
if scopeName == "" {
|
||||
scopeName = defaultScope
|
||||
}
|
||||
cluster, err := gocb.Connect(dbURL, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// To create the bucket and scope if not exist
|
||||
bucket, err := CreateBucketAndScope(cluster, bucketName, scopeName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scope := bucket.Scope(scopeName)
|
||||
scopeIdentifier := fmt.Sprintf("%s.%s", bucketName, scopeName)
|
||||
v := reflect.ValueOf(models.Collections)
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
collectionName := v.Field(i)
|
||||
user := gocb.CollectionSpec{
|
||||
Name: collectionName.String(),
|
||||
ScopeName: scopeName,
|
||||
}
|
||||
collectionOpts := gocb.CreateCollectionOptions{
|
||||
Context: context.TODO(),
|
||||
}
|
||||
err = bucket.Collections().CreateCollection(user, &collectionOpts)
|
||||
if err != nil && !errors.Is(err, gocb.ErrCollectionExists) {
|
||||
return nil, err
|
||||
}
|
||||
// TODO: find how to fix this sleep time.
|
||||
// Add wait time for successful collection creation
|
||||
time.Sleep(5 * time.Second)
|
||||
indexQuery := fmt.Sprintf("CREATE PRIMARY INDEX ON %s.%s", scopeIdentifier, collectionName.String())
|
||||
_, err = scope.Query(indexQuery, nil)
|
||||
if err != nil && !strings.Contains(err.Error(), "The index #primary already exists") {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
indices := GetIndex(scopeIdentifier)
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
field := v.Field(i)
|
||||
for _, indexQuery := range indices[field.String()] {
|
||||
scope.Query(indexQuery, nil)
|
||||
}
|
||||
}
|
||||
return &provider{
|
||||
db: scope,
|
||||
scopeName: scopeIdentifier,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func CreateBucketAndScope(cluster *gocb.Cluster, bucketName string, scopeName string) (*gocb.Bucket, error) {
|
||||
bucketRAMQuotaMB := memorystore.RequiredEnvStoreObj.GetRequiredEnv().CouchbaseBucketRAMQuotaMB
|
||||
if bucketRAMQuotaMB == "" {
|
||||
bucketRAMQuotaMB = "1000"
|
||||
}
|
||||
bucketRAMQuota, err := strconv.ParseInt(bucketRAMQuotaMB, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
settings := gocb.BucketSettings{
|
||||
Name: bucketName,
|
||||
RAMQuotaMB: uint64(bucketRAMQuota),
|
||||
BucketType: gocb.CouchbaseBucketType,
|
||||
EvictionPolicy: gocb.EvictionPolicyTypeValueOnly,
|
||||
FlushEnabled: true,
|
||||
CompressionMode: gocb.CompressionModeActive,
|
||||
}
|
||||
shouldCreateBucket := false
|
||||
// check if bucket exists
|
||||
_, err = cluster.Buckets().GetBucket(bucketName, nil)
|
||||
if err != nil {
|
||||
// bucket not found
|
||||
shouldCreateBucket = true
|
||||
}
|
||||
if shouldCreateBucket {
|
||||
err = cluster.Buckets().CreateBucket(gocb.CreateBucketSettings{
|
||||
BucketSettings: settings,
|
||||
ConflictResolutionType: gocb.ConflictResolutionTypeSequenceNumber,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
bucket := cluster.Bucket(bucketName)
|
||||
if scopeName != defaultScope {
|
||||
err = bucket.Collections().CreateScope(scopeName, nil)
|
||||
if err != nil && !errors.Is(err, gocb.ErrScopeExists) {
|
||||
return bucket, err
|
||||
}
|
||||
}
|
||||
return bucket, nil
|
||||
}
|
||||
|
||||
func GetIndex(scopeName string) map[string][]string {
|
||||
indices := make(map[string][]string)
|
||||
|
||||
// User Index
|
||||
userIndex1 := fmt.Sprintf("CREATE INDEX userEmailIndex ON %s.%s(email)", scopeName, models.Collections.User)
|
||||
userIndex2 := fmt.Sprintf("CREATE INDEX userPhoneIndex ON %s.%s(phone_number)", scopeName, models.Collections.User)
|
||||
indices[models.Collections.User] = []string{userIndex1, userIndex2}
|
||||
|
||||
// VerificationRequest
|
||||
verificationIndex1 := fmt.Sprintf("CREATE INDEX verificationRequestTokenIndex ON %s.%s(token)", scopeName, models.Collections.VerificationRequest)
|
||||
verificationIndex2 := fmt.Sprintf("CREATE INDEX verificationRequestEmailAndIdentifierIndex ON %s.%s(email,identifier)", scopeName, models.Collections.VerificationRequest)
|
||||
indices[models.Collections.VerificationRequest] = []string{verificationIndex1, verificationIndex2}
|
||||
|
||||
// Session index
|
||||
sessionIndex1 := fmt.Sprintf("CREATE INDEX SessionUserIdIndex ON %s.%s(user_id)", scopeName, models.Collections.Session)
|
||||
indices[models.Collections.Session] = []string{sessionIndex1}
|
||||
|
||||
// Webhook index
|
||||
webhookIndex1 := fmt.Sprintf("CREATE INDEX webhookEventNameIndex ON %s.%s(event_name)", scopeName, models.Collections.Webhook)
|
||||
indices[models.Collections.Webhook] = []string{webhookIndex1}
|
||||
|
||||
// WebhookLog index
|
||||
webhookLogIndex1 := fmt.Sprintf("CREATE INDEX webhookLogIdIndex ON %s.%s(webhook_id)", scopeName, models.Collections.WebhookLog)
|
||||
indices[models.Collections.Webhook] = []string{webhookLogIndex1}
|
||||
|
||||
// WebhookLog index
|
||||
emailTempIndex1 := fmt.Sprintf("CREATE INDEX EmailTemplateEventNameIndex ON %s.%s(event_name)", scopeName, models.Collections.EmailTemplate)
|
||||
indices[models.Collections.EmailTemplate] = []string{emailTempIndex1}
|
||||
|
||||
// OTP index
|
||||
otpIndex1 := fmt.Sprintf("CREATE INDEX OTPEmailIndex ON %s.%s(email)", scopeName, models.Collections.OTP)
|
||||
indices[models.Collections.OTP] = []string{otpIndex1}
|
||||
|
||||
return indices
|
||||
}
|
34
server/db/providers/couchbase/session.go
Normal file
34
server/db/providers/couchbase/session.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package couchbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/couchbase/gocb/v2"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddSession to save session information in database
|
||||
func (p *provider) AddSession(ctx context.Context, session models.Session) error {
|
||||
if session.ID == "" {
|
||||
session.ID = uuid.New().String()
|
||||
}
|
||||
|
||||
session.CreatedAt = time.Now().Unix()
|
||||
session.UpdatedAt = time.Now().Unix()
|
||||
insertOpt := gocb.InsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.Session).Insert(session.ID, session, &insertOpt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteSession to delete session information from database
|
||||
func (p *provider) DeleteSession(ctx context.Context, userId string) error {
|
||||
return nil
|
||||
}
|
65
server/db/providers/couchbase/shared.go
Normal file
65
server/db/providers/couchbase/shared.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package couchbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/couchbase/gocb/v2"
|
||||
)
|
||||
|
||||
func GetSetFields(webhookMap map[string]interface{}) (string, map[string]interface{}) {
|
||||
params := make(map[string]interface{}, 1)
|
||||
|
||||
updateFields := ""
|
||||
|
||||
for key, value := range webhookMap {
|
||||
if key == "_id" {
|
||||
continue
|
||||
}
|
||||
|
||||
if key == "_key" {
|
||||
continue
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
updateFields += fmt.Sprintf("%s=$%s,", key, key)
|
||||
params[key] = "null"
|
||||
continue
|
||||
}
|
||||
|
||||
valueType := reflect.TypeOf(value)
|
||||
if valueType.Name() == "string" {
|
||||
updateFields += fmt.Sprintf("%s = $%s, ", key, key)
|
||||
params[key] = value.(string)
|
||||
|
||||
} else {
|
||||
updateFields += fmt.Sprintf("%s = $%s, ", key, key)
|
||||
params[key] = value
|
||||
}
|
||||
}
|
||||
updateFields = strings.Trim(updateFields, " ")
|
||||
updateFields = strings.TrimSuffix(updateFields, ",")
|
||||
return updateFields, params
|
||||
}
|
||||
|
||||
func (p *provider) GetTotalDocs(ctx context.Context, collection string) (int64, error) {
|
||||
totalDocs := TotalDocs{}
|
||||
|
||||
countQuery := fmt.Sprintf("SELECT COUNT(*) as Total FROM %s.%s", p.scopeName, collection)
|
||||
queryRes, err := p.db.Query(countQuery, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
})
|
||||
|
||||
queryRes.One(&totalDocs)
|
||||
|
||||
if err != nil {
|
||||
return totalDocs.Total, err
|
||||
}
|
||||
return totalDocs.Total, nil
|
||||
}
|
||||
|
||||
type TotalDocs struct {
|
||||
Total int64
|
||||
}
|
199
server/db/providers/couchbase/user.go
Normal file
199
server/db/providers/couchbase/user.go
Normal file
@@ -0,0 +1,199 @@
|
||||
package couchbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/couchbase/gocb/v2"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddUser to save user information in database
|
||||
func (p *provider) AddUser(ctx context.Context, user models.User) (models.User, error) {
|
||||
if user.ID == "" {
|
||||
user.ID = uuid.New().String()
|
||||
}
|
||||
|
||||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
insertOpt := gocb.InsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.User).Insert(user.ID, user, &insertOpt)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// UpdateUser to update user information in database
|
||||
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
unsertOpt := gocb.UpsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &unsertOpt)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// DeleteUser to delete user information from database
|
||||
func (p *provider) DeleteUser(ctx context.Context, user models.User) error {
|
||||
removeOpt := gocb.RemoveOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.User).Remove(user.ID, &removeOpt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListUsers to get list of users from database
|
||||
func (p *provider) ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error) {
|
||||
users := []*model.User{}
|
||||
paginationClone := pagination
|
||||
|
||||
userQuery := 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, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s ORDER BY id OFFSET $1 LIMIT $2", p.scopeName, models.Collections.User)
|
||||
|
||||
queryResult, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
Context: ctx,
|
||||
PositionalParameters: []interface{}{paginationClone.Offset, paginationClone.Limit},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
total, err := p.GetTotalDocs(ctx, models.Collections.User)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paginationClone.Total = total
|
||||
for queryResult.Next() {
|
||||
var user models.User
|
||||
err := queryResult.Row(&user)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
users = append(users, user.AsAPIUser())
|
||||
}
|
||||
if err := queryResult.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &model.Users{
|
||||
Pagination: &paginationClone,
|
||||
Users: users,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetUserByEmail to get user information from database using email address
|
||||
func (p *provider) GetUserByEmail(ctx context.Context, email string) (models.User, error) {
|
||||
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, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s WHERE email = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
Context: ctx,
|
||||
PositionalParameters: []interface{}{email},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
err = q.One(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// GetUserByID to get user information from database using user ID
|
||||
func (p *provider) GetUserByID(ctx context.Context, id string) (models.User, error) {
|
||||
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, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s WHERE _id = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
Context: ctx,
|
||||
PositionalParameters: []interface{}{id},
|
||||
})
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
err = q.One(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// UpdateUsers to update multiple users, with parameters of user IDs slice
|
||||
// If ids set to nil / empty all the users will be updated
|
||||
func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{}, ids []string) error {
|
||||
// set updated_at time for all users
|
||||
data["updated_at"] = time.Now().Unix()
|
||||
updateFields, params := GetSetFields(data)
|
||||
if len(ids) > 0 {
|
||||
for _, id := range ids {
|
||||
params["id"] = id
|
||||
userQuery := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id = $id", p.scopeName, models.Collections.User, updateFields)
|
||||
|
||||
_, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
Context: ctx,
|
||||
NamedParameters: params,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
userQuery := fmt.Sprintf("UPDATE %s.%s SET %s WHERE _id IS NOT NULL", p.scopeName, models.Collections.User, updateFields)
|
||||
_, err := p.db.Query(userQuery, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
Context: ctx,
|
||||
NamedParameters: params,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUserByPhoneNumber to get user information from database using phone number
|
||||
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||
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, is_multi_factor_auth_enabled, created_at, updated_at FROM %s.%s WHERE phone_number = $1 LIMIT 1", p.scopeName, models.Collections.User)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
Context: ctx,
|
||||
PositionalParameters: []interface{}{phoneNumber},
|
||||
})
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
err = q.One(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
128
server/db/providers/couchbase/verification_requests.go
Normal file
128
server/db/providers/couchbase/verification_requests.go
Normal file
@@ -0,0 +1,128 @@
|
||||
package couchbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/couchbase/gocb/v2"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AddVerification to save verification request in database
|
||||
func (p *provider) AddVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) (models.VerificationRequest, error) {
|
||||
if verificationRequest.ID == "" {
|
||||
verificationRequest.ID = uuid.New().String()
|
||||
}
|
||||
|
||||
verificationRequest.Key = verificationRequest.ID
|
||||
verificationRequest.CreatedAt = time.Now().Unix()
|
||||
verificationRequest.UpdatedAt = time.Now().Unix()
|
||||
insertOpt := gocb.InsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.VerificationRequest).Insert(verificationRequest.ID, verificationRequest, &insertOpt)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
||||
// GetVerificationRequestByToken to get verification request from database using token
|
||||
func (p *provider) GetVerificationRequestByToken(ctx context.Context, token string) (models.VerificationRequest, error) {
|
||||
verificationRequest := models.VerificationRequest{}
|
||||
params := make(map[string]interface{}, 1)
|
||||
params["token"] = token
|
||||
query := fmt.Sprintf("SELECT _id, token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s.%s WHERE token=$1 LIMIT 1", p.scopeName, models.Collections.VerificationRequest)
|
||||
|
||||
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
PositionalParameters: []interface{}{token},
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
err = queryResult.One(&verificationRequest)
|
||||
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
||||
// GetVerificationRequestByEmail to get verification request by email from database
|
||||
func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email string, identifier string) (models.VerificationRequest, error) {
|
||||
|
||||
query := fmt.Sprintf("SELECT _id, identifier, token, expires_at, email, nonce, redirect_uri, created_at, updated_at FROM %s.%s WHERE email=$1 AND identifier=$2 LIMIT 1", p.scopeName, models.Collections.VerificationRequest)
|
||||
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
PositionalParameters: []interface{}{email, identifier},
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
})
|
||||
verificationRequest := models.VerificationRequest{}
|
||||
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
|
||||
err = queryResult.One(&verificationRequest)
|
||||
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
||||
// ListVerificationRequests to get list of verification requests from database
|
||||
func (p *provider) ListVerificationRequests(ctx context.Context, pagination model.Pagination) (*model.VerificationRequests, error) {
|
||||
var verificationRequests []*model.VerificationRequest
|
||||
paginationClone := pagination
|
||||
total, err := p.GetTotalDocs(ctx, models.Collections.VerificationRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paginationClone.Total = total
|
||||
query := fmt.Sprintf("SELECT _id, env, created_at, updated_at FROM %s.%s OFFSET $1 LIMIT $2", p.scopeName, models.Collections.VerificationRequest)
|
||||
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
PositionalParameters: []interface{}{paginationClone.Offset, paginationClone.Limit},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for queryResult.Next() {
|
||||
var verificationRequest models.VerificationRequest
|
||||
err := queryResult.Row(&verificationRequest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
verificationRequests = append(verificationRequests, verificationRequest.AsAPIVerificationRequest())
|
||||
}
|
||||
if err := queryResult.Err(); err != nil {
|
||||
return nil, err
|
||||
|
||||
}
|
||||
return &model.VerificationRequests{
|
||||
VerificationRequests: verificationRequests,
|
||||
Pagination: &paginationClone,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteVerificationRequest to delete verification request from database
|
||||
func (p *provider) DeleteVerificationRequest(ctx context.Context, verificationRequest models.VerificationRequest) error {
|
||||
removeOpt := gocb.RemoveOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.VerificationRequest).Remove(verificationRequest.ID, &removeOpt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
185
server/db/providers/couchbase/webhook.go
Normal file
185
server/db/providers/couchbase/webhook.go
Normal file
@@ -0,0 +1,185 @@
|
||||
package couchbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/couchbase/gocb/v2"
|
||||
"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()
|
||||
|
||||
insertOpt := gocb.InsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.Webhook).Insert(webhook.ID, webhook, &insertOpt)
|
||||
if err != nil {
|
||||
return webhook.AsAPIWebhook(), 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, params := GetSetFields(webhookMap)
|
||||
|
||||
query := fmt.Sprintf(`UPDATE %s.%s SET %s WHERE _id='%s'`, p.scopeName, models.Collections.Webhook, updateFields, webhook.ID)
|
||||
|
||||
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
NamedParameters: params,
|
||||
})
|
||||
|
||||
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
|
||||
|
||||
params := make(map[string]interface{}, 1)
|
||||
params["offset"] = paginationClone.Offset
|
||||
params["limit"] = paginationClone.Limit
|
||||
total, err := p.GetTotalDocs(ctx, models.Collections.Webhook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paginationClone.Total = total
|
||||
query := fmt.Sprintf("SELECT _id, env, created_at, updated_at FROM %s.%s OFFSET $offset LIMIT $limit", p.scopeName, models.Collections.Webhook)
|
||||
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
NamedParameters: params,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for queryResult.Next() {
|
||||
var webhook models.Webhook
|
||||
err := queryResult.Row(&webhook)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
webhooks = append(webhooks, webhook.AsAPIWebhook())
|
||||
}
|
||||
if err := queryResult.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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
|
||||
|
||||
params := make(map[string]interface{}, 1)
|
||||
params["_id"] = webhookID
|
||||
|
||||
query := fmt.Sprintf(`SELECT _id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s.%s WHERE _id=$_id LIMIT 1`, p.scopeName, models.Collections.Webhook)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
NamedParameters: params,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = q.One(&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
|
||||
params := make(map[string]interface{}, 1)
|
||||
params["event_name"] = eventName
|
||||
|
||||
query := fmt.Sprintf(`SELECT _id, event_name, endpoint, headers, enabled, created_at, updated_at FROM %s.%s WHERE event_name=$event_name LIMIT 1`, p.scopeName, models.Collections.Webhook)
|
||||
q, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
NamedParameters: params,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = q.One(&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 {
|
||||
|
||||
params := make(map[string]interface{}, 1)
|
||||
params["webhook_id"] = webhook.ID
|
||||
removeOpt := gocb.RemoveOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.Webhook).Remove(webhook.ID, &removeOpt)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`DELETE FROM %s.%s WHERE webhook_id=$webhook_id`, p.scopeName, models.Collections.WebhookLog)
|
||||
_, err = p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
NamedParameters: params,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
85
server/db/providers/couchbase/webhook_log.go
Normal file
85
server/db/providers/couchbase/webhook_log.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package couchbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/couchbase/gocb/v2"
|
||||
"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()
|
||||
|
||||
insertOpt := gocb.InsertOptions{
|
||||
Context: ctx,
|
||||
}
|
||||
_, err := p.db.Collection(models.Collections.WebhookLog).Insert(webhookLog.ID, webhookLog, &insertOpt)
|
||||
if err != nil {
|
||||
return webhookLog.AsAPIWebhookLog(), 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) {
|
||||
var query string
|
||||
var err error
|
||||
|
||||
webhookLogs := []*model.WebhookLog{}
|
||||
params := make(map[string]interface{}, 1)
|
||||
paginationClone := pagination
|
||||
|
||||
params["webhookID"] = webhookID
|
||||
params["offset"] = paginationClone.Offset
|
||||
params["limit"] = paginationClone.Limit
|
||||
total, err := p.GetTotalDocs(ctx, models.Collections.WebhookLog)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paginationClone.Total = total
|
||||
if webhookID != "" {
|
||||
query = fmt.Sprintf(`SELECT _id, http_status, response, request, webhook_id, created_at, updated_at FROM %s.%s WHERE webhook_id=$webhookID`, p.scopeName, models.Collections.WebhookLog)
|
||||
} else {
|
||||
query = fmt.Sprintf("SELECT _id, http_status, response, request, webhook_id, created_at, updated_at FROM %s.%s OFFSET $offset LIMIT $limit", p.scopeName, models.Collections.WebhookLog)
|
||||
}
|
||||
|
||||
queryResult, err := p.db.Query(query, &gocb.QueryOptions{
|
||||
Context: ctx,
|
||||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
NamedParameters: params,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for queryResult.Next() {
|
||||
var webhookLog models.WebhookLog
|
||||
err := queryResult.Row(&webhookLog)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
webhookLogs = append(webhookLogs, webhookLog.AsAPIWebhookLog())
|
||||
}
|
||||
|
||||
if err := queryResult.Err(); err != nil {
|
||||
return nil, err
|
||||
|
||||
}
|
||||
return &model.WebhookLogs{
|
||||
Pagination: &paginationClone,
|
||||
WebhookLogs: webhookLogs,
|
||||
}, nil
|
||||
}
|
28
server/env/env.go
vendored
28
server/env/env.go
vendored
@@ -81,6 +81,9 @@ func InitAllEnv() error {
|
||||
osAwsRegion := os.Getenv(constants.EnvAwsRegion)
|
||||
osAwsAccessKey := os.Getenv(constants.EnvAwsAccessKeyID)
|
||||
osAwsSecretKey := os.Getenv(constants.EnvAwsSecretAccessKey)
|
||||
osCouchbaseBucket := os.Getenv(constants.EnvCouchbaseBucket)
|
||||
osCouchbaseScope := os.Getenv(constants.EnvCouchbaseScope)
|
||||
osCouchbaseBucketRAMQuotaMB := os.Getenv(constants.EnvCouchbaseBucketRAMQuotaMB)
|
||||
|
||||
// os bool vars
|
||||
osAppCookieSecure := os.Getenv(constants.EnvKeyAppCookieSecure)
|
||||
@@ -134,17 +137,38 @@ func InitAllEnv() error {
|
||||
if val, ok := envData[constants.EnvAwsAccessKeyID]; !ok || val == "" {
|
||||
envData[constants.EnvAwsAccessKeyID] = osAwsAccessKey
|
||||
}
|
||||
if osAwsAccessKey != "" && envData[constants.EnvAwsAccessKeyID] != osAwsRegion {
|
||||
if osAwsAccessKey != "" && envData[constants.EnvAwsAccessKeyID] != osAwsAccessKey {
|
||||
envData[constants.EnvAwsAccessKeyID] = osAwsAccessKey
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvAwsSecretAccessKey]; !ok || val == "" {
|
||||
envData[constants.EnvAwsSecretAccessKey] = osAwsSecretKey
|
||||
}
|
||||
if osAwsSecretKey != "" && envData[constants.EnvAwsSecretAccessKey] != osAwsRegion {
|
||||
if osAwsSecretKey != "" && envData[constants.EnvAwsSecretAccessKey] != osAwsSecretKey {
|
||||
envData[constants.EnvAwsSecretAccessKey] = osAwsSecretKey
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvCouchbaseBucket]; !ok || val == "" {
|
||||
envData[constants.EnvCouchbaseBucket] = osCouchbaseBucket
|
||||
}
|
||||
if osCouchbaseBucket != "" && envData[constants.EnvCouchbaseBucket] != osCouchbaseBucket {
|
||||
envData[constants.EnvCouchbaseBucket] = osCouchbaseBucket
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvCouchbaseBucketRAMQuotaMB]; !ok || val == "" {
|
||||
envData[constants.EnvCouchbaseBucketRAMQuotaMB] = osCouchbaseBucketRAMQuotaMB
|
||||
}
|
||||
if osCouchbaseBucketRAMQuotaMB != "" && envData[constants.EnvCouchbaseBucketRAMQuotaMB] != osCouchbaseBucketRAMQuotaMB {
|
||||
envData[constants.EnvCouchbaseBucketRAMQuotaMB] = osCouchbaseBucketRAMQuotaMB
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvCouchbaseScope]; !ok || val == "" {
|
||||
envData[constants.EnvCouchbaseScope] = osCouchbaseScope
|
||||
}
|
||||
if osCouchbaseScope != "" && envData[constants.EnvCouchbaseScope] != osCouchbaseScope {
|
||||
envData[constants.EnvCouchbaseScope] = osCouchbaseScope
|
||||
}
|
||||
|
||||
if val, ok := envData[constants.EnvKeyAppURL]; !ok || val == "" {
|
||||
envData[constants.EnvKeyAppURL] = osAppURL
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ require (
|
||||
github.com/arangodb/go-driver v1.2.1
|
||||
github.com/aws/aws-sdk-go v1.44.109
|
||||
github.com/coreos/go-oidc/v3 v3.1.0
|
||||
github.com/couchbase/gocb/v2 v2.6.0 // indirect
|
||||
github.com/gin-gonic/gin v1.8.1
|
||||
github.com/glebarez/sqlite v1.5.0
|
||||
github.com/go-playground/validator/v10 v10.11.1 // indirect
|
||||
|
@@ -77,6 +77,11 @@ github.com/coreos/go-oidc/v3 v3.1.0 h1:6avEvcdvTa1qYsOZ6I5PRkSYHzpTNWgKYmaJfaYbr
|
||||
github.com/coreos/go-oidc/v3 v3.1.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/couchbase/gocb/v2 v2.6.0 h1:DhkLNatDcddCcS411D6kNwZspSEAWVeI/N3abzt/HLc=
|
||||
github.com/couchbase/gocb/v2 v2.6.0/go.mod h1:5su8b1gBF3V4j07SiGw+CA0bK9a84YWEb6UH7up0MEs=
|
||||
github.com/couchbase/gocbcore/v10 v10.2.0 h1:ZoSBLtcmt+lXbxVVT4SAhXDVNR+D48iSOZWNzHucVVk=
|
||||
github.com/couchbase/gocbcore/v10 v10.2.0/go.mod h1:qkPnOBziCs0guMEEvd0cRFo+AjOW0yEL99cU3I4n3Ao=
|
||||
github.com/couchbaselabs/gocaves/client v0.0.0-20220223122017-22859b310bd2/go.mod h1:AVekAZwIY2stsJOMWLAS/0uA/+qdp7pjO8EHnl61QkY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
@@ -174,6 +179,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
@@ -377,6 +384,7 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
|
@@ -76,7 +76,7 @@ func AppHandler() gin.HandlerFunc {
|
||||
"data": map[string]interface{}{
|
||||
"authorizerURL": hostname,
|
||||
"redirectURL": redirectURI,
|
||||
"scope": scope,
|
||||
"scope": strings.Join(scope, " "),
|
||||
"state": state,
|
||||
"organizationName": orgName,
|
||||
"organizationLogo": orgLogo,
|
||||
|
@@ -284,7 +284,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||
"access_token": authToken.AccessToken.Token,
|
||||
"id_token": authToken.IDToken.Token,
|
||||
"state": state,
|
||||
"scope": scope,
|
||||
"scope": strings.Join(scope, " "),
|
||||
"token_type": "Bearer",
|
||||
"expires_in": authToken.AccessToken.ExpiresAt,
|
||||
}
|
||||
|
@@ -259,7 +259,7 @@ func TokenHandler() gin.HandlerFunc {
|
||||
res := map[string]interface{}{
|
||||
"access_token": authToken.AccessToken.Token,
|
||||
"id_token": authToken.IDToken.Token,
|
||||
"scope": scope,
|
||||
"scope": strings.Join(scope, " "),
|
||||
"roles": roles,
|
||||
"expires_in": expiresIn,
|
||||
}
|
||||
|
@@ -32,6 +32,10 @@ type RequiredEnv struct {
|
||||
AwsRegion string `json:"AWS_REGION"`
|
||||
AwsAccessKeyID string `json:"AWS_ACCESS_KEY_ID"`
|
||||
AwsSecretAccessKey string `json:"AWS_SECRET_ACCESS_KEY"`
|
||||
// Couchbase related envs
|
||||
CouchbaseBucket string `json:"COUCHBASE_BUCKET"`
|
||||
CouchbaseScope string `json:"COUCHBASE_SCOPE"`
|
||||
CouchbaseBucketRAMQuotaMB string `json:"COUCHBASE_BUCKET_RAM_QUOTA"`
|
||||
}
|
||||
|
||||
// RequiredEnvObj is a simple in-memory store for sessions.
|
||||
@@ -93,6 +97,9 @@ func InitRequiredEnv() error {
|
||||
awsRegion := os.Getenv(constants.EnvAwsRegion)
|
||||
awsAccessKeyID := os.Getenv(constants.EnvAwsAccessKeyID)
|
||||
awsSecretAccessKey := os.Getenv(constants.EnvAwsSecretAccessKey)
|
||||
couchbaseBucket := os.Getenv(constants.EnvCouchbaseBucket)
|
||||
couchbaseScope := os.Getenv(constants.EnvCouchbaseScope)
|
||||
couchbaseBucketRAMQuotaMB := os.Getenv(constants.EnvCouchbaseBucketRAMQuotaMB)
|
||||
|
||||
if strings.TrimSpace(redisURL) == "" {
|
||||
if cli.ARG_REDIS_URL != nil && *cli.ARG_REDIS_URL != "" {
|
||||
@@ -135,22 +142,25 @@ func InitRequiredEnv() error {
|
||||
}
|
||||
|
||||
requiredEnv := RequiredEnv{
|
||||
EnvPath: envPath,
|
||||
DatabaseURL: dbURL,
|
||||
DatabaseType: dbType,
|
||||
DatabaseName: dbName,
|
||||
DatabaseHost: dbHost,
|
||||
DatabasePort: dbPort,
|
||||
DatabaseUsername: dbUsername,
|
||||
DatabasePassword: dbPassword,
|
||||
DatabaseCert: dbCert,
|
||||
DatabaseCertKey: dbCertKey,
|
||||
DatabaseCACert: dbCACert,
|
||||
RedisURL: redisURL,
|
||||
DisableRedisForEnv: disableRedisForEnv,
|
||||
AwsRegion: awsRegion,
|
||||
AwsAccessKeyID: awsAccessKeyID,
|
||||
AwsSecretAccessKey: awsSecretAccessKey,
|
||||
EnvPath: envPath,
|
||||
DatabaseURL: dbURL,
|
||||
DatabaseType: dbType,
|
||||
DatabaseName: dbName,
|
||||
DatabaseHost: dbHost,
|
||||
DatabasePort: dbPort,
|
||||
DatabaseUsername: dbUsername,
|
||||
DatabasePassword: dbPassword,
|
||||
DatabaseCert: dbCert,
|
||||
DatabaseCertKey: dbCertKey,
|
||||
DatabaseCACert: dbCACert,
|
||||
RedisURL: redisURL,
|
||||
DisableRedisForEnv: disableRedisForEnv,
|
||||
AwsRegion: awsRegion,
|
||||
AwsAccessKeyID: awsAccessKeyID,
|
||||
AwsSecretAccessKey: awsSecretAccessKey,
|
||||
CouchbaseBucket: couchbaseBucket,
|
||||
CouchbaseScope: couchbaseScope,
|
||||
CouchbaseBucketRAMQuotaMB: couchbaseBucketRAMQuotaMB,
|
||||
}
|
||||
|
||||
RequiredEnvStoreObj = &RequiredEnvStore{
|
||||
|
@@ -25,7 +25,6 @@ func adminSignupTests(t *testing.T, s TestSetup) {
|
||||
_, err = resolvers.AdminSignupResolver(ctx, model.AdminSignupInput{
|
||||
AdminSecret: "admin123",
|
||||
})
|
||||
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
|
@@ -16,11 +16,12 @@ import (
|
||||
|
||||
func TestResolvers(t *testing.T) {
|
||||
databases := map[string]string{
|
||||
constants.DbTypeSqlite: "../../test.db",
|
||||
constants.DbTypeArangodb: "http://localhost:8529",
|
||||
constants.DbTypeMongodb: "mongodb://localhost:27017",
|
||||
constants.DbTypeScyllaDB: "127.0.0.1:9042",
|
||||
constants.DbTypeDynamoDB: "http://0.0.0.0:8000",
|
||||
constants.DbTypeSqlite: "../../test.db",
|
||||
constants.DbTypeArangodb: "http://localhost:8529",
|
||||
constants.DbTypeMongodb: "mongodb://localhost:27017",
|
||||
constants.DbTypeScyllaDB: "127.0.0.1:9042",
|
||||
constants.DbTypeDynamoDB: "http://0.0.0.0:8000",
|
||||
constants.DbTypeCouchbaseDB: "couchbase://127.0.0.1",
|
||||
}
|
||||
|
||||
testDBs := strings.Split(os.Getenv("TEST_DBS"), ",")
|
||||
@@ -57,6 +58,12 @@ func TestResolvers(t *testing.T) {
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvAwsRegion, "ap-south-1")
|
||||
os.Setenv(constants.EnvAwsRegion, "ap-south-1")
|
||||
}
|
||||
if dbType == constants.DbTypeCouchbaseDB {
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabaseUsername, "Administrator")
|
||||
os.Setenv(constants.EnvKeyDatabaseUsername, "Administrator")
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDatabasePassword, "password")
|
||||
os.Setenv(constants.EnvKeyDatabasePassword, "password")
|
||||
}
|
||||
|
||||
memorystore.InitRequiredEnv()
|
||||
|
||||
|
@@ -162,9 +162,7 @@ func CreateAccessToken(user models.User, roles, scopes []string, hostName, nonce
|
||||
if err != nil {
|
||||
expiryBound = time.Minute * 30
|
||||
}
|
||||
|
||||
expiresAt := time.Now().Add(expiryBound).Unix()
|
||||
|
||||
clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
@@ -182,7 +180,41 @@ func CreateAccessToken(user models.User, roles, scopes []string, hostName, nonce
|
||||
"login_method": loginMethod,
|
||||
"allowed_roles": strings.Split(user.Roles, ","),
|
||||
}
|
||||
// check for the extra access token script
|
||||
accessTokenScript, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyCustomAccessTokenScript)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get custom access token script: ", err)
|
||||
accessTokenScript = ""
|
||||
}
|
||||
if accessTokenScript != "" {
|
||||
resUser := user.AsAPIUser()
|
||||
userBytes, _ := json.Marshal(&resUser)
|
||||
var userMap map[string]interface{}
|
||||
json.Unmarshal(userBytes, &userMap)
|
||||
vm := otto.New()
|
||||
claimBytes, _ := json.Marshal(customClaims)
|
||||
vm.Run(fmt.Sprintf(`
|
||||
var user = %s;
|
||||
var tokenPayload = %s;
|
||||
var customFunction = %s;
|
||||
var functionRes = JSON.stringify(customFunction(user, tokenPayload));
|
||||
`, string(userBytes), string(claimBytes), accessTokenScript))
|
||||
|
||||
val, err := vm.Get("functionRes")
|
||||
if err != nil {
|
||||
log.Debug("error getting custom access token script: ", err)
|
||||
} else {
|
||||
extraPayload := make(map[string]interface{})
|
||||
err = json.Unmarshal([]byte(fmt.Sprintf("%s", val)), &extraPayload)
|
||||
if err != nil {
|
||||
log.Debug("error converting accessTokenScript response to map: ", err)
|
||||
} else {
|
||||
for k, v := range extraPayload {
|
||||
customClaims[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
token, err := SignJWTToken(customClaims)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
@@ -345,14 +377,11 @@ func CreateIDToken(user models.User, roles []string, hostname, nonce, atHash, cH
|
||||
if err != nil {
|
||||
expiryBound = time.Minute * 30
|
||||
}
|
||||
|
||||
expiresAt := time.Now().Add(expiryBound).Unix()
|
||||
|
||||
resUser := user.AsAPIUser()
|
||||
userBytes, _ := json.Marshal(&resUser)
|
||||
var userMap map[string]interface{}
|
||||
json.Unmarshal(userBytes, &userMap)
|
||||
|
||||
claimKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtRoleClaim)
|
||||
if err != nil {
|
||||
claimKey = "roles"
|
||||
@@ -376,7 +405,6 @@ func CreateIDToken(user models.User, roles []string, hostname, nonce, atHash, cH
|
||||
}
|
||||
|
||||
// split nonce to see if its authorization code grant method
|
||||
|
||||
if cHash != "" {
|
||||
customClaims["at_hash"] = atHash
|
||||
customClaims["c_hash"] = cHash
|
||||
@@ -384,13 +412,11 @@ func CreateIDToken(user models.User, roles []string, hostname, nonce, atHash, cH
|
||||
customClaims["nonce"] = nonce
|
||||
customClaims["at_hash"] = atHash
|
||||
}
|
||||
|
||||
for k, v := range userMap {
|
||||
if k != "roles" {
|
||||
customClaims[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// check for the extra access token script
|
||||
accessTokenScript, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyCustomAccessTokenScript)
|
||||
if err != nil {
|
||||
@@ -399,7 +425,6 @@ func CreateIDToken(user models.User, roles []string, hostname, nonce, atHash, cH
|
||||
}
|
||||
if accessTokenScript != "" {
|
||||
vm := otto.New()
|
||||
|
||||
claimBytes, _ := json.Marshal(customClaims)
|
||||
vm.Run(fmt.Sprintf(`
|
||||
var user = %s;
|
||||
|
Reference in New Issue
Block a user