1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-08 05:57:03 +09:00

Fix objecttree tests

This commit is contained in:
mcrakhman 2023-03-26 18:36:07 +02:00 committed by Mikhail Iudin
parent dca0103899
commit 21a3ae0768
No known key found for this signature in database
GPG key ID: FAAAA8BAABDFF1C0
7 changed files with 178 additions and 172 deletions

View file

@ -1,7 +1,9 @@
package accountdata
import (
"crypto/rand"
"github.com/anytypeio/any-sync/util/crypto"
"github.com/anytypeio/any-sync/util/peer"
)
type AccountKeys struct {
@ -9,3 +11,23 @@ type AccountKeys struct {
SignKey crypto.PrivKey
PeerId string
}
func NewRandom() (*AccountKeys, error) {
peerKey, _, err := crypto.GenerateEd25519Key(rand.Reader)
if err != nil {
return nil, err
}
signKey, _, err := crypto.GenerateEd25519Key(rand.Reader)
if err != nil {
return nil, err
}
peerId, err := peer.IdFromSigningPubKey(peerKey.GetPublic())
if err != nil {
return nil, err
}
return &AccountKeys{
PeerKey: peerKey,
SignKey: signKey,
PeerId: peerId.String(),
}, nil
}

View file

@ -7,7 +7,6 @@ import (
"github.com/anytypeio/any-sync/app/logger"
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
"github.com/anytypeio/any-sync/commonspace/object/keychain"
"github.com/anytypeio/any-sync/util/crypto"
"github.com/gogo/protobuf/proto"
"go.uber.org/zap"
@ -48,8 +47,6 @@ type AclState struct {
totalReadKeys int
lastRecordId string
keychain *keychain.Keychain
}
func newAclStateWithKeys(

View file

@ -1,87 +1,16 @@
package list
import (
"fmt"
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
"github.com/stretchr/testify/require"
"testing"
)
func TestAclList_AclState_UserInviteAndJoin(t *testing.T) {
//st, err := acllistbuilder.NewListStorageWithTestName("userjoinexample.yml")
//require.NoError(t, err, "building storage should not result in error")
//
//keychain := st.(*acllistbuilder.AclListStorageBuilder).GetKeychain()
//
//aclList, err := BuildAclList(st)
//require.NoError(t, err, "building acl list should be without error")
//
//idA := keychain.GetIdentity("A")
//idB := keychain.GetIdentity("B")
//idC := keychain.GetIdentity("C")
//
//// checking final state
//assert.Equal(t, aclrecordproto.AclUserPermissions_Admin, aclList.AclState().UserStates()[idA].Permissions)
//assert.Equal(t, aclrecordproto.AclUserPermissions_Writer, aclList.AclState().UserStates()[idB].Permissions)
//assert.Equal(t, aclrecordproto.AclUserPermissions_Reader, aclList.AclState().UserStates()[idC].Permissions)
//assert.Equal(t, aclList.Head().CurrentReadKeyHash, aclList.AclState().CurrentReadKeyId())
//
//var records []*AclRecord
//aclList.Iterate(func(record *AclRecord) (IsContinue bool) {
// records = append(records, record)
// return true
//})
//
//// checking permissions at specific records
//assert.Equal(t, 3, len(records))
//
//_, err = aclList.AclState().StateAtRecord(records[1].Id, idB)
//assert.Error(t, err, "B should have no permissions at record 1")
//
//perm, err := aclList.AclState().StateAtRecord(records[2].Id, idB)
//assert.NoError(t, err, "should have no error with permissions of B in the record 2")
//assert.Equal(t, UserPermissionPair{
// Identity: idB,
// Permission: aclrecordproto.AclUserPermissions_Writer,
//}, perm)
}
func TestAclList_AclState_UserJoinAndRemove(t *testing.T) {
//st, err := acllistbuilder.NewListStorageWithTestName("userremoveexample.yml")
//require.NoError(t, err, "building storage should not result in error")
//
//keychain := st.(*acllistbuilder.AclListStorageBuilder).GetKeychain()
//
//aclList, err := BuildAclList(st)
//require.NoError(t, err, "building acl list should be without error")
//
//idA := keychain.GetIdentity("A")
//idB := keychain.GetIdentity("B")
//idC := keychain.GetIdentity("C")
//
//// checking final state
//assert.Equal(t, aclrecordproto.AclUserPermissions_Admin, aclList.AclState().UserStates()[idA].Permissions)
//assert.Equal(t, aclrecordproto.AclUserPermissions_Reader, aclList.AclState().UserStates()[idC].Permissions)
//assert.Equal(t, aclList.Head().CurrentReadKeyHash, aclList.AclState().CurrentReadKeyId())
//
//_, exists := aclList.AclState().UserStates()[idB]
//assert.Equal(t, false, exists)
//
//var records []*AclRecord
//aclList.Iterate(func(record *AclRecord) (IsContinue bool) {
// records = append(records, record)
// return true
//})
//
//// checking permissions at specific records
//assert.Equal(t, 4, len(records))
//
//assert.NotEqual(t, records[2].CurrentReadKeyHash, aclList.AclState().CurrentReadKeyId())
//
//perm, err := aclList.AclState().StateAtRecord(records[2].Id, idB)
//assert.NoError(t, err, "should have no error with permissions of B in the record 2")
//assert.Equal(t, UserPermissionPair{
// Identity: idB,
// Permission: aclrecordproto.AclUserPermissions_Writer,
//}, perm)
//
//_, err = aclList.AclState().StateAtRecord(records[3].Id, idB)
//assert.Error(t, err, "B should have no permissions at record 3, because user should be removed")
func TestAclList_BuildRoot(t *testing.T) {
randomKeys, err := accountdata.NewRandom()
require.NoError(t, err)
randomAcl, err := NewTestDerivedAcl("spaceId", randomKeys)
require.NoError(t, err)
fmt.Println(randomAcl.Id())
}

View file

@ -0,0 +1,27 @@
package list
import (
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
"github.com/anytypeio/any-sync/commonspace/object/acl/liststorage"
"github.com/anytypeio/any-sync/util/crypto"
)
func NewTestDerivedAcl(spaceId string, keys *accountdata.AccountKeys) (AclList, error) {
builder := NewAclRecordBuilder("", crypto.NewKeyStorage())
root, err := builder.BuildRoot(RootContent{
PrivKey: keys.SignKey,
SpaceId: spaceId,
DerivationPath: crypto.AnytypeAccountPath,
})
if err != nil {
return nil, err
}
st, err := liststorage.NewInMemoryAclListStorage(root.Id, []*aclrecordproto.RawAclRecordWithId{
root,
})
if err != nil {
return nil, err
}
return BuildAclListWithIdentity(keys, st)
}

View file

@ -1,29 +0,0 @@
package keychain
import (
"github.com/anytypeio/any-sync/util/crypto"
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
)
type Keychain struct {
keys map[string]signingkey.PubKey
}
func NewKeychain() *Keychain {
return &Keychain{
keys: make(map[string]signingkey.PubKey),
}
}
func (k *Keychain) GetOrAdd(identity string) (signingkey.PubKey, error) {
if key, exists := k.keys[identity]; exists {
return key, nil
}
res, err := crypto.NewSigningEd25519PubKeyFromBytes([]byte(identity))
if err != nil {
return nil, err
}
k.keys[identity] = res.(signingkey.PubKey)
return res.(signingkey.PubKey), nil
}

View file

@ -2,39 +2,101 @@ package objecttree
import (
"context"
"crypto/rand"
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
"github.com/anytypeio/any-sync/commonspace/object/acl/list"
"github.com/anytypeio/any-sync/commonspace/object/acl/testutils/acllistbuilder"
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
"github.com/anytypeio/any-sync/util/crypto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
)
type mockKeyStorage struct {
key crypto.PubKey
}
func newKeyStorage() mockKeyStorage {
_, pk, _ := crypto.GenerateEd25519Key(rand.Reader)
return mockKeyStorage{pk}
}
func (m mockKeyStorage) PubKeyFromProto(protoBytes []byte) (crypto.PubKey, error) {
return m.key, nil
}
type mockChangeCreator struct{}
func (c *mockChangeCreator) createRoot(id, aclId string) *treechangeproto.RawTreeChangeWithId {
aclChange := &treechangeproto.RootChange{
AclHeadId: aclId,
}
res, _ := aclChange.Marshal()
raw := &treechangeproto.RawTreeChange{
Payload: res,
Signature: nil,
}
rawMarshalled, _ := raw.Marshal()
return &treechangeproto.RawTreeChangeWithId{
RawChange: rawMarshalled,
Id: id,
}
}
func (c *mockChangeCreator) createRaw(id, aclId, snapshotId string, isSnapshot bool, prevIds ...string) *treechangeproto.RawTreeChangeWithId {
aclChange := &treechangeproto.TreeChange{
TreeHeadIds: prevIds,
AclHeadId: aclId,
SnapshotBaseId: snapshotId,
ChangesData: nil,
IsSnapshot: isSnapshot,
}
res, _ := aclChange.Marshal()
raw := &treechangeproto.RawTreeChange{
Payload: res,
Signature: nil,
}
rawMarshalled, _ := raw.Marshal()
return &treechangeproto.RawTreeChangeWithId{
RawChange: rawMarshalled,
Id: id,
}
}
func (c *mockChangeCreator) createNewTreeStorage(treeId, aclHeadId string) treestorage.TreeStorage {
root := c.createRoot(treeId, aclHeadId)
treeStorage, _ := treestorage.NewInMemoryTreeStorage(root, []string{root.Id}, []*treechangeproto.RawTreeChangeWithId{root})
return treeStorage
}
type testTreeContext struct {
aclList list.AclList
treeStorage treestorage.TreeStorage
changeBuilder ChangeBuilder
changeCreator *MockChangeCreator
changeCreator *mockChangeCreator
objTree ObjectTree
}
func prepareAclList(t *testing.T) list.AclList {
st, err := acllistbuilder.NewListStorageWithTestName("userjoinexample.yml")
require.NoError(t, err, "building storage should not result in error")
aclList, err := list.BuildAclList(st)
randKeys, err := accountdata.NewRandom()
require.NoError(t, err)
aclList, err := list.NewTestDerivedAcl("spaceId", randKeys)
require.NoError(t, err, "building acl list should be without error")
return aclList
}
func prepareTreeDeps(aclList list.AclList) (*MockChangeCreator, objectTreeDeps) {
changeCreator := &MockChangeCreator{}
treeStorage := changeCreator.CreateNewTreeStorage("0", aclList.Head().Id)
func prepareTreeDeps(aclList list.AclList) (*mockChangeCreator, objectTreeDeps) {
changeCreator := &mockChangeCreator{}
treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id)
root, _ := treeStorage.Root()
changeBuilder := &nonVerifiableChangeBuilder{
ChangeBuilder: NewChangeBuilder(nil, root),
ChangeBuilder: NewChangeBuilder(newKeyStorage(), root),
}
deps := objectTreeDeps{
changeBuilder: changeBuilder,
@ -48,11 +110,11 @@ func prepareTreeDeps(aclList list.AclList) (*MockChangeCreator, objectTreeDeps)
}
func prepareTreeContext(t *testing.T, aclList list.AclList) testTreeContext {
changeCreator := &MockChangeCreator{}
treeStorage := changeCreator.CreateNewTreeStorage("0", aclList.Head().Id)
changeCreator := &mockChangeCreator{}
treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id)
root, _ := treeStorage.Root()
changeBuilder := &nonVerifiableChangeBuilder{
ChangeBuilder: NewChangeBuilder(nil, root),
ChangeBuilder: NewChangeBuilder(newKeyStorage(), root),
}
deps := objectTreeDeps{
changeBuilder: changeBuilder,
@ -94,8 +156,8 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
}
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -139,7 +201,7 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("0", aclList.Head().Id, "", true, ""),
changeCreator.createRaw("0", aclList.Head().Id, "", true, ""),
}
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -163,7 +225,7 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
}
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -189,10 +251,10 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.CreateRaw("4", aclList.Head().Id, "3", false, "3"),
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("4", aclList.Head().Id, "3", false, "3"),
}
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -239,9 +301,9 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"),
}
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -263,12 +325,12 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.CreateRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.CreateRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.CreateRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.createRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
}
payload := RawChangesPayload{
@ -342,13 +404,13 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.CreateRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.CreateRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.createRaw("5", aclList.Head().Id, "0", false, "1"),
// main difference from tree example
changeCreator.CreateRaw("6", aclList.Head().Id, "0", true, "3", "4", "5"),
changeCreator.createRaw("6", aclList.Head().Id, "0", true, "3", "4", "5"),
}
payload := RawChangesPayload{
@ -423,9 +485,9 @@ func TestObjectTree(t *testing.T) {
objTree := ctx.objTree
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"),
}
payload := RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -437,9 +499,9 @@ func TestObjectTree(t *testing.T) {
require.Equal(t, "3", objTree.Root().Id)
rawChanges = []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.CreateRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.CreateRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
changeCreator.createRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.createRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
}
payload = RawChangesPayload{
NewHeads: []string{rawChanges[len(rawChanges)-1].Id},
@ -483,12 +545,12 @@ func TestObjectTree(t *testing.T) {
changeCreator, deps := prepareTreeDeps(aclList)
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.CreateRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.CreateRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.CreateRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.createRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
}
deps.treeStorage.TransactionAdd(rawChanges, []string{"6"})
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
@ -514,12 +576,12 @@ func TestObjectTree(t *testing.T) {
changeCreator, deps := prepareTreeDeps(aclList)
rawChanges := []*treechangeproto.RawTreeChangeWithId{
changeCreator.CreateRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.CreateRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.CreateRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.CreateRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.CreateRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.CreateRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
changeCreator.createRaw("1", aclList.Head().Id, "0", false, "0"),
changeCreator.createRaw("2", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("3", aclList.Head().Id, "0", true, "2"),
changeCreator.createRaw("4", aclList.Head().Id, "0", false, "2"),
changeCreator.createRaw("5", aclList.Head().Id, "0", false, "1"),
changeCreator.createRaw("6", aclList.Head().Id, "0", false, "3", "4", "5"),
}
deps.treeStorage.TransactionAdd(rawChanges, []string{"6"})
hTree, err := buildHistoryTree(deps, HistoryTreeParams{

View file

@ -5,10 +5,10 @@ import (
"context"
"errors"
"fmt"
"github.com/anytypeio/any-sync/util/crypto"
"github.com/anytypeio/any-sync/accountservice"
"github.com/anytypeio/any-sync/app/logger"
"github.com/anytypeio/any-sync/commonspace/object/keychain"
"github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
"github.com/anytypeio/any-sync/commonspace/object/tree/synctree"
"github.com/anytypeio/any-sync/commonspace/object/tree/synctree/updatelistener"
@ -207,7 +207,6 @@ func (s *settingsObject) SpaceDeleteRawChange() (raw *treechangeproto.RawTreeCha
return s.PrepareChange(objecttree.SignableChangeContent{
Data: data,
Key: accountData.SignKey,
Identity: accountData.Identity,
IsSnapshot: false,
IsEncrypted: false,
})
@ -252,7 +251,6 @@ func (s *settingsObject) addContent(data []byte) (err error) {
_, err = s.AddContent(context.Background(), objecttree.SignableChangeContent{
Data: data,
Key: accountData.SignKey,
Identity: accountData.Identity,
IsSnapshot: false,
IsEncrypted: false,
})
@ -264,13 +262,13 @@ func (s *settingsObject) addContent(data []byte) (err error) {
return
}
func VerifyDeleteChange(raw *treechangeproto.RawTreeChangeWithId, identity []byte, peerId string) (err error) {
changeBuilder := objecttree.NewChangeBuilder(keychain.NewKeychain(), nil)
func VerifyDeleteChange(raw *treechangeproto.RawTreeChangeWithId, identity crypto.PubKey, peerId string) (err error) {
changeBuilder := objecttree.NewChangeBuilder(crypto.NewKeyStorage(), nil)
res, err := changeBuilder.Unmarshall(raw, true)
if err != nil {
return
}
if res.Identity != string(identity) {
if !res.Identity.Equals(identity) {
return fmt.Errorf("incorrect identity")
}
return verifyDeleteContent(res.Data, peerId)