From f4cbbfa37464e3c632033bd9c534f00a1e70b861 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Thu, 29 Jun 2023 00:57:24 +0200 Subject: [PATCH] Update tests --- .../object/acl/list/aclrecordbuilder.go | 2 +- .../object/acl/list/aclrecordbuilder_test.go | 9 - commonspace/object/acl/list/aclstate.go | 39 ++++- commonspace/object/acl/list/list_test.go | 164 ++++++++++++++++++ commonspace/object/acl/list/models.go | 1 + 5 files changed, 196 insertions(+), 19 deletions(-) delete mode 100644 commonspace/object/acl/list/aclrecordbuilder_test.go diff --git a/commonspace/object/acl/list/aclrecordbuilder.go b/commonspace/object/acl/list/aclrecordbuilder.go index 1c0e0dd3..a949bd99 100644 --- a/commonspace/object/acl/list/aclrecordbuilder.go +++ b/commonspace/object/acl/list/aclrecordbuilder.go @@ -372,7 +372,7 @@ func (a *aclRecordBuilder) Unmarshall(rawRecord *aclrecordproto.RawAclRecord) (r return } aclData := &aclrecordproto.AclData{} - err = proto.Unmarshal(rawRecord.Payload, aclData) + err = proto.Unmarshal(aclRecord.Data, aclData) if err != nil { return } diff --git a/commonspace/object/acl/list/aclrecordbuilder_test.go b/commonspace/object/acl/list/aclrecordbuilder_test.go deleted file mode 100644 index 27a75a28..00000000 --- a/commonspace/object/acl/list/aclrecordbuilder_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package list - -import ( - "testing" -) - -func TestAclRecordBuilder_BuildUserJoin(t *testing.T) { - return -} diff --git a/commonspace/object/acl/list/aclstate.go b/commonspace/object/acl/list/aclstate.go index 65dfea0a..f11a99bd 100644 --- a/commonspace/object/acl/list/aclstate.go +++ b/commonspace/object/acl/list/aclstate.go @@ -53,8 +53,8 @@ type AclState struct { inviteKeys map[string]crypto.PubKey // requestRecords is a map recordId -> RequestRecord requestRecords map[string]RequestRecord - // pendingRequests is a map pubKey -> RequestType - pendingRequests map[string]RequestType + // pendingRequests is a map pubKey -> recordId + pendingRequests map[string]string key crypto.PrivKey pubKey crypto.PubKey keyStore crypto.KeyStorage @@ -76,7 +76,7 @@ func newAclStateWithKeys( statesAtRecord: make(map[string][]AclUserState), inviteKeys: make(map[string]crypto.PubKey), requestRecords: make(map[string]RequestRecord), - pendingRequests: make(map[string]RequestType), + pendingRequests: make(map[string]string), keyStore: crypto.NewKeyStorage(), } st.contentValidator = &contentValidator{ @@ -94,7 +94,7 @@ func newAclState(id string) *AclState { statesAtRecord: make(map[string][]AclUserState), inviteKeys: make(map[string]crypto.PubKey), requestRecords: make(map[string]RequestRecord), - pendingRequests: make(map[string]RequestType), + pendingRequests: make(map[string]string), keyStore: crypto.NewKeyStorage(), } st.contentValidator = &contentValidator{ @@ -113,7 +113,7 @@ func (st *AclState) CurrentReadKeyId() string { } func (st *AclState) CurrentReadKey() (crypto.SymKey, error) { - key, exists := st.userReadKeys[st.currentReadKeyId] + key, exists := st.userReadKeys[st.CurrentReadKeyId()] if !exists { return nil, ErrNoReadKey } @@ -302,10 +302,11 @@ func (st *AclState) applyRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, r if err != nil { return err } - st.pendingRequests[mapKeyFromPubKey(authorIdentity)] = RequestTypeJoin + st.pendingRequests[mapKeyFromPubKey(authorIdentity)] = recordId st.requestRecords[recordId] = RequestRecord{ RequestIdentity: authorIdentity, RequestMetadata: ch.Metadata, + Type: RequestTypeJoin, } return nil } @@ -358,7 +359,11 @@ func (st *AclState) applyRequestRemove(ch *aclrecordproto.AclAccountRequestRemov if err != nil { return err } - st.pendingRequests[mapKeyFromPubKey(authorIdentity)] = RequestTypeRemove + st.requestRecords[recordId] = RequestRecord{ + RequestIdentity: authorIdentity, + Type: RequestTypeRemove, + } + st.pendingRequests[mapKeyFromPubKey(authorIdentity)] = recordId return nil } @@ -422,8 +427,24 @@ func (st *AclState) Permissions(identity crypto.PubKey) AclPermissions { return state.Permissions } -func (st *AclState) UserStates() map[string]AclUserState { - return st.userStates +func (st *AclState) JoinRecords() (records []RequestRecord) { + for _, recId := range st.pendingRequests { + rec := st.requestRecords[recId] + if rec.Type == RequestTypeJoin { + records = append(records, rec) + } + } + return +} + +func (st *AclState) RemoveRecords() (records []RequestRecord) { + for _, recId := range st.pendingRequests { + rec := st.requestRecords[recId] + if rec.Type == RequestTypeRemove { + records = append(records, rec) + } + } + return } func (st *AclState) LastRecordId() string { diff --git a/commonspace/object/acl/list/list_test.go b/commonspace/object/acl/list/list_test.go index 070e97d6..17a4a9ec 100644 --- a/commonspace/object/acl/list/list_test.go +++ b/commonspace/object/acl/list/list_test.go @@ -88,6 +88,9 @@ func (fx *aclFixture) inviteAccount(t *testing.T, perms AclPermissions) { Permissions: perms, }) require.NoError(t, err) + // validate + err = ownerAcl.ValidateRawRecord(requestAccept) + require.NoError(t, err) requestAcceptRec := wrapRecord(requestAccept) fx.addRec(t, requestAcceptRec) @@ -98,6 +101,12 @@ func (fx *aclFixture) inviteAccount(t *testing.T, perms AclPermissions) { require.Equal(t, 0, len(accountState.pendingRequests)) require.True(t, accountState.Permissions(ownerState.pubKey).IsOwner()) require.True(t, accountState.Permissions(accountState.pubKey).CanWrite()) + + _, err = ownerState.StateAtRecord(requestJoinRec.Id, accountState.pubKey) + require.Equal(t, ErrNoSuchAccount, err) + stateAtRec, err := ownerState.StateAtRecord(requestAcceptRec.Id, accountState.pubKey) + require.NoError(t, err) + require.True(t, stateAtRec.Permissions == perms) } func TestAclList_BuildRoot(t *testing.T) { @@ -113,6 +122,67 @@ func TestAclList_InvitePipeline(t *testing.T) { fx.inviteAccount(t, AclPermissions(aclrecordproto.AclUserPermissions_Writer)) } +func TestAclList_InviteRevoke(t *testing.T) { + fx := newFixture(t) + var ( + ownerState = fx.ownerAcl.aclState + accountState = fx.accountAcl.aclState + ) + // building invite + inv, err := fx.ownerAcl.RecordBuilder().BuildInvite() + require.NoError(t, err) + inviteRec := wrapRecord(inv.InviteRec) + fx.addRec(t, inviteRec) + + // building invite revoke + inviteRevoke, err := fx.ownerAcl.RecordBuilder().BuildInviteRevoke(ownerState.lastRecordId) + require.NoError(t, err) + inviteRevokeRec := wrapRecord(inviteRevoke) + fx.addRec(t, inviteRevokeRec) + + // checking acl state + require.True(t, ownerState.Permissions(ownerState.pubKey).IsOwner()) + require.True(t, ownerState.Permissions(accountState.pubKey).NoPermissions()) + require.Empty(t, ownerState.inviteKeys) + require.Empty(t, accountState.inviteKeys) +} + +func TestAclList_RequestDecline(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) + fx.addRec(t, inviteRec) + + // building request join + requestJoin, err := accountAcl.RecordBuilder().BuildRequestJoin(RequestJoinPayload{ + InviteRecordId: inviteRec.Id, + InviteKey: inv.InviteKey, + }) + require.NoError(t, err) + requestJoinRec := wrapRecord(requestJoin) + fx.addRec(t, requestJoinRec) + + // building request decline + requestDecline, err := ownerAcl.RecordBuilder().BuildRequestDecline(ownerState.lastRecordId) + require.NoError(t, err) + requestDeclineRec := wrapRecord(requestDecline) + fx.addRec(t, requestDeclineRec) + + // checking acl state + require.True(t, ownerState.Permissions(ownerState.pubKey).IsOwner()) + require.True(t, ownerState.Permissions(accountState.pubKey).NoPermissions()) + require.Empty(t, ownerState.pendingRequests) + require.Empty(t, accountState.pendingRequests) +} + func TestAclList_Remove(t *testing.T) { fx := newFixture(t) var ( @@ -142,3 +212,97 @@ func TestAclList_Remove(t *testing.T) { require.Nil(t, accountState.userReadKeys[removeRec.Id]) require.NotNil(t, accountState.userReadKeys[fx.ownerAcl.Id()]) } + +func TestAclList_ReadKeyChange(t *testing.T) { + fx := newFixture(t) + var ( + ownerState = fx.ownerAcl.aclState + accountState = fx.accountAcl.aclState + ) + fx.inviteAccount(t, AclPermissions(aclrecordproto.AclUserPermissions_Admin)) + + newReadKey := crypto.NewAES() + readKeyChange, err := fx.ownerAcl.RecordBuilder().BuildReadKeyChange(newReadKey) + require.NoError(t, err) + readKeyRec := wrapRecord(readKeyChange) + fx.addRec(t, readKeyRec) + + // checking acl state + require.True(t, ownerState.Permissions(ownerState.pubKey).IsOwner()) + require.True(t, ownerState.Permissions(accountState.pubKey).CanManageAccounts()) + require.True(t, ownerState.userReadKeys[readKeyRec.Id].Equals(newReadKey)) + require.True(t, accountState.userReadKeys[readKeyRec.Id].Equals(newReadKey)) + require.NotNil(t, ownerState.userReadKeys[fx.ownerAcl.Id()]) + require.NotNil(t, accountState.userReadKeys[fx.ownerAcl.Id()]) + readKey, err := ownerState.CurrentReadKey() + require.NoError(t, err) + require.True(t, newReadKey.Equals(readKey)) + require.Equal(t, 0, len(ownerState.pendingRequests)) + require.Equal(t, 0, len(accountState.pendingRequests)) +} + +func TestAclList_PermissionChange(t *testing.T) { + fx := newFixture(t) + var ( + ownerState = fx.ownerAcl.aclState + accountState = fx.accountAcl.aclState + ) + fx.inviteAccount(t, AclPermissions(aclrecordproto.AclUserPermissions_Admin)) + + permissionChange, err := fx.ownerAcl.RecordBuilder().BuildPermissionChange(PermissionChangePayload{ + Identity: fx.accountKeys.SignKey.GetPublic(), + Permissions: AclPermissions(aclrecordproto.AclUserPermissions_Writer), + }) + require.NoError(t, err) + permissionChangeRec := wrapRecord(permissionChange) + fx.addRec(t, permissionChangeRec) + + // checking acl state + require.True(t, ownerState.Permissions(ownerState.pubKey).IsOwner()) + require.True(t, ownerState.Permissions(accountState.pubKey) == AclPermissions(aclrecordproto.AclUserPermissions_Writer)) + require.True(t, accountState.Permissions(ownerState.pubKey).IsOwner()) + require.True(t, accountState.Permissions(accountState.pubKey) == AclPermissions(aclrecordproto.AclUserPermissions_Writer)) + require.NotNil(t, ownerState.userReadKeys[fx.ownerAcl.Id()]) + require.NotNil(t, accountState.userReadKeys[fx.ownerAcl.Id()]) + require.Equal(t, 0, len(ownerState.pendingRequests)) + require.Equal(t, 0, len(accountState.pendingRequests)) +} + +func TestAclList_RequestRemove(t *testing.T) { + fx := newFixture(t) + var ( + ownerState = fx.ownerAcl.aclState + accountState = fx.accountAcl.aclState + ) + fx.inviteAccount(t, AclPermissions(aclrecordproto.AclUserPermissions_Writer)) + + removeRequest, err := fx.accountAcl.RecordBuilder().BuildRequestRemove() + require.NoError(t, err) + removeRequestRec := wrapRecord(removeRequest) + fx.addRec(t, removeRequestRec) + + recs := fx.accountAcl.AclState().RemoveRecords() + require.Len(t, recs, 1) + require.True(t, accountState.pubKey.Equals(recs[0].RequestIdentity)) + + newReadKey := crypto.NewAES() + remove, err := fx.ownerAcl.RecordBuilder().BuildAccountRemove(AccountRemovePayload{ + Identities: []crypto.PubKey{recs[0].RequestIdentity}, + ReadKey: newReadKey, + }) + require.NoError(t, err) + removeRec := wrapRecord(remove) + fx.addRec(t, removeRec) + + // checking acl state + require.True(t, ownerState.Permissions(ownerState.pubKey).IsOwner()) + require.True(t, ownerState.Permissions(accountState.pubKey).NoPermissions()) + require.True(t, ownerState.userReadKeys[removeRec.Id].Equals(newReadKey)) + require.NotNil(t, ownerState.userReadKeys[fx.ownerAcl.Id()]) + 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).NoPermissions()) + require.Nil(t, accountState.userReadKeys[removeRec.Id]) + require.NotNil(t, accountState.userReadKeys[fx.ownerAcl.Id()]) +} diff --git a/commonspace/object/acl/list/models.go b/commonspace/object/acl/list/models.go index 27238202..1f958303 100644 --- a/commonspace/object/acl/list/models.go +++ b/commonspace/object/acl/list/models.go @@ -18,6 +18,7 @@ type AclRecord struct { type RequestRecord struct { RequestIdentity crypto.PubKey RequestMetadata []byte + Type RequestType } type AclUserState struct {