From a8699f38f94153283cbe28a155ddb29cee05d92e Mon Sep 17 00:00:00 2001 From: Mikhail Rakhmanov Date: Sun, 11 May 2025 14:32:15 +0200 Subject: [PATCH] Rewrite batch requests --- .../object/acl/list/aclrecordbuilder.go | 53 ++++++++------- commonspace/object/acl/list/aclstate.go | 65 ++++++++----------- commonspace/object/acl/syncacl/syncacl.go | 4 +- 3 files changed, 60 insertions(+), 62 deletions(-) diff --git a/commonspace/object/acl/list/aclrecordbuilder.go b/commonspace/object/acl/list/aclrecordbuilder.go index 5efa17c4..a689c777 100644 --- a/commonspace/object/acl/list/aclrecordbuilder.go +++ b/commonspace/object/acl/list/aclrecordbuilder.go @@ -113,8 +113,15 @@ func NewAclRecordBuilder(id string, keyStorage crypto.KeyStorage, keys *accountd func (a *aclRecordBuilder) BuildBatchRequest(payload BatchRequestPayload) (rawRec *consensusproto.RawRecord, err error) { var aclContent []*aclrecordproto.AclContentValue + if len(payload.Removals.Identities) > 0 { + content, err := a.buildAccountRemove(payload.Removals) + if err != nil { + return nil, err + } + aclContent = append(aclContent, content) + } if len(payload.Additions) > 0 { - content, err := a.buildAccountsAdd(AccountsAddPayload{Additions: payload.Additions}) + content, err := a.buildAccountsAdd(AccountsAddPayload{Additions: payload.Additions}, payload.Removals.Change.MetadataKey.GetPublic(), payload.Removals.Change.ReadKey) if err != nil { return nil, err } @@ -128,7 +135,7 @@ func (a *aclRecordBuilder) BuildBatchRequest(payload BatchRequestPayload) (rawRe aclContent = append(aclContent, content) } for _, acc := range payload.Approvals { - content, err := a.buildRequestAccept(acc) + content, err := a.buildRequestAccept(acc, payload.Removals.Change.ReadKey) if err != nil { return nil, err } @@ -148,13 +155,6 @@ func (a *aclRecordBuilder) BuildBatchRequest(payload BatchRequestPayload) (rawRe } aclContent = append(aclContent, content) } - if len(payload.Removals.Identities) > 0 { - content, err := a.buildAccountRemove(payload.Removals) - if err != nil { - return nil, err - } - aclContent = append(aclContent, content) - } return a.buildRecords(aclContent) } @@ -231,14 +231,14 @@ func (a *aclRecordBuilder) buildPermissionChanges(payload PermissionChangesPaylo } func (a *aclRecordBuilder) BuildAccountsAdd(payload AccountsAddPayload) (rawRecord *consensusproto.RawRecord, err error) { - content, err := a.buildAccountsAdd(payload) + content, err := a.buildAccountsAdd(payload, nil, nil) if err != nil { return } return a.buildRecord(content) } -func (a *aclRecordBuilder) buildAccountsAdd(payload AccountsAddPayload) (value *aclrecordproto.AclContentValue, err error) { +func (a *aclRecordBuilder) buildAccountsAdd(payload AccountsAddPayload, mkKey crypto.PubKey, readKey crypto.SymKey) (value *aclrecordproto.AclContentValue, err error) { var accs []*aclrecordproto.AclAccountAdd for _, acc := range payload.Additions { if !a.state.Permissions(acc.Identity).NoPermissions() { @@ -247,9 +247,11 @@ func (a *aclRecordBuilder) buildAccountsAdd(payload AccountsAddPayload) (value * if acc.Permissions.IsOwner() { return nil, ErrIsOwner } - mkKey, err := a.state.CurrentMetadataKey() - if err != nil { - return nil, err + if mkKey == nil { + mkKey, err = a.state.CurrentMetadataKey() + if err != nil { + return nil, err + } } encMeta, err := mkKey.Encrypt(acc.Metadata) if err != nil { @@ -258,9 +260,11 @@ func (a *aclRecordBuilder) buildAccountsAdd(payload AccountsAddPayload) (value * if len(encMeta) > MaxMetadataLen { return nil, ErrMetadataTooLarge } - readKey, err := a.state.CurrentReadKey() - if err != nil { - return nil, ErrNoReadKey + if readKey == nil { + readKey, err = a.state.CurrentReadKey() + if err != nil { + return nil, ErrNoReadKey + } } protoKey, err := readKey.Marshall() if err != nil { @@ -386,14 +390,14 @@ func (a *aclRecordBuilder) BuildRequestJoin(payload RequestJoinPayload) (rawReco } func (a *aclRecordBuilder) BuildRequestAccept(payload RequestAcceptPayload) (rawRecord *consensusproto.RawRecord, err error) { - content, err := a.buildRequestAccept(payload) + content, err := a.buildRequestAccept(payload, nil) if err != nil { return } return a.buildRecord(content) } -func (a *aclRecordBuilder) buildRequestAccept(payload RequestAcceptPayload) (value *aclrecordproto.AclContentValue, err error) { +func (a *aclRecordBuilder) buildRequestAccept(payload RequestAcceptPayload, readKey crypto.SymKey) (value *aclrecordproto.AclContentValue, err error) { if !a.state.Permissions(a.state.pubKey).CanManageAccounts() { err = ErrInsufficientPermissions return @@ -403,9 +407,11 @@ func (a *aclRecordBuilder) buildRequestAccept(payload RequestAcceptPayload) (val err = ErrNoSuchRequest return } - readKey, err := a.state.CurrentReadKey() - if err != nil { - return nil, ErrNoReadKey + if readKey == nil { + readKey, err = a.state.CurrentReadKey() + if err != nil { + return nil, ErrNoReadKey + } } protoKey, err := readKey.Marshall() if err != nil { @@ -513,6 +519,9 @@ func (a *aclRecordBuilder) buildReadKeyChange(payload ReadKeyChangePayload, remo continue } } + if st.Permissions.NoPermissions() { + continue + } protoIdentity, err := st.PubKey.Marshall() if err != nil { return nil, err diff --git a/commonspace/object/acl/list/aclstate.go b/commonspace/object/acl/list/aclstate.go index 8c595ac2..8b8c6ee8 100644 --- a/commonspace/object/acl/list/aclstate.go +++ b/commonspace/object/acl/list/aclstate.go @@ -49,6 +49,9 @@ type AclKeys struct { ReadKey crypto.SymKey MetadataPrivKey crypto.PrivKey MetadataPubKey crypto.PubKey + + oldEncryptedReadKey []byte + encMetadatKey []byte } type Invite struct { @@ -360,7 +363,10 @@ func (st *AclState) applyRoot(record *AclRecord) (err error) { if err != nil { return err } - st.keys[record.Id] = AclKeys{MetadataPubKey: mkPubKey} + st.keys[record.Id] = AclKeys{ + MetadataPubKey: mkPubKey, + encMetadatKey: root.EncryptedMetadataPrivKey, + } } else { // this should be a derived acl st.keys[record.Id] = AclKeys{} @@ -672,6 +678,10 @@ func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccep } func (st *AclState) applyInviteJoin(ch *aclrecordproto.AclInviteJoin, record *AclRecord) error { + err := st.contentValidator.ValidateInviteJoin(ch, record.Identity) + if err != nil { + return err + } identity, err := st.keyStore.PubKeyFromProto(ch.Identity) if err != nil { return err @@ -716,42 +726,8 @@ func (st *AclState) unpackAllKeys(rk []byte) error { } for idx := len(st.readKeyChanges) - 1; idx >= 0; idx-- { recId := st.readKeyChanges[idx] - rec, err := st.list.Get(recId) - if err != nil { - return err - } - // if this is a first key change - if recId == st.id { - ch := rec.Model.(*aclrecordproto.AclRoot) - metadataKey, err := st.unmarshallDecryptPrivKey(ch.EncryptedMetadataPrivKey, iterReadKey.Decrypt) - if err != nil { - return err - } - aclKeys := st.keys[recId] - aclKeys.ReadKey = iterReadKey - aclKeys.MetadataPrivKey = metadataKey - st.keys[recId] = aclKeys - break - } - model := rec.Model.(*aclrecordproto.AclData) - content := model.GetAclContent() - var readKeyChange *aclrecordproto.AclReadKeyChange - for _, ch := range content { - switch { - case ch.GetReadKeyChange() != nil: - readKeyChange = ch.GetReadKeyChange() - case ch.GetAccountRemove() != nil: - readKeyChange = ch.GetAccountRemove().GetReadKeyChange() - } - } - if readKeyChange == nil { - return ErrIncorrectReadKey - } - oldReadKey, err := st.unmarshallDecryptReadKey(readKeyChange.EncryptedOldReadKey, iterReadKey.Decrypt) - if err != nil { - return err - } - metadataKey, err := st.unmarshallDecryptPrivKey(readKeyChange.EncryptedMetadataPrivKey, iterReadKey.Decrypt) + keys := st.keys[recId] + metadataKey, err := st.unmarshallDecryptPrivKey(keys.encMetadatKey, iterReadKey.Decrypt) if err != nil { return err } @@ -759,7 +735,16 @@ func (st *AclState) unpackAllKeys(rk []byte) error { aclKeys.ReadKey = iterReadKey aclKeys.MetadataPrivKey = metadataKey st.keys[recId] = aclKeys - iterReadKey = oldReadKey + if idx != 0 { + if keys.oldEncryptedReadKey == nil { + return ErrIncorrectReadKey + } + oldReadKey, err := st.unmarshallDecryptReadKey(keys.oldEncryptedReadKey, iterReadKey.Decrypt) + if err != nil { + return err + } + iterReadKey = oldReadKey + } } return nil } @@ -871,7 +856,9 @@ func (st *AclState) applyReadKeyChange(ch *aclrecordproto.AclReadKeyChange, reco return err } aclKeys := AclKeys{ - MetadataPubKey: mkPubKey, + MetadataPubKey: mkPubKey, + oldEncryptedReadKey: ch.EncryptedOldReadKey, + encMetadatKey: ch.EncryptedMetadataPrivKey, } for _, accKey := range ch.AccountKeys { identity, _ := st.keyStore.PubKeyFromProto(accKey.Identity) diff --git a/commonspace/object/acl/syncacl/syncacl.go b/commonspace/object/acl/syncacl/syncacl.go index 800d540f..3610c9d5 100644 --- a/commonspace/object/acl/syncacl/syncacl.go +++ b/commonspace/object/acl/syncacl/syncacl.go @@ -11,6 +11,7 @@ import ( "github.com/anyproto/any-sync/app" "github.com/anyproto/any-sync/app/logger" "github.com/anyproto/any-sync/commonspace/object/acl/list" + "github.com/anyproto/any-sync/commonspace/object/acl/recordverifier" "github.com/anyproto/any-sync/commonspace/object/acl/syncacl/headupdater" "github.com/anyproto/any-sync/commonspace/spacestorage" "github.com/anyproto/any-sync/commonspace/sync" @@ -67,7 +68,8 @@ func (s *syncAcl) Init(a *app.App) (err error) { return err } acc := a.MustComponent(accountservice.CName).(accountservice.Service) - s.AclList, err = list.BuildAclListWithIdentity(acc.Account(), aclStorage, list.NoOpAcceptorVerifier{}) + verifier := a.MustComponent(recordverifier.CName).(recordverifier.RecordVerifier) + s.AclList, err = list.BuildAclListWithIdentity(acc.Account(), aclStorage, verifier) if err != nil { return }