WIP proto refactoring

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

View File

@ -13,27 +13,24 @@ endif
export PATH=$(GOPATH)/bin:$(shell echo $$PATH)
# 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))

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -28,8 +28,8 @@ func TestAclList_ACLState_UserInviteAndJoin(t *testing.T) {
assert.Equal(t, aclpb.ACLChange_Reader, aclList.ACLState().GetUserStates()[idC].Permissions)
assert.Equal(t, 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
})

View File

@ -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
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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 {

View File

@ -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)

View File

@ -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 {

View File

@ -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
}

View File

@ -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")
)

View File

@ -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,
}
}

View File

@ -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

View File

@ -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
}

View File

@ -8,8 +8,6 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list"
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/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)
}

View File

@ -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
}

View File

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

View File

@ -18,7 +18,7 @@ type rawChangeLoader struct {
type rawCacheEntry struct {
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
}

View File

@ -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
}

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff