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)
|
||||
|
||||
# TODO: folders were changed, so we should update Makefile and protos generation
|
||||
protos:
|
||||
proto:
|
||||
@echo 'Generating protobuf packages (Go)...'
|
||||
# Uncomment if needed
|
||||
@$(eval ROOT_PKG := pkg)
|
||||
@$(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_PLAINTEXT_CHANGES_PATH_PB := $(ROOT_PKG)/acl/testutils/testchanges/testchangepb)
|
||||
@$(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_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_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))
|
||||
$(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_PLAINTEXT_CHANGES_PATH_PB)/protos/*.proto; mv $(P_PLAINTEXT_CHANGES_PATH_PB)/protos/*.go $(P_PLAINTEXT_CHANGES_PATH_PB)
|
||||
$(eval PKGMAP := $$(P_ACL_CHANGES),$$(P_TREE_CHANGES))
|
||||
$(GOGO_START) protoc --gogofaster_out=:. $(P_TEST_CHANGES_PATH_PB)/proto/*.proto
|
||||
$(eval PKGMAP := $$(P_ACL_CHANGES))
|
||||
$(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:
|
||||
@$(eval FLAGS := $$(shell govvv -flags -pkg github.com/anytypeio/go-anytype-infrastructure-experiments/app))
|
||||
|
||||
@ -1,16 +1,17 @@
|
||||
syntax = "proto3";
|
||||
package anySpace;
|
||||
|
||||
option go_package = "common/commonspace/spacesyncproto";
|
||||
import "pkg/acl/aclchanges/aclpb/protos/aclchanges.proto";
|
||||
|
||||
enum ErrCodes {
|
||||
Unexpected = 0;
|
||||
}
|
||||
|
||||
|
||||
service Space {
|
||||
// HeadSync compares all objects and their hashes in a space
|
||||
rpc HeadSync(HeadSyncRequest) returns (HeadSyncResponse);
|
||||
rpc Stream( stream Msg) returns (stream Msg);
|
||||
rpc Stream(stream ObjectSyncMessage) returns (stream ObjectSyncMessage);
|
||||
}
|
||||
|
||||
// TODO: temporary mock message
|
||||
@ -18,8 +19,6 @@ message Msg {
|
||||
string spaceId = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// HeadSyncRange presenting a request for one range
|
||||
message HeadSyncRange {
|
||||
uint64 from = 1;
|
||||
@ -50,3 +49,40 @@ message HeadSyncRequest {
|
||||
message HeadSyncResponse {
|
||||
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
|
||||
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
|
||||
EncKey encryptionkey.PrivKey
|
||||
Decoder keys.Decoder
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -2,147 +2,142 @@ syntax = "proto3";
|
||||
package acl;
|
||||
option go_package = "aclpb";
|
||||
|
||||
message RawChange {
|
||||
// ACL protos
|
||||
|
||||
message RawACLRecord {
|
||||
bytes payload = 1;
|
||||
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 {
|
||||
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 {
|
||||
UserAdd userAdd = 1;
|
||||
UserRemove userRemove = 2;
|
||||
UserPermissionChange userPermissionChange = 3;
|
||||
UserInvite userInvite = 4;
|
||||
UserJoin userJoin = 5;
|
||||
UserConfirm userConfirm = 6;
|
||||
ACLUserAdd userAdd = 1;
|
||||
ACLUserRemove userRemove = 2;
|
||||
ACLUserPermissionChange userPermissionChange = 3;
|
||||
ACLUserInvite userInvite = 4;
|
||||
ACLUserJoin userJoin = 5;
|
||||
ACLUserConfirm userConfirm = 6;
|
||||
}
|
||||
}
|
||||
|
||||
message ACLData {
|
||||
ACLSnapshot aclSnapshot = 1;
|
||||
repeated ACLContentValue aclContent = 2;
|
||||
}
|
||||
|
||||
message ACLSnapshot {
|
||||
// We don't need ACLState as a separate message now, because we simplified the snapshot model
|
||||
ACLState aclState = 1;
|
||||
repeated ACLContentValue aclContent = 1;
|
||||
}
|
||||
|
||||
message ACLState {
|
||||
repeated uint64 readKeyHashes = 1;
|
||||
repeated UserState userStates = 2;
|
||||
map<string, UserInvite> invites = 3; // TODO: later
|
||||
repeated ACLUserState userStates = 2;
|
||||
map<string, ACLUserInvite> invites = 3; // TODO: later
|
||||
// repeated string unconfirmedUsers = 4; // TODO: later
|
||||
}
|
||||
|
||||
message UserState {
|
||||
string identity = 1;
|
||||
message ACLUserState {
|
||||
bytes identity = 1;
|
||||
bytes encryptionKey = 2;
|
||||
repeated bytes encryptedReadKeys = 3; // all read keys that we know
|
||||
UserPermissions permissions = 4;
|
||||
bool IsConfirmed = 5;
|
||||
ACLUserPermissions permissions = 4;
|
||||
bool isConfirmed = 5;
|
||||
}
|
||||
|
||||
// we already know identity and encryptionKey
|
||||
message UserAdd {
|
||||
string identity = 1; // public signing key
|
||||
message ACLUserAdd {
|
||||
bytes identity = 1; // public signing key
|
||||
bytes encryptionKey = 2; // public encryption key
|
||||
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
|
||||
message UserConfirm { // not needed for read permissions
|
||||
string identity = 1; // not needed
|
||||
message ACLUserConfirm { // not needed for read permissions
|
||||
bytes identity = 1; // not needed
|
||||
string userAddId = 2;
|
||||
}
|
||||
|
||||
message UserInvite {
|
||||
message ACLUserInvite {
|
||||
bytes acceptPublicKey = 1;
|
||||
bytes encryptPublicKey = 2;
|
||||
repeated bytes encryptedReadKeys = 3; // all read keys that we know for the user
|
||||
UserPermissions permissions = 4;
|
||||
string InviteId = 5;
|
||||
ACLUserPermissions permissions = 4;
|
||||
string inviteId = 5;
|
||||
}
|
||||
|
||||
message UserJoin {
|
||||
string identity = 1;
|
||||
message ACLUserJoin {
|
||||
bytes identity = 1;
|
||||
bytes encryptionKey = 2;
|
||||
bytes acceptSignature = 3; // sign acceptPublicKey
|
||||
string userInviteId = 4;
|
||||
repeated bytes encryptedReadKeys = 5; // the idea is that user should itself reencrypt the keys with the pub key
|
||||
}
|
||||
|
||||
message UserRemove {
|
||||
string identity = 1;
|
||||
repeated ReadKeyReplace readKeyReplaces = 3; // new read key encrypted for all users
|
||||
message ACLUserRemove {
|
||||
bytes identity = 1;
|
||||
repeated ACLReadKeyReplace readKeyReplaces = 3; // new read key encrypted for all users
|
||||
}
|
||||
|
||||
message ReadKeyReplace {
|
||||
string identity = 1;
|
||||
message ACLReadKeyReplace {
|
||||
bytes identity = 1;
|
||||
bytes encryptionKey = 2;
|
||||
bytes encryptedReadKey = 3;
|
||||
}
|
||||
|
||||
message UserPermissionChange {
|
||||
string identity = 1;
|
||||
UserPermissions permissions = 2;
|
||||
message ACLUserPermissionChange {
|
||||
bytes identity = 1;
|
||||
ACLUserPermissions permissions = 2;
|
||||
}
|
||||
|
||||
enum UserPermissions {
|
||||
enum ACLUserPermissions {
|
||||
Admin = 0;
|
||||
Writer = 1;
|
||||
Reader = 2;
|
||||
Removed = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message Change {
|
||||
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 {
|
||||
message ACLRecord {
|
||||
string prevId = 1;
|
||||
string identity = 2;
|
||||
bytes identity = 2;
|
||||
bytes data = 3;
|
||||
uint64 currentReadKeyHash = 4;
|
||||
int64 timestamp = 5;
|
||||
}
|
||||
|
||||
message Header {
|
||||
message ACLHeader {
|
||||
string firstId = 1;
|
||||
string aclListId = 2;
|
||||
string workspaceId = 3;
|
||||
DocType docType = 4;
|
||||
bytes identity = 2; // the identity of the creator
|
||||
}
|
||||
|
||||
enum DocType {
|
||||
ACL = 0;
|
||||
DocTree = 1;
|
||||
// Tree protos
|
||||
|
||||
message RawTreeChange {
|
||||
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 (
|
||||
"bytes"
|
||||
"errors"
|
||||
"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/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/signingkey"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/symmetric"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"go.uber.org/zap"
|
||||
"hash/fnv"
|
||||
)
|
||||
|
||||
var log = logger.NewNamed("acllist").Sugar()
|
||||
|
||||
var ErrNoSuchUser = errors.New("no such user")
|
||||
var ErrFailedToDecrypt = errors.New("failed to decrypt key")
|
||||
var ErrUserRemoved = errors.New("user was removed from the document")
|
||||
var ErrDocumentForbidden = errors.New("your user was forbidden access to the document")
|
||||
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 {
|
||||
currentReadKeyHash uint64
|
||||
userReadKeys map[uint64]*symmetric.Key
|
||||
userStates map[string]*aclpb.ACLChange_UserState
|
||||
userInvites map[string]*aclpb.ACLChange_UserInvite
|
||||
signingPubKeyDecoder signingkey.PubKeyDecoder
|
||||
userStates map[string]*aclpb.ACLUserState
|
||||
userInvites map[string]*aclpb.ACLUserInvite
|
||||
|
||||
signingPubKeyDecoder keys.Decoder
|
||||
encryptionKey encryptionkey.PrivKey
|
||||
|
||||
identity string
|
||||
permissionsAtRecord map[string][]UserPermissionPair
|
||||
|
||||
keychain *common.Keychain
|
||||
}
|
||||
|
||||
func newACLState(
|
||||
func newACLStateWithIdentity(
|
||||
identity string,
|
||||
encryptionKey encryptionkey.PrivKey,
|
||||
signingPubKeyDecoder signingkey.PubKeyDecoder) *ACLState {
|
||||
decoder keys.Decoder) *ACLState {
|
||||
return &ACLState{
|
||||
identity: identity,
|
||||
encryptionKey: encryptionKey,
|
||||
userReadKeys: make(map[uint64]*symmetric.Key),
|
||||
userStates: make(map[string]*aclpb.ACLChange_UserState),
|
||||
userInvites: make(map[string]*aclpb.ACLChange_UserInvite),
|
||||
signingPubKeyDecoder: signingPubKeyDecoder,
|
||||
userStates: make(map[string]*aclpb.ACLUserState),
|
||||
userInvites: make(map[string]*aclpb.ACLUserInvite),
|
||||
signingPubKeyDecoder: decoder,
|
||||
permissionsAtRecord: make(map[string][]UserPermissionPair),
|
||||
keychain: common.NewKeychain(),
|
||||
}
|
||||
}
|
||||
|
||||
func newACLStateFromSnapshotChange(
|
||||
snapshotChange *aclpb.ACLChange,
|
||||
identity string,
|
||||
encryptionKey encryptionkey.PrivKey,
|
||||
signingPubKeyDecoder signingkey.PubKeyDecoder) (*ACLState, error) {
|
||||
st := &ACLState{
|
||||
identity: identity,
|
||||
encryptionKey: encryptionKey,
|
||||
func newACLState(decoder keys.Decoder) *ACLState {
|
||||
return &ACLState{
|
||||
signingPubKeyDecoder: decoder,
|
||||
userReadKeys: make(map[uint64]*symmetric.Key),
|
||||
userStates: make(map[string]*aclpb.ACLChange_UserState),
|
||||
userInvites: make(map[string]*aclpb.ACLChange_UserInvite),
|
||||
signingPubKeyDecoder: signingPubKeyDecoder,
|
||||
userStates: make(map[string]*aclpb.ACLUserState),
|
||||
userInvites: make(map[string]*aclpb.ACLUserInvite),
|
||||
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 {
|
||||
snapshot := snapshotChange.GetAclData().GetAclSnapshot()
|
||||
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
|
||||
func (st *ACLState) CurrentReadKeyHash() uint64 {
|
||||
return st.currentReadKeyHash
|
||||
}
|
||||
|
||||
userState, exists := st.userStates[st.identity]
|
||||
func (st *ACLState) CurrentReadKey() (*symmetric.Key, error) {
|
||||
key, exists := st.userReadKeys[st.currentReadKeyHash]
|
||||
if !exists {
|
||||
return ErrNoSuchUser
|
||||
return nil, ErrNoReadKey
|
||||
}
|
||||
for _, key := range userState.EncryptedReadKeys {
|
||||
key, hash, err := st.decryptReadKeyAndHash(key)
|
||||
if err != nil {
|
||||
return ErrFailedToDecrypt
|
||||
return key, nil
|
||||
}
|
||||
|
||||
st.userReadKeys[hash] = key
|
||||
func (st *ACLState) UserReadKeys() map[uint64]*symmetric.Key {
|
||||
return st.userReadKeys
|
||||
}
|
||||
st.currentReadKeyHash = snapshotChange.CurrentReadKeyHash
|
||||
if snapshot.GetAclState().GetInvites() != nil {
|
||||
st.userInvites = snapshot.GetAclState().GetInvites()
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
for _, perm := range permissions {
|
||||
if perm.Identity == identity {
|
||||
return perm, nil
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func (st *ACLState) makeSnapshot() *aclpb.ACLChange_ACLSnapshot {
|
||||
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) {
|
||||
func (st *ACLState) applyChangeData(changeData *aclpb.ACLData, hash uint64, identity []byte) (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
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
|
||||
// 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 {
|
||||
// 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
|
||||
return
|
||||
}
|
||||
|
||||
if !st.hasPermission(change.Identity, aclpb.ACLChange_Admin) {
|
||||
err = fmt.Errorf("user %s must have admin permissions", change.Identity)
|
||||
if !st.hasPermission(identity, aclpb.ACLUserPermissions_Admin) {
|
||||
err = fmt.Errorf("user %s must have admin permissions", identity)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, ch := range change.GetAclData().GetAclContent() {
|
||||
for _, ch := range changeData.GetAclContent() {
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -137,8 +192,7 @@ func (st *ACLState) applyChange(change *aclpb.ACLChange) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: remove changeId, because it is not needed
|
||||
func (st *ACLState) applyChangeContent(ch *aclpb.ACLChange_ACLContentValue) error {
|
||||
func (st *ACLState) applyChangeContent(ch *aclpb.ACLContentValue) error {
|
||||
switch {
|
||||
case ch.GetUserPermissionChange() != nil:
|
||||
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 {
|
||||
if _, exists := st.userStates[ch.Identity]; !exists {
|
||||
func (st *ACLState) applyUserPermissionChange(ch *aclpb.ACLUserPermissionChange) error {
|
||||
chIdentity := string(ch.Identity)
|
||||
if _, exists := st.userStates[chIdentity]; !exists {
|
||||
return ErrNoSuchUser
|
||||
}
|
||||
|
||||
st.userStates[ch.Identity].Permissions = ch.Permissions
|
||||
st.userStates[chIdentity].Permissions = ch.Permissions
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *ACLState) applyUserInvite(ch *aclpb.ACLChange_UserInvite) error {
|
||||
func (st *ACLState) applyUserInvite(ch *aclpb.ACLUserInvite) error {
|
||||
st.userInvites[ch.InviteId] = ch
|
||||
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]
|
||||
if !exists {
|
||||
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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
rawSignedId, err := st.signingPubKeyDecoder.DecodeFromStringIntoBytes(ch.Identity)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode signing identity as bytes")
|
||||
}
|
||||
|
||||
res, err := verificationKey.Verify(rawSignedId, signature)
|
||||
res, err := verificationKey.(signingkey.PubKey).Verify(ch.Identity, signature)
|
||||
if err != nil {
|
||||
return fmt.Errorf("verification returned error: %w", err)
|
||||
}
|
||||
if !res {
|
||||
return fmt.Errorf("signature is invalid")
|
||||
return ErrInvalidSignature
|
||||
}
|
||||
|
||||
// if ourselves -> we need to decrypt the read keys
|
||||
if st.identity == ch.Identity {
|
||||
if st.identity == chIdentity {
|
||||
for _, key := range ch.EncryptedReadKeys {
|
||||
key, hash, err := st.decryptReadKeyAndHash(key)
|
||||
if err != nil {
|
||||
@ -214,30 +265,31 @@ func (st *ACLState) applyUserJoin(ch *aclpb.ACLChange_UserJoin) error {
|
||||
}
|
||||
|
||||
// adding user to the list
|
||||
userState := &aclpb.ACLChange_UserState{
|
||||
userState := &aclpb.ACLUserState{
|
||||
Identity: ch.Identity,
|
||||
EncryptionKey: ch.EncryptionKey,
|
||||
EncryptedReadKeys: ch.EncryptedReadKeys,
|
||||
Permissions: invite.Permissions,
|
||||
IsConfirmed: true,
|
||||
}
|
||||
st.userStates[ch.Identity] = userState
|
||||
st.userStates[chIdentity] = userState
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *ACLState) applyUserAdd(ch *aclpb.ACLChange_UserAdd) error {
|
||||
if _, exists := st.userStates[ch.Identity]; exists {
|
||||
func (st *ACLState) applyUserAdd(ch *aclpb.ACLUserAdd) error {
|
||||
chIdentity := string(ch.Identity)
|
||||
if _, exists := st.userStates[chIdentity]; exists {
|
||||
return ErrUserAlreadyExists
|
||||
}
|
||||
|
||||
st.userStates[ch.Identity] = &aclpb.ACLChange_UserState{
|
||||
st.userStates[chIdentity] = &aclpb.ACLUserState{
|
||||
Identity: ch.Identity,
|
||||
EncryptionKey: ch.EncryptionKey,
|
||||
Permissions: ch.Permissions,
|
||||
EncryptedReadKeys: ch.EncryptedReadKeys,
|
||||
}
|
||||
|
||||
if ch.Identity == st.identity {
|
||||
if chIdentity == st.identity {
|
||||
for _, key := range ch.EncryptedReadKeys {
|
||||
key, hash, err := st.decryptReadKeyAndHash(key)
|
||||
if err != nil {
|
||||
@ -251,26 +303,28 @@ func (st *ACLState) applyUserAdd(ch *aclpb.ACLChange_UserAdd) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *ACLState) applyUserRemove(ch *aclpb.ACLChange_UserRemove) error {
|
||||
if ch.Identity == st.identity {
|
||||
func (st *ACLState) applyUserRemove(ch *aclpb.ACLUserRemove) error {
|
||||
chIdentity := string(ch.Identity)
|
||||
if chIdentity == st.identity {
|
||||
return ErrDocumentForbidden
|
||||
}
|
||||
|
||||
if _, exists := st.userStates[ch.Identity]; !exists {
|
||||
if _, exists := st.userStates[chIdentity]; !exists {
|
||||
return ErrNoSuchUser
|
||||
}
|
||||
|
||||
delete(st.userStates, ch.Identity)
|
||||
delete(st.userStates, chIdentity)
|
||||
|
||||
for _, replace := range ch.ReadKeyReplaces {
|
||||
userState, exists := st.userStates[replace.Identity]
|
||||
repIdentity := string(replace.Identity)
|
||||
userState, exists := st.userStates[repIdentity]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
userState.EncryptedReadKeys = append(userState.EncryptedReadKeys, replace.EncryptedReadKey)
|
||||
// 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)
|
||||
if err != nil {
|
||||
return ErrFailedToDecrypt
|
||||
@ -283,12 +337,13 @@ func (st *ACLState) applyUserRemove(ch *aclpb.ACLChange_UserRemove) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *ACLState) applyUserConfirm(ch *aclpb.ACLChange_UserConfirm) error {
|
||||
if _, exists := st.userStates[ch.Identity]; !exists {
|
||||
func (st *ACLState) applyUserConfirm(ch *aclpb.ACLUserConfirm) error {
|
||||
chIdentity := string(ch.Identity)
|
||||
if _, exists := st.userStates[chIdentity]; !exists {
|
||||
return ErrNoSuchUser
|
||||
}
|
||||
|
||||
userState := st.userStates[ch.Identity]
|
||||
userState := st.userStates[chIdentity]
|
||||
userState.IsConfirmed = true
|
||||
return nil
|
||||
}
|
||||
@ -309,8 +364,8 @@ func (st *ACLState) decryptReadKeyAndHash(msg []byte) (*symmetric.Key, uint64, e
|
||||
return key, hasher.Sum64(), nil
|
||||
}
|
||||
|
||||
func (st *ACLState) hasPermission(identity string, permission aclpb.ACLChange_UserPermissions) bool {
|
||||
state, exists := st.userStates[identity]
|
||||
func (st *ACLState) hasPermission(identity []byte, permission aclpb.ACLUserPermissions) bool {
|
||||
state, exists := st.userStates[string(identity)]
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
@ -318,94 +373,17 @@ func (st *ACLState) hasPermission(identity string, permission aclpb.ACLChange_Us
|
||||
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
|
||||
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
|
||||
userAdd := ch.AclData.GetAclContent()[0].GetUserAdd()
|
||||
return ch.AclData.GetAclContent() != nil && userAdd != nil && userAdd.GetIdentity() == ch.Identity
|
||||
userAdd := data.GetAclContent()[0].GetUserAdd()
|
||||
return data.GetAclContent() != nil && userAdd != nil && bytes.Compare(userAdd.GetIdentity(), identity) == 0
|
||||
}
|
||||
|
||||
func (st *ACLState) getPermissionDecreasedUsers(ch *aclpb.ACLChange) (identities []*aclpb.ACLChange_UserPermissionChange) {
|
||||
// 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
|
||||
func (st *ACLState) GetUserStates() map[string]*aclpb.ACLUserState {
|
||||
return st.userStates
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ type aclStateBuilder struct {
|
||||
func newACLStateBuilderWithIdentity(decoder keys.Decoder, accountData *account.AccountData) *aclStateBuilder {
|
||||
return &aclStateBuilder{
|
||||
decoder: decoder,
|
||||
identity: accountData.Identity,
|
||||
identity: string(accountData.Identity),
|
||||
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 (
|
||||
err error
|
||||
state *ACLState
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package acltree
|
||||
package list
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/account"
|
||||
@ -14,39 +14,31 @@ import (
|
||||
type MarshalledChange = []byte
|
||||
|
||||
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
|
||||
SetMakeSnapshot(bool) // TODO: who should decide this? probably ACLTree so we can delete it
|
||||
}
|
||||
|
||||
type ChangeBuilder interface {
|
||||
ACLChangeBuilder
|
||||
AddChangeContent(marshaler proto.Marshaler) // user code should be responsible for making regular snapshots
|
||||
}
|
||||
|
||||
type changeBuilder struct {
|
||||
type aclChangeBuilder struct {
|
||||
aclState *ACLState
|
||||
tree *Tree
|
||||
list ACLList
|
||||
acc *account.AccountData
|
||||
|
||||
aclData *aclpb.ACLChange_ACLData
|
||||
changeContent proto.Marshaler
|
||||
aclData *aclpb.ACLData
|
||||
id string
|
||||
makeSnapshot bool
|
||||
readKey *symmetric.Key
|
||||
readKeyHash uint64
|
||||
}
|
||||
|
||||
func newChangeBuilder() *changeBuilder {
|
||||
return &changeBuilder{}
|
||||
func newACLChangeBuilder() *aclChangeBuilder {
|
||||
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.tree = tree
|
||||
c.list = list
|
||||
c.acc = acc
|
||||
|
||||
c.aclData = &aclpb.ACLChange_ACLData{}
|
||||
c.aclData = &aclpb.ACLData{}
|
||||
// setting read key for further encryption etc
|
||||
if state.currentReadKeyHash == 0 {
|
||||
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
|
||||
}
|
||||
|
||||
func (c *changeBuilder) SetMakeSnapshot(b bool) {
|
||||
c.makeSnapshot = b
|
||||
}
|
||||
|
||||
func (c *changeBuilder) UserAdd(identity string, encryptionKey encryptionkey.PubKey, permissions aclpb.ACLChange_UserPermissions) error {
|
||||
func (c *aclChangeBuilder) UserAdd(identity string, encryptionKey encryptionkey.PubKey, permissions aclpb.ACLUserPermissions) error {
|
||||
var allKeys []*symmetric.Key
|
||||
if c.aclState.currentReadKeyHash != 0 {
|
||||
for _, key := range c.aclState.userReadKeys {
|
||||
@ -91,10 +79,10 @@ func (c *changeBuilder) UserAdd(identity string, encryptionKey encryptionkey.Pub
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ch := &aclpb.ACLChange_ACLContentValue{
|
||||
Value: &aclpb.ACLChange_ACLContent_Value_UserAdd{
|
||||
UserAdd: &aclpb.ACLChange_UserAdd{
|
||||
Identity: identity,
|
||||
ch := &aclpb.ACLContentValue{
|
||||
Value: &aclpb.ACLContentValue_UserAdd{
|
||||
UserAdd: &aclpb.ACLUserAdd{
|
||||
Identity: []byte(identity),
|
||||
EncryptionKey: rawKey,
|
||||
EncryptedReadKeys: encryptedKeys,
|
||||
Permissions: permissions,
|
||||
@ -105,41 +93,25 @@ func (c *changeBuilder) UserAdd(identity string, encryptionKey encryptionkey.Pub
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *changeBuilder) BuildAndApply() (*Change, []byte, error) {
|
||||
aclChange := &aclpb.ACLChange{
|
||||
TreeHeadIds: c.tree.Heads(),
|
||||
AclHeadIds: c.tree.ACLHeads(),
|
||||
SnapshotBaseId: c.tree.RootId(),
|
||||
AclData: c.aclData,
|
||||
func (c *aclChangeBuilder) BuildAndApply() (*ACLRecord, []byte, error) {
|
||||
aclRecord := &aclpb.ACLRecord{
|
||||
PrevId: c.list.Head().Id,
|
||||
CurrentReadKeyHash: c.readKeyHash,
|
||||
Timestamp: int64(time.Now().Nanosecond()),
|
||||
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 {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if c.makeSnapshot {
|
||||
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)
|
||||
fullMarshalledChange, err := proto.Marshal(aclRecord)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -151,13 +123,9 @@ func (c *changeBuilder) BuildAndApply() (*Change, []byte, error) {
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ch := NewChange(id, aclChange)
|
||||
ch.DecryptedDocumentChange = marshalled
|
||||
ch := NewRecord(id, aclRecord)
|
||||
ch.Model = c.aclData
|
||||
ch.Sign = signature
|
||||
|
||||
return ch, fullMarshalledChange, nil
|
||||
}
|
||||
|
||||
func (c *changeBuilder) AddChangeContent(marshaler proto.Marshaler) {
|
||||
c.changeContent = marshaler
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type IterFunc = func(record *Record) (IsContinue bool)
|
||||
type IterFunc = func(record *ACLRecord) (IsContinue bool)
|
||||
|
||||
var ErrIncorrectCID = errors.New("incorrect CID")
|
||||
|
||||
@ -26,20 +26,20 @@ type RWLocker interface {
|
||||
type ACLList interface {
|
||||
RWLocker
|
||||
ID() string
|
||||
Header() *aclpb.Header
|
||||
Records() []*Record
|
||||
Header() *aclpb.ACLHeader
|
||||
Records() []*ACLRecord
|
||||
ACLState() *ACLState
|
||||
IsAfter(first string, second string) (bool, error)
|
||||
Head() *Record
|
||||
Get(id string) (*Record, error)
|
||||
Head() *ACLRecord
|
||||
Get(id string) (*ACLRecord, error)
|
||||
Iterate(iterFunc IterFunc)
|
||||
IterateFrom(startId string, iterFunc IterFunc)
|
||||
Close() (err error)
|
||||
}
|
||||
|
||||
type aclList struct {
|
||||
header *aclpb.Header
|
||||
records []*Record
|
||||
header *aclpb.ACLHeader
|
||||
records []*ACLRecord
|
||||
indexes map[string]int
|
||||
id string
|
||||
|
||||
@ -84,7 +84,7 @@ func buildWithACLStateBuilder(builder *aclStateBuilder, storage storage.ListStor
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
records := []*Record{record}
|
||||
records := []*ACLRecord{record}
|
||||
|
||||
for record.Content.PrevId != "" {
|
||||
rawRecord, err = storage.GetRawRecord(context.Background(), record.Content.PrevId)
|
||||
@ -131,7 +131,7 @@ func buildWithACLStateBuilder(builder *aclStateBuilder, storage storage.ListStor
|
||||
return
|
||||
}
|
||||
|
||||
func (a *aclList) Records() []*Record {
|
||||
func (a *aclList) Records() []*ACLRecord {
|
||||
return a.records
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ func (a *aclList) ID() string {
|
||||
return a.id
|
||||
}
|
||||
|
||||
func (a *aclList) Header() *aclpb.Header {
|
||||
func (a *aclList) Header() *aclpb.ACLHeader {
|
||||
return a.header
|
||||
}
|
||||
|
||||
@ -156,11 +156,11 @@ func (a *aclList) IsAfter(first string, second string) (bool, error) {
|
||||
return firstRec >= secondRec, nil
|
||||
}
|
||||
|
||||
func (a *aclList) Head() *Record {
|
||||
func (a *aclList) Head() *ACLRecord {
|
||||
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]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no such record")
|
||||
@ -192,8 +192,8 @@ func (a *aclList) Close() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyRecord(keychain *common.Keychain, rawRecord *aclpb.RawRecord, record *Record) (err error) {
|
||||
identityKey, err := keychain.GetOrAdd(record.Content.Identity)
|
||||
func verifyRecord(keychain *common.Keychain, rawRecord *aclpb.RawACLRecord, record *ACLRecord) (err error) {
|
||||
identityKey, err := keychain.GetOrAdd(record.Identity)
|
||||
if err != nil {
|
||||
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, aclList.Head().Content.CurrentReadKeyHash, aclList.ACLState().CurrentReadKeyHash())
|
||||
|
||||
var records []*Record
|
||||
aclList.Iterate(func(record *Record) (IsContinue bool) {
|
||||
var records []*ACLRecord
|
||||
aclList.Iterate(func(record *ACLRecord) (IsContinue bool) {
|
||||
records = append(records, record)
|
||||
return true
|
||||
})
|
||||
@ -69,8 +69,8 @@ func TestAclList_ACLState_UserJoinAndRemove(t *testing.T) {
|
||||
_, exists := aclList.ACLState().GetUserStates()[idB]
|
||||
assert.Equal(t, false, exists)
|
||||
|
||||
var records []*Record
|
||||
aclList.Iterate(func(record *Record) (IsContinue bool) {
|
||||
var records []*ACLRecord
|
||||
aclList.Iterate(func(record *ACLRecord) (IsContinue bool) {
|
||||
records = append(records, record)
|
||||
return true
|
||||
})
|
||||
|
||||
@ -5,30 +5,33 @@ import (
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type Record struct {
|
||||
type ACLRecord struct {
|
||||
Id string
|
||||
Content *aclpb.Record
|
||||
Content *aclpb.ACLRecord
|
||||
Identity string
|
||||
Model interface{}
|
||||
Sign []byte
|
||||
}
|
||||
|
||||
func NewRecord(id string, aclRecord *aclpb.Record) *Record {
|
||||
return &Record{
|
||||
func NewRecord(id string, aclRecord *aclpb.ACLRecord) *ACLRecord {
|
||||
return &ACLRecord{
|
||||
Id: id,
|
||||
Content: aclRecord,
|
||||
Identity: string(aclRecord.Identity),
|
||||
}
|
||||
}
|
||||
|
||||
func NewFromRawRecord(rawRec *aclpb.RawRecord) (*Record, error) {
|
||||
aclRec := &aclpb.Record{}
|
||||
func NewFromRawRecord(rawRec *aclpb.RawACLRecord) (*ACLRecord, error) {
|
||||
aclRec := &aclpb.ACLRecord{}
|
||||
err := proto.Unmarshal(rawRec.Payload, aclRec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Record{
|
||||
return &ACLRecord{
|
||||
Id: rawRec.Id,
|
||||
Content: aclRec,
|
||||
Sign: rawRec.Signature,
|
||||
Identity: string(aclRec.Identity),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -8,8 +8,8 @@ import (
|
||||
)
|
||||
|
||||
type inMemoryACLListStorage struct {
|
||||
header *aclpb.Header
|
||||
records []*aclpb.RawRecord
|
||||
header *aclpb.ACLHeader
|
||||
records []*aclpb.RawACLRecord
|
||||
|
||||
id string
|
||||
|
||||
@ -18,8 +18,8 @@ type inMemoryACLListStorage struct {
|
||||
|
||||
func NewInMemoryACLListStorage(
|
||||
id string,
|
||||
header *aclpb.Header,
|
||||
records []*aclpb.RawRecord) (ListStorage, error) {
|
||||
header *aclpb.ACLHeader,
|
||||
records []*aclpb.RawACLRecord) (ListStorage, error) {
|
||||
return &inMemoryACLListStorage{
|
||||
id: id,
|
||||
header: header,
|
||||
@ -28,19 +28,19 @@ func NewInMemoryACLListStorage(
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (i *inMemoryACLListStorage) Header() (*aclpb.Header, error) {
|
||||
func (i *inMemoryACLListStorage) Header() (*aclpb.ACLHeader, error) {
|
||||
i.RLock()
|
||||
defer i.RUnlock()
|
||||
return i.header, nil
|
||||
}
|
||||
|
||||
func (i *inMemoryACLListStorage) Head() (*aclpb.RawRecord, error) {
|
||||
func (i *inMemoryACLListStorage) Head() (*aclpb.RawACLRecord, error) {
|
||||
i.RLock()
|
||||
defer i.RUnlock()
|
||||
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()
|
||||
defer i.RUnlock()
|
||||
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")
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
@ -63,19 +63,19 @@ func (i *inMemoryACLListStorage) ID() (string, error) {
|
||||
|
||||
type inMemoryTreeStorage struct {
|
||||
id string
|
||||
header *aclpb.Header
|
||||
header *aclpb.TreeHeader
|
||||
heads []string
|
||||
changes map[string]*aclpb.RawChange
|
||||
changes map[string]*aclpb.RawTreeChangeWithId
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func NewInMemoryTreeStorage(
|
||||
treeId string,
|
||||
header *aclpb.Header,
|
||||
header *aclpb.TreeHeader,
|
||||
heads []string,
|
||||
changes []*aclpb.RawChange) (TreeStorage, error) {
|
||||
allChanges := make(map[string]*aclpb.RawChange)
|
||||
changes []*aclpb.RawTreeChangeWithId) (TreeStorage, error) {
|
||||
allChanges := make(map[string]*aclpb.RawTreeChangeWithId)
|
||||
for _, ch := range changes {
|
||||
allChanges[ch.Id] = ch
|
||||
}
|
||||
@ -95,7 +95,7 @@ func (t *inMemoryTreeStorage) ID() (string, error) {
|
||||
return t.id, nil
|
||||
}
|
||||
|
||||
func (t *inMemoryTreeStorage) Header() (*aclpb.Header, error) {
|
||||
func (t *inMemoryTreeStorage) Header() (*aclpb.TreeHeader, error) {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
return t.header, nil
|
||||
@ -118,7 +118,7 @@ func (t *inMemoryTreeStorage) SetHeads(heads []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *inMemoryTreeStorage) AddRawChange(change *aclpb.RawChange) error {
|
||||
func (t *inMemoryTreeStorage) AddRawChange(change *aclpb.RawTreeChangeWithId) error {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
// TODO: better to do deep copy
|
||||
@ -126,7 +126,7 @@ func (t *inMemoryTreeStorage) AddRawChange(change *aclpb.RawChange) error {
|
||||
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()
|
||||
defer t.RUnlock()
|
||||
if res, exists := t.changes[changeId]; exists {
|
||||
|
||||
@ -7,8 +7,8 @@ import (
|
||||
|
||||
type ListStorage interface {
|
||||
Storage
|
||||
Head() (*aclpb.RawRecord, error)
|
||||
Head() (*aclpb.RawACLRecord, error)
|
||||
|
||||
GetRawRecord(ctx context.Context, id string) (*aclpb.RawRecord, error)
|
||||
AddRawRecord(ctx context.Context, rec *aclpb.RawRecord) error
|
||||
GetRawRecord(ctx context.Context, id string) (*aclpb.RawACLRecord, error)
|
||||
AddRawRecord(ctx context.Context, rec *aclpb.RawACLRecord) error
|
||||
}
|
||||
|
||||
@ -9,15 +9,15 @@ var ErrUnknownTreeId = errors.New("tree does not exist")
|
||||
|
||||
type TreeStorageCreatePayload struct {
|
||||
TreeId string
|
||||
Header *aclpb.Header
|
||||
Changes []*aclpb.RawChange
|
||||
Header *aclpb.TreeHeader
|
||||
Changes []*aclpb.RawTreeChangeWithId
|
||||
Heads []string
|
||||
}
|
||||
|
||||
type ACLListStorageCreatePayload struct {
|
||||
ListId string
|
||||
Header *aclpb.Header
|
||||
Records []*aclpb.RawRecord
|
||||
Header *aclpb.ACLHeader
|
||||
Records []*aclpb.RawACLRecord
|
||||
}
|
||||
|
||||
type Provider interface {
|
||||
|
||||
@ -10,8 +10,8 @@ type TreeStorage interface {
|
||||
Heads() ([]string, error)
|
||||
SetHeads(heads []string) error
|
||||
|
||||
AddRawChange(change *aclpb.RawChange) error
|
||||
GetRawChange(ctx context.Context, recordID string) (*aclpb.RawChange, error)
|
||||
AddRawChange(change *aclpb.RawTreeChangeWithId) error
|
||||
GetRawChange(ctx context.Context, recordID string) (*aclpb.RawTreeChangeWithId, error)
|
||||
}
|
||||
|
||||
type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error)
|
||||
|
||||
@ -19,8 +19,8 @@ import (
|
||||
|
||||
type ACLListStorageBuilder struct {
|
||||
aclList string
|
||||
records []*aclpb.Record
|
||||
rawRecords []*aclpb.RawRecord
|
||||
records []*aclpb.ACLRecord
|
||||
rawRecords []*aclpb.RawACLRecord
|
||||
indexes map[string]int
|
||||
keychain *Keychain
|
||||
header *aclpb.Header
|
||||
@ -29,7 +29,7 @@ type ACLListStorageBuilder struct {
|
||||
|
||||
func NewACLListStorageBuilder(keychain *Keychain) *ACLListStorageBuilder {
|
||||
return &ACLListStorageBuilder{
|
||||
records: make([]*aclpb.Record, 0),
|
||||
records: make([]*aclpb.ACLRecord, 0),
|
||||
indexes: make(map[string]int),
|
||||
keychain: keychain,
|
||||
}
|
||||
@ -58,7 +58,7 @@ func NewACLListStorageBuilderFromFile(file string) (*ACLListStorageBuilder, erro
|
||||
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)
|
||||
if err != nil {
|
||||
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)
|
||||
|
||||
return &aclpb.RawRecord{
|
||||
return &aclpb.RawACLRecord{
|
||||
Payload: aclMarshaled,
|
||||
Signature: signature,
|
||||
Id: id,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) getRecord(idx int) *aclpb.RawRecord {
|
||||
func (t *ACLListStorageBuilder) getRecord(idx int) *aclpb.RawACLRecord {
|
||||
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
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ func (t *ACLListStorageBuilder) Header() (*aclpb.Header, error) {
|
||||
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]
|
||||
if !ok {
|
||||
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
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
@ -106,7 +106,7 @@ func (t *ACLListStorageBuilder) ID() (string, error) {
|
||||
return t.id, nil
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) GetRawRecords() []*aclpb.RawRecord {
|
||||
func (t *ACLListStorageBuilder) GetRawRecords() []*aclpb.RawACLRecord {
|
||||
return t.rawRecords
|
||||
}
|
||||
|
||||
@ -132,7 +132,7 @@ func (t *ACLListStorageBuilder) Parse(tree *YMLList) {
|
||||
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)
|
||||
var aclChangeContents []*aclpb.ACLChangeACLContentValue
|
||||
for _, ch := range rec.AclChanges {
|
||||
@ -144,7 +144,7 @@ func (t *ACLListStorageBuilder) parseRecord(rec *Record, prevId string) *aclpb.R
|
||||
}
|
||||
bytes, _ := data.Marshal()
|
||||
|
||||
return &aclpb.Record{
|
||||
return &aclpb.ACLRecord{
|
||||
PrevId: prevId,
|
||||
Identity: t.keychain.GetIdentity(rec.Identity),
|
||||
Data: bytes,
|
||||
@ -163,7 +163,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL
|
||||
|
||||
convCh = &aclpb.ACLChangeACLContentValue{
|
||||
Value: &aclpb.ACLChangeACLContentValueValueOfUserAdd{
|
||||
UserAdd: &aclpb.ACLChangeUserAdd{
|
||||
UserAdd: &aclpb.ACLUserPermissionsAdd{
|
||||
Identity: t.keychain.GetIdentity(add.Identity),
|
||||
EncryptionKey: rawKey,
|
||||
EncryptedReadKeys: t.encryptReadKeys(add.EncryptedReadKeys, encKey),
|
||||
@ -187,7 +187,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL
|
||||
|
||||
convCh = &aclpb.ACLChangeACLContentValue{
|
||||
Value: &aclpb.ACLChangeACLContentValueValueOfUserJoin{
|
||||
UserJoin: &aclpb.ACLChangeUserJoin{
|
||||
UserJoin: &aclpb.ACLUserPermissionsJoin{
|
||||
Identity: t.keychain.GetIdentity(join.Identity),
|
||||
EncryptionKey: rawKey,
|
||||
AcceptSignature: signature,
|
||||
@ -205,7 +205,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL
|
||||
|
||||
convCh = &aclpb.ACLChangeACLContentValue{
|
||||
Value: &aclpb.ACLChangeACLContentValueValueOfUserInvite{
|
||||
UserInvite: &aclpb.ACLChangeUserInvite{
|
||||
UserInvite: &aclpb.ACLUserPermissionsInvite{
|
||||
AcceptPublicKey: rawAcceptKey,
|
||||
EncryptPublicKey: rawEncKey,
|
||||
EncryptedReadKeys: t.encryptReadKeys(invite.EncryptedReadKeys, encKey),
|
||||
@ -219,7 +219,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL
|
||||
|
||||
convCh = &aclpb.ACLChangeACLContentValue{
|
||||
Value: &aclpb.ACLChangeACLContentValueValueOfUserConfirm{
|
||||
UserConfirm: &aclpb.ACLChangeUserConfirm{
|
||||
UserConfirm: &aclpb.ACLUserPermissionsConfirm{
|
||||
Identity: t.keychain.GetIdentity(confirm.Identity),
|
||||
UserAddId: confirm.UserAddId,
|
||||
},
|
||||
@ -230,7 +230,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL
|
||||
|
||||
convCh = &aclpb.ACLChangeACLContentValue{
|
||||
Value: &aclpb.ACLChangeACLContentValueValueOfUserPermissionChange{
|
||||
UserPermissionChange: &aclpb.ACLChangeUserPermissionChange{
|
||||
UserPermissionChange: &aclpb.ACLUserPermissionsPermissionChange{
|
||||
Identity: t.keychain.GetIdentity(permissionChange.Identity),
|
||||
Permissions: t.convertPermission(permissionChange.Permission),
|
||||
},
|
||||
@ -259,7 +259,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclpb.ACL
|
||||
|
||||
convCh = &aclpb.ACLChangeACLContentValue{
|
||||
Value: &aclpb.ACLChangeACLContentValueValueOfUserRemove{
|
||||
UserRemove: &aclpb.ACLChangeUserRemove{
|
||||
UserRemove: &aclpb.ACLUserPermissionsRemove{
|
||||
Identity: t.keychain.GetIdentity(remove.RemovedIdentity),
|
||||
ReadKeyReplaces: replaces,
|
||||
},
|
||||
@ -286,7 +286,7 @@ func (t *ACLListStorageBuilder) encryptReadKeys(keys []string, encKey encryption
|
||||
return
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) convertPermission(perm string) aclpb.ACLChangeUserPermissions {
|
||||
func (t *ACLListStorageBuilder) convertPermission(perm string) aclpb.ACLUserPermissions {
|
||||
switch perm {
|
||||
case "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-- {
|
||||
err = f(t.records[i], t.rawRecords[i].Id)
|
||||
if err != nil {
|
||||
|
||||
@ -33,7 +33,7 @@ func (t *ACLListStorageBuilder) Graph() (string, error) {
|
||||
graph.SetDir(true)
|
||||
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"
|
||||
|
||||
var chSymbs []string
|
||||
@ -92,7 +92,7 @@ func (t *ACLListStorageBuilder) Graph() (string, error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var addLinks = func(r *aclpb.Record, id string) error {
|
||||
var addLinks = func(r *aclpb.ACLRecord, id string) error {
|
||||
if r.PrevId == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// 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 (
|
||||
fmt "fmt"
|
||||
@ -29,7 +29,7 @@ func (m *PlainTextChange) Reset() { *m = PlainTextChange{} }
|
||||
func (m *PlainTextChange) String() string { return proto.CompactTextString(m) }
|
||||
func (*PlainTextChange) ProtoMessage() {}
|
||||
func (*PlainTextChange) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c07268f9f08f2beb, []int{0}
|
||||
return fileDescriptor_37f33c266ada4318, []int{0}
|
||||
}
|
||||
func (m *PlainTextChange) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -60,7 +60,6 @@ var xxx_messageInfo_PlainTextChange proto.InternalMessageInfo
|
||||
|
||||
type PlainTextChange_Content struct {
|
||||
// Types that are valid to be assigned to Value:
|
||||
//
|
||||
// *PlainTextChange_Content_TextAppend
|
||||
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 (*PlainTextChange_Content) ProtoMessage() {}
|
||||
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 {
|
||||
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 (*PlainTextChange_TextAppend) ProtoMessage() {}
|
||||
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 {
|
||||
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 (*PlainTextChange_Snapshot) ProtoMessage() {}
|
||||
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 {
|
||||
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 (*PlainTextChange_Data) ProtoMessage() {}
|
||||
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 {
|
||||
return m.Unmarshal(b)
|
||||
@ -280,29 +279,28 @@ 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{
|
||||
// 278 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xf2, 0x2e, 0xc8, 0x4e, 0xd7,
|
||||
var fileDescriptor_37f33c266ada4318 = []byte{
|
||||
// 266 bytes of a gzipped FileDescriptorProto
|
||||
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,
|
||||
0x33, 0x12, 0xf3, 0xd2, 0x53, 0x91, 0xd9, 0x05, 0x49, 0xfa, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x10,
|
||||
0xb1, 0x94, 0xfc, 0xe4, 0xd2, 0xdc, 0xd4, 0x3c, 0x98, 0x3a, 0x3d, 0xb0, 0x94, 0x10, 0x7b, 0x62,
|
||||
0x5e, 0x65, 0x49, 0x65, 0x41, 0xaa, 0xd2, 0x26, 0x26, 0x2e, 0xfe, 0x80, 0x9c, 0xc4, 0xcc, 0xbc,
|
||||
0x90, 0xd4, 0x8a, 0x12, 0x67, 0xb0, 0x1a, 0xa9, 0x48, 0x2e, 0x76, 0xe7, 0xfc, 0xbc, 0x92, 0xd4,
|
||||
0xbc, 0x12, 0x21, 0x57, 0x2e, 0xae, 0x92, 0xd4, 0x8a, 0x12, 0xc7, 0x82, 0x82, 0xd4, 0xbc, 0x14,
|
||||
0x09, 0x46, 0x05, 0x46, 0x0d, 0x6e, 0x23, 0x65, 0x3d, 0xa8, 0x66, 0x3d, 0x34, 0x8d, 0x7a, 0x21,
|
||||
0x70, 0xa5, 0x1e, 0x0c, 0x41, 0x48, 0x1a, 0x9d, 0xd8, 0xb9, 0x58, 0xcb, 0x12, 0x73, 0x4a, 0x53,
|
||||
0xa5, 0x14, 0xb8, 0xb8, 0x10, 0x8a, 0x84, 0x84, 0xb8, 0x58, 0x40, 0x8a, 0xc0, 0xe6, 0x72, 0x06,
|
||||
0x81, 0xd9, 0x52, 0x72, 0x5c, 0x1c, 0xc1, 0x79, 0x89, 0x05, 0xc5, 0x19, 0xf9, 0x25, 0x58, 0xe5,
|
||||
0x1b, 0x19, 0xb9, 0x58, 0x5c, 0x12, 0x4b, 0x12, 0x85, 0xac, 0xb8, 0xd8, 0x93, 0x21, 0xae, 0x94,
|
||||
0x60, 0x54, 0x60, 0xd6, 0xe0, 0x36, 0x52, 0xc0, 0xe9, 0x2e, 0xa8, 0x6f, 0x82, 0x60, 0x1a, 0x84,
|
||||
0x6c, 0xb9, 0x38, 0x8a, 0xa1, 0x96, 0x48, 0x30, 0x81, 0x3d, 0xa5, 0x88, 0x53, 0x33, 0xcc, 0x35,
|
||||
0x41, 0x70, 0x2d, 0x4e, 0x6a, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91,
|
||||
0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0xc5,
|
||||
0x83, 0x1c, 0x0d, 0x49, 0x6c, 0xe0, 0xc0, 0x36, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xfd, 0x73,
|
||||
0xe1, 0xf2, 0xbb, 0x01, 0x00, 0x00,
|
||||
0x33, 0x12, 0xf3, 0xd2, 0x53, 0x8b, 0xf5, 0x0b, 0x8a, 0xf2, 0x4b, 0xf2, 0xc1, 0x22, 0x7a, 0x60,
|
||||
0xa6, 0x10, 0x7b, 0x62, 0x5e, 0x65, 0x49, 0x65, 0x41, 0xaa, 0xd2, 0x26, 0x26, 0x2e, 0xfe, 0x80,
|
||||
0x9c, 0xc4, 0xcc, 0xbc, 0x90, 0xd4, 0x8a, 0x12, 0x67, 0xb0, 0x72, 0xa9, 0x48, 0x2e, 0x76, 0xe7,
|
||||
0xfc, 0xbc, 0x92, 0xd4, 0xbc, 0x12, 0x21, 0x57, 0x2e, 0xae, 0x92, 0xd4, 0x8a, 0x12, 0xc7, 0x82,
|
||||
0x82, 0xd4, 0xbc, 0x14, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x6e, 0x23, 0x65, 0x3d, 0xa8, 0x66, 0x3d,
|
||||
0x34, 0x8d, 0x7a, 0x21, 0x70, 0xa5, 0x1e, 0x0c, 0x41, 0x48, 0x1a, 0x9d, 0xd8, 0xb9, 0x58, 0xcb,
|
||||
0x12, 0x73, 0x4a, 0x53, 0xa5, 0x14, 0xb8, 0xb8, 0x10, 0x8a, 0x84, 0x84, 0xb8, 0x58, 0x40, 0x8a,
|
||||
0xc0, 0xe6, 0x72, 0x06, 0x81, 0xd9, 0x52, 0x72, 0x5c, 0x1c, 0xc1, 0x79, 0x89, 0x05, 0xc5, 0x19,
|
||||
0xf9, 0x25, 0x58, 0xe5, 0x1b, 0x19, 0xb9, 0x58, 0x5c, 0x12, 0x4b, 0x12, 0x85, 0xac, 0xb8, 0xd8,
|
||||
0x93, 0x21, 0xae, 0x94, 0x60, 0x54, 0x60, 0xd6, 0xe0, 0x36, 0x52, 0xc0, 0xe9, 0x2e, 0xa8, 0x6f,
|
||||
0x82, 0x60, 0x1a, 0x84, 0x6c, 0xb9, 0x38, 0x8a, 0xa1, 0x96, 0x48, 0x30, 0x81, 0x3d, 0xa5, 0x88,
|
||||
0x53, 0x33, 0xcc, 0x35, 0x41, 0x70, 0x2d, 0x4e, 0xaa, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24,
|
||||
0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78,
|
||||
0x2c, 0xc7, 0x10, 0xc5, 0x8d, 0x14, 0xea, 0x49, 0x6c, 0xe0, 0xb0, 0x36, 0x06, 0x04, 0x00, 0x00,
|
||||
0xff, 0xff, 0xf8, 0x8c, 0x6a, 0x1d, 0x9d, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *PlainTextChange) Marshal() (dAtA []byte, err error) {
|
||||
@ -374,7 +372,7 @@ func (m *PlainTextChange_Content_TextAppend) MarshalToSizedBuffer(dAtA []byte) (
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintTestdocumentchanges(dAtA, i, uint64(size))
|
||||
i = encodeVarintTest(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
@ -404,7 +402,7 @@ func (m *PlainTextChange_TextAppend) MarshalToSizedBuffer(dAtA []byte) (int, err
|
||||
if len(m.Text) > 0 {
|
||||
i -= len(m.Text)
|
||||
copy(dAtA[i:], m.Text)
|
||||
i = encodeVarintTestdocumentchanges(dAtA, i, uint64(len(m.Text)))
|
||||
i = encodeVarintTest(dAtA, i, uint64(len(m.Text)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
@ -434,7 +432,7 @@ func (m *PlainTextChange_Snapshot) MarshalToSizedBuffer(dAtA []byte) (int, error
|
||||
if len(m.Text) > 0 {
|
||||
i -= len(m.Text)
|
||||
copy(dAtA[i:], m.Text)
|
||||
i = encodeVarintTestdocumentchanges(dAtA, i, uint64(len(m.Text)))
|
||||
i = encodeVarintTest(dAtA, i, uint64(len(m.Text)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
@ -468,7 +466,7 @@ func (m *PlainTextChange_Data) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintTestdocumentchanges(dAtA, i, uint64(size))
|
||||
i = encodeVarintTest(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
@ -481,7 +479,7 @@ func (m *PlainTextChange_Data) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintTestdocumentchanges(dAtA, i, uint64(size))
|
||||
i = encodeVarintTest(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
@ -490,8 +488,8 @@ func (m *PlainTextChange_Data) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintTestdocumentchanges(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovTestdocumentchanges(v)
|
||||
func encodeVarintTest(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovTest(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
@ -530,7 +528,7 @@ func (m *PlainTextChange_Content_TextAppend) Size() (n int) {
|
||||
_ = l
|
||||
if m.TextAppend != nil {
|
||||
l = m.TextAppend.Size()
|
||||
n += 1 + l + sovTestdocumentchanges(uint64(l))
|
||||
n += 1 + l + sovTest(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
@ -542,7 +540,7 @@ func (m *PlainTextChange_TextAppend) Size() (n int) {
|
||||
_ = l
|
||||
l = len(m.Text)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovTestdocumentchanges(uint64(l))
|
||||
n += 1 + l + sovTest(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
@ -555,7 +553,7 @@ func (m *PlainTextChange_Snapshot) Size() (n int) {
|
||||
_ = l
|
||||
l = len(m.Text)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovTestdocumentchanges(uint64(l))
|
||||
n += 1 + l + sovTest(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
@ -569,21 +567,21 @@ func (m *PlainTextChange_Data) Size() (n int) {
|
||||
if len(m.Content) > 0 {
|
||||
for _, e := range m.Content {
|
||||
l = e.Size()
|
||||
n += 1 + l + sovTestdocumentchanges(uint64(l))
|
||||
n += 1 + l + sovTest(uint64(l))
|
||||
}
|
||||
}
|
||||
if m.Snapshot != nil {
|
||||
l = m.Snapshot.Size()
|
||||
n += 1 + l + sovTestdocumentchanges(uint64(l))
|
||||
n += 1 + l + sovTest(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovTestdocumentchanges(x uint64) (n int) {
|
||||
func sovTest(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozTestdocumentchanges(x uint64) (n int) {
|
||||
return sovTestdocumentchanges(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
func sozTest(x uint64) (n int) {
|
||||
return sovTest(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *PlainTextChange) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
@ -593,7 +591,7 @@ func (m *PlainTextChange) Unmarshal(dAtA []byte) error {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTestdocumentchanges
|
||||
return ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -616,12 +614,12 @@ func (m *PlainTextChange) Unmarshal(dAtA []byte) error {
|
||||
switch fieldNum {
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTestdocumentchanges(dAtA[iNdEx:])
|
||||
skippy, err := skipTest(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -643,7 +641,7 @@ func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTestdocumentchanges
|
||||
return ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -671,7 +669,7 @@ func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTestdocumentchanges
|
||||
return ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -684,11 +682,11 @@ func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -701,12 +699,12 @@ func (m *PlainTextChange_Content) Unmarshal(dAtA []byte) error {
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTestdocumentchanges(dAtA[iNdEx:])
|
||||
skippy, err := skipTest(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -728,7 +726,7 @@ func (m *PlainTextChange_TextAppend) Unmarshal(dAtA []byte) error {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTestdocumentchanges
|
||||
return ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -756,7 +754,7 @@ func (m *PlainTextChange_TextAppend) Unmarshal(dAtA []byte) error {
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTestdocumentchanges
|
||||
return ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -770,11 +768,11 @@ func (m *PlainTextChange_TextAppend) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -783,12 +781,12 @@ func (m *PlainTextChange_TextAppend) Unmarshal(dAtA []byte) error {
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTestdocumentchanges(dAtA[iNdEx:])
|
||||
skippy, err := skipTest(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -810,7 +808,7 @@ func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTestdocumentchanges
|
||||
return ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -838,7 +836,7 @@ func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTestdocumentchanges
|
||||
return ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -852,11 +850,11 @@ func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -865,12 +863,12 @@ func (m *PlainTextChange_Snapshot) Unmarshal(dAtA []byte) error {
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTestdocumentchanges(dAtA[iNdEx:])
|
||||
skippy, err := skipTest(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -892,7 +890,7 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTestdocumentchanges
|
||||
return ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -920,7 +918,7 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTestdocumentchanges
|
||||
return ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -933,11 +931,11 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -954,7 +952,7 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTestdocumentchanges
|
||||
return ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -967,11 +965,11 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -985,12 +983,12 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTestdocumentchanges(dAtA[iNdEx:])
|
||||
skippy, err := skipTest(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthTestdocumentchanges
|
||||
return ErrInvalidLengthTest
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
@ -1004,7 +1002,7 @@ func (m *PlainTextChange_Data) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
|
||||
func skipTest(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
@ -1012,7 +1010,7 @@ func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowTestdocumentchanges
|
||||
return 0, ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
@ -1029,7 +1027,7 @@ func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowTestdocumentchanges
|
||||
return 0, ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
@ -1045,7 +1043,7 @@ func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowTestdocumentchanges
|
||||
return 0, ErrIntOverflowTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
@ -1058,14 +1056,14 @@ func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthTestdocumentchanges
|
||||
return 0, ErrInvalidLengthTest
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupTestdocumentchanges
|
||||
return 0, ErrUnexpectedEndOfGroupTest
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
@ -1074,7 +1072,7 @@ func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthTestdocumentchanges
|
||||
return 0, ErrInvalidLengthTest
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
@ -1084,7 +1082,7 @@ func skipTestdocumentchanges(dAtA []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthTestdocumentchanges = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowTestdocumentchanges = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupTestdocumentchanges = fmt.Errorf("proto: unexpected end of group")
|
||||
ErrInvalidLengthTest = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowTest = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupTest = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
|
||||
@ -16,7 +16,7 @@ var (
|
||||
|
||||
type ChangeContent struct {
|
||||
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
|
||||
}
|
||||
|
||||
@ -34,7 +34,8 @@ type Change struct {
|
||||
visited bool
|
||||
branchesFinished bool
|
||||
|
||||
Content *aclpb.Change
|
||||
Content *aclpb.TreeChange
|
||||
Identity string
|
||||
Sign []byte
|
||||
}
|
||||
|
||||
@ -56,7 +57,7 @@ func (ch *Change) DecryptContents(key *symmetric.Key) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewChange(id string, ch *aclpb.Change, signature []byte) *Change {
|
||||
func NewChange(id string, ch *aclpb.TreeChange, signature []byte) *Change {
|
||||
return &Change{
|
||||
Next: nil,
|
||||
PreviousIds: ch.TreeHeadIds,
|
||||
@ -64,6 +65,7 @@ func NewChange(id string, ch *aclpb.Change, signature []byte) *Change {
|
||||
Content: ch,
|
||||
SnapshotId: ch.SnapshotBaseId,
|
||||
IsSnapshot: ch.IsSnapshot,
|
||||
Identity: string(ch.Identity),
|
||||
Sign: signature,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package tree
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/common"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
|
||||
@ -10,25 +11,24 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const componentBuilder = "tree.changebuilder"
|
||||
var ErrEmptyChange = errors.New("change payload should not be empty")
|
||||
|
||||
type BuilderContent struct {
|
||||
treeHeadIds []string
|
||||
aclHeadId string
|
||||
snapshotBaseId string
|
||||
currentReadKeyHash uint64
|
||||
identity string
|
||||
identity []byte
|
||||
isSnapshot bool
|
||||
signingKey signingkey.PrivKey
|
||||
readKey *symmetric.Key
|
||||
content proto.Marshaler
|
||||
content []byte
|
||||
}
|
||||
|
||||
type ChangeBuilder interface {
|
||||
ConvertFromRaw(rawChange *aclpb.RawChange) (ch *Change, err error)
|
||||
ConvertFromRawAndVerify(rawChange *aclpb.RawChange) (ch *Change, err error)
|
||||
BuildContent(payload BuilderContent) (ch *Change, raw *aclpb.RawChange, err error)
|
||||
BuildRaw(ch *Change) (*aclpb.RawChange, error)
|
||||
ConvertFromRaw(rawIdChange *aclpb.RawTreeChangeWithId, verify bool) (ch *Change, err error)
|
||||
BuildContent(payload BuilderContent) (ch *Change, raw *aclpb.RawTreeChangeWithId, err error)
|
||||
BuildRaw(ch *Change) (*aclpb.RawTreeChangeWithId, error)
|
||||
}
|
||||
|
||||
type changeBuilder struct {
|
||||
@ -39,31 +39,34 @@ func newChangeBuilder(keys *common.Keychain) ChangeBuilder {
|
||||
return &changeBuilder{keys: keys}
|
||||
}
|
||||
|
||||
func (c *changeBuilder) ConvertFromRaw(rawChange *aclpb.RawChange) (ch *Change, err error) {
|
||||
unmarshalled := &aclpb.Change{}
|
||||
err = proto.Unmarshal(rawChange.Payload, unmarshalled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ch = NewChange(rawChange.Id, unmarshalled, rawChange.Signature)
|
||||
func (c *changeBuilder) ConvertFromRaw(rawIdChange *aclpb.RawTreeChangeWithId, verify bool) (ch *Change, err error) {
|
||||
if rawIdChange.GetRawChange() == nil {
|
||||
err = ErrEmptyChange
|
||||
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
|
||||
if verify {
|
||||
// verifying ID
|
||||
if !cid.VerifyCID(rawIdChange.RawChange, rawIdChange.Id) {
|
||||
err = ErrIncorrectCID
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
identityKey, err := c.keys.GetOrAdd(unmarshalled.Identity)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
// verifying signature
|
||||
res, err := identityKey.Verify(rawChange.Payload, rawChange.Signature)
|
||||
res, err := identityKey.Verify(raw.Payload, raw.Signature)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -71,17 +74,20 @@ func (c *changeBuilder) ConvertFromRawAndVerify(rawChange *aclpb.RawChange) (ch
|
||||
err = ErrIncorrectSignature
|
||||
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
|
||||
}
|
||||
|
||||
func (c *changeBuilder) BuildContent(payload BuilderContent) (ch *Change, raw *aclpb.RawChange, err error) {
|
||||
aclChange := &aclpb.Change{
|
||||
ch = NewChange(rawIdChange.Id, unmarshalled, raw.Signature)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *changeBuilder) BuildContent(payload BuilderContent) (ch *Change, rawIdChange *aclpb.RawTreeChangeWithId, err error) {
|
||||
change := &aclpb.TreeChange{
|
||||
TreeHeadIds: payload.treeHeadIds,
|
||||
AclHeadId: payload.aclHeadId,
|
||||
SnapshotBaseId: payload.snapshotBaseId,
|
||||
@ -90,53 +96,65 @@ func (c *changeBuilder) BuildContent(payload BuilderContent) (ch *Change, raw *a
|
||||
Identity: payload.identity,
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
encrypted, err := payload.readKey.Encrypt(marshalledData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
aclChange.ChangesData = encrypted
|
||||
|
||||
fullMarshalledChange, err := proto.Marshal(aclChange)
|
||||
signature, err := payload.signingKey.Sign(marshalledChange)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
signature, err := payload.signingKey.Sign(fullMarshalledChange)
|
||||
raw := &aclpb.RawTreeChange{
|
||||
Payload: marshalledChange,
|
||||
Signature: signature,
|
||||
}
|
||||
|
||||
marshalledRawChange, err := proto.Marshal(raw)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
id, err := cid.NewCIDFromBytes(fullMarshalledChange)
|
||||
id, err := cid.NewCIDFromBytes(marshalledRawChange)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ch = NewChange(id, aclChange, signature)
|
||||
ch = NewChange(id, change, signature)
|
||||
ch.ParsedModel = payload.content
|
||||
|
||||
raw = &aclpb.RawChange{
|
||||
Payload: fullMarshalledChange,
|
||||
Signature: signature,
|
||||
rawIdChange = &aclpb.RawTreeChangeWithId{
|
||||
RawChange: marshalledRawChange,
|
||||
Id: id,
|
||||
}
|
||||
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
|
||||
marshalled, err = ch.Content.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
raw = &aclpb.RawChange{
|
||||
marshalledRawChange, err := proto.Marshal(&aclpb.RawTreeChange{
|
||||
Payload: marshalled,
|
||||
Signature: ch.Signature(),
|
||||
Signature: ch.Sign,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
raw = &aclpb.RawTreeChangeWithId{
|
||||
RawChange: marshalledRawChange,
|
||||
Id: ch.Id,
|
||||
}
|
||||
return
|
||||
|
||||
@ -48,7 +48,7 @@ func (v *objectTreeValidator) validateChange(tree *Tree, aclList list.ACLList, c
|
||||
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
|
||||
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/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/symmetric"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@ -34,7 +32,7 @@ type AddResultSummary int
|
||||
type AddResult struct {
|
||||
OldHeads []string
|
||||
Heads []string
|
||||
Added []*aclpb.RawChange
|
||||
Added []*aclpb.RawTreeChangeWithId
|
||||
|
||||
Mode Mode
|
||||
}
|
||||
@ -46,7 +44,7 @@ type ObjectTree interface {
|
||||
RWLocker
|
||||
|
||||
ID() string
|
||||
Header() *aclpb.Header
|
||||
Header() *aclpb.TreeHeader
|
||||
Heads() []string
|
||||
Root() *Change
|
||||
HasChange(string) bool
|
||||
@ -55,13 +53,13 @@ type ObjectTree interface {
|
||||
IterateFrom(id string, convert ChangeConvertFunc, iterate ChangeIterateFunc) error
|
||||
|
||||
SnapshotPath() []string
|
||||
ChangesAfterCommonSnapshot(snapshotPath, heads []string) ([]*aclpb.RawChange, error)
|
||||
ChangesAfterCommonSnapshot(snapshotPath, heads []string) ([]*aclpb.RawTreeChangeWithId, error)
|
||||
|
||||
Storage() storage.TreeStorage
|
||||
DebugDump() (string, error)
|
||||
|
||||
AddContent(ctx context.Context, content SignableChangeContent) (*aclpb.RawChange, error)
|
||||
AddRawChanges(ctx context.Context, changes ...*aclpb.RawChange) (AddResult, error)
|
||||
AddContent(ctx context.Context, content SignableChangeContent) (*aclpb.RawTreeChangeWithId, error)
|
||||
AddRawChanges(ctx context.Context, changes ...*aclpb.RawTreeChangeWithId) (AddResult, error)
|
||||
|
||||
Close() error
|
||||
}
|
||||
@ -76,13 +74,13 @@ type objectTree struct {
|
||||
aclList list.ACLList
|
||||
|
||||
id string
|
||||
header *aclpb.Header
|
||||
header *aclpb.TreeHeader
|
||||
tree *Tree
|
||||
|
||||
keys map[uint64]*symmetric.Key
|
||||
|
||||
// buffers
|
||||
difSnapshotBuf []*aclpb.RawChange
|
||||
difSnapshotBuf []*aclpb.RawTreeChangeWithId
|
||||
tmpChangesBuf []*Change
|
||||
newSnapshotsBuf []*Change
|
||||
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) {
|
||||
ot.treeBuilder.Reset()
|
||||
|
||||
@ -201,7 +140,7 @@ func (ot *objectTree) ID() string {
|
||||
return ot.id
|
||||
}
|
||||
|
||||
func (ot *objectTree) Header() *aclpb.Header {
|
||||
func (ot *objectTree) Header() *aclpb.TreeHeader {
|
||||
return ot.header
|
||||
}
|
||||
|
||||
@ -209,7 +148,7 @@ func (ot *objectTree) Storage() storage.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() {
|
||||
if err == nil && ot.updateListener != nil {
|
||||
ot.updateListener.Update(ot)
|
||||
@ -258,12 +197,12 @@ func (ot *objectTree) prepareBuilderContent(content SignableChangeContent) (cnt
|
||||
isSnapshot: content.IsSnapshot,
|
||||
signingKey: content.Key,
|
||||
readKey: readKey,
|
||||
content: content.Proto,
|
||||
content: content.Data,
|
||||
}
|
||||
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
|
||||
mode, addResult, err = ot.addRawChanges(ctx, rawChanges...)
|
||||
if err != nil {
|
||||
@ -302,7 +241,7 @@ func (ot *objectTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.Ra
|
||||
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
|
||||
ot.tmpChangesBuf = ot.tmpChangesBuf[:0]
|
||||
ot.notSeenIdxBuf = ot.notSeenIdxBuf[:0]
|
||||
@ -329,7 +268,7 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*aclpb.Ra
|
||||
}
|
||||
|
||||
var change *Change
|
||||
change, err = ot.changeBuilder.ConvertFromRawAndVerify(ch)
|
||||
change, err = ot.changeBuilder.ConvertFromRaw(ch, true)
|
||||
if err != nil {
|
||||
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
|
||||
// they can include not only the changes that were added now,
|
||||
// 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{})
|
||||
|
||||
// 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 {
|
||||
// if we got some changes that we need to convert to raw
|
||||
if _, exists := alreadyConverted[ch]; !exists {
|
||||
var raw *aclpb.RawChange
|
||||
var raw *aclpb.RawTreeChangeWithId
|
||||
raw, err = ot.changeBuilder.BuildRaw(ch)
|
||||
if err != nil {
|
||||
return
|
||||
@ -421,7 +360,7 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*aclpb.Ra
|
||||
ot.rebuildFromStorage(nil)
|
||||
return
|
||||
}
|
||||
var added []*aclpb.RawChange
|
||||
var added []*aclpb.RawTreeChangeWithId
|
||||
added, err = getAddedChanges(nil)
|
||||
// we shouldn't get any error in this case
|
||||
if err != nil {
|
||||
@ -457,7 +396,7 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*aclpb.Ra
|
||||
err = ErrHasInvalidChanges
|
||||
return
|
||||
}
|
||||
var added []*aclpb.RawChange
|
||||
var added []*aclpb.RawTreeChangeWithId
|
||||
added, err = getAddedChanges(treeChangesAdded)
|
||||
if err != nil {
|
||||
// that means that some unattached changes were somehow corrupted in memory
|
||||
@ -553,7 +492,7 @@ func (ot *objectTree) SnapshotPath() []string {
|
||||
return path
|
||||
}
|
||||
|
||||
func (ot *objectTree) ChangesAfterCommonSnapshot(theirPath, theirHeads []string) ([]*aclpb.RawChange, error) {
|
||||
func (ot *objectTree) ChangesAfterCommonSnapshot(theirPath, theirHeads []string) ([]*aclpb.RawTreeChangeWithId, error) {
|
||||
var (
|
||||
needFullDocument = len(theirPath) == 0
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ import (
|
||||
type mockChangeCreator struct{}
|
||||
|
||||
func (c *mockChangeCreator) createRaw(id, aclId, snapshotId string, isSnapshot bool, prevIds ...string) *aclpb.RawChange {
|
||||
aclChange := &aclpb.Change{
|
||||
aclChange := &aclpb.TreeChange{
|
||||
TreeHeadIds: prevIds,
|
||||
AclHeadId: aclId,
|
||||
SnapshotBaseId: snapshotId,
|
||||
@ -23,22 +23,27 @@ func (c *mockChangeCreator) createRaw(id, aclId, snapshotId string, isSnapshot b
|
||||
IsSnapshot: isSnapshot,
|
||||
}
|
||||
res, _ := aclChange.Marshal()
|
||||
return &aclpb.RawChange{
|
||||
|
||||
raw := &aclpb.RawTreeChange{
|
||||
Payload: res,
|
||||
Signature: nil,
|
||||
}
|
||||
rawMarshalled, _ := raw.Marshal()
|
||||
|
||||
return &aclpb.RawTreeChangeWithId{
|
||||
RawChange: rawMarshalled,
|
||||
Id: id,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *mockChangeCreator) createNewTreeStorage(treeId, aclListId, aclHeadId, firstChangeId string) storage.TreeStorage {
|
||||
firstChange := c.createRaw(firstChangeId, aclHeadId, "", true)
|
||||
header := &aclpb.Header{
|
||||
header := &aclpb.TreeHeader{
|
||||
FirstId: firstChangeId,
|
||||
AclListId: aclListId,
|
||||
WorkspaceId: "",
|
||||
DocType: aclpb.Header_DocTree,
|
||||
AclId: aclListId,
|
||||
TreeHeaderType: aclpb.TreeHeaderType_Object,
|
||||
}
|
||||
treeStorage, _ := storage.NewInMemoryTreeStorage(treeId, header, []string{firstChangeId}, []*aclpb.RawChange{firstChange})
|
||||
treeStorage, _ := storage.NewInMemoryTreeStorage(treeId, header, []string{firstChangeId}, []*aclpb.RawTreeChangeWithId{firstChange})
|
||||
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 {
|
||||
change *Change
|
||||
rawChange *aclpb.RawChange
|
||||
rawChange *aclpb.RawTreeChangeWithId
|
||||
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
|
||||
for _, h := range t.headIds {
|
||||
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 {
|
||||
var raw *aclpb.RawChange
|
||||
var raw *aclpb.RawTreeChangeWithId
|
||||
raw, err = r.changeBuilder.BuildRaw(ch)
|
||||
if err != nil {
|
||||
return
|
||||
@ -95,7 +95,7 @@ func (r *rawChangeLoader) LoadFromTree(t *Tree, breakpoints []string) ([]*aclpb.
|
||||
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
|
||||
r.cache = make(map[string]rawCacheEntry)
|
||||
defer func() {
|
||||
@ -162,7 +162,7 @@ func (r *rawChangeLoader) LoadFromStorage(commonSnapshot string, heads, breakpoi
|
||||
|
||||
// preparing first pass
|
||||
r.idStack = append(r.idStack, heads...)
|
||||
var buffer []*aclpb.RawChange
|
||||
var buffer []*aclpb.RawTreeChangeWithId
|
||||
|
||||
rootVisited := dfs(commonSnapshot, heads, 0,
|
||||
func(counter int, mapExists bool) bool {
|
||||
@ -203,7 +203,7 @@ func (r *rawChangeLoader) LoadFromStorage(commonSnapshot string, heads, breakpoi
|
||||
})
|
||||
|
||||
// discarding visited
|
||||
buffer = discardFromSlice(buffer, func(change *aclpb.RawChange) bool {
|
||||
buffer = discardFromSlice(buffer, func(change *aclpb.RawTreeChangeWithId) bool {
|
||||
return change == nil
|
||||
})
|
||||
|
||||
@ -219,7 +219,7 @@ func (r *rawChangeLoader) loadEntry(id string) (entry rawCacheEntry, err error)
|
||||
return
|
||||
}
|
||||
|
||||
change, err := r.changeBuilder.ConvertFromRaw(rawChange)
|
||||
change, err := r.changeBuilder.ConvertFromRaw(rawChange, false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -2,12 +2,11 @@ package tree
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type SignableChangeContent struct {
|
||||
Proto proto.Marshaler
|
||||
Data []byte
|
||||
Key signingkey.PrivKey
|
||||
Identity string
|
||||
Identity []byte
|
||||
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
|
||||
}
|
||||
|
||||
ch, err = tb.builder.ConvertFromRawAndVerify(change)
|
||||
ch, err = tb.builder.ConvertFromRaw(change, true)
|
||||
if err != nil {
|
||||
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 {
|
||||
Id string
|
||||
Header *aclpb.Header
|
||||
Records []*aclpb.RawRecord
|
||||
Records []*aclpb.RawACLRecord
|
||||
}
|
||||
|
||||
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