diff --git a/commonspace/object/accountdata/accountdata.go b/commonspace/object/accountdata/accountdata.go index 841b9602..12d3f029 100644 --- a/commonspace/object/accountdata/accountdata.go +++ b/commonspace/object/accountdata/accountdata.go @@ -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 +} diff --git a/commonspace/object/acl/list/aclstate.go b/commonspace/object/acl/list/aclstate.go index 8fff1a8b..84d1e80a 100644 --- a/commonspace/object/acl/list/aclstate.go +++ b/commonspace/object/acl/list/aclstate.go @@ -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( diff --git a/commonspace/object/acl/list/list_test.go b/commonspace/object/acl/list/list_test.go index 9e3cedfb..ec087c8a 100644 --- a/commonspace/object/acl/list/list_test.go +++ b/commonspace/object/acl/list/list_test.go @@ -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()) } diff --git a/commonspace/object/acl/list/listutils.go b/commonspace/object/acl/list/listutils.go new file mode 100644 index 00000000..e9a92553 --- /dev/null +++ b/commonspace/object/acl/list/listutils.go @@ -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) +} diff --git a/commonspace/object/keychain/keychain.go b/commonspace/object/keychain/keychain.go deleted file mode 100644 index 1cedbf31..00000000 --- a/commonspace/object/keychain/keychain.go +++ /dev/null @@ -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 -} diff --git a/commonspace/object/tree/objecttree/objecttree_test.go b/commonspace/object/tree/objecttree/objecttree_test.go index ee8989e9..dbb31321 100644 --- a/commonspace/object/tree/objecttree/objecttree_test.go +++ b/commonspace/object/tree/objecttree/objecttree_test.go @@ -2,15 +2,30 @@ 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 { @@ -68,10 +83,9 @@ type testTreeContext struct { } 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 @@ -82,7 +96,7 @@ func prepareTreeDeps(aclList list.AclList) (*mockChangeCreator, objectTreeDeps) treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id) root, _ := treeStorage.Root() changeBuilder := &nonVerifiableChangeBuilder{ - ChangeBuilder: NewChangeBuilder(nil, root), + ChangeBuilder: NewChangeBuilder(newKeyStorage(), root), } deps := objectTreeDeps{ changeBuilder: changeBuilder, @@ -100,7 +114,7 @@ func prepareTreeContext(t *testing.T, aclList list.AclList) testTreeContext { treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id) root, _ := treeStorage.Root() changeBuilder := &nonVerifiableChangeBuilder{ - ChangeBuilder: NewChangeBuilder(nil, root), + ChangeBuilder: NewChangeBuilder(newKeyStorage(), root), } deps := objectTreeDeps{ changeBuilder: changeBuilder, diff --git a/commonspace/settings/settings.go b/commonspace/settings/settings.go index 453df055..42bd88ed 100644 --- a/commonspace/settings/settings.go +++ b/commonspace/settings/settings.go @@ -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)