Add some logic in validator

This commit is contained in:
mcrakhman 2022-08-19 22:31:13 +02:00
parent b0432487cc
commit 8cf5acd183
No known key found for this signature in database
GPG Key ID: DED12CFEF5B8396B
3 changed files with 88 additions and 8 deletions

View File

@ -22,6 +22,13 @@ var ErrFailedToDecrypt = errors.New("failed to decrypt key")
var ErrUserRemoved = errors.New("user was removed from the document") var ErrUserRemoved = errors.New("user was removed from the document")
var ErrDocumentForbidden = errors.New("your user was forbidden access to the document") var ErrDocumentForbidden = errors.New("your user was forbidden access to the document")
var ErrUserAlreadyExists = errors.New("user already exists") var ErrUserAlreadyExists = errors.New("user already exists")
var ErrNoSuchRecord = errors.New("no such record")
var ErrInsufficientPermissions = errors.New("insufficient permissions")
type UserPermissionPair struct {
Identity string
Permission aclpb.ACLChangeUserPermissions
}
type ACLState struct { type ACLState struct {
currentReadKeyHash uint64 currentReadKeyHash uint64
@ -31,6 +38,7 @@ type ACLState struct {
signingPubKeyDecoder keys.Decoder signingPubKeyDecoder keys.Decoder
encryptionKey encryptionkey.PrivKey encryptionKey encryptionkey.PrivKey
identity string identity string
permissionsAtRecord map[string][]UserPermissionPair
} }
func newACLStateWithIdentity( func newACLStateWithIdentity(
@ -44,14 +52,16 @@ func newACLStateWithIdentity(
userStates: make(map[string]*aclpb.ACLChangeUserState), userStates: make(map[string]*aclpb.ACLChangeUserState),
userInvites: make(map[string]*aclpb.ACLChangeUserInvite), userInvites: make(map[string]*aclpb.ACLChangeUserInvite),
signingPubKeyDecoder: decoder, signingPubKeyDecoder: decoder,
permissionsAtRecord: make(map[string][]UserPermissionPair),
} }
} }
func newACLState() *ACLState { func newACLState() *ACLState {
return &ACLState{ return &ACLState{
userReadKeys: make(map[uint64]*symmetric.Key), userReadKeys: make(map[uint64]*symmetric.Key),
userStates: make(map[string]*aclpb.ACLChangeUserState), userStates: make(map[string]*aclpb.ACLChangeUserState),
userInvites: make(map[string]*aclpb.ACLChangeUserInvite), userInvites: make(map[string]*aclpb.ACLChangeUserInvite),
permissionsAtRecord: make(map[string][]UserPermissionPair),
} }
} }
@ -63,7 +73,22 @@ func (st *ACLState) UserReadKeys() map[uint64]*symmetric.Key {
return st.userReadKeys return st.userReadKeys
} }
func (st *ACLState) PermissionsAtRecord(id string, identity string) (UserPermissionPair, error) {
permissions, ok := st.permissionsAtRecord[id]
if !ok {
return UserPermissionPair{}, ErrNoSuchRecord
}
for _, perm := range permissions {
if perm.Identity == identity {
return perm, nil
}
}
return UserPermissionPair{}, ErrNoSuchUser
}
func (st *ACLState) applyRecord(record *aclpb.Record) (err error) { func (st *ACLState) applyRecord(record *aclpb.Record) (err error) {
// TODO: this should be probably changed
aclData := &aclpb.ACLChangeACLData{} aclData := &aclpb.ACLChangeACLData{}
err = proto.Unmarshal(record.Data, aclData) err = proto.Unmarshal(record.Data, aclData)
@ -95,7 +120,21 @@ func (st *ACLState) applyChangeAndUpdate(recordWrapper *Record) (err error) {
recordWrapper.ParsedModel = aclData recordWrapper.ParsedModel = aclData
} }
return st.applyChangeData(aclData, recordWrapper.Content.CurrentReadKeyHash, recordWrapper.Content.Identity) err = st.applyChangeData(aclData, recordWrapper.Content.CurrentReadKeyHash, recordWrapper.Content.Identity)
if err != nil {
return err
}
var permissions []UserPermissionPair
for _, state := range st.userStates {
permission := UserPermissionPair{
Identity: state.Identity,
Permission: state.Permissions,
}
permissions = append(permissions, permission)
}
st.permissionsAtRecord[recordWrapper.Id] = permissions
return nil
} }
func (st *ACLState) applyChangeData(changeData *aclpb.ACLChangeACLData, hash uint64, identity string) (err error) { func (st *ACLState) applyChangeData(changeData *aclpb.ACLChangeACLData, hash uint64, identity string) (err error) {

View File

@ -1,6 +1,10 @@
package tree package tree
import "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list" import (
"fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list"
)
type DocTreeValidator interface { type DocTreeValidator interface {
ValidateTree(tree *Tree, aclList list.ACLList) error ValidateTree(tree *Tree, aclList list.ACLList) error
@ -11,8 +15,44 @@ type docTreeValidator struct{}
func newTreeValidator() DocTreeValidator { func newTreeValidator() DocTreeValidator {
return &docTreeValidator{} return &docTreeValidator{}
} }
func (v *docTreeValidator) ValidateTree(tree *Tree, list list.ACLList) error {
func (v *docTreeValidator) ValidateTree(tree *Tree, aclList list.ACLList) (err error) {
// TODO: add validation logic where we check that the change refers to correct acl heads // TODO: add validation logic where we check that the change refers to correct acl heads
// that means that more recent changes should refer to more recent acl heads // that means that more recent changes should refer to more recent acl heads
return nil var (
perm list.UserPermissionPair
state = aclList.ACLState()
)
tree.Iterate(tree.RootId(), func(c *Change) (isContinue bool) {
// checking if the user could write
perm, err = state.PermissionsAtRecord(c.Id, c.Content.Identity)
if err != nil {
return false
}
if perm.Permission != aclpb.ACLChange_Writer && perm.Permission != aclpb.ACLChange_Admin {
err = list.ErrInsufficientPermissions
return false
}
// checking if the change refers to later acl heads than its previous ids
for _, id := range c.PreviousIds {
prevChange := tree.attached[id]
if prevChange.Content.AclHeadId == c.Content.AclHeadId {
continue
}
var after bool
after, err = aclList.IsAfter(c.Content.AclHeadId, prevChange.Content.AclHeadId)
if err != nil {
return false
}
if !after {
err = fmt.Errorf("current acl head id (%s) should be after each of the previous ones (%s)", c.Content.AclHeadId, prevChange.Content.AclHeadId)
return false
}
}
return true
})
return err
} }

View File

@ -6,6 +6,7 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/app" "github.com/anytypeio/go-anytype-infrastructure-experiments/app"
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb" "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/tree" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ocache" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ocache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/service/account" "github.com/anytypeio/go-anytype-infrastructure-experiments/service/account"
@ -92,7 +93,7 @@ func (s *service) loadTree(ctx context.Context, id string) (ocache.Object, error
switch header.DocType { switch header.DocType {
case aclpb.Header_ACL: case aclpb.Header_ACL:
return tree.BuildACLTreeWithIdentity(t, s.account.Account(), nil) return list.BuildACLListWithIdentity(acc)
case aclpb.Header_DocTree: case aclpb.Header_DocTree:
break break
default: default: