Bootstrap copied BFF and local accounts with public Sendico contracts (#34)
This commit is contained in:
1 parent
67dc5b5b1e
commit
7062672a87
556 files changed
+42291
-777
No files matched your search
@@ -0,0 +1,357 @@
|
||||
package mongoadapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.sendico.io/tech/sxchnge/bff/pkg/merrors"
|
||||
"time"
|
||||
|
||||
"github.com/casbin/casbin/v3/model"
|
||||
"github.com/casbin/casbin/v3/persist"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo/options"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultDatabaseName = "casbin"
|
||||
defaultCollectionName = "casbin_rule"
|
||||
defaultTimeout = 30 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
_ persist.BatchAdapter = (*Adapter)(nil)
|
||||
_ persist.FilteredAdapter = (*Adapter)(nil)
|
||||
_ persist.UpdatableAdapter = (*Adapter)(nil)
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
DatabaseName string
|
||||
CollectionName string
|
||||
Timeout time.Duration
|
||||
IsFiltered bool
|
||||
}
|
||||
|
||||
type Rule struct {
|
||||
PType string
|
||||
V0 string
|
||||
V1 string
|
||||
V2 string
|
||||
V3 string
|
||||
V4 string
|
||||
V5 string
|
||||
}
|
||||
|
||||
type Adapter struct {
|
||||
collection *mongo.Collection
|
||||
timeout time.Duration
|
||||
filtered bool
|
||||
}
|
||||
|
||||
func New(client *mongo.Client, config *Config) (*Adapter, error) {
|
||||
if config == nil {
|
||||
config = &Config{}
|
||||
}
|
||||
|
||||
databaseName := config.DatabaseName
|
||||
if databaseName == "" {
|
||||
databaseName = defaultDatabaseName
|
||||
}
|
||||
collectionName := config.CollectionName
|
||||
if collectionName == "" {
|
||||
collectionName = defaultCollectionName
|
||||
}
|
||||
timeout := config.Timeout
|
||||
if timeout == 0 {
|
||||
timeout = defaultTimeout
|
||||
}
|
||||
|
||||
adapter := &Adapter{
|
||||
collection: client.Database(databaseName).Collection(collectionName),
|
||||
timeout: timeout,
|
||||
filtered: config.IsFiltered,
|
||||
}
|
||||
if err := adapter.prepareIndexes(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adapter, nil
|
||||
}
|
||||
|
||||
func (a *Adapter) prepareIndexes() error {
|
||||
keys := bson.D{
|
||||
{Key: "ptype", Value: 1},
|
||||
{Key: "v0", Value: 1},
|
||||
{Key: "v1", Value: 1},
|
||||
{Key: "v2", Value: 1},
|
||||
{Key: "v3", Value: 1},
|
||||
{Key: "v4", Value: 1},
|
||||
{Key: "v5", Value: 1},
|
||||
}
|
||||
|
||||
_, err := a.collection.Indexes().CreateOne(
|
||||
context.Background(),
|
||||
mongo.IndexModel{
|
||||
Keys: keys,
|
||||
Options: options.Index().SetUnique(true),
|
||||
},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *Adapter) withTimeout() (context.Context, context.CancelFunc) {
|
||||
return context.WithTimeout(context.Background(), a.timeout)
|
||||
}
|
||||
|
||||
func loadPolicyLine(line Rule, m model.Model) error {
|
||||
policy := line.policyWithType()
|
||||
for len(policy) > 0 && policy[len(policy)-1] == "" {
|
||||
policy = policy[:len(policy)-1]
|
||||
}
|
||||
if len(policy) == 0 {
|
||||
return nil
|
||||
}
|
||||
return persist.LoadPolicyArray(policy, m)
|
||||
}
|
||||
|
||||
func (r Rule) policyWithType() []string {
|
||||
return []string{r.PType, r.V0, r.V1, r.V2, r.V3, r.V4, r.V5}
|
||||
}
|
||||
|
||||
func (r Rule) policyValues() []string {
|
||||
values := []string{r.V0, r.V1, r.V2, r.V3, r.V4, r.V5}
|
||||
for len(values) > 0 && values[len(values)-1] == "" {
|
||||
values = values[:len(values)-1]
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
func ruleFromPolicy(ptype string, policy []string) Rule {
|
||||
rule := Rule{PType: ptype}
|
||||
if len(policy) > 0 {
|
||||
rule.V0 = policy[0]
|
||||
}
|
||||
if len(policy) > 1 {
|
||||
rule.V1 = policy[1]
|
||||
}
|
||||
if len(policy) > 2 {
|
||||
rule.V2 = policy[2]
|
||||
}
|
||||
if len(policy) > 3 {
|
||||
rule.V3 = policy[3]
|
||||
}
|
||||
if len(policy) > 4 {
|
||||
rule.V4 = policy[4]
|
||||
}
|
||||
if len(policy) > 5 {
|
||||
rule.V5 = policy[5]
|
||||
}
|
||||
return rule
|
||||
}
|
||||
|
||||
func rulesFromPolicies(ptype string, policies [][]string) []Rule {
|
||||
rules := make([]Rule, 0, len(policies))
|
||||
for _, policy := range policies {
|
||||
rules = append(rules, ruleFromPolicy(ptype, policy))
|
||||
}
|
||||
return rules
|
||||
}
|
||||
|
||||
func rulesAsDocuments(rules []Rule) []any {
|
||||
docs := make([]any, 0, len(rules))
|
||||
for _, rule := range rules {
|
||||
docs = append(docs, rule)
|
||||
}
|
||||
return docs
|
||||
}
|
||||
|
||||
func selectorForPolicy(ptype string, fieldIndex int, fieldValues ...string) bson.M {
|
||||
selector := bson.M{"ptype": ptype}
|
||||
fields := []string{"v0", "v1", "v2", "v3", "v4", "v5"}
|
||||
for i, fieldValue := range fieldValues {
|
||||
if fieldValue == "" {
|
||||
continue
|
||||
}
|
||||
field := fieldIndex + i
|
||||
if field < 0 || field >= len(fields) {
|
||||
continue
|
||||
}
|
||||
selector[fields[field]] = fieldValue
|
||||
}
|
||||
return selector
|
||||
}
|
||||
|
||||
func (a *Adapter) LoadPolicy(m model.Model) error {
|
||||
return a.LoadFilteredPolicy(m, nil)
|
||||
}
|
||||
|
||||
func (a *Adapter) LoadFilteredPolicy(m model.Model, filter any) error {
|
||||
if filter == nil {
|
||||
a.filtered = false
|
||||
filter = bson.D{}
|
||||
} else {
|
||||
a.filtered = true
|
||||
}
|
||||
|
||||
ctx, cancel := a.withTimeout()
|
||||
defer cancel()
|
||||
|
||||
cursor, err := a.collection.Find(ctx, filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = cursor.Close(ctx)
|
||||
}()
|
||||
|
||||
for cursor.Next(ctx) {
|
||||
var line Rule
|
||||
if err := cursor.Decode(&line); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := loadPolicyLine(line, m); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return cursor.Err()
|
||||
}
|
||||
|
||||
func (a *Adapter) IsFiltered() bool {
|
||||
return a.filtered
|
||||
}
|
||||
|
||||
func (a *Adapter) SavePolicy(m model.Model) error {
|
||||
if a.filtered {
|
||||
return merrors.Define("cannot save a filtered policy")
|
||||
}
|
||||
|
||||
ctx, cancel := a.withTimeout()
|
||||
defer cancel()
|
||||
|
||||
if _, err := a.collection.DeleteMany(ctx, bson.D{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var docs []any
|
||||
for ptype, ast := range m["p"] {
|
||||
docs = append(docs, rulesAsDocuments(rulesFromPolicies(ptype, ast.Policy))...)
|
||||
}
|
||||
for ptype, ast := range m["g"] {
|
||||
docs = append(docs, rulesAsDocuments(rulesFromPolicies(ptype, ast.Policy))...)
|
||||
}
|
||||
if len(docs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := a.collection.InsertMany(ctx, docs)
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *Adapter) AddPolicy(_ string, ptype string, policy []string) error {
|
||||
ctx, cancel := a.withTimeout()
|
||||
defer cancel()
|
||||
|
||||
_, err := a.collection.InsertOne(ctx, ruleFromPolicy(ptype, policy))
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *Adapter) AddPolicies(_ string, ptype string, policies [][]string) error {
|
||||
if len(policies) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, cancel := a.withTimeout()
|
||||
defer cancel()
|
||||
|
||||
_, err := a.collection.InsertMany(ctx, rulesAsDocuments(rulesFromPolicies(ptype, policies)))
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *Adapter) RemovePolicy(_ string, ptype string, policy []string) error {
|
||||
ctx, cancel := a.withTimeout()
|
||||
defer cancel()
|
||||
|
||||
_, err := a.collection.DeleteOne(ctx, ruleFromPolicy(ptype, policy))
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *Adapter) RemovePolicies(_ string, ptype string, policies [][]string) error {
|
||||
ctx, cancel := a.withTimeout()
|
||||
defer cancel()
|
||||
|
||||
for _, rule := range rulesFromPolicies(ptype, policies) {
|
||||
if _, err := a.collection.DeleteOne(ctx, rule); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Adapter) RemoveFilteredPolicy(_ string, ptype string, fieldIndex int, fieldValues ...string) error {
|
||||
ctx, cancel := a.withTimeout()
|
||||
defer cancel()
|
||||
|
||||
_, err := a.collection.DeleteMany(ctx, selectorForPolicy(ptype, fieldIndex, fieldValues...))
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *Adapter) UpdatePolicy(_ string, ptype string, oldPolicy, newPolicy []string) error {
|
||||
ctx, cancel := a.withTimeout()
|
||||
defer cancel()
|
||||
|
||||
_, err := a.collection.ReplaceOne(ctx, ruleFromPolicy(ptype, oldPolicy), ruleFromPolicy(ptype, newPolicy))
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *Adapter) UpdatePolicies(_ string, ptype string, oldPolicies, newPolicies [][]string) error {
|
||||
if len(oldPolicies) != len(newPolicies) {
|
||||
return merrors.Define("old and new policy counts differ")
|
||||
}
|
||||
|
||||
ctx, cancel := a.withTimeout()
|
||||
defer cancel()
|
||||
|
||||
for i := range oldPolicies {
|
||||
if _, err := a.collection.ReplaceOne(ctx, ruleFromPolicy(ptype, oldPolicies[i]), ruleFromPolicy(ptype, newPolicies[i])); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Adapter) UpdateFilteredPolicies(_ string, ptype string, newPolicies [][]string, fieldIndex int, fieldValues ...string) ([][]string, error) {
|
||||
ctx, cancel := a.withTimeout()
|
||||
defer cancel()
|
||||
|
||||
selector := selectorForPolicy(ptype, fieldIndex, fieldValues...)
|
||||
cursor, err := a.collection.Find(ctx, selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var oldPolicies [][]string
|
||||
for cursor.Next(ctx) {
|
||||
var line Rule
|
||||
if err := cursor.Decode(&line); err != nil {
|
||||
_ = cursor.Close(ctx)
|
||||
return nil, err
|
||||
}
|
||||
oldPolicies = append(oldPolicies, line.policyValues())
|
||||
}
|
||||
if err := cursor.Close(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cursor.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := a.collection.DeleteMany(ctx, selector); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(newPolicies) == 0 {
|
||||
return oldPolicies, nil
|
||||
}
|
||||
|
||||
if _, err := a.collection.InsertMany(ctx, rulesAsDocuments(rulesFromPolicies(ptype, newPolicies))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return oldPolicies, nil
|
||||
}
|
||||
Reference in new issue
Block a user