Add validate method in list

This commit is contained in:
mcrakhman 2023-06-26 10:10:14 +02:00
parent 7577c14d5f
commit 81aadfde7e
No known key found for this signature in database
GPG Key ID: DED12CFEF5B8396B
4 changed files with 133 additions and 34 deletions

View File

@ -17,7 +17,8 @@ type RootContent struct {
} }
type AclRecordBuilder interface { type AclRecordBuilder interface {
Unmarshall(rawIdRecord *aclrecordproto.RawAclRecordWithId) (rec *AclRecord, err error) UnmarshallWithId(rawIdRecord *aclrecordproto.RawAclRecordWithId) (rec *AclRecord, err error)
Unmarshall(rawRecord *aclrecordproto.RawAclRecord) (rec *AclRecord, err error)
BuildRoot(content RootContent) (rec *aclrecordproto.RawAclRecordWithId, err error) BuildRoot(content RootContent) (rec *aclrecordproto.RawAclRecordWithId, err error)
} }
@ -33,7 +34,41 @@ func NewAclRecordBuilder(id string, keyStorage crypto.KeyStorage) AclRecordBuild
} }
} }
func (a *aclRecordBuilder) Unmarshall(rawIdRecord *aclrecordproto.RawAclRecordWithId) (rec *AclRecord, err error) { func (a *aclRecordBuilder) Unmarshall(rawRecord *aclrecordproto.RawAclRecord) (rec *AclRecord, err error) {
aclRecord := &aclrecordproto.AclRecord{}
err = proto.Unmarshal(rawRecord.Payload, aclRecord)
if err != nil {
return
}
pubKey, err := a.keyStorage.PubKeyFromProto(aclRecord.Identity)
if err != nil {
return
}
aclData := &aclrecordproto.AclData{}
err = proto.Unmarshal(rawRecord.Payload, aclData)
if err != nil {
return
}
rec = &AclRecord{
PrevId: aclRecord.PrevId,
Timestamp: aclRecord.Timestamp,
Data: aclRecord.Data,
Signature: rawRecord.Signature,
Identity: pubKey,
Model: aclData,
}
res, err := pubKey.Verify(rawRecord.Payload, rawRecord.Signature)
if err != nil {
return
}
if !res {
err = ErrInvalidSignature
return
}
return
}
func (a *aclRecordBuilder) UnmarshallWithId(rawIdRecord *aclrecordproto.RawAclRecordWithId) (rec *AclRecord, err error) {
var ( var (
rawRec = &aclrecordproto.RawAclRecord{} rawRec = &aclrecordproto.RawAclRecord{}
pubKey crypto.PubKey pubKey crypto.PubKey
@ -69,6 +104,11 @@ func (a *aclRecordBuilder) Unmarshall(rawIdRecord *aclrecordproto.RawAclRecordWi
if err != nil { if err != nil {
return return
} }
aclData := &aclrecordproto.AclData{}
err = proto.Unmarshal(rawRec.Payload, aclData)
if err != nil {
return
}
rec = &AclRecord{ rec = &AclRecord{
Id: rawIdRecord.Id, Id: rawIdRecord.Id,
PrevId: aclRecord.PrevId, PrevId: aclRecord.PrevId,
@ -76,6 +116,7 @@ func (a *aclRecordBuilder) Unmarshall(rawIdRecord *aclrecordproto.RawAclRecordWi
Data: aclRecord.Data, Data: aclRecord.Data,
Signature: rawRec.Signature, Signature: rawRec.Signature,
Identity: pubKey, Identity: pubKey,
Model: aclData,
} }
} }

View File

@ -88,6 +88,10 @@ func newAclState(id string) *AclState {
return st return st
} }
func (st *AclState) Validator() ContentValidator {
return st.contentValidator
}
func (st *AclState) CurrentReadKeyId() string { func (st *AclState) CurrentReadKeyId() string {
return st.currentReadKeyId return st.currentReadKeyId
} }
@ -242,7 +246,7 @@ func (st *AclState) applyPermissionChange(ch *aclrecordproto.AclAccountPermissio
if err != nil { if err != nil {
return err return err
} }
err = st.contentValidator.ValidatePermissionChange(ch, recordId, authorIdentity) err = st.contentValidator.ValidatePermissionChange(ch, authorIdentity)
if err != nil { if err != nil {
return err return err
} }
@ -258,7 +262,7 @@ func (st *AclState) applyInvite(ch *aclrecordproto.AclAccountInvite, recordId st
if err != nil { if err != nil {
return err return err
} }
err = st.contentValidator.ValidateInvite(ch, recordId, authorIdentity) err = st.contentValidator.ValidateInvite(ch, authorIdentity)
if err != nil { if err != nil {
return err return err
} }
@ -267,7 +271,7 @@ func (st *AclState) applyInvite(ch *aclrecordproto.AclAccountInvite, recordId st
} }
func (st *AclState) applyInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, recordId string, authorIdentity crypto.PubKey) error { func (st *AclState) applyInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, recordId string, authorIdentity crypto.PubKey) error {
err := st.contentValidator.ValidateInviteRevoke(ch, recordId, authorIdentity) err := st.contentValidator.ValidateInviteRevoke(ch, authorIdentity)
if err != nil { if err != nil {
return err return err
} }
@ -276,7 +280,7 @@ func (st *AclState) applyInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke,
} }
func (st *AclState) applyRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, recordId string, authorIdentity crypto.PubKey) error { func (st *AclState) applyRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, recordId string, authorIdentity crypto.PubKey) error {
err := st.contentValidator.ValidateRequestJoin(ch, recordId, authorIdentity) err := st.contentValidator.ValidateRequestJoin(ch, authorIdentity)
if err != nil { if err != nil {
return err return err
} }
@ -288,7 +292,7 @@ func (st *AclState) applyRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, r
} }
func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, recordId string, authorIdentity crypto.PubKey) error { func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, recordId string, authorIdentity crypto.PubKey) error {
err := st.contentValidator.ValidateRequestAccept(ch, recordId, authorIdentity) err := st.contentValidator.ValidateRequestAccept(ch, authorIdentity)
if err != nil { if err != nil {
return err return err
} }
@ -314,18 +318,18 @@ func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccep
if err != nil { if err != nil {
return err return err
} }
for recordId, key := range keys.ReadKeys { for keyId, key := range keys.ReadKeys {
sym, err := crypto.UnmarshallAESKey(key) sym, err := crypto.UnmarshallAESKey(key)
if err != nil { if err != nil {
return err return err
} }
st.userReadKeys[recordId] = sym st.userReadKeys[keyId] = sym
} }
return nil return nil
} }
func (st *AclState) applyRequestDecline(ch *aclrecordproto.AclAccountRequestDecline, recordId string, authorIdentity crypto.PubKey) error { func (st *AclState) applyRequestDecline(ch *aclrecordproto.AclAccountRequestDecline, recordId string, authorIdentity crypto.PubKey) error {
err := st.contentValidator.ValidateRequestDecline(ch, recordId, authorIdentity) err := st.contentValidator.ValidateRequestDecline(ch, authorIdentity)
if err != nil { if err != nil {
return err return err
} }
@ -334,7 +338,7 @@ func (st *AclState) applyRequestDecline(ch *aclrecordproto.AclAccountRequestDecl
} }
func (st *AclState) applyAccountRemove(ch *aclrecordproto.AclAccountRemove, recordId string, authorIdentity crypto.PubKey) error { func (st *AclState) applyAccountRemove(ch *aclrecordproto.AclAccountRemove, recordId string, authorIdentity crypto.PubKey) error {
err := st.contentValidator.ValidateRemove(ch, recordId, authorIdentity) err := st.contentValidator.ValidateRemove(ch, authorIdentity)
if err != nil { if err != nil {
return err return err
} }
@ -342,7 +346,7 @@ func (st *AclState) applyAccountRemove(ch *aclrecordproto.AclAccountRemove, reco
} }
func (st *AclState) applyReadKeyChange(ch *aclrecordproto.AclReadKeyChange, recordId string, authorIdentity crypto.PubKey) error { func (st *AclState) applyReadKeyChange(ch *aclrecordproto.AclReadKeyChange, recordId string, authorIdentity crypto.PubKey) error {
err := st.contentValidator.ValidateReadKeyChange(ch, recordId, authorIdentity) err := st.contentValidator.ValidateReadKeyChange(ch, authorIdentity)
if err != nil { if err != nil {
return err return err
} }

View File

@ -5,11 +5,12 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"sync"
"github.com/anyproto/any-sync/commonspace/object/accountdata" "github.com/anyproto/any-sync/commonspace/object/accountdata"
"github.com/anyproto/any-sync/commonspace/object/acl/aclrecordproto" "github.com/anyproto/any-sync/commonspace/object/acl/aclrecordproto"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage" "github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/util/crypto" "github.com/anyproto/any-sync/util/crypto"
"sync"
) )
type IterFunc = func(record *AclRecord) (IsContinue bool) type IterFunc = func(record *AclRecord) (IsContinue bool)
@ -33,8 +34,11 @@ type AclList interface {
Get(id string) (*AclRecord, error) Get(id string) (*AclRecord, error)
Iterate(iterFunc IterFunc) Iterate(iterFunc IterFunc)
IterateFrom(startId string, iterFunc IterFunc) IterateFrom(startId string, iterFunc IterFunc)
KeyStorage() crypto.KeyStorage
KeyStorage() crypto.KeyStorage
RecordBuilder() AclRecordBuilder
ValidateRawRecord(record *aclrecordproto.RawAclRecord) (err error)
AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (added bool, err error) AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (added bool, err error)
Close() (err error) Close() (err error)
@ -77,7 +81,7 @@ func build(id string, keyStorage crypto.KeyStorage, stateBuilder *aclStateBuilde
return return
} }
record, err := recBuilder.Unmarshall(rawRecordWithId) record, err := recBuilder.UnmarshallWithId(rawRecordWithId)
if err != nil { if err != nil {
return return
} }
@ -89,7 +93,7 @@ func build(id string, keyStorage crypto.KeyStorage, stateBuilder *aclStateBuilde
return return
} }
record, err = recBuilder.Unmarshall(rawRecordWithId) record, err = recBuilder.UnmarshallWithId(rawRecordWithId)
if err != nil { if err != nil {
return return
} }
@ -132,15 +136,27 @@ func build(id string, keyStorage crypto.KeyStorage, stateBuilder *aclStateBuilde
return return
} }
func (a *aclList) RecordBuilder() AclRecordBuilder {
return a.recordBuilder
}
func (a *aclList) Records() []*AclRecord { func (a *aclList) Records() []*AclRecord {
return a.records return a.records
} }
func (a *aclList) ValidateRawRecord(rawRec *aclrecordproto.RawAclRecord) (err error) {
record, err := a.recordBuilder.Unmarshall(rawRec)
if err != nil {
return
}
return a.aclState.Validator().ValidateAclRecordContents(record)
}
func (a *aclList) AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (added bool, err error) { func (a *aclList) AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (added bool, err error) {
if _, ok := a.indexes[rawRec.Id]; ok { if _, ok := a.indexes[rawRec.Id]; ok {
return return
} }
record, err := a.recordBuilder.Unmarshall(rawRec) record, err := a.recordBuilder.UnmarshallWithId(rawRec)
if err != nil { if err != nil {
return return
} }
@ -159,7 +175,7 @@ func (a *aclList) AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (added
} }
func (a *aclList) IsValidNext(rawRec *aclrecordproto.RawAclRecordWithId) (err error) { func (a *aclList) IsValidNext(rawRec *aclrecordproto.RawAclRecordWithId) (err error) {
_, err = a.recordBuilder.Unmarshall(rawRec) _, err = a.recordBuilder.UnmarshallWithId(rawRec)
if err != nil { if err != nil {
return return
} }

View File

@ -6,14 +6,15 @@ import (
) )
type ContentValidator interface { type ContentValidator interface {
ValidatePermissionChange(ch *aclrecordproto.AclAccountPermissionChange, id string, authorIdentity crypto.PubKey) (err error) ValidateAclRecordContents(ch *AclRecord) (err error)
ValidateInvite(ch *aclrecordproto.AclAccountInvite, id string, authorIdentity crypto.PubKey) (err error) ValidatePermissionChange(ch *aclrecordproto.AclAccountPermissionChange, authorIdentity crypto.PubKey) (err error)
ValidateInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, id string, authorIdentity crypto.PubKey) (err error) ValidateInvite(ch *aclrecordproto.AclAccountInvite, authorIdentity crypto.PubKey) (err error)
ValidateRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, id string, authorIdentity crypto.PubKey) (err error) ValidateInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, authorIdentity crypto.PubKey) (err error)
ValidateRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, id string, authorIdentity crypto.PubKey) (err error) ValidateRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, authorIdentity crypto.PubKey) (err error)
ValidateRequestDecline(ch *aclrecordproto.AclAccountRequestDecline, id string, authorIdentity crypto.PubKey) (err error) ValidateRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, authorIdentity crypto.PubKey) (err error)
ValidateRemove(ch *aclrecordproto.AclAccountRemove, id string, authorIdentity crypto.PubKey) (err error) ValidateRequestDecline(ch *aclrecordproto.AclAccountRequestDecline, authorIdentity crypto.PubKey) (err error)
ValidateReadKeyChange(ch *aclrecordproto.AclReadKeyChange, id string, authorIdentity crypto.PubKey) (err error) ValidateRemove(ch *aclrecordproto.AclAccountRemove, authorIdentity crypto.PubKey) (err error)
ValidateReadKeyChange(ch *aclrecordproto.AclReadKeyChange, authorIdentity crypto.PubKey) (err error)
} }
type contentValidator struct { type contentValidator struct {
@ -21,7 +22,44 @@ type contentValidator struct {
aclState *AclState aclState *AclState
} }
func (c *contentValidator) ValidatePermissionChange(ch *aclrecordproto.AclAccountPermissionChange, id string, authorIdentity crypto.PubKey) (err error) { func (c *contentValidator) ValidateAclRecordContents(ch *AclRecord) (err error) {
if ch.PrevId != c.aclState.lastRecordId {
return ErrIncorrectRecordSequence
}
aclData := ch.Model.(*aclrecordproto.AclData)
for _, content := range aclData.AclContent {
err = c.validateAclRecordContent(content, ch.Identity)
if err != nil {
return
}
}
return
}
func (c *contentValidator) validateAclRecordContent(ch *aclrecordproto.AclContentValue, authorIdentity crypto.PubKey) (err error) {
switch {
case ch.GetPermissionChange() != nil:
return c.ValidatePermissionChange(ch.GetPermissionChange(), authorIdentity)
case ch.GetInvite() != nil:
return c.ValidateInvite(ch.GetInvite(), authorIdentity)
case ch.GetInviteRevoke() != nil:
return c.ValidateInviteRevoke(ch.GetInviteRevoke(), authorIdentity)
case ch.GetRequestJoin() != nil:
return c.ValidateRequestJoin(ch.GetRequestJoin(), authorIdentity)
case ch.GetRequestAccept() != nil:
return c.ValidateRequestAccept(ch.GetRequestAccept(), authorIdentity)
case ch.GetRequestDecline() != nil:
return c.ValidateRequestDecline(ch.GetRequestDecline(), authorIdentity)
case ch.GetAccountRemove() != nil:
return c.ValidateRemove(ch.GetAccountRemove(), authorIdentity)
case ch.GetReadKeyChange() != nil:
return c.ValidateReadKeyChange(ch.GetReadKeyChange(), authorIdentity)
default:
return ErrUnexpectedContentType
}
}
func (c *contentValidator) ValidatePermissionChange(ch *aclrecordproto.AclAccountPermissionChange, authorIdentity crypto.PubKey) (err error) {
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() { if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
return ErrInsufficientPermissions return ErrInsufficientPermissions
} }
@ -36,7 +74,7 @@ func (c *contentValidator) ValidatePermissionChange(ch *aclrecordproto.AclAccoun
return return
} }
func (c *contentValidator) ValidateInvite(ch *aclrecordproto.AclAccountInvite, id string, authorIdentity crypto.PubKey) (err error) { func (c *contentValidator) ValidateInvite(ch *aclrecordproto.AclAccountInvite, authorIdentity crypto.PubKey) (err error) {
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() { if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
return ErrInsufficientPermissions return ErrInsufficientPermissions
} }
@ -44,7 +82,7 @@ func (c *contentValidator) ValidateInvite(ch *aclrecordproto.AclAccountInvite, i
return return
} }
func (c *contentValidator) ValidateInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, id string, authorIdentity crypto.PubKey) (err error) { func (c *contentValidator) ValidateInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, authorIdentity crypto.PubKey) (err error) {
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() { if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
return ErrInsufficientPermissions return ErrInsufficientPermissions
} }
@ -55,7 +93,7 @@ func (c *contentValidator) ValidateInviteRevoke(ch *aclrecordproto.AclAccountInv
return return
} }
func (c *contentValidator) ValidateRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, id string, authorIdentity crypto.PubKey) (err error) { func (c *contentValidator) ValidateRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, authorIdentity crypto.PubKey) (err error) {
inviteKey, exists := c.aclState.inviteKeys[ch.InviteRecordId] inviteKey, exists := c.aclState.inviteKeys[ch.InviteRecordId]
if !exists { if !exists {
return ErrNoSuchInvite return ErrNoSuchInvite
@ -81,7 +119,7 @@ func (c *contentValidator) ValidateRequestJoin(ch *aclrecordproto.AclAccountRequ
return return
} }
func (c *contentValidator) ValidateRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, id string, authorIdentity crypto.PubKey) (err error) { func (c *contentValidator) ValidateRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, authorIdentity crypto.PubKey) (err error) {
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() { if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
return ErrInsufficientPermissions return ErrInsufficientPermissions
} }
@ -102,7 +140,7 @@ func (c *contentValidator) ValidateRequestAccept(ch *aclrecordproto.AclAccountRe
return return
} }
func (c *contentValidator) ValidateRequestDecline(ch *aclrecordproto.AclAccountRequestDecline, id string, authorIdentity crypto.PubKey) (err error) { func (c *contentValidator) ValidateRequestDecline(ch *aclrecordproto.AclAccountRequestDecline, authorIdentity crypto.PubKey) (err error) {
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() { if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
return ErrInsufficientPermissions return ErrInsufficientPermissions
} }
@ -113,7 +151,7 @@ func (c *contentValidator) ValidateRequestDecline(ch *aclrecordproto.AclAccountR
return return
} }
func (c *contentValidator) ValidateRemove(ch *aclrecordproto.AclAccountRemove, id string, authorIdentity crypto.PubKey) (err error) { func (c *contentValidator) ValidateRemove(ch *aclrecordproto.AclAccountRemove, authorIdentity crypto.PubKey) (err error) {
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() { if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
return ErrInsufficientPermissions return ErrInsufficientPermissions
} }
@ -128,7 +166,7 @@ func (c *contentValidator) ValidateRemove(ch *aclrecordproto.AclAccountRemove, i
return c.validateAccountReadKeys(ch.AccountKeys) return c.validateAccountReadKeys(ch.AccountKeys)
} }
func (c *contentValidator) ValidateReadKeyChange(ch *aclrecordproto.AclReadKeyChange, id string, authorIdentity crypto.PubKey) (err error) { func (c *contentValidator) ValidateReadKeyChange(ch *aclrecordproto.AclReadKeyChange, authorIdentity crypto.PubKey) (err error) {
return c.validateAccountReadKeys(ch.AccountKeys) return c.validateAccountReadKeys(ch.AccountKeys)
} }