visible

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 31, 2024 License: MIT Imports: 3 Imported by: 0

README

Visible

A lightweight library to control the visibility of struct fields based on roles.

Installation

go get github.com/fattymango/visible

Examples

import "github.com/fattymango/visible"

type User struct {
    ID int `json:"id"`
    Name string `json:"name"`
    AdminData interface{} `json:"admin_data" visible:"admin"`
}



func main() {
   user := User{
    ID: 1,
    Name: "John Doe",
    AdminData: "Admin Data",
}

res,err := visible.CleanStruct(user, "admin")
if err != nil {
    log.Fatal(err)
}
fmt.Println(res)
}
// Output: {id:1 name:John Doe admin_data:Admin Data}

res,err := visible.CleanStruct(user, "user")
if err != nil {
    log.Fatal(err)
}
fmt.Println(res)
}
// Output: {id:1 name:John Doe}

Example with Casbin and GoFiber

import (
	"github.com/fattymango/visible"

	"github.com/casbin/casbin/v2"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	"github.com/gofiber/fiber/v2"
	"gorm.io/driver/mysql"

	"gorm.io/gorm"
)

func NewCasbinMiddleware(e *casbin.Enforcer, resource, action string) fiber.Handler {
	return func(c *fiber.Ctx) error {

		// get role from path
		role := c.Params("role")

		if role == "" {
			return c.SendStatus(fiber.StatusForbidden)
		}

		if ok, _ := e.Enforce(role, resource, action); ok {
			return c.Next()

		}
		return c.SendStatus(fiber.StatusForbidden)

	}
}

type Data struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
	// AliceData is only visible to alice
	AliceData string `json:"alice_data" visible:"alice"`
	// BobData is only visible to bob
	BobData string `json:"bob_data" visible:"bob"`
	// AliceAndBobData is visible to both alice and bob
	AliceAndBobData string `json:"alice_and_bob_data" visible:"alice,bob"`
	// this field will never be visible to anyone
	PrivateData string `json:"-"`
}

func NewSuccessResponse(ctx *fiber.Ctx, data interface{}) error {

	cleanData, err := visible.CleanStruct(data, ctx.Params("role"))
	if err != nil {
		return ctx.SendStatus(fiber.StatusInternalServerError)
	}
	return ctx.Status(200).JSON(cleanData)
}
func main() {
	dsn := "test:test@tcp(localhost:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"

	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic(err)
	}
	a, err := gormadapter.NewAdapterByDB(db) // Your driver and data source.
	if err != nil {
		panic(err)
	}
	e, err := casbin.NewEnforcer("casbin_model.conf", a)
	if err != nil {
		panic(err)
	}
	e.LoadPolicy()
	e.AddPolicy("alice", "data1", "read")
	e.AddPolicy("bob", "data1", "read")
	e.AddPolicy("charlie", "data1", "read")
	app := fiber.New()

	// examples:
	// http://localhost:3000/alice --> {ID: 1, Name: "alice", AliceData: "alice_data", AliceAndBobData: "alice_and_bob_data"}
	// http://localhost:3000/bob --> {ID: 1, Name: "bob", BobData: "bob_data", AliceAndBobData: "alice_and_bob_data"}
	// http://localhost:3000/charlie --> {ID: 1, Name: "charlie"}
	// http://localhost:3000/saif --> 403 Forbidden
	app.Get("/:role",
		NewCasbinMiddleware(e, "data1", "read"),
		func(ctx *fiber.Ctx) error {
			data := Data{
				ID:              1,
				Name:            c.Params("role"),
				AliceData:       "alice_data",
				BobData:         "bob_data",
				AliceAndBobData: "alice_and_bob_data",
				PrivateData:     "private_data",
			}

			return NewSuccessResponse(ctx, data)
		})

	app.Listen(":3000")
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CleanStruct

func CleanStruct(data interface{}, visiblityValidator string) (map[string]interface{}, error)

delete all fields that doesn't have the visible tag value

example:

type Data struct {
	ID    int
	Name  string `json:"name"`
	Data1 string `json:"data1" visible:"alice,bob"`
	Data2 string `json:"data2" visible:"bob"`
	HiddenData string `json:"-"`
}

CleanStruct(data, "alice") -> {id: 1, name: "name", data1: "data1"} // only alice_data is visible

CleanStruct(data, "bob") -> {id: 1, name: "name", data1: "data1", data2: "data2"} // only bob_data is visible

CleanStruct(data, "charlie") -> {id: 1, name: "name"} // no data is visible

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL