Add test for thread utility

This commit is contained in:
mcrakhman 2022-07-12 21:27:27 +02:00 committed by Mikhail Iudin
parent dbfb8cbabc
commit acc2699b0e
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0
4 changed files with 88 additions and 17 deletions

View File

@ -110,8 +110,11 @@ func (st *ACLState) applyChange(change *pb.ACLChange) (err error) {
} }
st.currentReadKeyHash = change.CurrentReadKeyHash st.currentReadKeyHash = change.CurrentReadKeyHash
}() }()
// we can't check this for the user which is joining, because it will not be in our list // we can't check this for the user which is joining, because it will not be in our list
if !st.isUserJoin(change) { // the same is for the first change to be added
skipIdentityCheck := st.isUserJoin(change) || (st.currentReadKeyHash == 0 && st.isUserAdd(change))
if !skipIdentityCheck {
// we check signature when we add this to the Tree, so no need to do it here // we check signature when we add this to the Tree, so no need to do it here
if _, exists := st.userStates[change.Identity]; !exists { if _, exists := st.userStates[change.Identity]; !exists {
err = ErrNoSuchUser err = ErrNoSuchUser
@ -320,6 +323,12 @@ func (st *ACLState) isUserJoin(ch *pb.ACLChange) bool {
return ch.AclData.GetAclContent() != nil && ch.AclData.GetAclContent()[0].GetUserJoin() != nil return ch.AclData.GetAclContent() != nil && ch.AclData.GetAclContent()[0].GetUserJoin() != nil
} }
func (st *ACLState) isUserAdd(ch *pb.ACLChange) bool {
// if we have a UserAdd, then it should always be the first one applied
userAdd := ch.AclData.GetAclContent()[0].GetUserAdd()
return ch.AclData.GetAclContent() != nil && userAdd != nil && userAdd.GetIdentity() == ch.Identity
}
func (st *ACLState) getPermissionDecreasedUsers(ch *pb.ACLChange) (identities []*pb.ACLChangeUserPermissionChange) { func (st *ACLState) getPermissionDecreasedUsers(ch *pb.ACLChange) (identities []*pb.ACLChangeUserPermissionChange) {
// this should be called after general checks are completed // this should be called after general checks are completed
if ch.GetAclData().GetAclContent() == nil { if ch.GetAclData().GetAclContent() == nil {

View File

@ -8,6 +8,7 @@ import (
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
"github.com/textileio/go-threads/crypto/symmetric" "github.com/textileio/go-threads/crypto/symmetric"
"hash/fnv" "hash/fnv"
"time"
) )
type MarshalledChange = []byte type MarshalledChange = []byte
@ -105,28 +106,16 @@ func (c *changeBuilder) UserAdd(identity string, encryptionKey keys.EncryptionPu
} }
func (c *changeBuilder) BuildAndApply() (*Change, []byte, error) { func (c *changeBuilder) BuildAndApply() (*Change, []byte, error) {
marshalled, err := c.changeContent.Marshal()
if err != nil {
return nil, nil, err
}
encrypted, err := c.aclState.userReadKeys[c.aclState.currentReadKeyHash].
Encrypt(marshalled)
if err != nil {
return nil, nil, err
}
aclChange := &pb.ACLChange{ aclChange := &pb.ACLChange{
TreeHeadIds: c.tree.Heads(), TreeHeadIds: c.tree.Heads(),
AclHeadIds: c.tree.ACLHeads(), AclHeadIds: c.tree.ACLHeads(),
SnapshotBaseId: c.tree.RootId(), SnapshotBaseId: c.tree.RootId(),
AclData: c.aclData, AclData: c.aclData,
ChangesData: encrypted, CurrentReadKeyHash: c.readKeyHash,
CurrentReadKeyHash: c.aclState.currentReadKeyHash, Timestamp: int64(time.Now().Nanosecond()),
Timestamp: 0,
Identity: c.acc.Identity, Identity: c.acc.Identity,
} }
err = c.aclState.applyChange(aclChange) err := c.aclState.applyChange(aclChange)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -135,6 +124,21 @@ func (c *changeBuilder) BuildAndApply() (*Change, []byte, error) {
c.aclData.AclSnapshot = c.aclState.makeSnapshot() c.aclData.AclSnapshot = c.aclState.makeSnapshot()
} }
var marshalled []byte
if c.changeContent != nil {
marshalled, err = c.changeContent.Marshal()
if err != nil {
return nil, nil, err
}
encrypted, err := c.aclState.userReadKeys[c.aclState.currentReadKeyHash].
Encrypt(marshalled)
if err != nil {
return nil, nil, err
}
aclChange.ChangesData = encrypted
}
fullMarshalledChange, err := proto.Marshal(aclChange) fullMarshalledChange, err := proto.Marshal(aclChange)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err

View File

@ -31,5 +31,12 @@ func BuildThreadWithACL(
Signature: change.Signature(), Signature: change.Signature(),
Id: change.CID(), Id: change.CID(),
} }
return create(rawChange)
thr, err := create(rawChange)
if err != nil {
return nil, err
}
thr.SetHeads([]string{change.CID()})
return thr, nil
} }

View File

@ -0,0 +1,51 @@
package acltree
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/threadbuilder"
"github.com/anytypeio/go-anytype-infrastructure-experiments/thread"
"github.com/stretchr/testify/assert"
"testing"
)
func TestBuildThreadWithACL(t *testing.T) {
keychain := threadbuilder.NewKeychain()
keychain.AddSigningKey("A")
keychain.AddEncryptionKey("A")
data := &account.AccountData{
Identity: keychain.GetIdentity("A"),
SignKey: keychain.SigningKeys["A"],
EncKey: keychain.EncryptionKeys["A"],
}
thr, err := BuildThreadWithACL(
data,
func(builder ChangeBuilder) error {
return builder.UserAdd(
keychain.GetIdentity("A"),
keychain.EncryptionKeys["A"].GetPublic(),
pb.ACLChange_Admin)
},
thread.NewInMemoryThread)
if err != nil {
t.Fatalf("build should not return error")
}
if len(thr.Heads()) == 0 {
t.Fatalf("thread should have non-empty heads")
}
if thr.Header() == nil {
t.Fatalf("thread should have non-empty header")
}
assert.Equal(t, thr.Heads()[0], thr.Header().FirstChangeId)
assert.NotEmpty(t, thr.ID())
ch, err := thr.GetChange(context.Background(), thr.Header().FirstChangeId)
if err != nil {
t.Fatalf("get change should not return error: %v", err)
}
_, err = NewFromRawChange(ch)
if err != nil {
t.Fatalf("we should be able to unmarshall change: %v", err)
}
}