Unify changes loading in change loader

This commit is contained in:
mcrakhman 2022-07-05 15:42:17 +02:00 committed by Mikhail Iudin
parent f64db4b867
commit 6f53ceb768
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0
4 changed files with 125 additions and 127 deletions

View File

@ -12,6 +12,7 @@ type ACLStateBuilder struct {
aclState *ACLState aclState *ACLState
identity string identity string
key threadmodels.EncryptionPrivKey key threadmodels.EncryptionPrivKey
decoder threadmodels.SigningPubKeyDecoder
} }
type decreasedPermissionsParameters struct { type decreasedPermissionsParameters struct {
@ -19,28 +20,10 @@ type decreasedPermissionsParameters struct {
startChange string startChange string
} }
func NewACLStateBuilder( func NewACLStateBuilder(decoder threadmodels.SigningPubKeyDecoder) *ACLStateBuilder {
tree *Tree,
identity string,
key threadmodels.EncryptionPrivKey,
decoder threadmodels.SigningPubKeyDecoder) (*ACLStateBuilder, error) {
root := tree.Root()
if !root.IsSnapshot {
return nil, fmt.Errorf("root should always be a snapshot")
}
snapshot := root.Content.GetAclData().GetAclSnapshot()
state, err := NewACLStateFromSnapshot(snapshot, identity, key, decoder)
if err != nil {
return nil, fmt.Errorf("could not build aclState from snapshot: %w", err)
}
return &ACLStateBuilder{ return &ACLStateBuilder{
tree: tree, decoder: decoder,
aclState: state, }
identity: identity,
key: key,
}, nil
} }
func (sb *ACLStateBuilder) Build() (*ACLState, error) { func (sb *ACLStateBuilder) Build() (*ACLState, error) {
@ -48,6 +31,31 @@ func (sb *ACLStateBuilder) Build() (*ACLState, error) {
return state, err return state, err
} }
func (sb *ACLStateBuilder) Init(
tree *Tree,
accountData *AccountData) error {
root := tree.Root()
if !root.IsSnapshot {
return fmt.Errorf("root should always be a snapshot")
}
snapshot := root.Content.GetAclData().GetAclSnapshot()
state, err := NewACLStateFromSnapshot(
snapshot,
accountData.Identity,
accountData.EncKey,
sb.decoder)
if err != nil {
return fmt.Errorf("could not build aclState from snapshot: %w", err)
}
sb.tree = tree
sb.identity = accountData.Identity
sb.key = accountData.EncKey
sb.aclState = state
return nil
}
// TODO: we can probably have only one state builder, because we can build both at the same time // TODO: we can probably have only one state builder, because we can build both at the same time
func (sb *ACLStateBuilder) BuildBefore(beforeId string) (*ACLState, bool, error) { func (sb *ACLStateBuilder) BuildBefore(beforeId string) (*ACLState, bool, error) {
var ( var (

View File

@ -1,14 +1,10 @@
package data package data
import ( import (
"context"
"fmt" "fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/data/pb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/data/threadmodels" "github.com/anytypeio/go-anytype-infrastructure-experiments/data/threadmodels"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
"github.com/gogo/protobuf/proto"
"github.com/textileio/go-threads/core/thread" "github.com/textileio/go-threads/core/thread"
"time"
) )
type ACLTreeBuilder struct { type ACLTreeBuilder struct {
@ -17,64 +13,23 @@ type ACLTreeBuilder struct {
signingPubKeyDecoder threadmodels.SigningPubKeyDecoder signingPubKeyDecoder threadmodels.SigningPubKeyDecoder
tree *Tree tree *Tree
thread threadmodels.Thread thread threadmodels.Thread
*changeLoader
} }
func NewACLTreeBuilder(t threadmodels.Thread, decoder threadmodels.SigningPubKeyDecoder) *ACLTreeBuilder { func NewACLTreeBuilder(t threadmodels.Thread, decoder threadmodels.SigningPubKeyDecoder) *ACLTreeBuilder {
return &ACLTreeBuilder{ return &ACLTreeBuilder{
cache: make(map[string]*Change),
identityKeys: make(map[string]threadmodels.SigningPubKey),
signingPubKeyDecoder: decoder, signingPubKeyDecoder: decoder,
tree: &Tree{}, // TODO: add NewTree method
thread: t, thread: t,
changeLoader: newChangeLoader(t, decoder),
} }
} }
func (tb *ACLTreeBuilder) loadChange(id string) (ch *Change, err error) { func (tb *ACLTreeBuilder) Init() {
if ch, ok := tb.cache[id]; ok { tb.cache = make(map[string]*Change)
return ch, nil tb.identityKeys = make(map[string]threadmodels.SigningPubKey)
} tb.tree = &Tree{}
tb.changeLoader.init(tb.cache, tb.identityKeys)
// TODO: Add virtual changes logic
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
change, err := tb.thread.GetChange(ctx, id)
if err != nil {
return nil, err
}
aclChange := new(pb.ACLChange)
// TODO: think what should we do with such cases, because this can be used by attacker to break our tree
if err = proto.Unmarshal(change.Payload, aclChange); err != nil {
return
}
var verified bool
verified, err = tb.verify(aclChange.Identity, change.Payload, change.Signature)
if err != nil {
return
}
if !verified {
err = fmt.Errorf("the signature of the payload cannot be verified")
return
}
ch, err = NewACLChange(id, aclChange)
tb.cache[id] = ch
return ch, nil
}
func (tb *ACLTreeBuilder) verify(identity string, payload, signature []byte) (isVerified bool, err error) {
identityKey, exists := tb.identityKeys[identity]
if !exists {
identityKey, err = tb.signingPubKeyDecoder.DecodeFromString(identity)
if err != nil {
return
}
tb.identityKeys[identity] = identityKey
}
return identityKey.Verify(payload, signature)
} }
func (tb *ACLTreeBuilder) Build() (*Tree, error) { func (tb *ACLTreeBuilder) Build() (*Tree, error) {

80
data/changeloader.go Normal file
View File

@ -0,0 +1,80 @@
package data
import (
"context"
"fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/data/pb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/data/threadmodels"
"github.com/gogo/protobuf/proto"
"time"
)
type changeLoader struct {
cache map[string]*Change
identityKeys map[string]threadmodels.SigningPubKey
signingPubKeyDecoder threadmodels.SigningPubKeyDecoder
thread threadmodels.Thread
}
func newChangeLoader(
thread threadmodels.Thread,
signingPubKeyDecoder threadmodels.SigningPubKeyDecoder) *changeLoader {
return &changeLoader{
signingPubKeyDecoder: signingPubKeyDecoder,
thread: thread,
}
}
func (c *changeLoader) init(cache map[string]*Change,
identityKeys map[string]threadmodels.SigningPubKey) {
c.cache = cache
c.identityKeys = identityKeys
}
func (c *changeLoader) loadChange(id string) (ch *Change, err error) {
if ch, ok := c.cache[id]; ok {
return ch, nil
}
// TODO: Add virtual changes logic
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
change, err := c.thread.GetChange(ctx, id)
if err != nil {
return nil, err
}
aclChange := new(pb.ACLChange)
// TODO: think what should we do with such cases, because this can be used by attacker to break our tree
if err = proto.Unmarshal(change.Payload, aclChange); err != nil {
return
}
var verified bool
verified, err = c.verify(aclChange.Identity, change.Payload, change.Signature)
if err != nil {
return
}
if !verified {
err = fmt.Errorf("the signature of the payload cannot be verified")
return
}
ch, err = NewACLChange(id, aclChange)
c.cache[id] = ch
return ch, nil
}
func (c *changeLoader) verify(identity string, payload, signature []byte) (isVerified bool, err error) {
identityKey, exists := c.identityKeys[identity]
if !exists {
identityKey, err = c.signingPubKeyDecoder.DecodeFromString(identity)
if err != nil {
return
}
c.identityKeys[identity] = identityKey
}
return identityKey.Verify(payload, signature)
}

View File

@ -1,17 +1,13 @@
package data package data
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/data/pb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/data/threadmodels" "github.com/anytypeio/go-anytype-infrastructure-experiments/data/threadmodels"
//"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/lib/logging" //"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/lib/logging"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
"github.com/gogo/protobuf/proto"
"github.com/prometheus/common/log" "github.com/prometheus/common/log"
"github.com/textileio/go-threads/core/thread" "github.com/textileio/go-threads/core/thread"
"time"
) )
var ( var (
@ -25,64 +21,23 @@ type TreeBuilder struct {
signingPubKeyDecoder threadmodels.SigningPubKeyDecoder signingPubKeyDecoder threadmodels.SigningPubKeyDecoder
tree *Tree tree *Tree
thread threadmodels.Thread thread threadmodels.Thread
*changeLoader
} }
func NewTreeBuilder(t threadmodels.Thread, decoder threadmodels.SigningPubKeyDecoder) *TreeBuilder { func NewTreeBuilder(t threadmodels.Thread, decoder threadmodels.SigningPubKeyDecoder) *TreeBuilder {
return &TreeBuilder{ return &TreeBuilder{
cache: make(map[string]*Change),
identityKeys: make(map[string]threadmodels.SigningPubKey),
signingPubKeyDecoder: decoder, signingPubKeyDecoder: decoder,
tree: &Tree{}, // TODO: add NewTree method
thread: t, thread: t,
changeLoader: newChangeLoader(t, decoder),
} }
} }
func (tb *TreeBuilder) loadChange(id string) (ch *Change, err error) { func (tb *TreeBuilder) Init() {
if ch, ok := tb.cache[id]; ok { tb.cache = make(map[string]*Change)
return ch, nil tb.identityKeys = make(map[string]threadmodels.SigningPubKey)
} tb.tree = &Tree{}
tb.changeLoader.init(tb.cache, tb.identityKeys)
// TODO: Add virtual changes logic
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
change, err := tb.thread.GetChange(ctx, id)
if err != nil {
return nil, err
}
aclChange := new(pb.ACLChange)
// TODO: think what should we do with such cases, because this can be used by attacker to break our tree
if err = proto.Unmarshal(change.Payload, aclChange); err != nil {
return
}
var verified bool
verified, err = tb.verify(aclChange.Identity, change.Payload, change.Signature)
if err != nil {
return
}
if !verified {
err = fmt.Errorf("the signature of the payload cannot be verified")
return
}
ch, err = NewChange(id, aclChange)
tb.cache[id] = ch
return ch, nil
}
func (tb *TreeBuilder) verify(identity string, payload, signature []byte) (isVerified bool, err error) {
identityKey, exists := tb.identityKeys[identity]
if !exists {
identityKey, err = tb.signingPubKeyDecoder.DecodeFromString(identity)
if err != nil {
return
}
tb.identityKeys[identity] = identityKey
}
return identityKey.Verify(payload, signature)
} }
func (tb *TreeBuilder) Build(fromStart bool) (*Tree, error) { func (tb *TreeBuilder) Build(fromStart bool) (*Tree, error) {