any-sync/pkg/acl/tree/changebuilder.go
mcrakhman d41f736234
Revert "Use string instead of bytes, to simplify code"
This reverts commit a907cde3993868dbf27938fe609fd2bbc02db2b5.
2022-09-13 12:26:37 +02:00

164 lines
3.8 KiB
Go

package tree
import (
"errors"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/common"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/symmetric"
"github.com/gogo/protobuf/proto"
"time"
)
var ErrEmptyChange = errors.New("change payload should not be empty")
type BuilderContent struct {
treeHeadIds []string
aclHeadId string
snapshotBaseId string
currentReadKeyHash uint64
identity []byte
isSnapshot bool
signingKey signingkey.PrivKey
readKey *symmetric.Key
content []byte
}
type ChangeBuilder interface {
ConvertFromRaw(rawIdChange *aclpb.RawTreeChangeWithId, verify bool) (ch *Change, err error)
BuildContent(payload BuilderContent) (ch *Change, raw *aclpb.RawTreeChangeWithId, err error)
BuildRaw(ch *Change) (*aclpb.RawTreeChangeWithId, error)
}
type changeBuilder struct {
keys *common.Keychain
}
func newChangeBuilder(keys *common.Keychain) ChangeBuilder {
return &changeBuilder{keys: keys}
}
func (c *changeBuilder) ConvertFromRaw(rawIdChange *aclpb.RawTreeChangeWithId, verify bool) (ch *Change, err error) {
if rawIdChange.GetRawChange() == nil {
err = ErrEmptyChange
return
}
if verify {
// verifying ID
if !cid.VerifyCID(rawIdChange.RawChange, rawIdChange.Id) {
err = ErrIncorrectCID
return
}
}
raw := &aclpb.RawTreeChange{}
err = proto.Unmarshal(rawIdChange.GetRawChange(), raw)
if err != nil {
return
}
if verify {
var identityKey signingkey.PubKey
identityKey, err = c.keys.GetOrAdd(ch.Identity)
if err != nil {
return
}
// verifying signature
var res bool
res, err = identityKey.Verify(raw.Payload, raw.Signature)
if err != nil {
return
}
if !res {
err = ErrIncorrectSignature
return
}
}
unmarshalled := &aclpb.TreeChange{}
err = proto.Unmarshal(raw.Payload, unmarshalled)
if err != nil {
return
}
ch = NewChange(rawIdChange.Id, unmarshalled, raw.Signature)
return
}
func (c *changeBuilder) BuildContent(payload BuilderContent) (ch *Change, rawIdChange *aclpb.RawTreeChangeWithId, err error) {
change := &aclpb.TreeChange{
TreeHeadIds: payload.treeHeadIds,
AclHeadId: payload.aclHeadId,
SnapshotBaseId: payload.snapshotBaseId,
CurrentReadKeyHash: payload.currentReadKeyHash,
Timestamp: int64(time.Now().Nanosecond()),
Identity: payload.identity,
IsSnapshot: payload.isSnapshot,
}
encrypted, err := payload.readKey.Encrypt(payload.content)
if err != nil {
return
}
change.ChangesData = encrypted
marshalledChange, err := proto.Marshal(change)
if err != nil {
return
}
signature, err := payload.signingKey.Sign(marshalledChange)
if err != nil {
return
}
raw := &aclpb.RawTreeChange{
Payload: marshalledChange,
Signature: signature,
}
marshalledRawChange, err := proto.Marshal(raw)
if err != nil {
return
}
id, err := cid.NewCIDFromBytes(marshalledRawChange)
if err != nil {
return
}
ch = NewChange(id, change, signature)
ch.ParsedModel = payload.content
rawIdChange = &aclpb.RawTreeChangeWithId{
RawChange: marshalledRawChange,
Id: id,
}
return
}
func (c *changeBuilder) BuildRaw(ch *Change) (raw *aclpb.RawTreeChangeWithId, err error) {
var marshalled []byte
marshalled, err = ch.Content.Marshal()
if err != nil {
return
}
marshalledRawChange, err := proto.Marshal(&aclpb.RawTreeChange{
Payload: marshalled,
Signature: ch.Sign,
})
if err != nil {
return
}
raw = &aclpb.RawTreeChangeWithId{
RawChange: marshalledRawChange,
Id: ch.Id,
}
return
}