103 lines
2.4 KiB
Go
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
|
|
}
|