Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Subjects Rewrite #65

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions api/collections.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
_vault "github.com/subrose/vault"
)

// TODO: Extract and share the collection name validation logic

func (core *Core) GetCollection(c *fiber.Ctx) error {
collectionName := c.Params("name")
principal := GetSessionPrincipal(c)
Expand Down Expand Up @@ -37,6 +39,10 @@ func (core *Core) CreateCollection(c *fiber.Ctx) error {
return c.Status(fiber.StatusBadRequest).JSON(ErrorResponse{"Invalid body", nil})
}

if collection.Type == "" {
collection.Type = _vault.CollectionTypeSubject
}

err := core.vault.CreateCollection(c.Context(), principal, collection)
if err != nil {
return err
Expand Down Expand Up @@ -137,9 +143,7 @@ func (core *Core) GetRecords(c *fiber.Ctx) error {
if err != nil {
return err
}

return c.Status(http.StatusOK).JSON(records)

}

func (core *Core) GetRecord(c *fiber.Ctx) error {
Expand Down
5 changes: 4 additions & 1 deletion api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ require (
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.4.3 // indirect
github.com/jmoiron/sqlx v1.3.5 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
Expand All @@ -47,6 +48,8 @@ require (
golang.org/x/sys v0.14.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gorm.io/driver/postgres v1.5.4 // indirect
gorm.io/gorm v1.25.5 // indirect
)

replace github.com/subrose/vault v0.0.0 => ../vault
Expand Down
17 changes: 8 additions & 9 deletions api/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
Expand Down Expand Up @@ -154,10 +151,12 @@ github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
Expand All @@ -181,7 +180,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
Expand All @@ -199,9 +197,6 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
Expand Down Expand Up @@ -456,6 +451,10 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo=
gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0=
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
14 changes: 8 additions & 6 deletions api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func ApiLogger(core *Core) fiber.Handler {
ctx.Get("User-Agent"),
ctx.Get("X-Trace-Id"),
dt,
ctx.Response().StatusCode(),
ctx.Context().Response.StatusCode(), // This will now log the final status code
)
return err
}
Expand Down Expand Up @@ -87,6 +87,8 @@ func (core *Core) customErrorHandler(ctx *fiber.Ctx, err error) error {
return ctx.Status(code).SendString(err.Error())
}

core.logger.Error(err.Error())

// Handle custom errors from the vault package
var ve *_vault.ValueError
var fe *_vault.ForbiddenError
Expand Down Expand Up @@ -133,8 +135,8 @@ func SetupApi(core *Core) *fiber.App {
ErrorHandler: core.customErrorHandler,
})
app.Use(helmet.New())
app.Use(ApiLogger(core))
app.Use(recover.New())
app.Use(ApiLogger(core))

app.Get("/health", func(c *fiber.Ctx) error {
return c.Status(http.StatusOK).SendString("OK")
Expand All @@ -143,16 +145,16 @@ func SetupApi(core *Core) *fiber.App {
principalGroup := app.Group("/principals")
principalGroup.Use(authGuard(core))
principalGroup.Get(":username", core.GetPrincipal)
principalGroup.Post("", core.CreatePrincipal)
principalGroup.Post("", JSONOnlyMiddleware, core.CreatePrincipal)
principalGroup.Delete(":username", core.DeletePrincipal)

collectionsGroup := app.Group("/collections")
collectionsGroup.Use(authGuard(core))
collectionsGroup.Get("", core.GetCollections)
collectionsGroup.Get("/:name", core.GetCollection)
collectionsGroup.Delete("/:name", core.DeleteCollection)
collectionsGroup.Post("", core.CreateCollection)
collectionsGroup.Post("/:name/records", core.CreateRecord)
collectionsGroup.Post("", JSONOnlyMiddleware, core.CreateCollection)
collectionsGroup.Post("/:name/records", JSONOnlyMiddleware, core.CreateRecord)
collectionsGroup.Get("/:name/records", core.GetRecords)
collectionsGroup.Get("/:name/records/:id", core.GetRecord)
collectionsGroup.Put("/:name/records/:id", core.UpdateRecord)
Expand All @@ -168,7 +170,7 @@ func SetupApi(core *Core) *fiber.App {
tokensGroup := app.Group("/tokens")
tokensGroup.Use(authGuard(core))
tokensGroup.Get(":tokenId", core.GetTokenById)
tokensGroup.Post("", core.CreateToken)
tokensGroup.Post("", JSONOnlyMiddleware, core.CreateToken)

app.Use(func(c *fiber.Ctx) error {
return c.SendStatus(404)
Expand Down
7 changes: 0 additions & 7 deletions api/principals.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@ import (
_vault "github.com/subrose/vault"
)

// type NewPrincipal struct {
// Username string `json:"username" validate:"required,min=1,max=32"`
// Password string `json:"password" validate:"required,min=4,max=32"` // This is to limit the size of the password hash.
// Description string `json:"description"`
// Policies []string `json:"policies"`
// }

type PrincipalResponse struct {
Id string `json:"id"`
Username string `json:"username" validate:"required,min=3,max=32"`
Expand Down
3 changes: 3 additions & 0 deletions archive/sql/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module sql/m/v2

go 1.21.0
197 changes: 197 additions & 0 deletions archive/sql/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
package main

import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"log"
"time"

"github.com/lib/pq"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)

// Define your models
type dbPolicy struct {
Id string `gorm:"primaryKey"`
Name string
Description string
Effect string
Actions pq.StringArray `gorm:"type:text[]"`
Resources pq.StringArray `gorm:"type:text[]"`
CreatedAt time.Time
UpdatedAt time.Time
}

func (dbPolicy) TableName() string {
return "policies"
}

type dbPrincipal struct {
Id string `gorm:"primaryKey"`
Username string
Password string
Description string
CreatedAt time.Time
UpdatedAt time.Time
Policies []dbPolicy `gorm:"many2many:principal_policies;"`
}

func (dbPrincipal) TableName() string {
return "principals"
}

type dbToken struct {
Id string `gorm:"primaryKey"`
value string
CreatedAt time.Time
UpdatedAt time.Time
}

func (dbToken) TableName() string {
return "tokens"
}

type PrincipalPolicy struct {
PrincipalId string `gorm:"primaryKey;autoIncrement:false"`
PolicyId string `gorm:"primaryKey;autoIncrement:false"`
}

func (PrincipalPolicy) TableName() string {
return "principal_policies"
}

type Field struct {
Type string `json:"type"`
IsIndexed bool `json:"indexed"`
}

type FieldSchemaMap map[string]Field

func (f *FieldSchemaMap) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New("failed to unmarshal JSONB value")
}

result := FieldSchemaMap{}
if err := json.Unmarshal(bytes, &result); err != nil {
return err
}

*f = result
return nil
}

func (f FieldSchemaMap) Value() (driver.Value, error) {
if len(f) == 0 {
return nil, nil
}

return json.Marshal(f)
}

type dbCollectionMetadata struct {
Id string `gorm:"primaryKey"`
Name string `gorm:"unique"`
FieldSchema FieldSchemaMap `gorm:"type:json"` // Ensures JSON storage
CreatedAt time.Time
UpdatedAt time.Time
}

func (dbCollectionMetadata) TableName() string {
return "collections_metadata"
}

func main() {
// Setup database connection
time.Local = time.UTC
dsn := "host=localhost user=postgres dbname=postgres sslmode=disable password=postgres"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{TranslateError: true})
if err != nil {
log.Fatalf("Failed to connect to database: %v", err)
}

// Drop tables
db.Exec("DROP TABLE IF EXISTS principal_policies")
db.Exec("DROP TABLE IF EXISTS principals")
db.Exec("DROP TABLE IF EXISTS policies")
db.Exec("DROP TABLE IF EXISTS collections_metadata")

// AutoMigrate models
db.AutoMigrate(&dbPrincipal{}, &dbPolicy{}, &PrincipalPolicy{}, &dbCollectionMetadata{})

// Create a Policy

policy := dbPolicy{
Id: "policy1",
Name: "Test Policy",
Description: "A test policy",
Effect: "allow",
Actions: []string{"read", "write"},
Resources: []string{"resource1", "resource2"},
}

db.Create(&policy)

// Create a Principal with the created Policy
principal := dbPrincipal{
Id: "principal1",
Username: "john_doe",
Password: "secret",
Description: "A test principal",
Policies: []dbPolicy{policy},
}
db.Create(&principal)

// Retrieve a Principal with their Policies - this can be looped over
var retrievedPrincipal dbPrincipal
db.Preload("Policies").First(&retrievedPrincipal, "id = ?", "principal1")

// Pattern for deleting a Principal and associated records
// Start a new transaction
tx := db.Begin()

// Defer a function that will commit the transaction if no errors, or rollback if there were any
defer func() {
if r := recover(); r != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()

// Delete a Principal and cascade delete associated records in PrincipalPolicy
if err := tx.Where("principal_id = ?", principal.Id).Delete(&PrincipalPolicy{}).Error; err != nil {
log.Fatal(err)
}

// Then, delete the principal
if err := tx.Delete(principal).Error; err != nil {
log.Fatal(err)
}

// Create a CollectionMetadata
collectionMetadata := dbCollectionMetadata{
Id: "collection1",
Name: "customers",
FieldSchema: map[string]Field{"name": {Type: "phone", IsIndexed: true}},
}

db.Create(&collectionMetadata)
result := db.Create(&collectionMetadata)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrDuplicatedKey) {
log.Print("Collection already exists") // we'd return a 409 here
} else {
log.Fatal(result.Error)
}
}

// Now let's retrieve the CollectionMetadata
var retrievedCollectionMetadata dbCollectionMetadata
db.First(&retrievedCollectionMetadata, "id = ?", "collection1")
fmt.Println(retrievedCollectionMetadata.FieldSchema["name"].Type)
}
Loading
Loading