any-sync/service/storage/service.go
2022-09-12 21:06:20 +02:00

137 lines
3.8 KiB
Go

package storage
import (
"context"
"fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/app"
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/etc"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/testutils/acllistbuilder"
"github.com/anytypeio/go-anytype-infrastructure-experiments/service/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/service/node"
)
var CName = "storage"
var log = logger.NewNamed("storage").Sugar()
type ImportedACLSyncData struct {
Id string
Header *aclpb.Header
Records []*aclpb.RawACLRecord
}
type Service interface {
storage.Provider
ImportedACLSyncData() ImportedACLSyncData
}
func New() app.Component {
return &service{}
}
type service struct {
storageProvider storage.Provider
importedACLSyncData ImportedACLSyncData
}
func (s *service) Init(ctx context.Context, a *app.App) (err error) {
s.storageProvider = storage.NewInMemoryTreeStorageProvider()
// importing hardcoded acl list, check that the keys there are correct
return s.importACLList(a)
}
func (s *service) Storage(treeId string) (storage.Storage, error) {
return s.storageProvider.Storage(treeId)
}
func (s *service) AddStorage(id string, st storage.Storage) error {
return s.storageProvider.AddStorage(id, st)
}
func (s *service) CreateTreeStorage(treeId string, header *aclpb.Header, changes []*aclpb.RawChange) (storage.TreeStorage, error) {
return s.storageProvider.CreateTreeStorage(treeId, header, changes)
}
func (s *service) CreateACLListStorage(id string, header *aclpb.Header, records []*aclpb.RawRecord) (storage.ListStorage, error) {
return s.storageProvider.CreateACLListStorage(id, header, records)
}
func (s *service) Name() (name string) {
return CName
}
func (s *service) ImportedACLSyncData() ImportedACLSyncData {
return s.importedACLSyncData
}
func (s *service) Run(ctx context.Context) (err error) {
return nil
}
func (s service) Close(ctx context.Context) (err error) {
return nil
}
func (s *service) importACLList(a *app.App) (err error) {
path := fmt.Sprintf("%s/%s", etc.Path(), "acl.yml")
st, err := acllistbuilder.NewACLListStorageBuilderFromFile(path)
if err != nil {
return err
}
id, err := st.ID()
if err != nil {
return err
}
header, err := st.Header()
if err != nil {
return err
}
// checking that acl list contains all the needed permissions for all our nodes
err = s.checkActualNodesPermissions(st, a)
if err != nil {
return err
}
s.importedACLSyncData = ImportedACLSyncData{
Id: id,
Header: header,
Records: st.GetRawRecords(),
}
log.Infof("imported ACLList with id %s", id)
return s.storageProvider.AddStorage(id, st)
}
func (s *service) checkActualNodesPermissions(st *acllistbuilder.ACLListStorageBuilder, a *app.App) error {
nodes := a.MustComponent(node.CName).(node.Service)
acc := a.MustComponent(account.CName).(account.Service)
aclList, err := list.BuildACLListWithIdentity(acc.Account(), st)
if err != nil {
return err
}
state := aclList.ACLState()
// checking own state
if state.GetUserStates()[acc.Account().Identity].Permissions != aclpb.ACLChange_Admin {
return fmt.Errorf("own node with signing key %s should be admin", acc.Account().Identity)
}
// checking other nodes' states
for _, n := range nodes.Nodes() {
if state.GetUserStates()[n.SigningKeyString].Permissions != aclpb.ACLChange_Admin {
return fmt.Errorf("other node with signing key %s should be admin", n.SigningKeyString)
}
}
return nil
}