mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-08 05:57:03 +09:00
Add verifier logic
This commit is contained in:
parent
ab01e874bb
commit
c2dc1770b6
7 changed files with 73 additions and 15 deletions
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/app/logger"
|
"github.com/anyproto/any-sync/app/logger"
|
||||||
"github.com/anyproto/any-sync/commonspace/deletionstate"
|
"github.com/anyproto/any-sync/commonspace/deletionstate"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/object/tree/synctree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
|
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/treemanager"
|
"github.com/anyproto/any-sync/commonspace/object/treemanager"
|
||||||
"github.com/anyproto/any-sync/commonspace/spacestorage"
|
"github.com/anyproto/any-sync/commonspace/spacestorage"
|
||||||
|
@ -43,7 +44,7 @@ func (d *deleter) Delete(ctx context.Context) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = d.getter.DeleteTree(ctx, spaceId, id)
|
err = d.getter.DeleteTree(ctx, spaceId, id)
|
||||||
if err != nil && !errors.Is(err, spacestorage.ErrTreeStorageAlreadyDeleted) {
|
if err != nil && !errors.Is(err, spacestorage.ErrTreeStorageAlreadyDeleted) && !errors.Is(err, synctree.ErrSyncTreeDeleted) {
|
||||||
log.Error("failed to delete object", zap.Error(err))
|
log.Error("failed to delete object", zap.Error(err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,8 @@ type AclState struct {
|
||||||
|
|
||||||
func newAclStateWithKeys(
|
func newAclStateWithKeys(
|
||||||
rootRecord *AclRecord,
|
rootRecord *AclRecord,
|
||||||
key crypto.PrivKey) (st *AclState, err error) {
|
key crypto.PrivKey,
|
||||||
|
verifier AcceptorVerifier) (st *AclState, err error) {
|
||||||
st = &AclState{
|
st = &AclState{
|
||||||
id: rootRecord.Id,
|
id: rootRecord.Id,
|
||||||
key: key,
|
key: key,
|
||||||
|
@ -98,10 +99,7 @@ func newAclStateWithKeys(
|
||||||
pendingRequests: make(map[string]string),
|
pendingRequests: make(map[string]string),
|
||||||
keyStore: crypto.NewKeyStorage(),
|
keyStore: crypto.NewKeyStorage(),
|
||||||
}
|
}
|
||||||
st.contentValidator = &contentValidator{
|
st.contentValidator = newContentValidator(st.keyStore, st, verifier)
|
||||||
keyStore: st.keyStore,
|
|
||||||
aclState: st,
|
|
||||||
}
|
|
||||||
err = st.applyRoot(rootRecord)
|
err = st.applyRoot(rootRecord)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -109,7 +107,7 @@ func newAclStateWithKeys(
|
||||||
return st, nil
|
return st, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAclState(rootRecord *AclRecord) (st *AclState, err error) {
|
func newAclState(rootRecord *AclRecord, verifier AcceptorVerifier) (st *AclState, err error) {
|
||||||
st = &AclState{
|
st = &AclState{
|
||||||
id: rootRecord.Id,
|
id: rootRecord.Id,
|
||||||
keys: make(map[string]AclKeys),
|
keys: make(map[string]AclKeys),
|
||||||
|
@ -119,10 +117,7 @@ func newAclState(rootRecord *AclRecord) (st *AclState, err error) {
|
||||||
pendingRequests: make(map[string]string),
|
pendingRequests: make(map[string]string),
|
||||||
keyStore: crypto.NewKeyStorage(),
|
keyStore: crypto.NewKeyStorage(),
|
||||||
}
|
}
|
||||||
st.contentValidator = &contentValidator{
|
st.contentValidator = newContentValidator(st.keyStore, st, verifier)
|
||||||
keyStore: st.keyStore,
|
|
||||||
aclState: st,
|
|
||||||
}
|
|
||||||
err = st.applyRoot(rootRecord)
|
err = st.applyRoot(rootRecord)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -418,7 +413,7 @@ func (st *AclState) Copy() *AclState {
|
||||||
newSt.readKeyChanges = append(newSt.readKeyChanges, st.readKeyChanges...)
|
newSt.readKeyChanges = append(newSt.readKeyChanges, st.readKeyChanges...)
|
||||||
newSt.list = st.list
|
newSt.list = st.list
|
||||||
newSt.lastRecordId = st.lastRecordId
|
newSt.lastRecordId = st.lastRecordId
|
||||||
newSt.contentValidator = newContentValidator(newSt.keyStore, newSt)
|
newSt.contentValidator = newContentValidator(newSt.keyStore, newSt, st.list.verifier)
|
||||||
return newSt
|
return newSt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,12 +29,12 @@ func (sb *aclStateBuilder) Build(records []*AclRecord, list *aclList) (state *Ac
|
||||||
return nil, ErrIncorrectRecordSequence
|
return nil, ErrIncorrectRecordSequence
|
||||||
}
|
}
|
||||||
if sb.privKey != nil {
|
if sb.privKey != nil {
|
||||||
state, err = newAclStateWithKeys(records[0], sb.privKey)
|
state, err = newAclStateWithKeys(records[0], sb.privKey, list.verifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state, err = newAclState(records[0])
|
state, err = newAclState(records[0], list.verifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ type RWLocker interface {
|
||||||
|
|
||||||
type AcceptorVerifier interface {
|
type AcceptorVerifier interface {
|
||||||
VerifyAcceptor(rec *consensusproto.RawRecord) (err error)
|
VerifyAcceptor(rec *consensusproto.RawRecord) (err error)
|
||||||
|
ShouldValidate() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type NoOpAcceptorVerifier struct {
|
type NoOpAcceptorVerifier struct {
|
||||||
|
@ -37,6 +38,10 @@ func (n NoOpAcceptorVerifier) VerifyAcceptor(rec *consensusproto.RawRecord) (err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n NoOpAcceptorVerifier) ShouldValidate() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
type AclList interface {
|
type AclList interface {
|
||||||
RWLocker
|
RWLocker
|
||||||
Id() string
|
Id() string
|
||||||
|
@ -75,6 +80,7 @@ type aclList struct {
|
||||||
keyStorage crypto.KeyStorage
|
keyStorage crypto.KeyStorage
|
||||||
aclState *AclState
|
aclState *AclState
|
||||||
storage Storage
|
storage Storage
|
||||||
|
verifier AcceptorVerifier
|
||||||
|
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
@ -159,6 +165,7 @@ func build(deps internalDeps) (list AclList, err error) {
|
||||||
stateBuilder: stateBuilder,
|
stateBuilder: stateBuilder,
|
||||||
recordBuilder: recBuilder,
|
recordBuilder: recBuilder,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
|
verifier: deps.acceptorVerifier,
|
||||||
id: id,
|
id: id,
|
||||||
}
|
}
|
||||||
stateBuilder.Init(id)
|
stateBuilder.Init(id)
|
||||||
|
|
|
@ -27,16 +27,21 @@ type ContentValidator interface {
|
||||||
type contentValidator struct {
|
type contentValidator struct {
|
||||||
keyStore crypto.KeyStorage
|
keyStore crypto.KeyStorage
|
||||||
aclState *AclState
|
aclState *AclState
|
||||||
|
verifier AcceptorVerifier
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContentValidator(keyStore crypto.KeyStorage, aclState *AclState) ContentValidator {
|
func newContentValidator(keyStore crypto.KeyStorage, aclState *AclState, verifier AcceptorVerifier) ContentValidator {
|
||||||
return &contentValidator{
|
return &contentValidator{
|
||||||
keyStore: keyStore,
|
keyStore: keyStore,
|
||||||
aclState: aclState,
|
aclState: aclState,
|
||||||
|
verifier: verifier,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidatePermissionChanges(ch *aclrecordproto.AclAccountPermissionChanges, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidatePermissionChanges(ch *aclrecordproto.AclAccountPermissionChanges, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
for _, ch := range ch.Changes {
|
for _, ch := range ch.Changes {
|
||||||
err := c.ValidatePermissionChange(ch, authorIdentity)
|
err := c.ValidatePermissionChange(ch, authorIdentity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -47,6 +52,9 @@ func (c *contentValidator) ValidatePermissionChanges(ch *aclrecordproto.AclAccou
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidateAccountsAdd(ch *aclrecordproto.AclAccountsAdd, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidateAccountsAdd(ch *aclrecordproto.AclAccountsAdd, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
||||||
return ErrInsufficientPermissions
|
return ErrInsufficientPermissions
|
||||||
}
|
}
|
||||||
|
@ -70,6 +78,9 @@ func (c *contentValidator) ValidateAccountsAdd(ch *aclrecordproto.AclAccountsAdd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidateInviteJoin(ch *aclrecordproto.AclAccountInviteJoin, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidateInviteJoin(ch *aclrecordproto.AclAccountInviteJoin, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if !c.aclState.Permissions(authorIdentity).NoPermissions() {
|
if !c.aclState.Permissions(authorIdentity).NoPermissions() {
|
||||||
return ErrInsufficientPermissions
|
return ErrInsufficientPermissions
|
||||||
}
|
}
|
||||||
|
@ -111,6 +122,9 @@ func (c *contentValidator) ValidateInviteJoin(ch *aclrecordproto.AclAccountInvit
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidateAclRecordContents(ch *AclRecord) (err error) {
|
func (c *contentValidator) ValidateAclRecordContents(ch *AclRecord) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if ch.PrevId != c.aclState.lastRecordId {
|
if ch.PrevId != c.aclState.lastRecordId {
|
||||||
return ErrIncorrectRecordSequence
|
return ErrIncorrectRecordSequence
|
||||||
}
|
}
|
||||||
|
@ -156,6 +170,9 @@ func (c *contentValidator) validateAclRecordContent(ch *aclrecordproto.AclConten
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidatePermissionChange(ch *aclrecordproto.AclAccountPermissionChange, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidatePermissionChange(ch *aclrecordproto.AclAccountPermissionChange, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
||||||
return ErrInsufficientPermissions
|
return ErrInsufficientPermissions
|
||||||
}
|
}
|
||||||
|
@ -195,6 +212,9 @@ func (c *contentValidator) ValidatePermissionChange(ch *aclrecordproto.AclAccoun
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidateInvite(ch *aclrecordproto.AclAccountInvite, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidateInvite(ch *aclrecordproto.AclAccountInvite, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
||||||
return ErrInsufficientPermissions
|
return ErrInsufficientPermissions
|
||||||
}
|
}
|
||||||
|
@ -207,6 +227,9 @@ func (c *contentValidator) ValidateInvite(ch *aclrecordproto.AclAccountInvite, a
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidateInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidateInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
||||||
return ErrInsufficientPermissions
|
return ErrInsufficientPermissions
|
||||||
}
|
}
|
||||||
|
@ -218,6 +241,9 @@ func (c *contentValidator) ValidateInviteRevoke(ch *aclrecordproto.AclAccountInv
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidateRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidateRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
invite, exists := c.aclState.invites[ch.InviteRecordId]
|
invite, exists := c.aclState.invites[ch.InviteRecordId]
|
||||||
if !exists {
|
if !exists {
|
||||||
return ErrNoSuchInvite
|
return ErrNoSuchInvite
|
||||||
|
@ -253,6 +279,9 @@ func (c *contentValidator) ValidateRequestJoin(ch *aclrecordproto.AclAccountRequ
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidateRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidateRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
||||||
return ErrInsufficientPermissions
|
return ErrInsufficientPermissions
|
||||||
}
|
}
|
||||||
|
@ -274,6 +303,9 @@ func (c *contentValidator) ValidateRequestAccept(ch *aclrecordproto.AclAccountRe
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidateRequestDecline(ch *aclrecordproto.AclAccountRequestDecline, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidateRequestDecline(ch *aclrecordproto.AclAccountRequestDecline, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
||||||
return ErrInsufficientPermissions
|
return ErrInsufficientPermissions
|
||||||
}
|
}
|
||||||
|
@ -285,6 +317,9 @@ func (c *contentValidator) ValidateRequestDecline(ch *aclrecordproto.AclAccountR
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidateRequestCancel(ch *aclrecordproto.AclAccountRequestCancel, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidateRequestCancel(ch *aclrecordproto.AclAccountRequestCancel, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
rec, exists := c.aclState.requestRecords[ch.RecordId]
|
rec, exists := c.aclState.requestRecords[ch.RecordId]
|
||||||
if !exists {
|
if !exists {
|
||||||
return ErrNoSuchRequest
|
return ErrNoSuchRequest
|
||||||
|
@ -296,6 +331,9 @@ func (c *contentValidator) ValidateRequestCancel(ch *aclrecordproto.AclAccountRe
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidateAccountRemove(ch *aclrecordproto.AclAccountRemove, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidateAccountRemove(ch *aclrecordproto.AclAccountRemove, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
|
||||||
return ErrInsufficientPermissions
|
return ErrInsufficientPermissions
|
||||||
}
|
}
|
||||||
|
@ -325,6 +363,9 @@ func (c *contentValidator) ValidateAccountRemove(ch *aclrecordproto.AclAccountRe
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidateRequestRemove(ch *aclrecordproto.AclAccountRequestRemove, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidateRequestRemove(ch *aclrecordproto.AclAccountRequestRemove, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if c.aclState.Permissions(authorIdentity).NoPermissions() {
|
if c.aclState.Permissions(authorIdentity).NoPermissions() {
|
||||||
return ErrInsufficientPermissions
|
return ErrInsufficientPermissions
|
||||||
}
|
}
|
||||||
|
@ -338,10 +379,16 @@ func (c *contentValidator) ValidateRequestRemove(ch *aclrecordproto.AclAccountRe
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) ValidateReadKeyChange(ch *aclrecordproto.AclReadKeyChange, authorIdentity crypto.PubKey) (err error) {
|
func (c *contentValidator) ValidateReadKeyChange(ch *aclrecordproto.AclReadKeyChange, authorIdentity crypto.PubKey) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return c.validateReadKeyChange(ch, nil)
|
return c.validateReadKeyChange(ch, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentValidator) validateReadKeyChange(ch *aclrecordproto.AclReadKeyChange, removedUsers map[string]struct{}) (err error) {
|
func (c *contentValidator) validateReadKeyChange(ch *aclrecordproto.AclReadKeyChange, removedUsers map[string]struct{}) (err error) {
|
||||||
|
if !c.verifier.ShouldValidate() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
_, err = c.keyStore.PubKeyFromProto(ch.MetadataPubKey)
|
_, err = c.keyStore.PubKeyFromProto(ch.MetadataPubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrNoMetadataKey
|
return ErrNoMetadataKey
|
||||||
|
|
|
@ -22,3 +22,7 @@ func (a *AlwaysAccept) Name() string {
|
||||||
func (a *AlwaysAccept) VerifyAcceptor(_ *consensusproto.RawRecord) error {
|
func (a *AlwaysAccept) VerifyAcceptor(_ *consensusproto.RawRecord) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AlwaysAccept) ShouldValidate() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -50,3 +50,7 @@ func (r *recordVerifier) VerifyAcceptor(rec *consensusproto.RawRecord) (err erro
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *recordVerifier) ShouldValidate() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue