132 lines
3.1 KiB
Go
132 lines
3.1 KiB
Go
package allowlist
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
lru "github.com/hashicorp/golang-lru"
|
|
portainer "github.com/portainer/portainer/api"
|
|
"github.com/portainer/portainer/api/dataservices"
|
|
"github.com/portainer/portainer/pkg/libhttp/ssrf"
|
|
)
|
|
|
|
const (
|
|
BucketName = "allowlist"
|
|
)
|
|
|
|
type Service struct {
|
|
baseService dataservices.BaseDataService[portainer.AllowList, portainer.AllowListKey]
|
|
cache *lru.Cache
|
|
}
|
|
|
|
func (service *Service) BucketName() string {
|
|
return service.baseService.BucketName()
|
|
}
|
|
|
|
func NewService(connection portainer.Connection) (*Service, error) {
|
|
err := connection.SetServiceName(BucketName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
service := &Service{
|
|
baseService: dataservices.BaseDataService[portainer.AllowList, portainer.AllowListKey]{
|
|
Bucket: BucketName,
|
|
Connection: connection,
|
|
},
|
|
}
|
|
|
|
err = service.populateCache()
|
|
|
|
return service, err
|
|
}
|
|
|
|
func (service *Service) populateCache() error {
|
|
allowListKeys := []portainer.AllowListKey{portainer.AllowListSSRF}
|
|
cache, err := lru.New(len(allowListKeys))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, k := range allowListKeys {
|
|
allowList, err := service.baseService.Read(k)
|
|
if dataservices.IsErrObjectNotFound(err) {
|
|
allowList = &portainer.AllowList{
|
|
ID: k,
|
|
Mode: portainer.SSRFModeOff,
|
|
Entries: []string{},
|
|
}
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
|
|
parsedAllowList := ssrf.ParseAllowedHosts(allowList.Entries)
|
|
parsedAllowList.Mode = allowList.Mode
|
|
|
|
cache.Add(k, &parsedAllowList)
|
|
}
|
|
|
|
service.cache = cache
|
|
|
|
return nil
|
|
}
|
|
|
|
func (service *Service) Tx(tx portainer.Transaction) *ServiceTx {
|
|
return &ServiceTx{
|
|
baseService: service.baseService.Tx(tx),
|
|
cache: service.cache,
|
|
}
|
|
}
|
|
|
|
func (service *Service) Read(id portainer.AllowListKey) (*portainer.AllowList, error) {
|
|
var result *portainer.AllowList
|
|
if err := service.baseService.Connection.ViewTx(func(tx portainer.Transaction) error {
|
|
var err error
|
|
result, err = service.Tx(tx).Read(id)
|
|
return err
|
|
}); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (service *Service) ReadAll() ([]portainer.AllowList, error) {
|
|
var result []portainer.AllowList
|
|
if err := service.baseService.Connection.ViewTx(func(tx portainer.Transaction) error {
|
|
var err error
|
|
result, err = service.Tx(tx).ReadAll()
|
|
return err
|
|
}); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (service *Service) ReadParsed(id portainer.AllowListKey) (*portainer.ParsedAllowList, error) {
|
|
allowListAny, ok := service.cache.Get(id)
|
|
if ok {
|
|
allowList, ok := allowListAny.(*portainer.ParsedAllowList)
|
|
if !ok {
|
|
return nil, fmt.Errorf("expected ParsedAllowList in cache but got %T", allowListAny)
|
|
}
|
|
|
|
return allowList, nil
|
|
}
|
|
|
|
var result *portainer.ParsedAllowList
|
|
err := service.baseService.Connection.ViewTx(func(tx portainer.Transaction) error {
|
|
var err error
|
|
result, err = service.Tx(tx).ReadParsed(id)
|
|
return err
|
|
})
|
|
|
|
return result, err
|
|
}
|
|
|
|
func (service *Service) Update(id portainer.AllowListKey, allowList *portainer.AllowList) error {
|
|
return service.baseService.Connection.UpdateTx(func(tx portainer.Transaction) error {
|
|
return service.Tx(tx).Update(id, allowList)
|
|
})
|
|
}
|