WIP proto refactoring
This commit is contained in:
parent
d5244cf6e3
commit
e743e34849
13
Makefile
13
Makefile
@ -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))
|
||||||
|
|||||||
@ -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
@ -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
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
|
||||||
}
|
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
})
|
})
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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")
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
161
pkg/acl/tree/objecttreefactory.go
Normal file
161
pkg/acl/tree/objecttreefactory.go
Normal 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
|
||||||
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
91
pkg/acl/tree/tests/benches_test.go
Normal file
91
pkg/acl/tree/tests/benches_test.go
Normal 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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
|
||||||
}
|
|
||||||
@ -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 {
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
2042
syncproto/sync.pb.go
2042
syncproto/sync.pb.go
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user