From 2946c050b90fdb00a937bfb4cdd5dddd1a217280 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Fri, 28 Oct 2022 12:04:23 +0200 Subject: [PATCH] Add raw record to list --- common/pkg/acl/list/aclrecordbuilder.go | 1 + common/pkg/acl/list/aclstate.go | 21 ++++++-- common/pkg/acl/list/aclstatebuilder.go | 10 ++++ common/pkg/acl/list/list.go | 59 ++++++++++++++++++---- common/pkg/acl/list/mock_list/mock_list.go | 15 ++++++ 5 files changed, 93 insertions(+), 13 deletions(-) diff --git a/common/pkg/acl/list/aclrecordbuilder.go b/common/pkg/acl/list/aclrecordbuilder.go index 07d6e6a8..ac435a73 100644 --- a/common/pkg/acl/list/aclrecordbuilder.go +++ b/common/pkg/acl/list/aclrecordbuilder.go @@ -11,6 +11,7 @@ import ( type ACLRecordBuilder interface { ConvertFromRaw(rawIdRecord *aclrecordproto.RawACLRecordWithId) (rec *ACLRecord, err error) + BuildUserJoin(acceptPrivKeyBytes []byte, encSymKeyBytes []byte, state *ACLState) (rec *aclrecordproto.RawACLRecord, err error) } type aclRecordBuilder struct { diff --git a/common/pkg/acl/list/aclstate.go b/common/pkg/acl/list/aclstate.go index 0bdcc853..ec2bd7b7 100644 --- a/common/pkg/acl/list/aclstate.go +++ b/common/pkg/acl/list/aclstate.go @@ -30,6 +30,7 @@ var ErrInsufficientPermissions = errors.New("insufficient permissions") var ErrNoReadKey = errors.New("acl state doesn't have a read key") var ErrInvalidSignature = errors.New("signature is invalid") var ErrIncorrectRoot = errors.New("incorrect root") +var ErrIncorrectRecordSequence = errors.New("incorrect prev id of a record") type UserPermissionPair struct { Identity string @@ -48,6 +49,7 @@ type ACLState struct { identity string permissionsAtRecord map[string][]UserPermissionPair + lastRecordId string keychain *common.Keychain } @@ -114,15 +116,28 @@ func (st *ACLState) PermissionsAtRecord(id string, identity string) (UserPermiss } func (st *ACLState) applyRecord(record *ACLRecord) (err error) { + defer func() { + if err == nil { + st.lastRecordId = record.Id + } + }() + if st.lastRecordId != record.PrevId { + err = ErrIncorrectRecordSequence + return + } if record.Id == st.id { root, ok := record.Model.(*aclrecordproto.ACLRoot) if !ok { return ErrIncorrectRoot } + err = st.applyRoot(root) + if err != nil { + return + } st.permissionsAtRecord[record.Id] = []UserPermissionPair{ {Identity: string(root.Identity), Permission: aclrecordproto.ACLUserPermissions_Admin}, } - return st.applyRoot(root) + return } aclData := &aclrecordproto.ACLData{} @@ -152,7 +167,7 @@ func (st *ACLState) applyRecord(record *ACLRecord) (err error) { } st.permissionsAtRecord[record.Id] = permissions - return nil + return } func (st *ACLState) applyRoot(root *aclrecordproto.ACLRoot) (err error) { @@ -170,6 +185,7 @@ func (st *ACLState) applyRoot(root *aclrecordproto.ACLRoot) (err error) { Permissions: aclrecordproto.ACLUserPermissions_Admin, } st.userStates[string(root.Identity)] = userState + st.totalReadKeys++ return } @@ -203,7 +219,6 @@ func (st *ACLState) saveReadKeyFromRoot(root *aclrecordproto.ACLRoot) (err error } st.currentReadKeyHash = root.CurrentReadKeyHash st.userReadKeys[root.CurrentReadKeyHash] = readKey - st.totalReadKeys++ return } diff --git a/common/pkg/acl/list/aclstatebuilder.go b/common/pkg/acl/list/aclstatebuilder.go index 1b847865..2ef79cd5 100644 --- a/common/pkg/acl/list/aclstatebuilder.go +++ b/common/pkg/acl/list/aclstatebuilder.go @@ -45,3 +45,13 @@ func (sb *aclStateBuilder) Build(records []*ACLRecord) (state *ACLState, err err return state, err } + +func (sb *aclStateBuilder) Append(state *ACLState, records []*ACLRecord) (err error) { + for _, rec := range records { + err = state.applyRecord(rec) + if err != nil { + return + } + } + return +} diff --git a/common/pkg/acl/list/list.go b/common/pkg/acl/list/list.go index 6e8d259e..ccbe120c 100644 --- a/common/pkg/acl/list/list.go +++ b/common/pkg/acl/list/list.go @@ -29,6 +29,7 @@ type ACLList interface { Records() []*ACLRecord ACLState() *ACLState IsAfter(first string, second string) (bool, error) + AddRawRecords(ctx context.Context, rec []*aclrecordproto.RawACLRecordWithId) (err error) Head() *ACLRecord Get(id string) (*ACLRecord, error) Iterate(iterFunc IterFunc) @@ -42,9 +43,11 @@ type aclList struct { indexes map[string]int id string - builder *aclStateBuilder - aclState *ACLState - keychain *common.Keychain + stateBuilder *aclStateBuilder + recordBuilder ACLRecordBuilder + aclState *ACLState + keychain *common.Keychain + storage storage.ListStorage sync.RWMutex } @@ -120,13 +123,15 @@ func build(id string, stateBuilder *aclStateBuilder, recBuilder ACLRecordBuilder } list = &aclList{ - root: aclRecRoot.Model.(*aclrecordproto.ACLRoot), - records: records, - indexes: indexes, - builder: stateBuilder, - aclState: state, - id: id, - RWMutex: sync.RWMutex{}, + root: aclRecRoot.Model.(*aclrecordproto.ACLRoot), + records: records, + indexes: indexes, + stateBuilder: stateBuilder, + recordBuilder: recBuilder, + aclState: state, + storage: storage, + id: id, + RWMutex: sync.RWMutex{}, } return } @@ -143,6 +148,40 @@ func (a *aclList) Root() *aclrecordproto.ACLRoot { return a.root } +func (a *aclList) AddRawRecords(ctx context.Context, records []*aclrecordproto.RawACLRecordWithId) (err error) { + if len(records) == 0 { + return + } + // converting and verifying + var aclRecords []*ACLRecord + for _, rec := range records { + var record *ACLRecord + record, err = a.recordBuilder.ConvertFromRaw(rec) + if err != nil { + return + } + aclRecords = append(aclRecords, record) + } + + // trying to append them to state + err = a.stateBuilder.Append(a.aclState, aclRecords) + if err != nil { + return + } + + // saving to storage + for _, rec := range records { + err = a.storage.AddRawRecord(ctx, rec) + if err != nil { + return + } + } + + // setting new head + err = a.storage.SetHead(records[len(records)-1].Id) + return +} + func (a *aclList) ACLState() *ACLState { return a.aclState } diff --git a/common/pkg/acl/list/mock_list/mock_list.go b/common/pkg/acl/list/mock_list/mock_list.go index 2c545599..a4aeb396 100644 --- a/common/pkg/acl/list/mock_list/mock_list.go +++ b/common/pkg/acl/list/mock_list/mock_list.go @@ -5,6 +5,7 @@ package mock_list import ( + context "context" reflect "reflect" aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" @@ -49,6 +50,20 @@ func (mr *MockACLListMockRecorder) ACLState() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ACLState", reflect.TypeOf((*MockACLList)(nil).ACLState)) } +// AddRawRecords mocks base method. +func (m *MockACLList) AddRawRecords(arg0 context.Context, arg1 []*aclrecordproto.RawACLRecordWithId) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddRawRecords", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddRawRecords indicates an expected call of AddRawRecords. +func (mr *MockACLListMockRecorder) AddRawRecords(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawRecords", reflect.TypeOf((*MockACLList)(nil).AddRawRecords), arg0, arg1) +} + // Close mocks base method. func (m *MockACLList) Close() error { m.ctrl.T.Helper()