any-sync/pkg/acl/tree/aclstatebuilder.go
2022-08-10 14:48:17 +02:00

103 lines
2.4 KiB
Go

package tree
import (
"fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/encryptionkey"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
)
type aclStateBuilder struct {
tree *Tree
identity string
key encryptionkey.PrivKey
decoder signingkey.PubKeyDecoder
}
func newACLStateBuilderWithIdentity(decoder signingkey.PubKeyDecoder, accountData *account.AccountData) *aclStateBuilder {
return &aclStateBuilder{
decoder: decoder,
identity: accountData.Identity,
key: accountData.EncKey,
}
}
func newACLStateBuilder() *aclStateBuilder {
return &aclStateBuilder{}
}
func (sb *aclStateBuilder) Init(tree *Tree) error {
sb.tree = tree
return nil
}
func (sb *aclStateBuilder) Build() (*ACLState, error) {
state, _, err := sb.BuildBefore("")
return state, err
}
func (sb *aclStateBuilder) BuildBefore(beforeId string) (*ACLState, bool, error) {
var (
err error
startChange = sb.tree.root
state *ACLState
foundId = false
)
if sb.decoder != nil {
state = newACLStateWithIdentity(sb.identity, sb.key, sb.decoder)
} else {
state = newACLState()
}
if beforeId == startChange.Id {
return state, true, nil
}
iterFunc := func(c *Change) (isContinue bool) {
defer func() {
if err == nil {
startChange = c
} else if err != ErrDocumentForbidden {
log.Errorf("marking change %s as invalid: %v", c.Id, err)
sb.tree.RemoveInvalidChange(c.Id)
}
}()
err = state.applyChangeAndUpdate(c)
if err != nil {
return false
}
// the user can't make changes
if !state.hasPermission(c.Content.Identity, aclpb.ACLChange_Writer) && !state.hasPermission(c.Content.Identity, aclpb.ACLChange_Admin) {
err = fmt.Errorf("user %s cannot make changes", c.Content.Identity)
return false
}
if c.Id == beforeId {
foundId = true
return false
}
return true
}
for {
sb.tree.IterateSkip(sb.tree.root.Id, startChange.Id, iterFunc)
if err == nil {
break
}
// the user is forbidden to access the document
if err == ErrDocumentForbidden {
return nil, foundId, err
}
// otherwise we have to continue from the change which we had
err = nil
}
return state, foundId, err
}