WIP proto refactoring

This commit is contained in:
mcrakhman 2022-09-12 21:06:20 +02:00 committed by Mikhail Iudin
parent d5244cf6e3
commit e743e34849
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0
33 changed files with 5022 additions and 4198 deletions

View File

@ -13,27 +13,24 @@ endif
export PATH=$(GOPATH)/bin:$(shell echo $$PATH) export PATH=$(GOPATH)/bin:$(shell echo $$PATH)
# TODO: folders were changed, so we should update Makefile and protos generation # TODO: folders were changed, so we should update Makefile and protos generation
protos: proto:
@echo 'Generating protobuf packages (Go)...' @echo 'Generating protobuf packages (Go)...'
# Uncomment if needed # Uncomment if needed
@$(eval ROOT_PKG := pkg) @$(eval ROOT_PKG := pkg)
@$(eval GOGO_START := GOGO_NO_UNDERSCORE=1 GOGO_EXPORT_ONEOF_INTERFACE=1) @$(eval GOGO_START := GOGO_NO_UNDERSCORE=1 GOGO_EXPORT_ONEOF_INTERFACE=1)
@$(eval P_TREE_STORAGE_PATH_PB := $(ROOT_PKG)/acl/treestorage/treepb)
@$(eval P_ACL_CHANGES_PATH_PB := $(ROOT_PKG)/acl/aclchanges/aclpb) @$(eval P_ACL_CHANGES_PATH_PB := $(ROOT_PKG)/acl/aclchanges/aclpb)
@$(eval P_PLAINTEXT_CHANGES_PATH_PB := $(ROOT_PKG)/acl/testutils/testchanges/testchangepb)
@$(eval P_SYNC_CHANGES_PATH_PB := syncproto) @$(eval P_SYNC_CHANGES_PATH_PB := syncproto)
@$(eval P_TEST_CHANGES_PATH_PB := $(ROOT_PKG)/acl/testutils/testchanges)
@$(eval P_TIMESTAMP := Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types) @$(eval P_TIMESTAMP := Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types)
@$(eval P_STRUCT := Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types) @$(eval P_STRUCT := Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types)
@$(eval P_ACL_CHANGES := M$(P_ACL_CHANGES_PATH_PB)/protos/aclchanges.proto=github.com/anytypeio/go-anytype-infrastructure-experiments/$(P_ACL_CHANGES_PATH_PB)) @$(eval P_ACL_CHANGES := M$(P_ACL_CHANGES_PATH_PB)/protos/aclchanges.proto=github.com/anytypeio/go-anytype-infrastructure-experiments/$(P_ACL_CHANGES_PATH_PB))
@$(eval P_TREE_CHANGES := M$(P_TREE_STORAGE_PATH_PB)/protos/tree.proto=github.com/anytypeio/go-anytype-infrastructure-experiments/$(P_TREE_STORAGE_PATH_PB))
# use if needed $(eval PKGMAP := $$(P_TIMESTAMP),$$(P_STRUCT)) # use if needed $(eval PKGMAP := $$(P_TIMESTAMP),$$(P_STRUCT))
$(GOGO_START) protoc --gogofaster_out=:. $(P_ACL_CHANGES_PATH_PB)/protos/*.proto; mv $(P_ACL_CHANGES_PATH_PB)/protos/*.go $(P_ACL_CHANGES_PATH_PB) $(GOGO_START) protoc --gogofaster_out=:. $(P_ACL_CHANGES_PATH_PB)/protos/*.proto; mv $(P_ACL_CHANGES_PATH_PB)/protos/*.go $(P_ACL_CHANGES_PATH_PB)
$(GOGO_START) protoc --gogofaster_out=:. $(P_TREE_STORAGE_PATH_PB)/protos/*.proto; mv $(P_TREE_STORAGE_PATH_PB)/protos/*.go $(P_TREE_STORAGE_PATH_PB) $(GOGO_START) protoc --gogofaster_out=:. $(P_TEST_CHANGES_PATH_PB)/proto/*.proto
$(GOGO_START) protoc --gogofaster_out=:. $(P_PLAINTEXT_CHANGES_PATH_PB)/protos/*.proto; mv $(P_PLAINTEXT_CHANGES_PATH_PB)/protos/*.go $(P_PLAINTEXT_CHANGES_PATH_PB) $(eval PKGMAP := $$(P_ACL_CHANGES))
$(eval PKGMAP := $$(P_ACL_CHANGES),$$(P_TREE_CHANGES))
$(GOGO_START) protoc --gogofaster_out=$(PKGMAP):. $(P_SYNC_CHANGES_PATH_PB)/proto/*.proto $(GOGO_START) protoc --gogofaster_out=$(PKGMAP):. $(P_SYNC_CHANGES_PATH_PB)/proto/*.proto
protoc --gogofaster_out=$(PKGMAP):. --go-drpc_out=protolib=github.com/gogo/protobuf:. common/commonspace/spacesyncproto/protos/*.proto $(GOGO_START) protoc --gogofaster_out=$(PKGMAP):. common/commonspace/spacesyncproto/protos/*.proto
build: build:
@$(eval FLAGS := $$(shell govvv -flags -pkg github.com/anytypeio/go-anytype-infrastructure-experiments/app)) @$(eval FLAGS := $$(shell govvv -flags -pkg github.com/anytypeio/go-anytype-infrastructure-experiments/app))

View File

@ -1,16 +1,17 @@
syntax = "proto3"; syntax = "proto3";
package anySpace; package anySpace;
option go_package = "common/commonspace/spacesyncproto"; option go_package = "common/commonspace/spacesyncproto";
import "pkg/acl/aclchanges/aclpb/protos/aclchanges.proto";
enum ErrCodes { enum ErrCodes {
Unexpected = 0; Unexpected = 0;
} }
service Space { service Space {
// HeadSync compares all objects and their hashes in a space // HeadSync compares all objects and their hashes in a space
rpc HeadSync(HeadSyncRequest) returns (HeadSyncResponse); rpc HeadSync(HeadSyncRequest) returns (HeadSyncResponse);
rpc Stream( stream Msg) returns (stream Msg); rpc Stream(stream ObjectSyncMessage) returns (stream ObjectSyncMessage);
} }
// TODO: temporary mock message // TODO: temporary mock message
@ -18,8 +19,6 @@ message Msg {
string spaceId = 1; string spaceId = 1;
} }
// HeadSyncRange presenting a request for one range // HeadSyncRange presenting a request for one range
message HeadSyncRange { message HeadSyncRange {
uint64 from = 1; uint64 from = 1;
@ -50,3 +49,40 @@ message HeadSyncRequest {
message HeadSyncResponse { message HeadSyncResponse {
repeated HeadSyncResult results = 1; repeated HeadSyncResult results = 1;
} }
// ObjectSyncMessage is a message sent on object sync
message ObjectSyncMessage {
string spaceId = 1;
ObjectSyncContentValue content = 2;
acl.TreeHeader treeHeader = 3;
string treeId = 4;
}
// ObjectSyncContentValue provides different types for object sync
message ObjectSyncContentValue {
oneof value {
ObjectHeadUpdate headUpdate = 1;
ObjectFullSyncRequest fullSyncRequest = 2;
ObjectFullSyncResponse fullSyncResponse = 3;
}
}
// ObjectHeadUpdate is a message sent on document head update
message ObjectHeadUpdate {
repeated string heads = 1;
repeated acl.RawTreeChangeWithId changes = 2;
repeated string snapshotPath = 3;
}
// ObjectHeadUpdate is a message sent when document needs full sync
message ObjectFullSyncRequest {
repeated string heads = 1;
repeated string snapshotPath = 2;
}
// ObjectFullSyncResponse is a message sent as a response for a specific full sync
message ObjectFullSyncResponse {
repeated string heads = 1;
repeated acl.RawTreeChangeWithId changes = 2;
repeated string snapshotPath = 3;
}

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ import (
) )
type AccountData struct { // TODO: create a convenient constructor for this type AccountData struct { // TODO: create a convenient constructor for this
Identity string // TODO: this is essentially the same as sign key Identity []byte // TODO: this is essentially the same as sign key
SignKey signingkey.PrivKey SignKey signingkey.PrivKey
EncKey encryptionkey.PrivKey EncKey encryptionkey.PrivKey
Decoder keys.Decoder Decoder keys.Decoder

File diff suppressed because it is too large Load Diff

View File

@ -2,147 +2,142 @@ syntax = "proto3";
package acl; package acl;
option go_package = "aclpb"; option go_package = "aclpb";
message RawChange { // ACL protos
message RawACLRecord {
bytes payload = 1; bytes payload = 1;
bytes signature = 2; bytes signature = 2;
string id = 3; string id = 3; // this field is only used on user side for convenience, it should be empty when saving to db
} }
message RawRecord { message ACLContentValue {
bytes payload = 1;
bytes signature = 2;
string id = 3;
}
// the element of change tree used to store and internal apply smartBlock history
message ACLChange {
repeated string treeHeadIds = 1;
repeated string aclHeadIds = 2;
string snapshotBaseId = 3; // we will only have one base snapshot for both
ACLData aclData = 4;
// the data is encoded with read key and should be read in ChangesData format
bytes changesData = 5;
uint64 currentReadKeyHash = 6;
int64 timestamp = 7;
string identity = 8;
message ACLContentValue {
oneof value { oneof value {
UserAdd userAdd = 1; ACLUserAdd userAdd = 1;
UserRemove userRemove = 2; ACLUserRemove userRemove = 2;
UserPermissionChange userPermissionChange = 3; ACLUserPermissionChange userPermissionChange = 3;
UserInvite userInvite = 4; ACLUserInvite userInvite = 4;
UserJoin userJoin = 5; ACLUserJoin userJoin = 5;
UserConfirm userConfirm = 6; ACLUserConfirm userConfirm = 6;
}
} }
}
message ACLData { message ACLData {
ACLSnapshot aclSnapshot = 1; repeated ACLContentValue aclContent = 1;
repeated ACLContentValue aclContent = 2; }
}
message ACLSnapshot { message ACLState {
// We don't need ACLState as a separate message now, because we simplified the snapshot model
ACLState aclState = 1;
}
message ACLState {
repeated uint64 readKeyHashes = 1; repeated uint64 readKeyHashes = 1;
repeated UserState userStates = 2; repeated ACLUserState userStates = 2;
map<string, UserInvite> invites = 3; // TODO: later map<string, ACLUserInvite> invites = 3; // TODO: later
// repeated string unconfirmedUsers = 4; // TODO: later // repeated string unconfirmedUsers = 4; // TODO: later
} }
message UserState { message ACLUserState {
string identity = 1; bytes identity = 1;
bytes encryptionKey = 2; bytes encryptionKey = 2;
repeated bytes encryptedReadKeys = 3; // all read keys that we know repeated bytes encryptedReadKeys = 3; // all read keys that we know
UserPermissions permissions = 4; ACLUserPermissions permissions = 4;
bool IsConfirmed = 5; bool isConfirmed = 5;
} }
// we already know identity and encryptionKey // we already know identity and encryptionKey
message UserAdd { message ACLUserAdd {
string identity = 1; // public signing key bytes identity = 1; // public signing key
bytes encryptionKey = 2; // public encryption key bytes encryptionKey = 2; // public encryption key
repeated bytes encryptedReadKeys = 3; // all read keys that we know for the user repeated bytes encryptedReadKeys = 3; // all read keys that we know for the user
UserPermissions permissions = 4; ACLUserPermissions permissions = 4;
} }
// TODO: this is not used as of now // TODO: this is not used as of now
message UserConfirm { // not needed for read permissions message ACLUserConfirm { // not needed for read permissions
string identity = 1; // not needed bytes identity = 1; // not needed
string userAddId = 2; string userAddId = 2;
} }
message UserInvite { message ACLUserInvite {
bytes acceptPublicKey = 1; bytes acceptPublicKey = 1;
bytes encryptPublicKey = 2; bytes encryptPublicKey = 2;
repeated bytes encryptedReadKeys = 3; // all read keys that we know for the user repeated bytes encryptedReadKeys = 3; // all read keys that we know for the user
UserPermissions permissions = 4; ACLUserPermissions permissions = 4;
string InviteId = 5; string inviteId = 5;
} }
message UserJoin { message ACLUserJoin {
string identity = 1; bytes identity = 1;
bytes encryptionKey = 2; bytes encryptionKey = 2;
bytes acceptSignature = 3; // sign acceptPublicKey bytes acceptSignature = 3; // sign acceptPublicKey
string userInviteId = 4; string userInviteId = 4;
repeated bytes encryptedReadKeys = 5; // the idea is that user should itself reencrypt the keys with the pub key repeated bytes encryptedReadKeys = 5; // the idea is that user should itself reencrypt the keys with the pub key
} }
message UserRemove { message ACLUserRemove {
string identity = 1; bytes identity = 1;
repeated ReadKeyReplace readKeyReplaces = 3; // new read key encrypted for all users repeated ACLReadKeyReplace readKeyReplaces = 3; // new read key encrypted for all users
} }
message ReadKeyReplace { message ACLReadKeyReplace {
string identity = 1; bytes identity = 1;
bytes encryptionKey = 2; bytes encryptionKey = 2;
bytes encryptedReadKey = 3; bytes encryptedReadKey = 3;
} }
message UserPermissionChange { message ACLUserPermissionChange {
string identity = 1; bytes identity = 1;
UserPermissions permissions = 2; ACLUserPermissions permissions = 2;
} }
enum UserPermissions { enum ACLUserPermissions {
Admin = 0; Admin = 0;
Writer = 1; Writer = 1;
Reader = 2; Reader = 2;
Removed = 3; Removed = 3;
}
} }
message Change { message ACLRecord {
repeated string treeHeadIds = 1;
string aclHeadId = 2;
string snapshotBaseId = 3; // we will only have one base snapshot for both
bytes changesData = 4;
uint64 currentReadKeyHash = 5;
int64 timestamp = 6;
string identity = 7;
bool isSnapshot = 8;
}
message Record {
string prevId = 1; string prevId = 1;
string identity = 2; bytes identity = 2;
bytes data = 3; bytes data = 3;
uint64 currentReadKeyHash = 4; uint64 currentReadKeyHash = 4;
int64 timestamp = 5; int64 timestamp = 5;
} }
message Header { message ACLHeader {
string firstId = 1; string firstId = 1;
string aclListId = 2; bytes identity = 2; // the identity of the creator
string workspaceId = 3; }
DocType docType = 4;
// Tree protos
enum DocType {
ACL = 0; message RawTreeChange {
DocTree = 1; bytes payload = 1;
} bytes signature = 2;
}
message RawTreeChangeWithId {
bytes rawChange = 1;
string id = 2;
}
message TreeChange {
repeated string treeHeadIds = 1;
string aclHeadId = 2;
string snapshotBaseId = 3;
bytes changesData = 4;
uint64 currentReadKeyHash = 5;
int64 timestamp = 6;
bytes identity = 7;
bool isSnapshot = 8;
}
enum TreeHeaderType {
Object = 0;
Space = 1;
}
message TreeHeader {
string firstId = 1;
string aclId = 2;
TreeHeaderType treeHeaderType = 3;
bytes identity = 4;
bytes data = 5; // this should be reserved for the client to add the data it needs
} }

View File

@ -1,135 +1,190 @@
package acltree package list
import ( import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb" "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/keys"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/encryptionkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/encryptionkey"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/symmetric" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/symmetric"
"github.com/gogo/protobuf/proto"
"go.uber.org/zap"
"hash/fnv" "hash/fnv"
) )
var log = logger.NewNamed("acllist").Sugar()
var ErrNoSuchUser = errors.New("no such user") var ErrNoSuchUser = errors.New("no such user")
var ErrFailedToDecrypt = errors.New("failed to decrypt key") var ErrFailedToDecrypt = errors.New("failed to decrypt key")
var ErrUserRemoved = errors.New("user was removed from the document") var ErrUserRemoved = errors.New("user was removed from the document")
var ErrDocumentForbidden = errors.New("your user was forbidden access to the document") var ErrDocumentForbidden = errors.New("your user was forbidden access to the document")
var ErrUserAlreadyExists = errors.New("user already exists") var ErrUserAlreadyExists = errors.New("user already exists")
var ErrNoSuchRecord = errors.New("no such record")
var ErrInsufficientPermissions = errors.New("insufficient permissions")
var ErrNoReadKey = errors.New("acl state doesn't have a read key")
var ErrInvalidSignature = errors.New("signature is invalid")
type UserPermissionPair struct {
Identity string
Permission aclpb.ACLUserPermissions
}
type ACLState struct { type ACLState struct {
currentReadKeyHash uint64 currentReadKeyHash uint64
userReadKeys map[uint64]*symmetric.Key userReadKeys map[uint64]*symmetric.Key
userStates map[string]*aclpb.ACLChange_UserState userStates map[string]*aclpb.ACLUserState
userInvites map[string]*aclpb.ACLChange_UserInvite userInvites map[string]*aclpb.ACLUserInvite
signingPubKeyDecoder signingkey.PubKeyDecoder
signingPubKeyDecoder keys.Decoder
encryptionKey encryptionkey.PrivKey encryptionKey encryptionkey.PrivKey
identity string identity string
permissionsAtRecord map[string][]UserPermissionPair
keychain *common.Keychain
} }
func newACLState( func newACLStateWithIdentity(
identity string, identity string,
encryptionKey encryptionkey.PrivKey, encryptionKey encryptionkey.PrivKey,
signingPubKeyDecoder signingkey.PubKeyDecoder) *ACLState { decoder keys.Decoder) *ACLState {
return &ACLState{ return &ACLState{
identity: identity, identity: identity,
encryptionKey: encryptionKey, encryptionKey: encryptionKey,
userReadKeys: make(map[uint64]*symmetric.Key), userReadKeys: make(map[uint64]*symmetric.Key),
userStates: make(map[string]*aclpb.ACLChange_UserState), userStates: make(map[string]*aclpb.ACLUserState),
userInvites: make(map[string]*aclpb.ACLChange_UserInvite), userInvites: make(map[string]*aclpb.ACLUserInvite),
signingPubKeyDecoder: signingPubKeyDecoder, signingPubKeyDecoder: decoder,
permissionsAtRecord: make(map[string][]UserPermissionPair),
keychain: common.NewKeychain(),
} }
} }
func newACLStateFromSnapshotChange( func newACLState(decoder keys.Decoder) *ACLState {
snapshotChange *aclpb.ACLChange, return &ACLState{
identity string, signingPubKeyDecoder: decoder,
encryptionKey encryptionkey.PrivKey,
signingPubKeyDecoder signingkey.PubKeyDecoder) (*ACLState, error) {
st := &ACLState{
identity: identity,
encryptionKey: encryptionKey,
userReadKeys: make(map[uint64]*symmetric.Key), userReadKeys: make(map[uint64]*symmetric.Key),
userStates: make(map[string]*aclpb.ACLChange_UserState), userStates: make(map[string]*aclpb.ACLUserState),
userInvites: make(map[string]*aclpb.ACLChange_UserInvite), userInvites: make(map[string]*aclpb.ACLUserInvite),
signingPubKeyDecoder: signingPubKeyDecoder, permissionsAtRecord: make(map[string][]UserPermissionPair),
keychain: common.NewKeychain(),
} }
err := st.recreateFromSnapshotChange(snapshotChange)
if err != nil {
return nil, err
}
return st, nil
} }
func (st *ACLState) recreateFromSnapshotChange(snapshotChange *aclpb.ACLChange) error { func (st *ACLState) CurrentReadKeyHash() uint64 {
snapshot := snapshotChange.GetAclData().GetAclSnapshot() return st.currentReadKeyHash
if snapshot == nil { }
return fmt.Errorf("could not create state from snapshot, because it is nil")
}
state := snapshot.AclState
for _, userState := range state.UserStates {
st.userStates[userState.Identity] = userState
}
userState, exists := st.userStates[st.identity] func (st *ACLState) CurrentReadKey() (*symmetric.Key, error) {
key, exists := st.userReadKeys[st.currentReadKeyHash]
if !exists { if !exists {
return ErrNoSuchUser return nil, ErrNoReadKey
} }
for _, key := range userState.EncryptedReadKeys { return key, nil
key, hash, err := st.decryptReadKeyAndHash(key) }
if err != nil {
return ErrFailedToDecrypt func (st *ACLState) UserReadKeys() map[uint64]*symmetric.Key {
return st.userReadKeys
}
func (st *ACLState) PermissionsAtRecord(id string, identity string) (UserPermissionPair, error) {
permissions, ok := st.permissionsAtRecord[id]
if !ok {
log.Errorf("missing record at id %s", id)
return UserPermissionPair{}, ErrNoSuchRecord
} }
st.userReadKeys[hash] = key for _, perm := range permissions {
if perm.Identity == identity {
return perm, nil
} }
st.currentReadKeyHash = snapshotChange.CurrentReadKeyHash
if snapshot.GetAclState().GetInvites() != nil {
st.userInvites = snapshot.GetAclState().GetInvites()
} }
return UserPermissionPair{}, ErrNoSuchUser
}
func (st *ACLState) applyRecord(record *aclpb.ACLRecord) (err error) {
aclData := &aclpb.ACLData{}
err = proto.Unmarshal(record.Data, aclData)
if err != nil {
return
}
err = st.applyChangeData(aclData, record.CurrentReadKeyHash, record.Identity)
if err != nil {
return
}
st.currentReadKeyHash = record.CurrentReadKeyHash
return
}
func (st *ACLState) applyChangeAndUpdate(recordWrapper *ACLRecord) (err error) {
var (
change = recordWrapper.Content
aclData = &aclpb.ACLData{}
)
if recordWrapper.Model != nil {
aclData = recordWrapper.Model.(*aclpb.ACLData)
} else {
err = proto.Unmarshal(change.Data, aclData)
if err != nil {
return
}
recordWrapper.Model = aclData
}
err = st.applyChangeData(aclData, recordWrapper.Content.CurrentReadKeyHash, recordWrapper.Content.Identity)
if err != nil {
return
}
// getting all permissions for users at record
var permissions []UserPermissionPair
for _, state := range st.userStates {
permission := UserPermissionPair{
Identity: string(state.Identity),
Permission: state.Permissions,
}
permissions = append(permissions, permission)
}
st.permissionsAtRecord[recordWrapper.Id] = permissions
return nil return nil
} }
func (st *ACLState) makeSnapshot() *aclpb.ACLChange_ACLSnapshot { func (st *ACLState) applyChangeData(changeData *aclpb.ACLData, hash uint64, identity []byte) (err error) {
var userStates []*aclpb.ACLChange_UserState
for _, st := range st.userStates {
userStates = append(userStates, st)
}
return &aclpb.ACLChange_ACLSnapshot{AclState: &aclpb.ACLChange_ACLState{
ReadKeyHashes: nil,
UserStates: userStates, // TODO: make states and invites in same format
Invites: st.userInvites,
}}
}
func (st *ACLState) applyChange(change *aclpb.ACLChange) (err error) {
defer func() { defer func() {
if err != nil { if err != nil {
return return
} }
st.currentReadKeyHash = change.CurrentReadKeyHash st.currentReadKeyHash = hash
}() }()
// we can't check this for the user which is joining, because it will not be in our list // we can't check this for the user which is joining, because it will not be in our list
// the same is for the first change to be added // the same is for the first change to be added
skipIdentityCheck := st.isUserJoin(change) || (st.currentReadKeyHash == 0 && st.isUserAdd(change)) skipIdentityCheck := st.isUserJoin(changeData) || (st.currentReadKeyHash == 0 && st.isUserAdd(changeData, identity))
if !skipIdentityCheck { if !skipIdentityCheck {
// we check signature when we add this to the Tree, so no need to do it here // we check signature when we add this to the Tree, so no need to do it here
if _, exists := st.userStates[change.Identity]; !exists { if _, exists := st.userStates[string(identity)]; !exists {
err = ErrNoSuchUser err = ErrNoSuchUser
return return
} }
if !st.hasPermission(change.Identity, aclpb.ACLChange_Admin) { if !st.hasPermission(identity, aclpb.ACLUserPermissions_Admin) {
err = fmt.Errorf("user %s must have admin permissions", change.Identity) err = fmt.Errorf("user %s must have admin permissions", identity)
return return
} }
} }
for _, ch := range change.GetAclData().GetAclContent() { for _, ch := range changeData.GetAclContent() {
if err = st.applyChangeContent(ch); err != nil { if err = st.applyChangeContent(ch); err != nil {
//log.Infof("error while applying changes: %v; ignore", err) log.Info("error while applying changes: %v; ignore", zap.Error(err))
return err return err
} }
} }
@ -137,8 +192,7 @@ func (st *ACLState) applyChange(change *aclpb.ACLChange) (err error) {
return nil return nil
} }
// TODO: remove changeId, because it is not needed func (st *ACLState) applyChangeContent(ch *aclpb.ACLContentValue) error {
func (st *ACLState) applyChangeContent(ch *aclpb.ACLChange_ACLContentValue) error {
switch { switch {
case ch.GetUserPermissionChange() != nil: case ch.GetUserPermissionChange() != nil:
return st.applyUserPermissionChange(ch.GetUserPermissionChange()) return st.applyUserPermissionChange(ch.GetUserPermissionChange())
@ -157,27 +211,29 @@ func (st *ACLState) applyChangeContent(ch *aclpb.ACLChange_ACLContentValue) erro
} }
} }
func (st *ACLState) applyUserPermissionChange(ch *aclpb.ACLChange_UserPermissionChange) error { func (st *ACLState) applyUserPermissionChange(ch *aclpb.ACLUserPermissionChange) error {
if _, exists := st.userStates[ch.Identity]; !exists { chIdentity := string(ch.Identity)
if _, exists := st.userStates[chIdentity]; !exists {
return ErrNoSuchUser return ErrNoSuchUser
} }
st.userStates[ch.Identity].Permissions = ch.Permissions st.userStates[chIdentity].Permissions = ch.Permissions
return nil return nil
} }
func (st *ACLState) applyUserInvite(ch *aclpb.ACLChange_UserInvite) error { func (st *ACLState) applyUserInvite(ch *aclpb.ACLUserInvite) error {
st.userInvites[ch.InviteId] = ch st.userInvites[ch.InviteId] = ch
return nil return nil
} }
func (st *ACLState) applyUserJoin(ch *aclpb.ACLChange_UserJoin) error { func (st *ACLState) applyUserJoin(ch *aclpb.ACLUserJoin) error {
invite, exists := st.userInvites[ch.UserInviteId] invite, exists := st.userInvites[ch.UserInviteId]
if !exists { if !exists {
return fmt.Errorf("no such invite with id %s", ch.UserInviteId) return fmt.Errorf("no such invite with id %s", ch.UserInviteId)
} }
chIdentity := string(ch.Identity)
if _, exists = st.userStates[ch.Identity]; exists { if _, exists = st.userStates[chIdentity]; exists {
return ErrUserAlreadyExists return ErrUserAlreadyExists
} }
@ -188,21 +244,16 @@ func (st *ACLState) applyUserJoin(ch *aclpb.ACLChange_UserJoin) error {
return fmt.Errorf("public key verifying invite accepts is given in incorrect format: %v", err) return fmt.Errorf("public key verifying invite accepts is given in incorrect format: %v", err)
} }
rawSignedId, err := st.signingPubKeyDecoder.DecodeFromStringIntoBytes(ch.Identity) res, err := verificationKey.(signingkey.PubKey).Verify(ch.Identity, signature)
if err != nil {
return fmt.Errorf("failed to decode signing identity as bytes")
}
res, err := verificationKey.Verify(rawSignedId, signature)
if err != nil { if err != nil {
return fmt.Errorf("verification returned error: %w", err) return fmt.Errorf("verification returned error: %w", err)
} }
if !res { if !res {
return fmt.Errorf("signature is invalid") return ErrInvalidSignature
} }
// if ourselves -> we need to decrypt the read keys // if ourselves -> we need to decrypt the read keys
if st.identity == ch.Identity { if st.identity == chIdentity {
for _, key := range ch.EncryptedReadKeys { for _, key := range ch.EncryptedReadKeys {
key, hash, err := st.decryptReadKeyAndHash(key) key, hash, err := st.decryptReadKeyAndHash(key)
if err != nil { if err != nil {
@ -214,30 +265,31 @@ func (st *ACLState) applyUserJoin(ch *aclpb.ACLChange_UserJoin) error {
} }
// adding user to the list // adding user to the list
userState := &aclpb.ACLChange_UserState{ userState := &aclpb.ACLUserState{
Identity: ch.Identity, Identity: ch.Identity,
EncryptionKey: ch.EncryptionKey, EncryptionKey: ch.EncryptionKey,
EncryptedReadKeys: ch.EncryptedReadKeys, EncryptedReadKeys: ch.EncryptedReadKeys,
Permissions: invite.Permissions, Permissions: invite.Permissions,
IsConfirmed: true, IsConfirmed: true,
} }
st.userStates[ch.Identity] = userState st.userStates[chIdentity] = userState
return nil return nil
} }
func (st *ACLState) applyUserAdd(ch *aclpb.ACLChange_UserAdd) error { func (st *ACLState) applyUserAdd(ch *aclpb.ACLUserAdd) error {
if _, exists := st.userStates[ch.Identity]; exists { chIdentity := string(ch.Identity)
if _, exists := st.userStates[chIdentity]; exists {
return ErrUserAlreadyExists return ErrUserAlreadyExists
} }
st.userStates[ch.Identity] = &aclpb.ACLChange_UserState{ st.userStates[chIdentity] = &aclpb.ACLUserState{
Identity: ch.Identity, Identity: ch.Identity,
EncryptionKey: ch.EncryptionKey, EncryptionKey: ch.EncryptionKey,
Permissions: ch.Permissions, Permissions: ch.Permissions,
EncryptedReadKeys: ch.EncryptedReadKeys, EncryptedReadKeys: ch.EncryptedReadKeys,
} }
if ch.Identity == st.identity { if chIdentity == st.identity {
for _, key := range ch.EncryptedReadKeys { for _, key := range ch.EncryptedReadKeys {
key, hash, err := st.decryptReadKeyAndHash(key) key, hash, err := st.decryptReadKeyAndHash(key)
if err != nil { if err != nil {
@ -251,26 +303,28 @@ func (st *ACLState) applyUserAdd(ch *aclpb.ACLChange_UserAdd) error {
return nil return nil
} }
func (st *ACLState) applyUserRemove(ch *aclpb.ACLChange_UserRemove) error { func (st *ACLState) applyUserRemove(ch *aclpb.ACLUserRemove) error {
if ch.Identity == st.identity { chIdentity := string(ch.Identity)
if chIdentity == st.identity {
return ErrDocumentForbidden return ErrDocumentForbidden
} }
if _, exists := st.userStates[ch.Identity]; !exists { if _, exists := st.userStates[chIdentity]; !exists {
return ErrNoSuchUser return ErrNoSuchUser
} }
delete(st.userStates, ch.Identity) delete(st.userStates, chIdentity)
for _, replace := range ch.ReadKeyReplaces { for _, replace := range ch.ReadKeyReplaces {
userState, exists := st.userStates[replace.Identity] repIdentity := string(replace.Identity)
userState, exists := st.userStates[repIdentity]
if !exists { if !exists {
continue continue
} }
userState.EncryptedReadKeys = append(userState.EncryptedReadKeys, replace.EncryptedReadKey) userState.EncryptedReadKeys = append(userState.EncryptedReadKeys, replace.EncryptedReadKey)
// if this is our identity then we have to decrypt the key // if this is our identity then we have to decrypt the key
if replace.Identity == st.identity { if repIdentity == st.identity {
key, hash, err := st.decryptReadKeyAndHash(replace.EncryptedReadKey) key, hash, err := st.decryptReadKeyAndHash(replace.EncryptedReadKey)
if err != nil { if err != nil {
return ErrFailedToDecrypt return ErrFailedToDecrypt
@ -283,12 +337,13 @@ func (st *ACLState) applyUserRemove(ch *aclpb.ACLChange_UserRemove) error {
return nil return nil
} }
func (st *ACLState) applyUserConfirm(ch *aclpb.ACLChange_UserConfirm) error { func (st *ACLState) applyUserConfirm(ch *aclpb.ACLUserConfirm) error {
if _, exists := st.userStates[ch.Identity]; !exists { chIdentity := string(ch.Identity)
if _, exists := st.userStates[chIdentity]; !exists {
return ErrNoSuchUser return ErrNoSuchUser
} }
userState := st.userStates[ch.Identity] userState := st.userStates[chIdentity]
userState.IsConfirmed = true userState.IsConfirmed = true
return nil return nil
} }
@ -309,8 +364,8 @@ func (st *ACLState) decryptReadKeyAndHash(msg []byte) (*symmetric.Key, uint64, e
return key, hasher.Sum64(), nil return key, hasher.Sum64(), nil
} }
func (st *ACLState) hasPermission(identity string, permission aclpb.ACLChange_UserPermissions) bool { func (st *ACLState) hasPermission(identity []byte, permission aclpb.ACLUserPermissions) bool {
state, exists := st.userStates[identity] state, exists := st.userStates[string(identity)]
if !exists { if !exists {
return false return false
} }
@ -318,94 +373,17 @@ func (st *ACLState) hasPermission(identity string, permission aclpb.ACLChange_Us
return state.Permissions == permission return state.Permissions == permission
} }
func (st *ACLState) isUserJoin(ch *aclpb.ACLChange) bool { func (st *ACLState) isUserJoin(data *aclpb.ACLData) bool {
// if we have a UserJoin, then it should always be the first one applied // if we have a UserJoin, then it should always be the first one applied
return ch.AclData.GetAclContent() != nil && ch.AclData.GetAclContent()[0].GetUserJoin() != nil return data.GetAclContent() != nil && data.GetAclContent()[0].GetUserJoin() != nil
} }
func (st *ACLState) isUserAdd(ch *aclpb.ACLChange) bool { func (st *ACLState) isUserAdd(data *aclpb.ACLData, identity []byte) bool {
// if we have a UserAdd, then it should always be the first one applied // if we have a UserAdd, then it should always be the first one applied
userAdd := ch.AclData.GetAclContent()[0].GetUserAdd() userAdd := data.GetAclContent()[0].GetUserAdd()
return ch.AclData.GetAclContent() != nil && userAdd != nil && userAdd.GetIdentity() == ch.Identity return data.GetAclContent() != nil && userAdd != nil && bytes.Compare(userAdd.GetIdentity(), identity) == 0
} }
func (st *ACLState) getPermissionDecreasedUsers(ch *aclpb.ACLChange) (identities []*aclpb.ACLChange_UserPermissionChange) { func (st *ACLState) GetUserStates() map[string]*aclpb.ACLUserState {
// this should be called after general checks are completed
if ch.GetAclData().GetAclContent() == nil {
return nil
}
contents := ch.GetAclData().GetAclContent()
for _, c := range contents {
if c.GetUserPermissionChange() != nil {
content := c.GetUserPermissionChange()
currentState := st.userStates[content.Identity]
// the comparison works in different direction :-)
if content.Permissions > currentState.Permissions {
identities = append(identities, &aclpb.ACLChange_UserPermissionChange{
Identity: content.Identity,
Permissions: content.Permissions,
})
}
}
if c.GetUserRemove() != nil {
content := c.GetUserRemove()
identities = append(identities, &aclpb.ACLChange_UserPermissionChange{
Identity: content.Identity,
Permissions: aclpb.ACLChange_Removed,
})
}
}
return identities
}
func (st *ACLState) equal(other *ACLState) bool {
if st == nil && other == nil {
return true
}
if st == nil || other == nil {
return false
}
if st.currentReadKeyHash != other.currentReadKeyHash {
return false
}
if st.identity != other.identity {
return false
}
if len(st.userStates) != len(other.userStates) {
return false
}
for _, st := range st.userStates {
otherSt, exists := other.userStates[st.Identity]
if !exists {
return false
}
if st.Permissions != otherSt.Permissions {
return false
}
if bytes.Compare(st.EncryptionKey, otherSt.EncryptionKey) != 0 {
return false
}
}
if len(st.userInvites) != len(other.userInvites) {
return false
}
// TODO: add detailed user invites comparison + compare other stuff
return true
}
func (st *ACLState) GetUserStates() map[string]*aclpb.ACLChange_UserState {
// TODO: we should provide better API that would not allow to change this map from the outside
return st.userStates return st.userStates
} }

View File

@ -15,7 +15,7 @@ type aclStateBuilder struct {
func newACLStateBuilderWithIdentity(decoder keys.Decoder, accountData *account.AccountData) *aclStateBuilder { func newACLStateBuilderWithIdentity(decoder keys.Decoder, accountData *account.AccountData) *aclStateBuilder {
return &aclStateBuilder{ return &aclStateBuilder{
decoder: decoder, decoder: decoder,
identity: accountData.Identity, identity: string(accountData.Identity),
key: accountData.EncKey, key: accountData.EncKey,
} }
} }
@ -26,7 +26,7 @@ func newACLStateBuilder(decoder keys.Decoder) *aclStateBuilder {
} }
} }
func (sb *aclStateBuilder) Build(records []*Record) (*ACLState, error) { func (sb *aclStateBuilder) Build(records []*ACLRecord) (*ACLState, error) {
var ( var (
err error err error
state *ACLState state *ACLState

View File

@ -1,4 +1,4 @@
package acltree package list
import ( import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/account" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/account"
@ -14,39 +14,31 @@ import (
type MarshalledChange = []byte type MarshalledChange = []byte
type ACLChangeBuilder interface { type ACLChangeBuilder interface {
UserAdd(identity string, encryptionKey encryptionkey.PubKey, permissions aclpb.ACLChange_UserPermissions) error UserAdd(identity string, encryptionKey encryptionkey.PubKey, permissions aclpb.ACLUserPermissions) error
AddId(id string) // TODO: this is only for testing AddId(id string) // TODO: this is only for testing
SetMakeSnapshot(bool) // TODO: who should decide this? probably ACLTree so we can delete it
} }
type ChangeBuilder interface { type aclChangeBuilder struct {
ACLChangeBuilder
AddChangeContent(marshaler proto.Marshaler) // user code should be responsible for making regular snapshots
}
type changeBuilder struct {
aclState *ACLState aclState *ACLState
tree *Tree list ACLList
acc *account.AccountData acc *account.AccountData
aclData *aclpb.ACLChange_ACLData aclData *aclpb.ACLData
changeContent proto.Marshaler
id string id string
makeSnapshot bool
readKey *symmetric.Key readKey *symmetric.Key
readKeyHash uint64 readKeyHash uint64
} }
func newChangeBuilder() *changeBuilder { func newACLChangeBuilder() *aclChangeBuilder {
return &changeBuilder{} return &aclChangeBuilder{}
} }
func (c *changeBuilder) Init(state *ACLState, tree *Tree, acc *account.AccountData) { func (c *aclChangeBuilder) Init(state *ACLState, list ACLList, acc *account.AccountData) {
c.aclState = state c.aclState = state
c.tree = tree c.list = list
c.acc = acc c.acc = acc
c.aclData = &aclpb.ACLChange_ACLData{} c.aclData = &aclpb.ACLData{}
// setting read key for further encryption etc // setting read key for further encryption etc
if state.currentReadKeyHash == 0 { if state.currentReadKeyHash == 0 {
c.readKey, _ = symmetric.NewRandom() c.readKey, _ = symmetric.NewRandom()
@ -60,15 +52,11 @@ func (c *changeBuilder) Init(state *ACLState, tree *Tree, acc *account.AccountDa
} }
} }
func (c *changeBuilder) AddId(id string) { func (c *aclChangeBuilder) AddId(id string) {
c.id = id c.id = id
} }
func (c *changeBuilder) SetMakeSnapshot(b bool) { func (c *aclChangeBuilder) UserAdd(identity string, encryptionKey encryptionkey.PubKey, permissions aclpb.ACLUserPermissions) error {
c.makeSnapshot = b
}
func (c *changeBuilder) UserAdd(identity string, encryptionKey encryptionkey.PubKey, permissions aclpb.ACLChange_UserPermissions) error {
var allKeys []*symmetric.Key var allKeys []*symmetric.Key
if c.aclState.currentReadKeyHash != 0 { if c.aclState.currentReadKeyHash != 0 {
for _, key := range c.aclState.userReadKeys { for _, key := range c.aclState.userReadKeys {
@ -91,10 +79,10 @@ func (c *changeBuilder) UserAdd(identity string, encryptionKey encryptionkey.Pub
if err != nil { if err != nil {
return err return err
} }
ch := &aclpb.ACLChange_ACLContentValue{ ch := &aclpb.ACLContentValue{
Value: &aclpb.ACLChange_ACLContent_Value_UserAdd{ Value: &aclpb.ACLContentValue_UserAdd{
UserAdd: &aclpb.ACLChange_UserAdd{ UserAdd: &aclpb.ACLUserAdd{
Identity: identity, Identity: []byte(identity),
EncryptionKey: rawKey, EncryptionKey: rawKey,
EncryptedReadKeys: encryptedKeys, EncryptedReadKeys: encryptedKeys,
Permissions: permissions, Permissions: permissions,
@ -105,41 +93,25 @@ func (c *changeBuilder) UserAdd(identity string, encryptionKey encryptionkey.Pub
return nil return nil
} }
func (c *changeBuilder) BuildAndApply() (*Change, []byte, error) { func (c *aclChangeBuilder) BuildAndApply() (*ACLRecord, []byte, error) {
aclChange := &aclpb.ACLChange{ aclRecord := &aclpb.ACLRecord{
TreeHeadIds: c.tree.Heads(), PrevId: c.list.Head().Id,
AclHeadIds: c.tree.ACLHeads(),
SnapshotBaseId: c.tree.RootId(),
AclData: c.aclData,
CurrentReadKeyHash: c.readKeyHash, CurrentReadKeyHash: c.readKeyHash,
Timestamp: int64(time.Now().Nanosecond()), Timestamp: int64(time.Now().Nanosecond()),
Identity: c.acc.Identity, Identity: c.acc.Identity,
} }
err := c.aclState.applyChange(aclChange)
marshalledData, err := proto.Marshal(c.aclData)
if err != nil {
return nil, nil, err
}
aclRecord.Data = marshalledData
err = c.aclState.applyRecord(aclRecord)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if c.makeSnapshot { fullMarshalledChange, err := proto.Marshal(aclRecord)
c.aclData.AclSnapshot = c.aclState.makeSnapshot()
}
var marshalled []byte
if c.changeContent != nil {
marshalled, err = c.changeContent.Marshal()
if err != nil {
return nil, nil, err
}
encrypted, err := c.aclState.userReadKeys[c.aclState.currentReadKeyHash].
Encrypt(marshalled)
if err != nil {
return nil, nil, err
}
aclChange.ChangesData = encrypted
}
fullMarshalledChange, err := proto.Marshal(aclChange)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -151,13 +123,9 @@ func (c *changeBuilder) BuildAndApply() (*Change, []byte, error) {
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
ch := NewChange(id, aclChange) ch := NewRecord(id, aclRecord)
ch.DecryptedDocumentChange = marshalled ch.Model = c.aclData
ch.Sign = signature ch.Sign = signature
return ch, fullMarshalledChange, nil return ch, fullMarshalledChange, nil
} }
func (c *changeBuilder) AddChangeContent(marshaler proto.Marshaler) {
c.changeContent = marshaler
}

View File

@ -13,7 +13,7 @@ import (
"sync" "sync"
) )
type IterFunc = func(record *Record) (IsContinue bool) type IterFunc = func(record *ACLRecord) (IsContinue bool)
var ErrIncorrectCID = errors.New("incorrect CID") var ErrIncorrectCID = errors.New("incorrect CID")
@ -26,20 +26,20 @@ type RWLocker interface {
type ACLList interface { type ACLList interface {
RWLocker RWLocker
ID() string ID() string
Header() *aclpb.Header Header() *aclpb.ACLHeader
Records() []*Record Records() []*ACLRecord
ACLState() *ACLState ACLState() *ACLState
IsAfter(first string, second string) (bool, error) IsAfter(first string, second string) (bool, error)
Head() *Record Head() *ACLRecord
Get(id string) (*Record, error) Get(id string) (*ACLRecord, error)
Iterate(iterFunc IterFunc) Iterate(iterFunc IterFunc)
IterateFrom(startId string, iterFunc IterFunc) IterateFrom(startId string, iterFunc IterFunc)
Close() (err error) Close() (err error)
} }
type aclList struct { type aclList struct {
header *aclpb.Header header *aclpb.ACLHeader
records []*Record records []*ACLRecord
indexes map[string]int indexes map[string]int
id string id string
@ -84,7 +84,7 @@ func buildWithACLStateBuilder(builder *aclStateBuilder, storage storage.ListStor
if err != nil { if err != nil {
return return
} }
records := []*Record{record} records := []*ACLRecord{record}
for record.Content.PrevId != "" { for record.Content.PrevId != "" {
rawRecord, err = storage.GetRawRecord(context.Background(), record.Content.PrevId) rawRecord, err = storage.GetRawRecord(context.Background(), record.Content.PrevId)
@ -131,7 +131,7 @@ func buildWithACLStateBuilder(builder *aclStateBuilder, storage storage.ListStor
return return
} }
func (a *aclList) Records() []*Record { func (a *aclList) Records() []*ACLRecord {
return a.records return a.records
} }
@ -139,7 +139,7 @@ func (a *aclList) ID() string {
return a.id return a.id
} }
func (a *aclList) Header() *aclpb.Header { func (a *aclList) Header() *aclpb.ACLHeader {
return a.header return a.header
} }
@ -156,11 +156,11 @@ func (a *aclList) IsAfter(first string, second string) (bool, error) {
return firstRec >= secondRec, nil return firstRec >= secondRec, nil
} }
func (a *aclList) Head() *Record { func (a *aclList) Head() *ACLRecord {
return a.records[len(a.records)-1] return a.records[len(a.records)-1]
} }
func (a *aclList) Get(id string) (*Record, error) { func (a *aclList) Get(id string) (*ACLRecord, error) {
recIdx, ok := a.indexes[id] recIdx, ok := a.indexes[id]
if !ok { if !ok {
return nil, fmt.Errorf("no such record") return nil, fmt.Errorf("no such record")
@ -192,8 +192,8 @@ func (a *aclList) Close() (err error) {
return nil return nil
} }
func verifyRecord(keychain *common.Keychain, rawRecord *aclpb.RawRecord, record *Record) (err error) { func verifyRecord(keychain *common.Keychain, rawRecord *aclpb.RawACLRecord, record *ACLRecord) (err error) {
identityKey, err := keychain.GetOrAdd(record.Content.Identity) identityKey, err := keychain.GetOrAdd(record.Identity)
if err != nil { if err != nil {
return return
} }

View File

@ -28,8 +28,8 @@ func TestAclList_ACLState_UserInviteAndJoin(t *testing.T) {
assert.Equal(t, aclpb.ACLChange_Reader, aclList.ACLState().GetUserStates()[idC].Permissions) assert.Equal(t, aclpb.ACLChange_Reader, aclList.ACLState().GetUserStates()[idC].Permissions)
assert.Equal(t, aclList.Head().Content.CurrentReadKeyHash, aclList.ACLState().CurrentReadKeyHash()) assert.Equal(t, aclList.Head().Content.CurrentReadKeyHash, aclList.ACLState().CurrentReadKeyHash())
var records []*Record var records []*ACLRecord
aclList.Iterate(func(record *Record) (IsContinue bool) { aclList.Iterate(func(record *ACLRecord) (IsContinue bool) {
records = append(records, record) records = append(records, record)
return true return true
}) })
@ -69,8 +69,8 @@ func TestAclList_ACLState_UserJoinAndRemove(t *testing.T) {
_, exists := aclList.ACLState().GetUserStates()[idB] _, exists := aclList.ACLState().GetUserStates()[idB]
assert.Equal(t, false, exists) assert.Equal(t, false, exists)
var records []*Record var records []*ACLRecord
aclList.Iterate(func(record *Record) (IsContinue bool) { aclList.Iterate(func(record *ACLRecord) (IsContinue bool) {
records = append(records, record) records = append(records, record)
return true return true
}) })

View File

@ -5,30 +5,33 @@ import (
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
) )
type Record struct { type ACLRecord struct {
Id string Id string
Content *aclpb.Record Content *aclpb.ACLRecord
Identity string
Model interface{} Model interface{}
Sign []byte Sign []byte
} }
func NewRecord(id string, aclRecord *aclpb.Record) *Record { func NewRecord(id string, aclRecord *aclpb.ACLRecord) *ACLRecord {
return &Record{ return &ACLRecord{
Id: id, Id: id,
Content: aclRecord, Content: aclRecord,
Identity: string(aclRecord.Identity),
} }
} }
func NewFromRawRecord(rawRec *aclpb.RawRecord) (*Record, error) { func NewFromRawRecord(rawRec *aclpb.RawACLRecord) (*ACLRecord, error) {
aclRec := &aclpb.Record{} aclRec := &aclpb.ACLRecord{}
err := proto.Unmarshal(rawRec.Payload, aclRec) err := proto.Unmarshal(rawRec.Payload, aclRec)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Record{ return &ACLRecord{
Id: rawRec.Id, Id: rawRec.Id,
Content: aclRec, Content: aclRec,
Sign: rawRec.Signature, Sign: rawRec.Signature,
Identity: string(aclRec.Identity),
}, nil }, nil
} }

View File

@ -8,8 +8,8 @@ import (
) )
type inMemoryACLListStorage struct { type inMemoryACLListStorage struct {
header *aclpb.Header header *aclpb.ACLHeader
records []*aclpb.RawRecord records []*aclpb.RawACLRecord
id string id string
@ -18,8 +18,8 @@ type inMemoryACLListStorage struct {
func NewInMemoryACLListStorage( func NewInMemoryACLListStorage(
id string, id string,
header *aclpb.Header, header *aclpb.ACLHeader,
records []*aclpb.RawRecord) (ListStorage, error) { records []*aclpb.RawACLRecord) (ListStorage, error) {
return &inMemoryACLListStorage{ return &inMemoryACLListStorage{
id: id, id: id,
header: header, header: header,
@ -28,19 +28,19 @@ func NewInMemoryACLListStorage(
}, nil }, nil
} }
func (i *inMemoryACLListStorage) Header() (*aclpb.Header, error) { func (i *inMemoryACLListStorage) Header() (*aclpb.ACLHeader, error) {
i.RLock() i.RLock()
defer i.RUnlock() defer i.RUnlock()
return i.header, nil return i.header, nil
} }
func (i *inMemoryACLListStorage) Head() (*aclpb.RawRecord, error) { func (i *inMemoryACLListStorage) Head() (*aclpb.RawACLRecord, error) {
i.RLock() i.RLock()
defer i.RUnlock() defer i.RUnlock()
return i.records[len(i.records)-1], nil return i.records[len(i.records)-1], nil
} }
func (i *inMemoryACLListStorage) GetRawRecord(ctx context.Context, id string) (*aclpb.RawRecord, error) { func (i *inMemoryACLListStorage) GetRawRecord(ctx context.Context, id string) (*aclpb.RawACLRecord, error) {
i.RLock() i.RLock()
defer i.RUnlock() defer i.RUnlock()
for _, rec := range i.records { for _, rec := range i.records {
@ -51,7 +51,7 @@ func (i *inMemoryACLListStorage) GetRawRecord(ctx context.Context, id string) (*
return nil, fmt.Errorf("no such record") return nil, fmt.Errorf("no such record")
} }
func (i *inMemoryACLListStorage) AddRawRecord(ctx context.Context, rec *aclpb.RawRecord) error { func (i *inMemoryACLListStorage) AddRawRecord(ctx context.Context, rec *aclpb.RawACLRecord) error {
panic("implement me") panic("implement me")
} }
@ -63,19 +63,19 @@ func (i *inMemoryACLListStorage) ID() (string, error) {
type inMemoryTreeStorage struct { type inMemoryTreeStorage struct {
id string id string
header *aclpb.Header header *aclpb.TreeHeader
heads []string heads []string
changes map[string]*aclpb.RawChange changes map[string]*aclpb.RawTreeChangeWithId
sync.RWMutex sync.RWMutex
} }
func NewInMemoryTreeStorage( func NewInMemoryTreeStorage(
treeId string, treeId string,
header *aclpb.Header, header *aclpb.TreeHeader,
heads []string, heads []string,
changes []*aclpb.RawChange) (TreeStorage, error) { changes []*aclpb.RawTreeChangeWithId) (TreeStorage, error) {
allChanges := make(map[string]*aclpb.RawChange) allChanges := make(map[string]*aclpb.RawTreeChangeWithId)
for _, ch := range changes { for _, ch := range changes {
allChanges[ch.Id] = ch allChanges[ch.Id] = ch
} }
@ -95,7 +95,7 @@ func (t *inMemoryTreeStorage) ID() (string, error) {
return t.id, nil return t.id, nil
} }
func (t *inMemoryTreeStorage) Header() (*aclpb.Header, error) { func (t *inMemoryTreeStorage) Header() (*aclpb.TreeHeader, error) {
t.RLock() t.RLock()
defer t.RUnlock() defer t.RUnlock()
return t.header, nil return t.header, nil
@ -118,7 +118,7 @@ func (t *inMemoryTreeStorage) SetHeads(heads []string) error {
return nil return nil
} }
func (t *inMemoryTreeStorage) AddRawChange(change *aclpb.RawChange) error { func (t *inMemoryTreeStorage) AddRawChange(change *aclpb.RawTreeChangeWithId) error {
t.Lock() t.Lock()
defer t.Unlock() defer t.Unlock()
// TODO: better to do deep copy // TODO: better to do deep copy
@ -126,7 +126,7 @@ func (t *inMemoryTreeStorage) AddRawChange(change *aclpb.RawChange) error {
return nil return nil
} }
func (t *inMemoryTreeStorage) GetRawChange(ctx context.Context, changeId string) (*aclpb.RawChange, error) { func (t *inMemoryTreeStorage) GetRawChange(ctx context.Context, changeId string) (*aclpb.RawTreeChangeWithId, error) {
t.RLock() t.RLock()
defer t.RUnlock() defer t.RUnlock()
if res, exists := t.changes[changeId]; exists { if res, exists := t.changes[changeId]; exists {

View File

@ -7,8 +7,8 @@ import (
type ListStorage interface { type ListStorage interface {
Storage Storage
Head() (*aclpb.RawRecord, error) Head() (*aclpb.RawACLRecord, error)
GetRawRecord(ctx context.Context, id string) (*aclpb.RawRecord, error) GetRawRecord(ctx context.Context, id string) (*aclpb.RawACLRecord, error)
AddRawRecord(ctx context.Context, rec *aclpb.RawRecord) error AddRawRecord(ctx context.Context, rec *aclpb.RawACLRecord) error
} }

View File

@ -9,15 +9,15 @@ var ErrUnknownTreeId = errors.New("tree does not exist")
type TreeStorageCreatePayload struct { type TreeStorageCreatePayload struct {
TreeId string TreeId string
Header *aclpb.Header Header *aclpb.TreeHeader
Changes []*aclpb.RawChange Changes []*aclpb.RawTreeChangeWithId
Heads []string Heads []string
} }
type ACLListStorageCreatePayload struct { type ACLListStorageCreatePayload struct {
ListId string ListId string
Header *aclpb.Header Header *aclpb.ACLHeader
Records []*aclpb.RawRecord Records []*aclpb.RawACLRecord
} }
type Provider interface { type Provider interface {

View File

@ -10,8 +10,8 @@ type TreeStorage interface {
Heads() ([]string, error) Heads() ([]string, error)
SetHeads(heads []string) error SetHeads(heads []string) error
AddRawChange(change *aclpb.RawChange) error AddRawChange(change *aclpb.RawTreeChangeWithId) error
GetRawChange(ctx context.Context, recordID string) (*aclpb.RawChange, error) GetRawChange(ctx context.Context, recordID string) (*aclpb.RawTreeChangeWithId, error)
} }
type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error) type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error)

View File

@ -19,8 +19,8 @@ import (
type ACLListStorageBuilder struct { type ACLListStorageBuilder struct {
aclList string aclList string
records []*aclpb.Record records []*aclpb.ACLRecord
rawRecords []*aclpb.RawRecord rawRecords []*aclpb.RawACLRecord
indexes map[string]int indexes map[string]int
keychain *Keychain keychain *Keychain
header *aclpb.Header header *aclpb.Header
@ -29,7 +29,7 @@ type ACLListStorageBuilder struct {
func NewACLListStorageBuilder(keychain *Keychain) *ACLListStorageBuilder { func NewACLListStorageBuilder(keychain *Keychain) *ACLListStorageBuilder {
return &ACLListStorageBuilder{ return &ACLListStorageBuilder{
records: make([]*aclpb.Record, 0), records: make([]*aclpb.ACLRecord, 0),
indexes: make(map[string]int), indexes: make(map[string]int),
keychain: keychain, keychain: keychain,
} }
@ -58,7 +58,7 @@ func NewACLListStorageBuilderFromFile(file string) (*ACLListStorageBuilder, erro
return tb, nil return tb, nil
} }
func (t *ACLListStorageBuilder) createRaw(rec *aclpb.Record) *aclpb.RawRecord { func (t *ACLListStorageBuilder) createRaw(rec *aclpb.ACLRecord) *aclpb.RawACLRecord {
aclMarshaled, err := proto.Marshal(rec) aclMarshaled, err := proto.Marshal(rec)
if err != nil { if err != nil {
panic("should be able to marshal final acl message!") panic("should be able to marshal final acl message!")
@ -71,18 +71,18 @@ func (t *ACLListStorageBuilder) createRaw(rec *aclpb.Record) *aclpb.RawRecord {
id, _ := cid.NewCIDFromBytes(aclMarshaled) id, _ := cid.NewCIDFromBytes(aclMarshaled)
return &aclpb.RawRecord{ return &aclpb.RawACLRecord{
Payload: aclMarshaled, Payload: aclMarshaled,
Signature: signature, Signature: signature,
Id: id, Id: id,
} }
} }
func (t *ACLListStorageBuilder) getRecord(idx int) *aclpb.RawRecord { func (t *ACLListStorageBuilder) getRecord(idx int) *aclpb.RawACLRecord {
return t.rawRecords[idx] return t.rawRecords[idx]
} }
func (t *ACLListStorageBuilder) Head() (*aclpb.RawRecord, error) { func (t *ACLListStorageBuilder) Head() (*aclpb.RawACLRecord, error) {
return t.getRecord(len(t.records) - 1), nil return t.getRecord(len(t.records) - 1), nil
} }
@ -90,7 +90,7 @@ func (t *ACLListStorageBuilder) Header() (*aclpb.Header, error) {
return t.header, nil return t.header, nil
} }
func (t *ACLListStorageBuilder) GetRawRecord(ctx context.Context, id string) (*aclpb.RawRecord, error) { func (t *ACLListStorageBuilder) GetRawRecord(ctx context.Context, id string) (*aclpb.RawACLRecord, error) {
recIdx, ok := t.indexes[id] recIdx, ok := t.indexes[id]
if !ok { if !ok {
return nil, fmt.Errorf("no such record") return nil, fmt.Errorf("no such record")
@ -98,7 +98,7 @@ func (t *ACLListStorageBuilder) GetRawRecord(ctx context.Context, id string) (*a
return t.getRecord(recIdx), nil return t.getRecord(recIdx), nil
} }
func (t *ACLListStorageBuilder) AddRawRecord(ctx context.Context, rec *aclpb.RawRecord) error { func (t *ACLListStorageBuilder) AddRawRecord(ctx context.Context, rec *aclpb.RawACLRecord) error {
panic("implement me") panic("implement me")
} }
@ -106,7 +106,7 @@ func (t *ACLListStorageBuilder) ID() (string, error) {
return t.id, nil return t.id, nil
} }
func (t *ACLListStorageBuilder) GetRawRecords() []*aclpb.RawRecord { func (t *ACLListStorageBuilder) GetRawRecords() []*aclpb.RawACLRecord {
return t.rawRecords return t.rawRecords
} }
@ -132,7 +132,7 @@ func (t *ACLListStorageBuilder) Parse(tree *YMLList) {
t.createHeaderAndId() t.createHeaderAndId()
} }
func (t *ACLListStorageBuilder) parseRecord(rec *Record, prevId string) *aclpb.Record { func (t *ACLListStorageBuilder) parseRecord(rec *Record, prevId string) *aclpb.ACLRecord {
k := t.keychain.GetKey(rec.ReadKey).(*SymKey) k := t.keychain.GetKey(rec.ReadKey).(*SymKey)
var aclChangeContents []*aclpb.ACLChangeACLContentValue var aclChangeContents []*aclpb.ACLChangeACLContentValue
for _, ch := range rec.AclChanges { for _, ch := range rec.AclChanges {
@ -144,7 +144,7 @@ func (t *ACLListStorageBuilder) parseRecord(rec *Record, prevId string) *aclpb.R
} }
bytes, _ := data.Marshal() bytes, _ := data.Marshal()
return &aclpb.Record{ return &aclpb.ACLRecord{
PrevId: prevId, PrevId: prevId,
Identity: t.keychain.GetIdentity(rec.Identity), Identity: t.keychain.GetIdentity(rec.Identity),
Data: bytes, Data: bytes,
@ -163,7 +163,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL
convCh = &aclpb.ACLChangeACLContentValue{ convCh = &aclpb.ACLChangeACLContentValue{
Value: &aclpb.ACLChangeACLContentValueValueOfUserAdd{ Value: &aclpb.ACLChangeACLContentValueValueOfUserAdd{
UserAdd: &aclpb.ACLChangeUserAdd{ UserAdd: &aclpb.ACLUserPermissionsAdd{
Identity: t.keychain.GetIdentity(add.Identity), Identity: t.keychain.GetIdentity(add.Identity),
EncryptionKey: rawKey, EncryptionKey: rawKey,
EncryptedReadKeys: t.encryptReadKeys(add.EncryptedReadKeys, encKey), EncryptedReadKeys: t.encryptReadKeys(add.EncryptedReadKeys, encKey),
@ -187,7 +187,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL
convCh = &aclpb.ACLChangeACLContentValue{ convCh = &aclpb.ACLChangeACLContentValue{
Value: &aclpb.ACLChangeACLContentValueValueOfUserJoin{ Value: &aclpb.ACLChangeACLContentValueValueOfUserJoin{
UserJoin: &aclpb.ACLChangeUserJoin{ UserJoin: &aclpb.ACLUserPermissionsJoin{
Identity: t.keychain.GetIdentity(join.Identity), Identity: t.keychain.GetIdentity(join.Identity),
EncryptionKey: rawKey, EncryptionKey: rawKey,
AcceptSignature: signature, AcceptSignature: signature,
@ -205,7 +205,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL
convCh = &aclpb.ACLChangeACLContentValue{ convCh = &aclpb.ACLChangeACLContentValue{
Value: &aclpb.ACLChangeACLContentValueValueOfUserInvite{ Value: &aclpb.ACLChangeACLContentValueValueOfUserInvite{
UserInvite: &aclpb.ACLChangeUserInvite{ UserInvite: &aclpb.ACLUserPermissionsInvite{
AcceptPublicKey: rawAcceptKey, AcceptPublicKey: rawAcceptKey,
EncryptPublicKey: rawEncKey, EncryptPublicKey: rawEncKey,
EncryptedReadKeys: t.encryptReadKeys(invite.EncryptedReadKeys, encKey), EncryptedReadKeys: t.encryptReadKeys(invite.EncryptedReadKeys, encKey),
@ -219,7 +219,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL
convCh = &aclpb.ACLChangeACLContentValue{ convCh = &aclpb.ACLChangeACLContentValue{
Value: &aclpb.ACLChangeACLContentValueValueOfUserConfirm{ Value: &aclpb.ACLChangeACLContentValueValueOfUserConfirm{
UserConfirm: &aclpb.ACLChangeUserConfirm{ UserConfirm: &aclpb.ACLUserPermissionsConfirm{
Identity: t.keychain.GetIdentity(confirm.Identity), Identity: t.keychain.GetIdentity(confirm.Identity),
UserAddId: confirm.UserAddId, UserAddId: confirm.UserAddId,
}, },
@ -230,7 +230,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL
convCh = &aclpb.ACLChangeACLContentValue{ convCh = &aclpb.ACLChangeACLContentValue{
Value: &aclpb.ACLChangeACLContentValueValueOfUserPermissionChange{ Value: &aclpb.ACLChangeACLContentValueValueOfUserPermissionChange{
UserPermissionChange: &aclpb.ACLChangeUserPermissionChange{ UserPermissionChange: &aclpb.ACLUserPermissionsPermissionChange{
Identity: t.keychain.GetIdentity(permissionChange.Identity), Identity: t.keychain.GetIdentity(permissionChange.Identity),
Permissions: t.convertPermission(permissionChange.Permission), Permissions: t.convertPermission(permissionChange.Permission),
}, },
@ -259,7 +259,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL
convCh = &aclpb.ACLChangeACLContentValue{ convCh = &aclpb.ACLChangeACLContentValue{
Value: &aclpb.ACLChangeACLContentValueValueOfUserRemove{ Value: &aclpb.ACLChangeACLContentValueValueOfUserRemove{
UserRemove: &aclpb.ACLChangeUserRemove{ UserRemove: &aclpb.ACLUserPermissionsRemove{
Identity: t.keychain.GetIdentity(remove.RemovedIdentity), Identity: t.keychain.GetIdentity(remove.RemovedIdentity),
ReadKeyReplaces: replaces, ReadKeyReplaces: replaces,
}, },
@ -286,7 +286,7 @@ func (t *ACLListStorageBuilder) encryptReadKeys(keys []string, encKey encryption
return return
} }
func (t *ACLListStorageBuilder) convertPermission(perm string) aclpb.ACLChangeUserPermissions { func (t *ACLListStorageBuilder) convertPermission(perm string) aclpb.ACLUserPermissions {
switch perm { switch perm {
case "admin": case "admin":
return aclpb.ACLChange_Admin return aclpb.ACLChange_Admin
@ -299,7 +299,7 @@ func (t *ACLListStorageBuilder) convertPermission(perm string) aclpb.ACLChangeUs
} }
} }
func (t *ACLListStorageBuilder) traverseFromHead(f func(rec *aclpb.Record, id string) error) (err error) { func (t *ACLListStorageBuilder) traverseFromHead(f func(rec *aclpb.ACLRecord, id string) error) (err error) {
for i := len(t.records) - 1; i >= 0; i-- { for i := len(t.records) - 1; i >= 0; i-- {
err = f(t.records[i], t.rawRecords[i].Id) err = f(t.records[i], t.rawRecords[i].Id)
if err != nil { if err != nil {

View File

@ -33,7 +33,7 @@ func (t *ACLListStorageBuilder) Graph() (string, error) {
graph.SetDir(true) graph.SetDir(true)
var nodes = make(map[string]struct{}) var nodes = make(map[string]struct{})
var addNodes = func(r *aclpb.Record, id string) error { var addNodes = func(r *aclpb.ACLRecord, id string) error {
style := "solid" style := "solid"
var chSymbs []string var chSymbs []string
@ -92,7 +92,7 @@ func (t *ACLListStorageBuilder) Graph() (string, error) {
return nil return nil
} }
var addLinks = func(r *aclpb.Record, id string) error { var addLinks = func(r *aclpb.ACLRecord, id string) error {
if r.PrevId == "" { if r.PrevId == "" {
return nil return nil
} }

View File

@ -1,7 +1,7 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT. // Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: pkg/acl/testutils/testchanges/testchangepb/protos/testdocumentchanges.proto // source: pkg/acl/testutils/testchanges/proto/test.proto
package testchangepb package testchanges
import ( import (
fmt "fmt" fmt "fmt"
@ -29,7 +29,7 @@ func (m *PlainTextChange) Reset() { *m = PlainTextChange{} }
func (m *PlainTextChange) String() string { return proto.CompactTextString(m) } func (m *PlainTextChange) String() string { return proto.CompactTextString(m) }
func (*PlainTextChange) ProtoMessage() {} func (*PlainTextChange) ProtoMessage() {}
func (*PlainTextChange) Descriptor() ([]byte, []int) { func (*PlainTextChange) Descriptor() ([]byte, []int) {
return fileDescriptor_c07268f9f08f2beb, []int{0} return fileDescriptor_37f33c266ada4318, []int{0}
} }
func (m *PlainTextChange) XXX_Unmarshal(b []byte) error { func (m *PlainTextChange) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b) return m.Unmarshal(b)
@ -60,7 +60,6 @@ var xxx_messageInfo_PlainTextChange proto.InternalMessageInfo
type PlainTextChange_Content struct { type PlainTextChange_Content struct {
// Types that are valid to be assigned to Value: // Types that are valid to be assigned to Value:
//
// *PlainTextChange_Content_TextAppend // *PlainTextChange_Content_TextAppend
Value isPlainTextChange_Content_Value `protobuf_oneof:"value"` Value isPlainTextChange_Content_Value `protobuf_oneof:"value"`
} }
@ -69,7 +68,7 @@ func (m *PlainTextChange_Content) Reset() { *m = PlainTextChange_Content
func (m *PlainTextChange_Content) String() string { return proto.CompactTextString(m) } func (m *PlainTextChange_Content) String() string { return proto.CompactTextString(m) }
func (*PlainTextChange_Content) ProtoMessage() {} func (*PlainTextChange_Content) ProtoMessage() {}
func (*PlainTextChange_Content) Descriptor() ([]byte, []int) { func (*PlainTextChange_Content) Descriptor() ([]byte, []int) {
return fileDescriptor_c07268f9f08f2beb, []int{0, 0} return fileDescriptor_37f33c266ada4318, []int{0, 0}
} }
func (m *PlainTextChange_Content) XXX_Unmarshal(b []byte) error { func (m *PlainTextChange_Content) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b) return m.Unmarshal(b)
@ -139,7 +138,7 @@ func (m *PlainTextChange_TextAppend) Reset() { *m = PlainTextChange_Text
func (m *PlainTextChange_TextAppend) String() string { return proto.CompactTextString(m) } func (m *PlainTextChange_TextAppend) String() string { return proto.CompactTextString(m) }
func (*PlainTextChange_TextAppend) ProtoMessage() {} func (*PlainTextChange_TextAppend) ProtoMessage() {}
func (*PlainTextChange_TextAppend) Descriptor() ([]byte, []int) { func (*PlainTextChange_TextAppend) Descriptor() ([]byte, []int) {
return fileDescriptor_c07268f9f08f2beb, []int{0, 1} return fileDescriptor_37f33c266ada4318, []int{0, 1}
} }
func (m *PlainTextChange_TextAppend) XXX_Unmarshal(b []byte) error { func (m *PlainTextChange_TextAppend) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b) return m.Unmarshal(b)
@ -183,7 +182,7 @@ func (m *PlainTextChange_Snapshot) Reset() { *m = PlainTextChange_Snapsh
func (m *PlainTextChange_Snapshot) String() string { return proto.CompactTextString(m) } func (m *PlainTextChange_Snapshot) String() string { return proto.CompactTextString(m) }
func (*PlainTextChange_Snapshot) ProtoMessage() {} func (*PlainTextChange_Snapshot) ProtoMessage() {}
func (*PlainTextChange_Snapshot) Descriptor() ([]byte, []int) { func (*PlainTextChange_Snapshot) Descriptor() ([]byte, []int) {
return fileDescriptor_c07268f9f08f2beb, []int{0, 2} return fileDescriptor_37f33c266ada4318, []int{0, 2}
} }
func (m *PlainTextChange_Snapshot) XXX_Unmarshal(b []byte) error { func (m *PlainTextChange_Snapshot) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b) return m.Unmarshal(b)
@ -228,7 +227,7 @@ func (m *PlainTextChange_Data) Reset() { *m = PlainTextChange_Data{} }
func (m *PlainTextChange_Data) String() string { return proto.CompactTextString(m) } func (m *PlainTextChange_Data) String() string { return proto.CompactTextString(m) }
func (*PlainTextChange_Data) ProtoMessage() {} func (*PlainTextChange_Data) ProtoMessage() {}
func (*PlainTextChange_Data) Descriptor() ([]byte, []int) { func (*PlainTextChange_Data) Descriptor() ([]byte, []int) {
return fileDescriptor_c07268f9f08f2beb, []int{0, 3} return fileDescriptor_37f33c266ada4318, []int{0, 3}
} }
func (m *PlainTextChange_Data) XXX_Unmarshal(b []byte) error { func (m *PlainTextChange_Data) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b) return m.Unmarshal(b)
@ -280,29 +279,28 @@ func init() {
} }
func init() { func init() {
proto.RegisterFile("pkg/acl/testutils/testchanges/testchangepb/protos/testdocumentchanges.proto", fileDescriptor_c07268f9f08f2beb) proto.RegisterFile("pkg/acl/testutils/testchanges/proto/test.proto", fileDescriptor_37f33c266ada4318)
} }
var fileDescriptor_c07268f9f08f2beb = []byte{ var fileDescriptor_37f33c266ada4318 = []byte{
// 278 bytes of a gzipped FileDescriptorProto // 266 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xf2, 0x2e, 0xc8, 0x4e, 0xd7, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x2b, 0xc8, 0x4e, 0xd7,
0x4f, 0x4c, 0xce, 0xd1, 0x2f, 0x49, 0x2d, 0x2e, 0x29, 0x2d, 0xc9, 0xcc, 0x29, 0x06, 0xb3, 0x92, 0x4f, 0x4c, 0xce, 0xd1, 0x2f, 0x49, 0x2d, 0x2e, 0x29, 0x2d, 0xc9, 0xcc, 0x29, 0x06, 0xb3, 0x92,
0x33, 0x12, 0xf3, 0xd2, 0x53, 0x91, 0xd9, 0x05, 0x49, 0xfa, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x10, 0x33, 0x12, 0xf3, 0xd2, 0x53, 0x8b, 0xf5, 0x0b, 0x8a, 0xf2, 0x4b, 0xf2, 0xc1, 0x22, 0x7a, 0x60,
0xb1, 0x94, 0xfc, 0xe4, 0xd2, 0xdc, 0xd4, 0x3c, 0x98, 0x3a, 0x3d, 0xb0, 0x94, 0x10, 0x7b, 0x62, 0xa6, 0x10, 0x7b, 0x62, 0x5e, 0x65, 0x49, 0x65, 0x41, 0xaa, 0xd2, 0x26, 0x26, 0x2e, 0xfe, 0x80,
0x5e, 0x65, 0x49, 0x65, 0x41, 0xaa, 0xd2, 0x26, 0x26, 0x2e, 0xfe, 0x80, 0x9c, 0xc4, 0xcc, 0xbc, 0x9c, 0xc4, 0xcc, 0xbc, 0x90, 0xd4, 0x8a, 0x12, 0x67, 0xb0, 0x72, 0xa9, 0x48, 0x2e, 0x76, 0xe7,
0x90, 0xd4, 0x8a, 0x12, 0x67, 0xb0, 0x1a, 0xa9, 0x48, 0x2e, 0x76, 0xe7, 0xfc, 0xbc, 0x92, 0xd4, 0xfc, 0xbc, 0x92, 0xd4, 0xbc, 0x12, 0x21, 0x57, 0x2e, 0xae, 0x92, 0xd4, 0x8a, 0x12, 0xc7, 0x82,
0xbc, 0x12, 0x21, 0x57, 0x2e, 0xae, 0x92, 0xd4, 0x8a, 0x12, 0xc7, 0x82, 0x82, 0xd4, 0xbc, 0x14, 0x82, 0xd4, 0xbc, 0x14, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x6e, 0x23, 0x65, 0x3d, 0xa8, 0x66, 0x3d,
0x09, 0x46, 0x05, 0x46, 0x0d, 0x6e, 0x23, 0x65, 0x3d, 0xa8, 0x66, 0x3d, 0x34, 0x8d, 0x7a, 0x21, 0x34, 0x8d, 0x7a, 0x21, 0x70, 0xa5, 0x1e, 0x0c, 0x41, 0x48, 0x1a, 0x9d, 0xd8, 0xb9, 0x58, 0xcb,
0x70, 0xa5, 0x1e, 0x0c, 0x41, 0x48, 0x1a, 0x9d, 0xd8, 0xb9, 0x58, 0xcb, 0x12, 0x73, 0x4a, 0x53, 0x12, 0x73, 0x4a, 0x53, 0xa5, 0x14, 0xb8, 0xb8, 0x10, 0x8a, 0x84, 0x84, 0xb8, 0x58, 0x40, 0x8a,
0xa5, 0x14, 0xb8, 0xb8, 0x10, 0x8a, 0x84, 0x84, 0xb8, 0x58, 0x40, 0x8a, 0xc0, 0xe6, 0x72, 0x06, 0xc0, 0xe6, 0x72, 0x06, 0x81, 0xd9, 0x52, 0x72, 0x5c, 0x1c, 0xc1, 0x79, 0x89, 0x05, 0xc5, 0x19,
0x81, 0xd9, 0x52, 0x72, 0x5c, 0x1c, 0xc1, 0x79, 0x89, 0x05, 0xc5, 0x19, 0xf9, 0x25, 0x58, 0xe5, 0xf9, 0x25, 0x58, 0xe5, 0x1b, 0x19, 0xb9, 0x58, 0x5c, 0x12, 0x4b, 0x12, 0x85, 0xac, 0xb8, 0xd8,
0x1b, 0x19, 0xb9, 0x58, 0x5c, 0x12, 0x4b, 0x12, 0x85, 0xac, 0xb8, 0xd8, 0x93, 0x21, 0xae, 0x94, 0x93, 0x21, 0xae, 0x94, 0x60, 0x54, 0x60, 0xd6, 0xe0, 0x36, 0x52, 0xc0, 0xe9, 0x2e, 0xa8, 0x6f,
0x60, 0x54, 0x60, 0xd6, 0xe0, 0x36, 0x52, 0xc0, 0xe9, 0x2e, 0xa8, 0x6f, 0x82, 0x60, 0x1a, 0x84, 0x82, 0x60, 0x1a, 0x84, 0x6c, 0xb9, 0x38, 0x8a, 0xa1, 0x96, 0x48, 0x30, 0x81, 0x3d, 0xa5, 0x88,
0x6c, 0xb9, 0x38, 0x8a, 0xa1, 0x96, 0x48, 0x30, 0x81, 0x3d, 0xa5, 0x88, 0x53, 0x33, 0xcc, 0x35, 0x53, 0x33, 0xcc, 0x35, 0x41, 0x70, 0x2d, 0x4e, 0xaa, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24,
0x41, 0x70, 0x2d, 0x4e, 0x6a, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78,
0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0xc5, 0x2c, 0xc7, 0x10, 0xc5, 0x8d, 0x14, 0xea, 0x49, 0x6c, 0xe0, 0xb0, 0x36, 0x06, 0x04, 0x00, 0x00,
0x83, 0x1c, 0x0d, 0x49, 0x6c, 0xe0, 0xc0, 0x36, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xfd, 0x73, 0xff, 0xff, 0xf8, 0x8c, 0x6a, 0x1d, 0x9d, 0x01, 0x00, 0x00,
0xe1, 0xf2, 0xbb, 0x01, 0x00, 0x00,
} }
func (m *PlainTextChange) Marshal() (dAtA []byte, err error) { func (m *PlainTextChange) Marshal() (dAtA []byte, err error) {
@ -374,7 +372,7 @@ func (m *PlainTextChange_Content_TextAppend) MarshalToSizedBuffer(dAtA []byte) (
return 0, err return 0, err
} }
i -= size i -= size
i = encodeVarintTestdocumentchanges(dAtA, i, uint64(size)) i = encodeVarintTest(dAtA, i, uint64(size))
} }
i-- i--
dAtA[i] = 0xa dAtA[i] = 0xa
@ -404,7 +402,7 @@ func (m *PlainTextChange_TextAppend) MarshalToSizedBuffer(dAtA []byte) (int, err
if len(m.Text) > 0 { if len(m.Text) > 0 {
i -= len(m.Text) i -= len(m.Text)
copy(dAtA[i:], m.Text) copy(dAtA[i:], m.Text)
i = encodeVarintTestdocumentchanges(dAtA, i, uint64(len(m.Text))) i = encodeVarintTest(dAtA, i, uint64(len(m.Text)))
i-- i--
dAtA[i] = 0xa dAtA[i] = 0xa
} }
@ -434,7 +432,7 @@ func (m *PlainTextChange_Snapshot) MarshalToSizedBuffer(dAtA []byte) (int, error
if len(m.Text) > 0 { if len(m.Text) > 0 {
i -= len(m.Text) i -= len(m.Text)
copy(dAtA[i:], m.Text) copy(dAtA[i:], m.Text)
i = encodeVarintTestdocumentchanges(dAtA, i, uint64(len(m.Text))) i = encodeVarintTest(dAtA, i, uint64(len(m.Text)))
i-- i--
dAtA[i] = 0xa dAtA[i] = 0xa
} }
@ -468,7 +466,7 @@ func (m *PlainTextChange_Data) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return 0, err return 0, err
} }
i -= size i -= size
i = encodeVarintTestdocumentchanges(dAtA, i, uint64(size)) i = encodeVarintTest(dAtA, i, uint64(size))
} }
i-- i--
dAtA[i] = 0x12 dAtA[i] = 0x12
@ -481,7 +479,7 @@ func (m *PlainTextChange_Data) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return 0, err return 0, err
} }
i -= size i -= size
i = encodeVarintTestdocumentchanges(dAtA, i, uint64(size)) i = encodeVarintTest(dAtA, i, uint64(size))
} }
i-- i--
dAtA[i] = 0xa dAtA[i] = 0xa
@ -490,8 +488,8 @@ func (m *PlainTextChange_Data) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil return len(dAtA) - i, nil
} }
func encodeVarintTestdocumentchanges(dAtA []byte, offset int, v uint64) int { func encodeVarintTest(dAtA []byte, offset int, v uint64) int {
offset -= sovTestdocumentchanges(v) offset -= sovTest(v)
base := offset base := offset
for v >= 1<<7 { for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80) dAtA[offset] = uint8(v&0x7f | 0x80)
@ -530,7 +528,7 @@ func (m *PlainTextChange_Content_TextAppend) Size() (n int) {
_ = l _ = l
if m.TextAppend != nil { if m.TextAppend != nil {
l = m.TextAppend.Size() l = m.TextAppend.Size()
n += 1 + l + sovTestdocumentchanges(uint64(l)) n += 1 + l + sovTest(uint64(l))
} }
return n return n
} }
@ -542,7 +540,7 @@ func (m *PlainTextChange_TextAppend) Size() (n int) {
_ = l _ = l
l = len(m.Text) l = len(m.Text)
if l > 0 { if l > 0 {
n += 1 + l + sovTestdocumentchanges(uint64(l)) n += 1 + l + sovTest(uint64(l))
} }
return n return n
} }
@ -555,7 +553,7 @@ func (m *PlainTextChange_Snapshot) Size() (n int) {
_ = l _ = l
l = len(m.Text) l = len(m.Text)
if l > 0 { if l > 0 {
n += 1 + l + sovTestdocumentchanges(uint64(l)) n += 1 + l + sovTest(uint64(l))
} }
return n return n
} }
@ -569,21 +567,21 @@ func (m *PlainTextChange_Data) Size() (n int) {
if len(m.Content) > 0 { if len(m.Content) > 0 {
for _, e := range m.Content { for _, e := range m.Content {
l = e.Size() l = e.Size()
n += 1 + l + sovTestdocumentchanges(uint64(l)) n += 1 + l + sovTest(uint64(l))
} }
} }
if m.Snapshot != nil { if m.Snapshot != nil {
l = m.Snapshot.Size() l = m.Snapshot.Size()
n += 1 + l + sovTestdocumentchanges(uint64(l)) n += 1 + l + sovTest(uint64(l))
} }
return n return n
} }
func sovTestdocumentchanges(x uint64) (n int) { func sovTest(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7 return (math_bits.Len64(x|1) + 6) / 7
} }
func sozTestdocumentchanges(x uint64) (n int) { func sozTest(x uint64) (n int) {
return sovTestdocumentchanges(uint64((x << 1) ^ uint64((int64(x) >> 63)))) return sovTest(uint64((x << 1) ^ uint64((int64(x) >> 63))))
} }
func (m *PlainTextChange) Unmarshal(dAtA []byte) error { func (m *PlainTextChange) Unmarshal(dAtA []byte) error {
l := len(dAtA) l := len(dAtA)
@ -593,7 +591,7 @@ func (m *PlainTextChange) Unmarshal(dAtA []byte) error {
var wire uint64 var wire uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowTestdocumentchanges return ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -616,12 +614,12 @@ func (m *PlainTextChange) Unmarshal(dAtA []byte) error {
switch fieldNum { switch fieldNum {
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipTestdocumentchanges(dAtA[iNdEx:]) skippy, err := skipTest(dAtA[iNdEx:])
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -643,7 +641,7 @@ func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
var wire uint64 var wire uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowTestdocumentchanges return ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -671,7 +669,7 @@ func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
var msglen int var msglen int
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowTestdocumentchanges return ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -684,11 +682,11 @@ func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
} }
} }
if msglen < 0 { if msglen < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
postIndex := iNdEx + msglen postIndex := iNdEx + msglen
if postIndex < 0 { if postIndex < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
if postIndex > l { if postIndex > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -701,12 +699,12 @@ func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
iNdEx = postIndex iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipTestdocumentchanges(dAtA[iNdEx:]) skippy, err := skipTest(dAtA[iNdEx:])
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -728,7 +726,7 @@ func (m *PlainTextChange_TextAppend) Unmarshal(dAtA []byte) error {
var wire uint64 var wire uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowTestdocumentchanges return ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -756,7 +754,7 @@ func (m *PlainTextChange_TextAppend) Unmarshal(dAtA []byte) error {
var stringLen uint64 var stringLen uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowTestdocumentchanges return ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -770,11 +768,11 @@ func (m *PlainTextChange_TextAppend) Unmarshal(dAtA []byte) error {
} }
intStringLen := int(stringLen) intStringLen := int(stringLen)
if intStringLen < 0 { if intStringLen < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
postIndex := iNdEx + intStringLen postIndex := iNdEx + intStringLen
if postIndex < 0 { if postIndex < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
if postIndex > l { if postIndex > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -783,12 +781,12 @@ func (m *PlainTextChange_TextAppend) Unmarshal(dAtA []byte) error {
iNdEx = postIndex iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipTestdocumentchanges(dAtA[iNdEx:]) skippy, err := skipTest(dAtA[iNdEx:])
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -810,7 +808,7 @@ func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
var wire uint64 var wire uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowTestdocumentchanges return ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -838,7 +836,7 @@ func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
var stringLen uint64 var stringLen uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowTestdocumentchanges return ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -852,11 +850,11 @@ func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
} }
intStringLen := int(stringLen) intStringLen := int(stringLen)
if intStringLen < 0 { if intStringLen < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
postIndex := iNdEx + intStringLen postIndex := iNdEx + intStringLen
if postIndex < 0 { if postIndex < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
if postIndex > l { if postIndex > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -865,12 +863,12 @@ func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
iNdEx = postIndex iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipTestdocumentchanges(dAtA[iNdEx:]) skippy, err := skipTest(dAtA[iNdEx:])
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -892,7 +890,7 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
var wire uint64 var wire uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowTestdocumentchanges return ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -920,7 +918,7 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
var msglen int var msglen int
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowTestdocumentchanges return ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -933,11 +931,11 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
} }
} }
if msglen < 0 { if msglen < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
postIndex := iNdEx + msglen postIndex := iNdEx + msglen
if postIndex < 0 { if postIndex < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
if postIndex > l { if postIndex > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -954,7 +952,7 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
var msglen int var msglen int
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowTestdocumentchanges return ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -967,11 +965,11 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
} }
} }
if msglen < 0 { if msglen < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
postIndex := iNdEx + msglen postIndex := iNdEx + msglen
if postIndex < 0 { if postIndex < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
if postIndex > l { if postIndex > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -985,12 +983,12 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
iNdEx = postIndex iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipTestdocumentchanges(dAtA[iNdEx:]) skippy, err := skipTest(dAtA[iNdEx:])
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthTestdocumentchanges return ErrInvalidLengthTest
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
@ -1004,7 +1002,7 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
} }
return nil return nil
} }
func skipTestdocumentchanges(dAtA []byte) (n int, err error) { func skipTest(dAtA []byte) (n int, err error) {
l := len(dAtA) l := len(dAtA)
iNdEx := 0 iNdEx := 0
depth := 0 depth := 0
@ -1012,7 +1010,7 @@ func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
var wire uint64 var wire uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return 0, ErrIntOverflowTestdocumentchanges return 0, ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return 0, io.ErrUnexpectedEOF return 0, io.ErrUnexpectedEOF
@ -1029,7 +1027,7 @@ func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
case 0: case 0:
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return 0, ErrIntOverflowTestdocumentchanges return 0, ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return 0, io.ErrUnexpectedEOF return 0, io.ErrUnexpectedEOF
@ -1045,7 +1043,7 @@ func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
var length int var length int
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return 0, ErrIntOverflowTestdocumentchanges return 0, ErrIntOverflowTest
} }
if iNdEx >= l { if iNdEx >= l {
return 0, io.ErrUnexpectedEOF return 0, io.ErrUnexpectedEOF
@ -1058,14 +1056,14 @@ func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
} }
} }
if length < 0 { if length < 0 {
return 0, ErrInvalidLengthTestdocumentchanges return 0, ErrInvalidLengthTest
} }
iNdEx += length iNdEx += length
case 3: case 3:
depth++ depth++
case 4: case 4:
if depth == 0 { if depth == 0 {
return 0, ErrUnexpectedEndOfGroupTestdocumentchanges return 0, ErrUnexpectedEndOfGroupTest
} }
depth-- depth--
case 5: case 5:
@ -1074,7 +1072,7 @@ func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
return 0, fmt.Errorf("proto: illegal wireType %d", wireType) return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
} }
if iNdEx < 0 { if iNdEx < 0 {
return 0, ErrInvalidLengthTestdocumentchanges return 0, ErrInvalidLengthTest
} }
if depth == 0 { if depth == 0 {
return iNdEx, nil return iNdEx, nil
@ -1084,7 +1082,7 @@ func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
} }
var ( var (
ErrInvalidLengthTestdocumentchanges = fmt.Errorf("proto: negative length found during unmarshaling") ErrInvalidLengthTest = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowTestdocumentchanges = fmt.Errorf("proto: integer overflow") ErrIntOverflowTest = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupTestdocumentchanges = fmt.Errorf("proto: unexpected end of group") ErrUnexpectedEndOfGroupTest = fmt.Errorf("proto: unexpected end of group")
) )

View File

@ -16,7 +16,7 @@ var (
type ChangeContent struct { type ChangeContent struct {
ChangesData proto.Marshaler ChangesData proto.Marshaler
ACLData *aclpb.ACLChangeACLData ACLData *aclpb.ACLData
Id string // TODO: this is just for testing, because id should be created automatically from content Id string // TODO: this is just for testing, because id should be created automatically from content
} }
@ -34,7 +34,8 @@ type Change struct {
visited bool visited bool
branchesFinished bool branchesFinished bool
Content *aclpb.Change Content *aclpb.TreeChange
Identity string
Sign []byte Sign []byte
} }
@ -56,7 +57,7 @@ func (ch *Change) DecryptContents(key *symmetric.Key) error {
return nil return nil
} }
func NewChange(id string, ch *aclpb.Change, signature []byte) *Change { func NewChange(id string, ch *aclpb.TreeChange, signature []byte) *Change {
return &Change{ return &Change{
Next: nil, Next: nil,
PreviousIds: ch.TreeHeadIds, PreviousIds: ch.TreeHeadIds,
@ -64,6 +65,7 @@ func NewChange(id string, ch *aclpb.Change, signature []byte) *Change {
Content: ch, Content: ch,
SnapshotId: ch.SnapshotBaseId, SnapshotId: ch.SnapshotBaseId,
IsSnapshot: ch.IsSnapshot, IsSnapshot: ch.IsSnapshot,
Identity: string(ch.Identity),
Sign: signature, Sign: signature,
} }
} }

View File

@ -1,6 +1,7 @@
package tree package tree
import ( import (
"errors"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb" "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/pkg/acl/common"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
@ -10,25 +11,24 @@ import (
"time" "time"
) )
const componentBuilder = "tree.changebuilder" var ErrEmptyChange = errors.New("change payload should not be empty")
type BuilderContent struct { type BuilderContent struct {
treeHeadIds []string treeHeadIds []string
aclHeadId string aclHeadId string
snapshotBaseId string snapshotBaseId string
currentReadKeyHash uint64 currentReadKeyHash uint64
identity string identity []byte
isSnapshot bool isSnapshot bool
signingKey signingkey.PrivKey signingKey signingkey.PrivKey
readKey *symmetric.Key readKey *symmetric.Key
content proto.Marshaler content []byte
} }
type ChangeBuilder interface { type ChangeBuilder interface {
ConvertFromRaw(rawChange *aclpb.RawChange) (ch *Change, err error) ConvertFromRaw(rawIdChange *aclpb.RawTreeChangeWithId, verify bool) (ch *Change, err error)
ConvertFromRawAndVerify(rawChange *aclpb.RawChange) (ch *Change, err error) BuildContent(payload BuilderContent) (ch *Change, raw *aclpb.RawTreeChangeWithId, err error)
BuildContent(payload BuilderContent) (ch *Change, raw *aclpb.RawChange, err error) BuildRaw(ch *Change) (*aclpb.RawTreeChangeWithId, error)
BuildRaw(ch *Change) (*aclpb.RawChange, error)
} }
type changeBuilder struct { type changeBuilder struct {
@ -39,31 +39,34 @@ func newChangeBuilder(keys *common.Keychain) ChangeBuilder {
return &changeBuilder{keys: keys} return &changeBuilder{keys: keys}
} }
func (c *changeBuilder) ConvertFromRaw(rawChange *aclpb.RawChange) (ch *Change, err error) { func (c *changeBuilder) ConvertFromRaw(rawIdChange *aclpb.RawTreeChangeWithId, verify bool) (ch *Change, err error) {
unmarshalled := &aclpb.Change{} if rawIdChange.GetRawChange() == nil {
err = proto.Unmarshal(rawChange.Payload, unmarshalled) err = ErrEmptyChange
if err != nil {
return nil, err
}
ch = NewChange(rawChange.Id, unmarshalled, rawChange.Signature)
return return
}
func (c *changeBuilder) ConvertFromRawAndVerify(rawChange *aclpb.RawChange) (ch *Change, err error) {
unmarshalled := &aclpb.Change{}
ch, err = c.ConvertFromRaw(rawChange)
if err != nil {
return nil, err
} }
identityKey, err := c.keys.GetOrAdd(unmarshalled.Identity) 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 {
identityKey, err := c.keys.GetOrAdd(ch.Identity)
if err != nil { if err != nil {
return return
} }
// verifying signature // verifying signature
res, err := identityKey.Verify(rawChange.Payload, rawChange.Signature) res, err := identityKey.Verify(raw.Payload, raw.Signature)
if err != nil { if err != nil {
return return
} }
@ -71,17 +74,20 @@ func (c *changeBuilder) ConvertFromRawAndVerify(rawChange *aclpb.RawChange) (ch
err = ErrIncorrectSignature err = ErrIncorrectSignature
return return
} }
// verifying ID
if !cid.VerifyCID(rawChange.Payload, rawChange.Id) {
err = ErrIncorrectCID
} }
unmarshalled := &aclpb.TreeChange{}
err = proto.Unmarshal(raw.Payload, unmarshalled)
if err != nil {
return
}
ch = NewChange(rawIdChange.Id, unmarshalled, raw.Signature)
return return
} }
func (c *changeBuilder) BuildContent(payload BuilderContent) (ch *Change, raw *aclpb.RawChange, err error) { func (c *changeBuilder) BuildContent(payload BuilderContent) (ch *Change, rawIdChange *aclpb.RawTreeChangeWithId, err error) {
aclChange := &aclpb.Change{ change := &aclpb.TreeChange{
TreeHeadIds: payload.treeHeadIds, TreeHeadIds: payload.treeHeadIds,
AclHeadId: payload.aclHeadId, AclHeadId: payload.aclHeadId,
SnapshotBaseId: payload.snapshotBaseId, SnapshotBaseId: payload.snapshotBaseId,
@ -90,53 +96,65 @@ func (c *changeBuilder) BuildContent(payload BuilderContent) (ch *Change, raw *a
Identity: payload.identity, Identity: payload.identity,
IsSnapshot: payload.isSnapshot, IsSnapshot: payload.isSnapshot,
} }
marshalledData, err := payload.content.Marshal()
encrypted, err := payload.readKey.Encrypt(payload.content)
if err != nil {
return
}
change.ChangesData = encrypted
marshalledChange, err := proto.Marshal(change)
if err != nil { if err != nil {
return return
} }
encrypted, err := payload.readKey.Encrypt(marshalledData) signature, err := payload.signingKey.Sign(marshalledChange)
if err != nil {
return
}
aclChange.ChangesData = encrypted
fullMarshalledChange, err := proto.Marshal(aclChange)
if err != nil { if err != nil {
return return
} }
signature, err := payload.signingKey.Sign(fullMarshalledChange) raw := &aclpb.RawTreeChange{
Payload: marshalledChange,
Signature: signature,
}
marshalledRawChange, err := proto.Marshal(raw)
if err != nil { if err != nil {
return return
} }
id, err := cid.NewCIDFromBytes(fullMarshalledChange) id, err := cid.NewCIDFromBytes(marshalledRawChange)
if err != nil { if err != nil {
return return
} }
ch = NewChange(id, aclChange, signature) ch = NewChange(id, change, signature)
ch.ParsedModel = payload.content ch.ParsedModel = payload.content
raw = &aclpb.RawChange{ rawIdChange = &aclpb.RawTreeChangeWithId{
Payload: fullMarshalledChange, RawChange: marshalledRawChange,
Signature: signature,
Id: id, Id: id,
} }
return return
} }
func (c *changeBuilder) BuildRaw(ch *Change) (raw *aclpb.RawChange, err error) { func (c *changeBuilder) BuildRaw(ch *Change) (raw *aclpb.RawTreeChangeWithId, err error) {
var marshalled []byte var marshalled []byte
marshalled, err = ch.Content.Marshal() marshalled, err = ch.Content.Marshal()
if err != nil { if err != nil {
return return
} }
raw = &aclpb.RawChange{ marshalledRawChange, err := proto.Marshal(&aclpb.RawTreeChange{
Payload: marshalled, Payload: marshalled,
Signature: ch.Signature(), Signature: ch.Sign,
})
if err != nil {
return
}
raw = &aclpb.RawTreeChangeWithId{
RawChange: marshalledRawChange,
Id: ch.Id, Id: ch.Id,
} }
return return

View File

@ -48,7 +48,7 @@ func (v *objectTreeValidator) validateChange(tree *Tree, aclList list.ACLList, c
return return
} }
if perm.Permission != aclpb.ACLChange_Writer && perm.Permission != aclpb.ACLChange_Admin { if perm.Permission != aclpb.ACLUserPermissions_Writer && perm.Permission != aclpb.ACLUserPermissions_Admin {
err = list.ErrInsufficientPermissions err = list.ErrInsufficientPermissions
return return
} }

View File

@ -8,8 +8,6 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/symmetric" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/symmetric"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
"go.uber.org/zap"
"sync" "sync"
) )
@ -34,7 +32,7 @@ type AddResultSummary int
type AddResult struct { type AddResult struct {
OldHeads []string OldHeads []string
Heads []string Heads []string
Added []*aclpb.RawChange Added []*aclpb.RawTreeChangeWithId
Mode Mode Mode Mode
} }
@ -46,7 +44,7 @@ type ObjectTree interface {
RWLocker RWLocker
ID() string ID() string
Header() *aclpb.Header Header() *aclpb.TreeHeader
Heads() []string Heads() []string
Root() *Change Root() *Change
HasChange(string) bool HasChange(string) bool
@ -55,13 +53,13 @@ type ObjectTree interface {
IterateFrom(id string, convert ChangeConvertFunc, iterate ChangeIterateFunc) error IterateFrom(id string, convert ChangeConvertFunc, iterate ChangeIterateFunc) error
SnapshotPath() []string SnapshotPath() []string
ChangesAfterCommonSnapshot(snapshotPath, heads []string) ([]*aclpb.RawChange, error) ChangesAfterCommonSnapshot(snapshotPath, heads []string) ([]*aclpb.RawTreeChangeWithId, error)
Storage() storage.TreeStorage Storage() storage.TreeStorage
DebugDump() (string, error) DebugDump() (string, error)
AddContent(ctx context.Context, content SignableChangeContent) (*aclpb.RawChange, error) AddContent(ctx context.Context, content SignableChangeContent) (*aclpb.RawTreeChangeWithId, error)
AddRawChanges(ctx context.Context, changes ...*aclpb.RawChange) (AddResult, error) AddRawChanges(ctx context.Context, changes ...*aclpb.RawTreeChangeWithId) (AddResult, error)
Close() error Close() error
} }
@ -76,13 +74,13 @@ type objectTree struct {
aclList list.ACLList aclList list.ACLList
id string id string
header *aclpb.Header header *aclpb.TreeHeader
tree *Tree tree *Tree
keys map[uint64]*symmetric.Key keys map[uint64]*symmetric.Key
// buffers // buffers
difSnapshotBuf []*aclpb.RawChange difSnapshotBuf []*aclpb.RawTreeChangeWithId
tmpChangesBuf []*Change tmpChangesBuf []*Change
newSnapshotsBuf []*Change newSnapshotsBuf []*Change
notSeenIdxBuf []int notSeenIdxBuf []int
@ -121,65 +119,6 @@ func defaultObjectTreeDeps(
} }
} }
func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
objTree := &objectTree{
treeStorage: deps.treeStorage,
updateListener: deps.updateListener,
treeBuilder: deps.treeBuilder,
validator: deps.validator,
aclList: deps.aclList,
changeBuilder: deps.changeBuilder,
rawChangeLoader: deps.rawChangeLoader,
tree: nil,
keys: make(map[uint64]*symmetric.Key),
tmpChangesBuf: make([]*Change, 0, 10),
difSnapshotBuf: make([]*aclpb.RawChange, 0, 10),
notSeenIdxBuf: make([]int, 0, 10),
newSnapshotsBuf: make([]*Change, 0, 10),
}
err := objTree.rebuildFromStorage(nil)
if err != nil {
return nil, err
}
storageHeads, err := objTree.treeStorage.Heads()
if err != nil {
return nil, err
}
// comparing rebuilt heads with heads in storage
// in theory it can happen that we didn't set heads because the process has crashed
// therefore we want to set them later
if !slice.UnsortedEquals(storageHeads, objTree.tree.Heads()) {
log.With(zap.Strings("storage", storageHeads), zap.Strings("rebuilt", objTree.tree.Heads())).
Errorf("the heads in storage and objTree are different")
err = objTree.treeStorage.SetHeads(objTree.tree.Heads())
if err != nil {
return nil, err
}
}
objTree.id, err = objTree.treeStorage.ID()
if err != nil {
return nil, err
}
objTree.header, err = objTree.treeStorage.Header()
if err != nil {
return nil, err
}
if objTree.updateListener != nil {
objTree.updateListener.Rebuild(objTree)
}
return objTree, nil
}
func BuildObjectTree(treeStorage storage.TreeStorage, listener ObjectTreeUpdateListener, aclList list.ACLList) (ObjectTree, error) {
deps := defaultObjectTreeDeps(treeStorage, listener, aclList)
return buildObjectTree(deps)
}
func (ot *objectTree) rebuildFromStorage(newChanges []*Change) (err error) { func (ot *objectTree) rebuildFromStorage(newChanges []*Change) (err error) {
ot.treeBuilder.Reset() ot.treeBuilder.Reset()
@ -201,7 +140,7 @@ func (ot *objectTree) ID() string {
return ot.id return ot.id
} }
func (ot *objectTree) Header() *aclpb.Header { func (ot *objectTree) Header() *aclpb.TreeHeader {
return ot.header return ot.header
} }
@ -209,7 +148,7 @@ func (ot *objectTree) Storage() storage.TreeStorage {
return ot.treeStorage return ot.treeStorage
} }
func (ot *objectTree) AddContent(ctx context.Context, content SignableChangeContent) (rawChange *aclpb.RawChange, err error) { func (ot *objectTree) AddContent(ctx context.Context, content SignableChangeContent) (rawChange *aclpb.RawTreeChangeWithId, err error) {
defer func() { defer func() {
if err == nil && ot.updateListener != nil { if err == nil && ot.updateListener != nil {
ot.updateListener.Update(ot) ot.updateListener.Update(ot)
@ -258,12 +197,12 @@ func (ot *objectTree) prepareBuilderContent(content SignableChangeContent) (cnt
isSnapshot: content.IsSnapshot, isSnapshot: content.IsSnapshot,
signingKey: content.Key, signingKey: content.Key,
readKey: readKey, readKey: readKey,
content: content.Proto, content: content.Data,
} }
return return
} }
func (ot *objectTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.RawChange) (addResult AddResult, err error) { func (ot *objectTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.RawTreeChangeWithId) (addResult AddResult, err error) {
var mode Mode var mode Mode
mode, addResult, err = ot.addRawChanges(ctx, rawChanges...) mode, addResult, err = ot.addRawChanges(ctx, rawChanges...)
if err != nil { if err != nil {
@ -302,7 +241,7 @@ func (ot *objectTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.Ra
return return
} }
func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*aclpb.RawChange) (mode Mode, addResult AddResult, err error) { func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*aclpb.RawTreeChangeWithId) (mode Mode, addResult AddResult, err error) {
// resetting buffers // resetting buffers
ot.tmpChangesBuf = ot.tmpChangesBuf[:0] ot.tmpChangesBuf = ot.tmpChangesBuf[:0]
ot.notSeenIdxBuf = ot.notSeenIdxBuf[:0] ot.notSeenIdxBuf = ot.notSeenIdxBuf[:0]
@ -329,7 +268,7 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*aclpb.Ra
} }
var change *Change var change *Change
change, err = ot.changeBuilder.ConvertFromRawAndVerify(ch) change, err = ot.changeBuilder.ConvertFromRaw(ch, true)
if err != nil { if err != nil {
return return
} }
@ -354,7 +293,7 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*aclpb.Ra
// returns changes that we added to the tree as attached this round // returns changes that we added to the tree as attached this round
// they can include not only the changes that were added now, // they can include not only the changes that were added now,
// but also the changes that were previously in the tree // but also the changes that were previously in the tree
getAddedChanges := func(toConvert []*Change) (added []*aclpb.RawChange, err error) { getAddedChanges := func(toConvert []*Change) (added []*aclpb.RawTreeChangeWithId, err error) {
alreadyConverted := make(map[*Change]struct{}) alreadyConverted := make(map[*Change]struct{})
// first we see if we have already unmarshalled those changes // first we see if we have already unmarshalled those changes
@ -379,7 +318,7 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*aclpb.Ra
for _, ch := range toConvert { for _, ch := range toConvert {
// if we got some changes that we need to convert to raw // if we got some changes that we need to convert to raw
if _, exists := alreadyConverted[ch]; !exists { if _, exists := alreadyConverted[ch]; !exists {
var raw *aclpb.RawChange var raw *aclpb.RawTreeChangeWithId
raw, err = ot.changeBuilder.BuildRaw(ch) raw, err = ot.changeBuilder.BuildRaw(ch)
if err != nil { if err != nil {
return return
@ -421,7 +360,7 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*aclpb.Ra
ot.rebuildFromStorage(nil) ot.rebuildFromStorage(nil)
return return
} }
var added []*aclpb.RawChange var added []*aclpb.RawTreeChangeWithId
added, err = getAddedChanges(nil) added, err = getAddedChanges(nil)
// we shouldn't get any error in this case // we shouldn't get any error in this case
if err != nil { if err != nil {
@ -457,7 +396,7 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*aclpb.Ra
err = ErrHasInvalidChanges err = ErrHasInvalidChanges
return return
} }
var added []*aclpb.RawChange var added []*aclpb.RawTreeChangeWithId
added, err = getAddedChanges(treeChangesAdded) added, err = getAddedChanges(treeChangesAdded)
if err != nil { if err != nil {
// that means that some unattached changes were somehow corrupted in memory // that means that some unattached changes were somehow corrupted in memory
@ -553,7 +492,7 @@ func (ot *objectTree) SnapshotPath() []string {
return path return path
} }
func (ot *objectTree) ChangesAfterCommonSnapshot(theirPath, theirHeads []string) ([]*aclpb.RawChange, error) { func (ot *objectTree) ChangesAfterCommonSnapshot(theirPath, theirHeads []string) ([]*aclpb.RawTreeChangeWithId, error) {
var ( var (
needFullDocument = len(theirPath) == 0 needFullDocument = len(theirPath) == 0
ourPath = ot.SnapshotPath() ourPath = ot.SnapshotPath()
@ -577,11 +516,11 @@ func (ot *objectTree) ChangesAfterCommonSnapshot(theirPath, theirHeads []string)
} }
} }
func (ot *objectTree) getChangesFromTree(theirHeads []string) (rawChanges []*aclpb.RawChange, err error) { func (ot *objectTree) getChangesFromTree(theirHeads []string) (rawChanges []*aclpb.RawTreeChangeWithId, err error) {
return ot.rawChangeLoader.LoadFromTree(ot.tree, theirHeads) return ot.rawChangeLoader.LoadFromTree(ot.tree, theirHeads)
} }
func (ot *objectTree) getChangesFromDB(commonSnapshot string, theirHeads []string) (rawChanges []*aclpb.RawChange, err error) { func (ot *objectTree) getChangesFromDB(commonSnapshot string, theirHeads []string) (rawChanges []*aclpb.RawTreeChangeWithId, err error) {
return ot.rawChangeLoader.LoadFromStorage(commonSnapshot, ot.tree.headIds, theirHeads) return ot.rawChangeLoader.LoadFromStorage(commonSnapshot, ot.tree.headIds, theirHeads)
} }

View File

@ -15,7 +15,7 @@ import (
type mockChangeCreator struct{} type mockChangeCreator struct{}
func (c *mockChangeCreator) createRaw(id, aclId, snapshotId string, isSnapshot bool, prevIds ...string) *aclpb.RawChange { func (c *mockChangeCreator) createRaw(id, aclId, snapshotId string, isSnapshot bool, prevIds ...string) *aclpb.RawChange {
aclChange := &aclpb.Change{ aclChange := &aclpb.TreeChange{
TreeHeadIds: prevIds, TreeHeadIds: prevIds,
AclHeadId: aclId, AclHeadId: aclId,
SnapshotBaseId: snapshotId, SnapshotBaseId: snapshotId,
@ -23,22 +23,27 @@ func (c *mockChangeCreator) createRaw(id, aclId, snapshotId string, isSnapshot b
IsSnapshot: isSnapshot, IsSnapshot: isSnapshot,
} }
res, _ := aclChange.Marshal() res, _ := aclChange.Marshal()
return &aclpb.RawChange{
raw := &aclpb.RawTreeChange{
Payload: res, Payload: res,
Signature: nil, Signature: nil,
}
rawMarshalled, _ := raw.Marshal()
return &aclpb.RawTreeChangeWithId{
RawChange: rawMarshalled,
Id: id, Id: id,
} }
} }
func (c *mockChangeCreator) createNewTreeStorage(treeId, aclListId, aclHeadId, firstChangeId string) storage.TreeStorage { func (c *mockChangeCreator) createNewTreeStorage(treeId, aclListId, aclHeadId, firstChangeId string) storage.TreeStorage {
firstChange := c.createRaw(firstChangeId, aclHeadId, "", true) firstChange := c.createRaw(firstChangeId, aclHeadId, "", true)
header := &aclpb.Header{ header := &aclpb.TreeHeader{
FirstId: firstChangeId, FirstId: firstChangeId,
AclListId: aclListId, AclId: aclListId,
WorkspaceId: "", TreeHeaderType: aclpb.TreeHeaderType_Object,
DocType: aclpb.Header_DocTree,
} }
treeStorage, _ := storage.NewInMemoryTreeStorage(treeId, header, []string{firstChangeId}, []*aclpb.RawChange{firstChange}) treeStorage, _ := storage.NewInMemoryTreeStorage(treeId, header, []string{firstChangeId}, []*aclpb.RawTreeChangeWithId{firstChange})
return treeStorage return treeStorage
} }

View File

@ -0,0 +1,161 @@
package tree
import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/symmetric"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
"github.com/gogo/protobuf/proto"
"go.uber.org/zap"
)
type ObjectTreeCreatePayload struct {
AccountData *account.AccountData
HeaderData []byte
ChangeData []byte
TreeType aclpb.TreeHeaderType
}
func BuildObjectTree(treeStorage storage.TreeStorage, listener ObjectTreeUpdateListener, aclList list.ACLList) (ObjectTree, error) {
deps := defaultObjectTreeDeps(treeStorage, listener, aclList)
return buildObjectTree(deps)
}
func CreateObjectTree(
payload ObjectTreeCreatePayload,
listener ObjectTreeUpdateListener,
aclList list.ACLList,
createStorage storage.TreeStorageCreatorFunc) (objTree ObjectTree, err error) {
aclList.RLock()
var (
deps = defaultObjectTreeDeps(nil, listener, aclList)
state = aclList.ACLState()
aclId = aclList.ID()
aclHeadId = aclList.Head().Id
readKeyHash = state.CurrentReadKeyHash()
)
readKey, err := state.CurrentReadKey()
aclList.RUnlock()
if err != nil {
return
}
// create first change
cnt := BuilderContent{
treeHeadIds: nil,
aclHeadId: aclHeadId,
snapshotBaseId: "",
currentReadKeyHash: readKeyHash,
isSnapshot: true,
readKey: readKey,
identity: payload.AccountData.Identity,
signingKey: payload.AccountData.SignKey,
content: payload.ChangeData,
}
_, raw, err := deps.changeBuilder.BuildContent(cnt)
if err != nil {
return
}
// create header
header, id, err := createTreeHeaderAndId(
raw,
payload.TreeType,
aclId,
payload.AccountData.Identity,
payload.HeaderData)
if err != nil {
return
}
// create storage
st, err := createStorage(storage.TreeStorageCreatePayload{
TreeId: id,
Header: header,
Changes: []*aclpb.RawTreeChangeWithId{raw},
Heads: []string{raw.Id},
})
if err != nil {
return
}
deps.treeStorage = st
return buildObjectTree(deps)
}
func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
objTree := &objectTree{
treeStorage: deps.treeStorage,
updateListener: deps.updateListener,
treeBuilder: deps.treeBuilder,
validator: deps.validator,
aclList: deps.aclList,
changeBuilder: deps.changeBuilder,
rawChangeLoader: deps.rawChangeLoader,
tree: nil,
keys: make(map[uint64]*symmetric.Key),
tmpChangesBuf: make([]*Change, 0, 10),
difSnapshotBuf: make([]*aclpb.RawTreeChangeWithId, 0, 10),
notSeenIdxBuf: make([]int, 0, 10),
newSnapshotsBuf: make([]*Change, 0, 10),
}
err := objTree.rebuildFromStorage(nil)
if err != nil {
return nil, err
}
storageHeads, err := objTree.treeStorage.Heads()
if err != nil {
return nil, err
}
// comparing rebuilt heads with heads in storage
// in theory it can happen that we didn't set heads because the process has crashed
// therefore we want to set them later
if !slice.UnsortedEquals(storageHeads, objTree.tree.Heads()) {
log.With(zap.Strings("storage", storageHeads), zap.Strings("rebuilt", objTree.tree.Heads())).
Errorf("the heads in storage and objTree are different")
err = objTree.treeStorage.SetHeads(objTree.tree.Heads())
if err != nil {
return nil, err
}
}
objTree.id, err = objTree.treeStorage.ID()
if err != nil {
return nil, err
}
objTree.header, err = objTree.treeStorage.Header()
if err != nil {
return nil, err
}
return objTree, nil
}
func createTreeHeaderAndId(
raw *aclpb.RawTreeChangeWithId,
treeType aclpb.TreeHeaderType,
aclId string,
identity []byte,
headerData []byte) (header *aclpb.TreeHeader, treeId string, err error) {
header = &aclpb.TreeHeader{
FirstId: raw.Id,
TreeHeaderType: treeType,
AclId: aclId,
Identity: identity,
Data: headerData,
}
marshalledHeader, err := proto.Marshal(header)
if err != nil {
return
}
treeId, err = cid.NewCIDFromBytes(marshalledHeader)
return
}

View File

@ -18,7 +18,7 @@ type rawChangeLoader struct {
type rawCacheEntry struct { type rawCacheEntry struct {
change *Change change *Change
rawChange *aclpb.RawChange rawChange *aclpb.RawTreeChangeWithId
position int position int
} }
@ -29,15 +29,15 @@ func newRawChangeLoader(treeStorage storage.TreeStorage, changeBuilder ChangeBui
} }
} }
func (r *rawChangeLoader) LoadFromTree(t *Tree, breakpoints []string) ([]*aclpb.RawChange, error) { func (r *rawChangeLoader) LoadFromTree(t *Tree, breakpoints []string) ([]*aclpb.RawTreeChangeWithId, error) {
var stack []*Change var stack []*Change
for _, h := range t.headIds { for _, h := range t.headIds {
stack = append(stack, t.attached[h]) stack = append(stack, t.attached[h])
} }
convert := func(chs []*Change) (rawChanges []*aclpb.RawChange, err error) { convert := func(chs []*Change) (rawChanges []*aclpb.RawTreeChangeWithId, err error) {
for _, ch := range chs { for _, ch := range chs {
var raw *aclpb.RawChange var raw *aclpb.RawTreeChangeWithId
raw, err = r.changeBuilder.BuildRaw(ch) raw, err = r.changeBuilder.BuildRaw(ch)
if err != nil { if err != nil {
return return
@ -95,7 +95,7 @@ func (r *rawChangeLoader) LoadFromTree(t *Tree, breakpoints []string) ([]*aclpb.
return convert(results) return convert(results)
} }
func (r *rawChangeLoader) LoadFromStorage(commonSnapshot string, heads, breakpoints []string) ([]*aclpb.RawChange, error) { func (r *rawChangeLoader) LoadFromStorage(commonSnapshot string, heads, breakpoints []string) ([]*aclpb.RawTreeChangeWithId, error) {
// resetting cache // resetting cache
r.cache = make(map[string]rawCacheEntry) r.cache = make(map[string]rawCacheEntry)
defer func() { defer func() {
@ -162,7 +162,7 @@ func (r *rawChangeLoader) LoadFromStorage(commonSnapshot string, heads, breakpoi
// preparing first pass // preparing first pass
r.idStack = append(r.idStack, heads...) r.idStack = append(r.idStack, heads...)
var buffer []*aclpb.RawChange var buffer []*aclpb.RawTreeChangeWithId
rootVisited := dfs(commonSnapshot, heads, 0, rootVisited := dfs(commonSnapshot, heads, 0,
func(counter int, mapExists bool) bool { func(counter int, mapExists bool) bool {
@ -203,7 +203,7 @@ func (r *rawChangeLoader) LoadFromStorage(commonSnapshot string, heads, breakpoi
}) })
// discarding visited // discarding visited
buffer = discardFromSlice(buffer, func(change *aclpb.RawChange) bool { buffer = discardFromSlice(buffer, func(change *aclpb.RawTreeChangeWithId) bool {
return change == nil return change == nil
}) })
@ -219,7 +219,7 @@ func (r *rawChangeLoader) loadEntry(id string) (entry rawCacheEntry, err error)
return return
} }
change, err := r.changeBuilder.ConvertFromRaw(rawChange) change, err := r.changeBuilder.ConvertFromRaw(rawChange, false)
if err != nil { if err != nil {
return return
} }

View File

@ -2,12 +2,11 @@ package tree
import ( import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
"github.com/gogo/protobuf/proto"
) )
type SignableChangeContent struct { type SignableChangeContent struct {
Proto proto.Marshaler Data []byte
Key signingkey.PrivKey Key signingkey.PrivKey
Identity string Identity []byte
IsSnapshot bool IsSnapshot bool
} }

View File

@ -0,0 +1,91 @@
package tests
import (
"bytes"
"math/rand"
"testing"
"time"
)
func BenchmarkHashes(b *testing.B) {
genRandomBytes := func() [][]byte {
var res [][]byte
s := rand.NewSource(time.Now().Unix())
r := rand.New(s)
for i := 0; i < 10000; i++ {
var newBytes []byte
for j := 0; j < 64; j++ {
newBytes = append(newBytes, byte(r.Intn(256)))
}
res = append(res, newBytes)
}
return res
}
makeStrings := func(input [][]byte) []string {
var res []string
for _, bytes := range input {
res = append(res, string(bytes))
}
return res
}
res := genRandomBytes()
stringRes := makeStrings(res)
stringMap := map[string]struct{}{}
b.Run("string bytes hash map write", func(b *testing.B) {
stringMap = map[string]struct{}{}
for i := 0; i < b.N; i++ {
for _, bytes := range res {
stringMap[string(bytes)] = struct{}{}
}
}
b.Run("hash map read", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, bytes := range res {
_, _ = stringMap[string(bytes)]
}
}
})
})
b.Run("compare byte slices as strings", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, bytes := range res {
if string(bytes) == string(bytes) {
}
}
}
})
b.Run("compare byte slices", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, bt := range res {
if bytes.Compare(bt, bt) == 0 {
}
}
}
})
b.Run("compare strings", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, st := range stringRes {
if st == st {
}
}
}
})
b.Run("string hash map write", func(b *testing.B) {
stringMap = map[string]struct{}{}
for i := 0; i < b.N; i++ {
for _, str := range stringRes {
stringMap[str] = struct{}{}
}
}
b.Run("hash map read", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, str := range stringRes {
_, _ = stringMap[str]
}
}
})
})
}

View File

@ -129,7 +129,7 @@ func (tb *treeBuilder) loadChange(id string) (ch *Change, err error) {
return nil, err return nil, err
} }
ch, err = tb.builder.ConvertFromRawAndVerify(change) ch, err = tb.builder.ConvertFromRaw(change, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,91 +0,0 @@
package tree
import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
"github.com/gogo/protobuf/proto"
"time"
)
func CreateNewTreeStorage(
acc *account.AccountData,
aclList list.ACLList,
content proto.Marshaler,
create storage.TreeStorageCreatorFunc) (thr storage.TreeStorage, err error) {
state := aclList.ACLState()
change := &aclpb.Change{
AclHeadId: aclList.Head().Id,
CurrentReadKeyHash: state.CurrentReadKeyHash(),
Timestamp: int64(time.Now().Nanosecond()),
Identity: acc.Identity,
IsSnapshot: true,
}
marshalledData, err := content.Marshal()
if err != nil {
return
}
readKey, err := state.CurrentReadKey()
if err != nil {
return
}
encrypted, err := readKey.Encrypt(marshalledData)
if err != nil {
return
}
change.ChangesData = encrypted
fullMarshalledChange, err := proto.Marshal(change)
if err != nil {
return
}
signature, err := acc.SignKey.Sign(fullMarshalledChange)
if err != nil {
return
}
changeId, err := cid.NewCIDFromBytes(fullMarshalledChange)
if err != nil {
return
}
rawChange := &aclpb.RawChange{
Payload: fullMarshalledChange,
Signature: signature,
Id: changeId,
}
header, treeId, err := createTreeHeaderAndId(rawChange, aclpb.Header_DocTree, aclList.ID())
if err != nil {
return
}
return create(storage.TreeStorageCreatePayload{
TreeId: treeId,
Header: header,
Changes: []*aclpb.RawChange{rawChange},
Heads: []string{rawChange.Id},
})
}
func createTreeHeaderAndId(change *aclpb.RawChange, treeType aclpb.HeaderDocType, aclListId string) (header *aclpb.Header, treeId string, err error) {
header = &aclpb.Header{
FirstId: change.Id,
DocType: treeType,
AclListId: aclListId,
}
marshalledHeader, err := proto.Marshal(header)
if err != nil {
return
}
treeId, err = cid.NewCIDFromBytes(marshalledHeader)
return
}

View File

@ -21,7 +21,7 @@ var log = logger.NewNamed("storage").Sugar()
type ImportedACLSyncData struct { type ImportedACLSyncData struct {
Id string Id string
Header *aclpb.Header Header *aclpb.Header
Records []*aclpb.RawRecord Records []*aclpb.RawACLRecord
} }
type Service interface { type Service interface {

View File

@ -48,44 +48,3 @@ message System {
} }
} }
} }
message Sync {
string spaceId = 1;
ContentValue message = 2;
acl.Header treeHeader = 3;
string treeId = 4;
message ContentValue {
oneof value {
HeadUpdate headUpdate = 1;
Full.Request fullSyncRequest = 2;
Full.Response fullSyncResponse = 3;
ACLList aclList = 4;
}
}
message ACLList {
repeated acl.RawRecord records = 1;
}
message HeadUpdate {
repeated string heads = 1;
repeated acl.RawChange changes = 2;
repeated string snapshotPath = 3;
}
message Full {
// here with send the request with all changes we have (we already know sender's snapshot path)
message Request {
repeated string heads = 1;
repeated acl.RawChange changes = 2;
repeated string snapshotPath = 3;
}
message Response {
repeated string heads = 1;
repeated acl.RawChange changes = 2;
repeated string snapshotPath = 3;
}
}
}

File diff suppressed because it is too large Load Diff