mirror of https://github.com/astaxie/beego.git
138 lines
3.4 KiB
Go
138 lines
3.4 KiB
Go
// Copyright 2017 The casbin Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package fileadapter
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/casbin/casbin/model"
|
|
"github.com/casbin/casbin/persist"
|
|
)
|
|
|
|
// FilteredAdapter is the filtered file adapter for Casbin. It can load policy
|
|
// from file or save policy to file and supports loading of filtered policies.
|
|
type FilteredAdapter struct {
|
|
*Adapter
|
|
filtered bool
|
|
}
|
|
|
|
// Filter defines the filtering rules for a FilteredAdapter's policy. Empty values
|
|
// are ignored, but all others must match the filter.
|
|
type Filter struct {
|
|
P []string
|
|
G []string
|
|
}
|
|
|
|
// NewFilteredAdapter is the constructor for FilteredAdapter.
|
|
func NewFilteredAdapter(filePath string) *FilteredAdapter {
|
|
a := FilteredAdapter{}
|
|
a.Adapter = NewAdapter(filePath)
|
|
return &a
|
|
}
|
|
|
|
// LoadPolicy loads all policy rules from the storage.
|
|
func (a *FilteredAdapter) LoadPolicy(model model.Model) error {
|
|
a.filtered = false
|
|
return a.Adapter.LoadPolicy(model)
|
|
}
|
|
|
|
// LoadFilteredPolicy loads only policy rules that match the filter.
|
|
func (a *FilteredAdapter) LoadFilteredPolicy(model model.Model, filter interface{}) error {
|
|
if filter == nil {
|
|
return a.LoadPolicy(model)
|
|
}
|
|
if a.filePath == "" {
|
|
return errors.New("invalid file path, file path cannot be empty")
|
|
}
|
|
|
|
filterValue, ok := filter.(*Filter)
|
|
if !ok {
|
|
return errors.New("invalid filter type")
|
|
}
|
|
err := a.loadFilteredPolicyFile(model, filterValue, persist.LoadPolicyLine)
|
|
if err == nil {
|
|
a.filtered = true
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (a *FilteredAdapter) loadFilteredPolicyFile(model model.Model, filter *Filter, handler func(string, model.Model)) error {
|
|
f, err := os.Open(a.filePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
scanner := bufio.NewScanner(f)
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
|
|
if filterLine(line, filter) {
|
|
continue
|
|
}
|
|
|
|
handler(line, model)
|
|
}
|
|
return scanner.Err()
|
|
}
|
|
|
|
// IsFiltered returns true if the loaded policy has been filtered.
|
|
func (a *FilteredAdapter) IsFiltered() bool {
|
|
return a.filtered
|
|
}
|
|
|
|
// SavePolicy saves all policy rules to the storage.
|
|
func (a *FilteredAdapter) SavePolicy(model model.Model) error {
|
|
if a.filtered {
|
|
return errors.New("cannot save a filtered policy")
|
|
}
|
|
return a.Adapter.SavePolicy(model)
|
|
}
|
|
|
|
func filterLine(line string, filter *Filter) bool {
|
|
if filter == nil {
|
|
return false
|
|
}
|
|
p := strings.Split(line, ",")
|
|
if len(p) == 0 {
|
|
return true
|
|
}
|
|
var filterSlice []string
|
|
switch strings.TrimSpace(p[0]) {
|
|
case "p":
|
|
filterSlice = filter.P
|
|
case "g":
|
|
filterSlice = filter.G
|
|
}
|
|
return filterWords(p, filterSlice)
|
|
}
|
|
|
|
func filterWords(line []string, filter []string) bool {
|
|
if len(line) < len(filter)+1 {
|
|
return true
|
|
}
|
|
var skipLine bool
|
|
for i, v := range filter {
|
|
if len(v) > 0 && strings.TrimSpace(v) != strings.TrimSpace(line[i+1]) {
|
|
skipLine = true
|
|
break
|
|
}
|
|
}
|
|
return skipLine
|
|
}
|