diff --git a/commonspace/object/acl/list/aclrecordbuilder.go b/commonspace/object/acl/list/aclrecordbuilder.go index cae3a2b8..3fe15ff2 100644 --- a/commonspace/object/acl/list/aclrecordbuilder.go +++ b/commonspace/object/acl/list/aclrecordbuilder.go @@ -163,8 +163,12 @@ func (a *aclRecordBuilder) BuildRequestJoin(payload RequestJoinPayload) (rawReco if err != nil { return } + protoIdentity, err := a.accountKeys.SignKey.GetPublic().Marshall() + if err != nil { + return + } joinRec := &aclrecordproto.AclAccountRequestJoin{ - InviteIdentity: rawIdentity, + InviteIdentity: protoIdentity, InviteRecordId: payload.InviteRecordId, InviteIdentitySignature: signature, Metadata: payload.Metadata, @@ -426,7 +430,7 @@ func (a *aclRecordBuilder) UnmarshallWithId(rawIdRecord *aclrecordproto.RawAclRe return } aclData := &aclrecordproto.AclData{} - err = proto.Unmarshal(rawRec.Payload, aclData) + err = proto.Unmarshal(aclRecord.Data, aclData) if err != nil { return } diff --git a/commonspace/object/acl/list/aclstate.go b/commonspace/object/acl/list/aclstate.go index 44336458..0e2a6568 100644 --- a/commonspace/object/acl/list/aclstate.go +++ b/commonspace/object/acl/list/aclstate.go @@ -193,7 +193,7 @@ func (st *AclState) applyRoot(record *AclRecord) (err error) { // adding user to the list userState := AclUserState{ PubKey: record.Identity, - Permissions: AclPermissions(aclrecordproto.AclUserPermissions_Admin), + Permissions: AclPermissions(aclrecordproto.AclUserPermissions_Owner), } st.currentReadKeyId = record.Id st.userStates[mapKeyFromPubKey(record.Identity)] = userState diff --git a/commonspace/object/acl/list/list.go b/commonspace/object/acl/list/list.go index 5ae2af33..86ee570f 100644 --- a/commonspace/object/acl/list/list.go +++ b/commonspace/object/acl/list/list.go @@ -15,7 +15,10 @@ import ( type IterFunc = func(record *AclRecord) (IsContinue bool) -var ErrIncorrectCID = errors.New("incorrect CID") +var ( + ErrIncorrectCID = errors.New("incorrect CID") + ErrRecordAlreadyExists = errors.New("record already exists") +) type RWLocker interface { sync.Locker @@ -51,7 +54,7 @@ type AclList interface { RecordBuilder() AclRecordBuilder ValidateRawRecord(record *aclrecordproto.RawAclRecord) (err error) - AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (added bool, err error) + AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (err error) Close() (err error) } @@ -160,6 +163,7 @@ func build(deps internalDeps) (list AclList, err error) { return } + recBuilder.(*aclRecordBuilder).state = state list = &aclList{ root: rootWithId, records: records, @@ -189,9 +193,9 @@ func (a *aclList) ValidateRawRecord(rawRec *aclrecordproto.RawAclRecord) (err er return a.aclState.Validator().ValidateAclRecordContents(record) } -func (a *aclList) AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (added bool, err error) { +func (a *aclList) AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (err error) { if _, ok := a.indexes[rawRec.Id]; ok { - return + return ErrRecordAlreadyExists } record, err := a.recordBuilder.UnmarshallWithId(rawRec) if err != nil { @@ -208,7 +212,7 @@ func (a *aclList) AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (added if err = a.storage.SetHead(rawRec.Id); err != nil { return } - return true, nil + return } func (a *aclList) IsValidNext(rawRec *aclrecordproto.RawAclRecordWithId) (err error) { diff --git a/commonspace/object/acl/list/list_test.go b/commonspace/object/acl/list/list_test.go index 19229ace..9f1ca77d 100644 --- a/commonspace/object/acl/list/list_test.go +++ b/commonspace/object/acl/list/list_test.go @@ -2,11 +2,56 @@ package list import ( "fmt" - "github.com/anyproto/any-sync/commonspace/object/accountdata" - "github.com/stretchr/testify/require" "testing" + + "github.com/anyproto/any-sync/commonspace/object/accountdata" + "github.com/anyproto/any-sync/commonspace/object/acl/aclrecordproto" + "github.com/anyproto/any-sync/util/cidutil" + "github.com/stretchr/testify/require" ) +func wrapRecord(rawRec *aclrecordproto.RawAclRecord) *aclrecordproto.RawAclRecordWithId { + payload, err := rawRec.Marshal() + if err != nil { + panic(err) + } + id, err := cidutil.NewCidFromBytes(payload) + if err != nil { + panic(err) + } + return &aclrecordproto.RawAclRecordWithId{ + Payload: payload, + Id: id, + } +} + +type aclFixture struct { + ownerKeys *accountdata.AccountKeys + accountKeys *accountdata.AccountKeys + ownerAcl *aclList + accountAcl *aclList + spaceId string +} + +func newFixture(t *testing.T) *aclFixture { + ownerKeys, err := accountdata.NewRandom() + require.NoError(t, err) + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + spaceId := "spaceId" + ownerAcl, err := NewTestDerivedAcl(spaceId, ownerKeys) + require.NoError(t, err) + accountAcl, err := NewTestAclWithRoot(accountKeys, ownerAcl.Root()) + require.NoError(t, err) + return &aclFixture{ + ownerKeys: ownerKeys, + accountKeys: accountKeys, + ownerAcl: ownerAcl.(*aclList), + accountAcl: accountAcl.(*aclList), + spaceId: spaceId, + } +} + func TestAclList_BuildRoot(t *testing.T) { randomKeys, err := accountdata.NewRandom() require.NoError(t, err) @@ -14,3 +59,53 @@ func TestAclList_BuildRoot(t *testing.T) { require.NoError(t, err) fmt.Println(randomAcl.Id()) } + +func TestAclList_InvitePipeline(t *testing.T) { + fx := newFixture(t) + var ( + ownerAcl = fx.ownerAcl + ownerState = fx.ownerAcl.aclState + accountAcl = fx.accountAcl + accountState = fx.accountAcl.aclState + ) + // building invite + inv, err := ownerAcl.RecordBuilder().BuildInvite() + require.NoError(t, err) + inviteRec := wrapRecord(inv.InviteRec) + err = ownerAcl.AddRawRecord(inviteRec) + require.NoError(t, err) + err = accountAcl.AddRawRecord(inviteRec) + require.NoError(t, err) + + // building request join + requestJoin, err := accountAcl.RecordBuilder().BuildRequestJoin(RequestJoinPayload{ + InviteRecordId: inviteRec.Id, + InviteKey: inv.InviteKey, + }) + require.NoError(t, err) + requestJoinRec := wrapRecord(requestJoin) + err = ownerAcl.AddRawRecord(requestJoinRec) + require.NoError(t, err) + err = accountAcl.AddRawRecord(requestJoinRec) + require.NoError(t, err) + + // building request accept + requestAccept, err := ownerAcl.RecordBuilder().BuildRequestAccept(RequestAcceptPayload{ + RequestRecordId: requestJoinRec.Id, + Permissions: AclPermissions(aclrecordproto.AclUserPermissions_Writer), + }) + require.NoError(t, err) + requestAcceptRec := wrapRecord(requestAccept) + err = ownerAcl.AddRawRecord(requestAcceptRec) + require.NoError(t, err) + err = accountAcl.AddRawRecord(requestAcceptRec) + require.NoError(t, err) + + // checking acl state + require.True(t, ownerState.Permissions(ownerState.pubKey).IsOwner()) + require.True(t, ownerState.Permissions(accountState.pubKey).CanWrite()) + require.Equal(t, 0, len(ownerState.pendingRequests)) + require.Equal(t, 0, len(accountState.pendingRequests)) + require.True(t, accountState.Permissions(ownerState.pubKey).IsOwner()) + require.True(t, accountState.Permissions(accountState.pubKey).CanWrite()) +} diff --git a/commonspace/object/acl/list/listutils.go b/commonspace/object/acl/list/listutils.go index 9f7d7331..10513ecb 100644 --- a/commonspace/object/acl/list/listutils.go +++ b/commonspace/object/acl/list/listutils.go @@ -29,3 +29,13 @@ func NewTestDerivedAcl(spaceId string, keys *accountdata.AccountKeys) (AclList, } return BuildAclListWithIdentity(keys, st, NoOpAcceptorVerifier{}) } + +func NewTestAclWithRoot(keys *accountdata.AccountKeys, root *aclrecordproto.RawAclRecordWithId) (AclList, error) { + st, err := liststorage.NewInMemoryAclListStorage(root.Id, []*aclrecordproto.RawAclRecordWithId{ + root, + }) + if err != nil { + return nil, err + } + return BuildAclListWithIdentity(keys, st, NoOpAcceptorVerifier{}) +}