node acl service (wip), fixes
This commit is contained in:
parent
348acd6d84
commit
41a3f0502e
@ -37,7 +37,7 @@ func newListStorage(spaceId string, db *badger.DB, txn *badger.Txn) (ls storage.
|
||||
|
||||
ls = &listStorage{
|
||||
db: db,
|
||||
keys: keys,
|
||||
keys: newACLKeys(spaceId),
|
||||
id: stringId,
|
||||
root: rootWithId,
|
||||
}
|
||||
@ -70,14 +70,14 @@ func createListStorage(spaceId string, db *badger.DB, txn *badger.Txn, root *acl
|
||||
|
||||
ls = &listStorage{
|
||||
db: db,
|
||||
keys: keys,
|
||||
keys: newACLKeys(spaceId),
|
||||
id: root.Id,
|
||||
root: root,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (l *listStorage) ID() string {
|
||||
func (l *listStorage) Id() string {
|
||||
return l.id
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ package storage
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
"github.com/dgraph-io/badger/v3"
|
||||
"sync"
|
||||
)
|
||||
@ -12,7 +12,7 @@ type spaceStorage struct {
|
||||
spaceId string
|
||||
objDb *badger.DB
|
||||
keys spaceKeys
|
||||
aclStorage storage2.ListStorage
|
||||
aclStorage storage.ListStorage
|
||||
header *spacesyncproto.RawSpaceHeaderWithId
|
||||
mx sync.Mutex
|
||||
}
|
||||
@ -77,15 +77,15 @@ func createSpaceStorage(db *badger.DB, payload spacestorage.SpaceStorageCreatePa
|
||||
return
|
||||
}
|
||||
|
||||
func (s *spaceStorage) ID() string {
|
||||
func (s *spaceStorage) Id() string {
|
||||
return s.spaceId
|
||||
}
|
||||
|
||||
func (s *spaceStorage) TreeStorage(id string) (storage2.TreeStorage, error) {
|
||||
func (s *spaceStorage) TreeStorage(id string) (storage.TreeStorage, error) {
|
||||
return newTreeStorage(s.objDb, s.spaceId, id)
|
||||
}
|
||||
|
||||
func (s *spaceStorage) CreateTreeStorage(payload storage2.TreeStorageCreatePayload) (ts storage2.TreeStorage, err error) {
|
||||
func (s *spaceStorage) CreateTreeStorage(payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) {
|
||||
// we have mutex here, so we prevent overwriting the heads of a tree on concurrent creation
|
||||
s.mx.Lock()
|
||||
defer s.mx.Unlock()
|
||||
@ -93,7 +93,7 @@ func (s *spaceStorage) CreateTreeStorage(payload storage2.TreeStorageCreatePaylo
|
||||
return createTreeStorage(s.objDb, s.spaceId, payload)
|
||||
}
|
||||
|
||||
func (s *spaceStorage) ACLStorage() (storage2.ListStorage, error) {
|
||||
func (s *spaceStorage) ACLStorage() (storage.ListStorage, error) {
|
||||
return s.aclStorage, nil
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
"github.com/dgraph-io/badger/v3"
|
||||
)
|
||||
@ -40,14 +40,11 @@ func newTreeStorage(db *badger.DB, spaceId, treeId string) (ts storage.TreeStora
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err == badger.ErrKeyNotFound {
|
||||
err = storage.ErrUnknownTreeId
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func createTreeStorage(db *badger.DB, spaceId string, payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) {
|
||||
keys := newTreeKeys(spaceId, payload.RootRawChange.Id)
|
||||
keys := newTreeKeys(spaceId, payload.TreeId)
|
||||
if hasDB(db, keys.RootIdKey()) {
|
||||
err = storage.ErrTreeExists
|
||||
return
|
||||
@ -88,7 +85,7 @@ func createTreeStorage(db *badger.DB, spaceId string, payload storage.TreeStorag
|
||||
return
|
||||
}
|
||||
|
||||
func (t *treeStorage) ID() string {
|
||||
func (t *treeStorage) Id() string {
|
||||
return t.id
|
||||
}
|
||||
|
||||
|
||||
@ -6,15 +6,12 @@ import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
|
||||
config2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/config"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/config"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
)
|
||||
|
||||
const CName = "common.commonspace"
|
||||
@ -29,12 +26,11 @@ type Service interface {
|
||||
DeriveSpace(ctx context.Context, payload SpaceDerivePayload) (string, error)
|
||||
CreateSpace(ctx context.Context, payload SpaceCreatePayload) (string, error)
|
||||
GetSpace(ctx context.Context, id string) (sp Space, err error)
|
||||
AddSpace(ctx context.Context, spaceDescription SpaceDescription) (err error)
|
||||
app.Component
|
||||
}
|
||||
|
||||
type service struct {
|
||||
config config2.Space
|
||||
config config.Space
|
||||
account account.Service
|
||||
configurationService nodeconf.Service
|
||||
storageProvider storage.SpaceStorageProvider
|
||||
@ -43,7 +39,7 @@ type service struct {
|
||||
}
|
||||
|
||||
func (s *service) Init(a *app.App) (err error) {
|
||||
s.config = a.MustComponent(config2.CName).(*config2.Config).Space
|
||||
s.config = a.MustComponent(config.CName).(*config.Config).Space
|
||||
s.account = a.MustComponent(account.CName).(account.Service)
|
||||
s.storageProvider = a.MustComponent(storage.CName).(storage.SpaceStorageProvider)
|
||||
s.configurationService = a.MustComponent(nodeconf.CName).(nodeconf.Service)
|
||||
@ -56,9 +52,7 @@ func (s *service) Name() (name string) {
|
||||
return CName
|
||||
}
|
||||
|
||||
func (s *service) CreateSpace(
|
||||
ctx context.Context,
|
||||
payload SpaceCreatePayload) (id string, err error) {
|
||||
func (s *service) CreateSpace(ctx context.Context, payload SpaceCreatePayload) (id string, err error) {
|
||||
storageCreate, err := storagePayloadForSpaceCreate(payload)
|
||||
if err != nil {
|
||||
return
|
||||
@ -68,12 +62,10 @@ func (s *service) CreateSpace(
|
||||
return
|
||||
}
|
||||
|
||||
return store.ID(), nil
|
||||
return store.Id(), nil
|
||||
}
|
||||
|
||||
func (s *service) DeriveSpace(
|
||||
ctx context.Context,
|
||||
payload SpaceDerivePayload) (id string, err error) {
|
||||
func (s *service) DeriveSpace(ctx context.Context, payload SpaceDerivePayload) (id string, err error) {
|
||||
storageCreate, err := storagePayloadForSpaceDerive(payload)
|
||||
if err != nil {
|
||||
return
|
||||
@ -83,53 +75,15 @@ func (s *service) DeriveSpace(
|
||||
return
|
||||
}
|
||||
|
||||
return store.ID(), nil
|
||||
}
|
||||
|
||||
func (s *service) AddSpace(ctx context.Context, spaceDescription SpaceDescription) (err error) {
|
||||
_, err = s.storageProvider.SpaceStorage(spaceDescription.SpaceHeader.Id)
|
||||
if err == nil {
|
||||
err = spacesyncproto.ErrSpaceExists
|
||||
return
|
||||
}
|
||||
if err != storage.ErrSpaceStorageMissing {
|
||||
err = spacesyncproto.ErrUnexpected
|
||||
return
|
||||
}
|
||||
|
||||
payload := storage.SpaceStorageCreatePayload{
|
||||
RecWithId: &aclrecordproto.RawACLRecordWithId{
|
||||
Payload: spaceDescription.AclPayload,
|
||||
Id: spaceDescription.AclId,
|
||||
},
|
||||
SpaceHeaderWithId: spaceDescription.SpaceHeader,
|
||||
}
|
||||
st, err := s.storageProvider.CreateSpaceStorage(payload)
|
||||
if err != nil {
|
||||
err = spacesyncproto.ErrUnexpected
|
||||
if err == storage.ErrSpaceStorageExists {
|
||||
err = spacesyncproto.ErrSpaceExists
|
||||
}
|
||||
return
|
||||
}
|
||||
err = st.Close()
|
||||
return
|
||||
return store.Id(), nil
|
||||
}
|
||||
|
||||
func (s *service) GetSpace(ctx context.Context, id string) (Space, error) {
|
||||
st, err := s.storageProvider.SpaceStorage(id)
|
||||
if err != nil {
|
||||
if err != spacesyncproto.ErrSpaceMissing {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
st, err = s.getSpaceStorageFromRemote(ctx, id)
|
||||
if err != nil {
|
||||
err = storage.ErrSpaceStorageMissing
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
lastConfiguration := s.configurationService.GetLast()
|
||||
confConnector := nodeconf.NewConfConnector(lastConfiguration, s.pool)
|
||||
diffService := diffservice.NewDiffService(id, s.config.SyncPeriod, st, confConnector, s.treeGetter, log)
|
||||
@ -148,38 +102,3 @@ func (s *service) GetSpace(ctx context.Context, id string) (Space, error) {
|
||||
}
|
||||
return sp, nil
|
||||
}
|
||||
|
||||
func (s *service) getSpaceStorageFromRemote(ctx context.Context, id string) (st storage.SpaceStorage, err error) {
|
||||
var p peer.Peer
|
||||
peerId, err := syncservice.GetPeerIdFromStreamContext(ctx)
|
||||
if err == nil {
|
||||
p, err = s.pool.Dial(ctx, peerId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
lastConfiguration := s.configurationService.GetLast()
|
||||
// for nodes we always get remote space only if we have id in the context
|
||||
if lastConfiguration.IsResponsible(id) {
|
||||
err = spacesyncproto.ErrSpaceMissing
|
||||
return
|
||||
}
|
||||
p, err = s.pool.DialOneOf(ctx, lastConfiguration.NodeIds(id))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
cl := spacesyncproto.NewDRPCSpaceClient(p)
|
||||
res, err := cl.PullSpace(ctx, &spacesyncproto.PullSpaceRequest{Id: id})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
st, err = s.storageProvider.CreateSpaceStorage(storage.SpaceStorageCreatePayload{
|
||||
RecWithId: &aclrecordproto.RawACLRecordWithId{
|
||||
Payload: res.AclPayload,
|
||||
Id: res.AclPayloadId,
|
||||
},
|
||||
SpaceHeaderWithId: res.SpaceHeader,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@ -162,18 +162,18 @@ func (mr *MockSpaceStorageMockRecorder) CreateTreeStorage(arg0 interface{}) *gom
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTreeStorage", reflect.TypeOf((*MockSpaceStorage)(nil).CreateTreeStorage), arg0)
|
||||
}
|
||||
|
||||
// ID mocks base method.
|
||||
func (m *MockSpaceStorage) ID() string {
|
||||
// Id mocks base method.
|
||||
func (m *MockSpaceStorage) Id() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ID")
|
||||
ret := m.ctrl.Call(m, "Id")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ID indicates an expected call of ID.
|
||||
func (mr *MockSpaceStorageMockRecorder) ID() *gomock.Call {
|
||||
// Id indicates an expected call of Id.
|
||||
func (mr *MockSpaceStorageMockRecorder) Id() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockSpaceStorage)(nil).ID))
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockSpaceStorage)(nil).Id))
|
||||
}
|
||||
|
||||
// SpaceHeader mocks base method.
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
)
|
||||
|
||||
const CName = "commonspace.storage"
|
||||
@ -16,7 +16,7 @@ var ErrSpaceStorageMissing = errors.New("space storage missing")
|
||||
|
||||
type SpaceStorage interface {
|
||||
storage.Provider
|
||||
ID() string
|
||||
Id() string
|
||||
ACLStorage() (storage.ListStorage, error)
|
||||
SpaceHeader() (*spacesyncproto.RawSpaceHeaderWithId, error)
|
||||
StoredIds() ([]string, error)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,8 @@ message RawACLRecord {
|
||||
message RawACLRecordWithId {
|
||||
bytes payload = 1;
|
||||
string id = 2;
|
||||
bytes acceptorIdentity = 3;
|
||||
bytes acceptorSignature = 4;
|
||||
}
|
||||
|
||||
message ACLRecord {
|
||||
@ -63,24 +65,31 @@ message ACLUserAdd {
|
||||
ACLUserPermissions permissions = 4;
|
||||
}
|
||||
|
||||
// accept key, encrypt key, invite id
|
||||
// GetSpace(id) -> ... (space header + acl root) -> diff
|
||||
// Join(ACLJoinRecord) -> Ok
|
||||
|
||||
message ACLUserInvite {
|
||||
bytes acceptPublicKey = 1;
|
||||
uint64 encryptSymKeyHash = 2;
|
||||
// TODO: change to read key
|
||||
bytes encryptPublicKey = 2;
|
||||
repeated bytes encryptedReadKeys = 3;
|
||||
ACLUserPermissions permissions = 4;
|
||||
// TODO: either derive inviteId from pub keys or think if it is possible to just use ACL record id
|
||||
string inviteId = 5;
|
||||
}
|
||||
|
||||
message ACLUserJoin {
|
||||
bytes identity = 1;
|
||||
bytes encryptionKey = 2;
|
||||
bytes acceptSignature = 3;
|
||||
bytes acceptPubKey = 4;
|
||||
string inviteId = 4;
|
||||
repeated bytes encryptedReadKeys = 5;
|
||||
}
|
||||
|
||||
message ACLUserRemove {
|
||||
bytes identity = 1;
|
||||
repeated ACLReadKeyReplace readKeyReplaces = 2;
|
||||
repeated ACLReadKeyReplace readKeyReplaces = 3;
|
||||
}
|
||||
|
||||
message ACLReadKeyReplace {
|
||||
@ -99,3 +108,19 @@ enum ACLUserPermissions {
|
||||
Writer = 1;
|
||||
Reader = 2;
|
||||
}
|
||||
|
||||
|
||||
message ACLSyncMessage {
|
||||
ACLSyncContentValue content = 2;
|
||||
}
|
||||
|
||||
// ACLSyncContentValue provides different types for acl sync
|
||||
message ACLSyncContentValue {
|
||||
oneof value {
|
||||
ACLAddRecords addRecords = 1;
|
||||
}
|
||||
}
|
||||
|
||||
message ACLAddRecords {
|
||||
repeated RawACLRecordWithId records = 1;
|
||||
}
|
||||
@ -25,11 +25,10 @@ type RWLocker interface {
|
||||
type ACLList interface {
|
||||
RWLocker
|
||||
ID() string
|
||||
Root() *aclrecordproto.RawACLRecordWithId
|
||||
Root() *aclrecordproto.ACLRoot
|
||||
Records() []*ACLRecord
|
||||
ACLState() *ACLState
|
||||
IsAfter(first string, second string) (bool, error)
|
||||
AddRawRecords(ctx context.Context, rec []*aclrecordproto.RawACLRecordWithId) (err error)
|
||||
Head() *ACLRecord
|
||||
Get(id string) (*ACLRecord, error)
|
||||
Iterate(iterFunc IterFunc)
|
||||
@ -38,32 +37,38 @@ type ACLList interface {
|
||||
}
|
||||
|
||||
type aclList struct {
|
||||
root *aclrecordproto.RawACLRecordWithId
|
||||
root *aclrecordproto.ACLRoot
|
||||
records []*ACLRecord
|
||||
indexes map[string]int
|
||||
id string
|
||||
|
||||
stateBuilder *aclStateBuilder
|
||||
recordBuilder ACLRecordBuilder
|
||||
builder *aclStateBuilder
|
||||
aclState *ACLState
|
||||
keychain *common.Keychain
|
||||
storage storage.ListStorage
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func BuildACLListWithIdentity(acc *account.AccountData, storage storage.ListStorage) (ACLList, error) {
|
||||
id := storage.ID()
|
||||
builder := newACLStateBuilderWithIdentity(acc)
|
||||
return build(id, builder, newACLRecordBuilder(id, common.NewKeychain()), storage)
|
||||
return build(storage.Id(), builder, newACLRecordBuilder(storage.Id(), common.NewKeychain()), storage)
|
||||
}
|
||||
|
||||
func BuildACLList(storage storage.ListStorage) (ACLList, error) {
|
||||
id := storage.ID()
|
||||
return build(id, newACLStateBuilder(), newACLRecordBuilder(id, common.NewKeychain()), storage)
|
||||
return build(storage.Id(), newACLStateBuilder(), newACLRecordBuilder(storage.Id(), common.NewKeychain()), storage)
|
||||
}
|
||||
|
||||
func build(id string, stateBuilder *aclStateBuilder, recBuilder ACLRecordBuilder, storage storage.ListStorage) (list ACLList, err error) {
|
||||
// TODO: need to add context here
|
||||
rootWithId, err := storage.Root()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
aclRecRoot, err := recBuilder.ConvertFromRaw(rootWithId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
head, err := storage.Head()
|
||||
if err != nil {
|
||||
return
|
||||
@ -80,7 +85,7 @@ func build(id string, stateBuilder *aclStateBuilder, recBuilder ACLRecordBuilder
|
||||
}
|
||||
records := []*ACLRecord{record}
|
||||
|
||||
for record.PrevId != "" {
|
||||
for record.PrevId != "" && record.PrevId != id {
|
||||
rawRecordWithId, err = storage.GetRawRecord(context.Background(), record.PrevId)
|
||||
if err != nil {
|
||||
return
|
||||
@ -92,6 +97,8 @@ func build(id string, stateBuilder *aclStateBuilder, recBuilder ACLRecordBuilder
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
// adding root in the end, because we already parsed it
|
||||
records = append(records, aclRecRoot)
|
||||
|
||||
indexes := make(map[string]int)
|
||||
for i, j := 0, len(records)-1; i < j; i, j = i+1, j-1 {
|
||||
@ -110,19 +117,12 @@ func build(id string, stateBuilder *aclStateBuilder, recBuilder ACLRecordBuilder
|
||||
return
|
||||
}
|
||||
|
||||
rootWithId, err := storage.Root()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
list = &aclList{
|
||||
root: rootWithId,
|
||||
root: aclRecRoot.Model.(*aclrecordproto.ACLRoot),
|
||||
records: records,
|
||||
indexes: indexes,
|
||||
stateBuilder: stateBuilder,
|
||||
recordBuilder: recBuilder,
|
||||
builder: stateBuilder,
|
||||
aclState: state,
|
||||
storage: storage,
|
||||
id: id,
|
||||
RWMutex: sync.RWMutex{},
|
||||
}
|
||||
@ -137,44 +137,10 @@ func (a *aclList) ID() string {
|
||||
return a.id
|
||||
}
|
||||
|
||||
func (a *aclList) Root() *aclrecordproto.RawACLRecordWithId {
|
||||
func (a *aclList) Root() *aclrecordproto.ACLRoot {
|
||||
return a.root
|
||||
}
|
||||
|
||||
func (a *aclList) AddRawRecords(ctx context.Context, records []*aclrecordproto.RawACLRecordWithId) (err error) {
|
||||
if len(records) == 0 {
|
||||
return
|
||||
}
|
||||
// converting and verifying
|
||||
var aclRecords []*ACLRecord
|
||||
for _, rec := range records {
|
||||
var record *ACLRecord
|
||||
record, err = a.recordBuilder.ConvertFromRaw(rec)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
aclRecords = append(aclRecords, record)
|
||||
}
|
||||
|
||||
// trying to append them to state
|
||||
err = a.stateBuilder.Append(a.aclState, aclRecords)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// saving to storage
|
||||
for _, rec := range records {
|
||||
err = a.storage.AddRawRecord(ctx, rec)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// setting new head
|
||||
err = a.storage.SetHead(records[len(records)-1].Id)
|
||||
return
|
||||
}
|
||||
|
||||
func (a *aclList) ACLState() *ACLState {
|
||||
return a.aclState
|
||||
}
|
||||
|
||||
@ -9,10 +9,8 @@ import (
|
||||
)
|
||||
|
||||
type inMemoryACLListStorage struct {
|
||||
records []*aclrecordproto.RawACLRecordWithId
|
||||
id string
|
||||
root *aclrecordproto.RawACLRecordWithId
|
||||
head string
|
||||
records map[string]*aclrecordproto.RawACLRecordWithId
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
@ -20,63 +18,48 @@ type inMemoryACLListStorage struct {
|
||||
func NewInMemoryACLListStorage(
|
||||
id string,
|
||||
records []*aclrecordproto.RawACLRecordWithId) (ListStorage, error) {
|
||||
|
||||
allRecords := make(map[string]*aclrecordproto.RawACLRecordWithId)
|
||||
for _, ch := range records {
|
||||
allRecords[ch.Id] = ch
|
||||
}
|
||||
root := records[0]
|
||||
head := records[len(records)-1]
|
||||
|
||||
return &inMemoryACLListStorage{
|
||||
id: root.Id,
|
||||
root: root,
|
||||
head: head.Id,
|
||||
records: allRecords,
|
||||
id: id,
|
||||
records: records,
|
||||
RWMutex: sync.RWMutex{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *inMemoryACLListStorage) ID() string {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
return t.id
|
||||
func (i *inMemoryACLListStorage) Root() (*aclrecordproto.RawACLRecordWithId, error) {
|
||||
i.RLock()
|
||||
defer i.RUnlock()
|
||||
return i.records[0], nil
|
||||
}
|
||||
|
||||
func (t *inMemoryACLListStorage) Root() (*aclrecordproto.RawACLRecordWithId, error) {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
return t.root, nil
|
||||
func (i *inMemoryACLListStorage) SetHead(headId string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t *inMemoryACLListStorage) Head() (string, error) {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
return t.head, nil
|
||||
func (i *inMemoryACLListStorage) Head() (string, error) {
|
||||
i.RLock()
|
||||
defer i.RUnlock()
|
||||
return i.records[len(i.records)-1].Id, nil
|
||||
}
|
||||
|
||||
func (t *inMemoryACLListStorage) SetHead(head string) error {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
t.head = head
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *inMemoryACLListStorage) AddRawRecord(ctx context.Context, record *aclrecordproto.RawACLRecordWithId) error {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
// TODO: better to do deep copy
|
||||
t.records[record.Id] = record
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *inMemoryACLListStorage) GetRawRecord(ctx context.Context, recordId string) (*aclrecordproto.RawACLRecordWithId, error) {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
if res, exists := t.records[recordId]; exists {
|
||||
return res, nil
|
||||
func (i *inMemoryACLListStorage) GetRawRecord(ctx context.Context, id string) (*aclrecordproto.RawACLRecordWithId, error) {
|
||||
i.RLock()
|
||||
defer i.RUnlock()
|
||||
for _, rec := range i.records {
|
||||
if rec.Id == id {
|
||||
return rec, nil
|
||||
}
|
||||
return nil, fmt.Errorf("could not get record with id: %s", recordId)
|
||||
}
|
||||
return nil, fmt.Errorf("no such record")
|
||||
}
|
||||
|
||||
func (i *inMemoryACLListStorage) AddRawRecord(ctx context.Context, rec *aclrecordproto.RawACLRecordWithId) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (i *inMemoryACLListStorage) Id() string {
|
||||
i.RLock()
|
||||
defer i.RUnlock()
|
||||
return i.id
|
||||
}
|
||||
|
||||
type inMemoryTreeStorage struct {
|
||||
@ -89,6 +72,7 @@ type inMemoryTreeStorage struct {
|
||||
}
|
||||
|
||||
func NewInMemoryTreeStorage(
|
||||
treeId string,
|
||||
root *treechangeproto.RawTreeChangeWithId,
|
||||
heads []string,
|
||||
changes []*treechangeproto.RawTreeChangeWithId) (TreeStorage, error) {
|
||||
@ -96,10 +80,10 @@ func NewInMemoryTreeStorage(
|
||||
for _, ch := range changes {
|
||||
allChanges[ch.Id] = ch
|
||||
}
|
||||
allChanges[root.Id] = root
|
||||
allChanges[treeId] = root
|
||||
|
||||
return &inMemoryTreeStorage{
|
||||
id: root.Id,
|
||||
id: treeId,
|
||||
root: root,
|
||||
heads: heads,
|
||||
changes: allChanges,
|
||||
@ -112,7 +96,7 @@ func (t *inMemoryTreeStorage) HasChange(ctx context.Context, id string) (bool, e
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
func (t *inMemoryTreeStorage) ID() string {
|
||||
func (t *inMemoryTreeStorage) Id() string {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
return t.id
|
||||
@ -175,12 +159,12 @@ func (i *inMemoryStorageProvider) TreeStorage(id string) (TreeStorage, error) {
|
||||
func (i *inMemoryStorageProvider) CreateTreeStorage(payload TreeStorageCreatePayload) (TreeStorage, error) {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
res, err := NewInMemoryTreeStorage(payload.RootRawChange, payload.Heads, payload.Changes)
|
||||
res, err := NewInMemoryTreeStorage(payload.TreeId, payload.RootRawChange, payload.Heads, payload.Changes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i.objects[payload.RootRawChange.Id] = res
|
||||
i.objects[payload.TreeId] = res
|
||||
return res, nil
|
||||
}
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ var ErrACLExists = errors.New("acl already exists")
|
||||
var ErrUnknownRecord = errors.New("record doesn't exist")
|
||||
|
||||
type ListStorage interface {
|
||||
ID() string
|
||||
Id() string
|
||||
Root() (*aclrecordproto.RawACLRecordWithId, error)
|
||||
Head() (string, error)
|
||||
SetHead(headId string) error
|
||||
|
||||
@ -80,18 +80,18 @@ func (mr *MockListStorageMockRecorder) Head() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Head", reflect.TypeOf((*MockListStorage)(nil).Head))
|
||||
}
|
||||
|
||||
// ID mocks base method.
|
||||
func (m *MockListStorage) ID() string {
|
||||
// Id mocks base method.
|
||||
func (m *MockListStorage) Id() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ID")
|
||||
ret := m.ctrl.Call(m, "Id")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ID indicates an expected call of ID.
|
||||
func (mr *MockListStorageMockRecorder) ID() *gomock.Call {
|
||||
// Id indicates an expected call of Id.
|
||||
func (mr *MockListStorageMockRecorder) Id() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockListStorage)(nil).ID))
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockListStorage)(nil).Id))
|
||||
}
|
||||
|
||||
// Root mocks base method.
|
||||
@ -205,18 +205,18 @@ func (mr *MockTreeStorageMockRecorder) Heads() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Heads", reflect.TypeOf((*MockTreeStorage)(nil).Heads))
|
||||
}
|
||||
|
||||
// ID mocks base method.
|
||||
func (m *MockTreeStorage) ID() string {
|
||||
// Id mocks base method.
|
||||
func (m *MockTreeStorage) Id() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ID")
|
||||
ret := m.ctrl.Call(m, "Id")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ID indicates an expected call of ID.
|
||||
func (mr *MockTreeStorageMockRecorder) ID() *gomock.Call {
|
||||
// Id indicates an expected call of Id.
|
||||
func (mr *MockTreeStorageMockRecorder) Id() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockTreeStorage)(nil).ID))
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockTreeStorage)(nil).Id))
|
||||
}
|
||||
|
||||
// Root mocks base method.
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
type TreeStorage interface {
|
||||
ID() string
|
||||
Id() string
|
||||
Root() (*treechangeproto.RawTreeChangeWithId, error)
|
||||
Heads() ([]string, error)
|
||||
SetHeads(heads []string) error
|
||||
|
||||
@ -3,13 +3,13 @@ package acllistbuilder
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
aclrecordproto2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/testutils/yamltests"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/cid"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/encryptionkey"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/symmetric"
|
||||
"hash/fnv"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"time"
|
||||
@ -19,12 +19,20 @@ import (
|
||||
)
|
||||
|
||||
type ACLListStorageBuilder struct {
|
||||
storage.ListStorage
|
||||
aclList string
|
||||
records []*aclrecordproto2.ACLRecord
|
||||
rawRecords []*aclrecordproto2.RawACLRecordWithId
|
||||
indexes map[string]int
|
||||
keychain *YAMLKeychain
|
||||
rawRoot *aclrecordproto2.RawACLRecordWithId
|
||||
root *aclrecordproto2.ACLRoot
|
||||
id string
|
||||
}
|
||||
|
||||
func NewACLListStorageBuilder(keychain *YAMLKeychain) *ACLListStorageBuilder {
|
||||
return &ACLListStorageBuilder{
|
||||
records: make([]*aclrecordproto2.ACLRecord, 0),
|
||||
indexes: make(map[string]int),
|
||||
keychain: keychain,
|
||||
}
|
||||
}
|
||||
@ -52,7 +60,7 @@ func NewACLListStorageBuilderFromFile(file string) (*ACLListStorageBuilder, erro
|
||||
return tb, nil
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) createRaw(rec proto.Marshaler, identity []byte) *aclrecordproto.RawACLRecordWithId {
|
||||
func (t *ACLListStorageBuilder) createRaw(rec proto.Marshaler, identity []byte) *aclrecordproto2.RawACLRecordWithId {
|
||||
protoMarshalled, err := rec.Marshal()
|
||||
if err != nil {
|
||||
panic("should be able to marshal final acl message!")
|
||||
@ -63,7 +71,7 @@ func (t *ACLListStorageBuilder) createRaw(rec proto.Marshaler, identity []byte)
|
||||
panic("should be able to sign final acl message!")
|
||||
}
|
||||
|
||||
rawRec := &aclrecordproto.RawACLRecord{
|
||||
rawRec := &aclrecordproto2.RawACLRecord{
|
||||
Payload: protoMarshalled,
|
||||
Signature: signature,
|
||||
}
|
||||
@ -75,62 +83,94 @@ func (t *ACLListStorageBuilder) createRaw(rec proto.Marshaler, identity []byte)
|
||||
|
||||
id, _ := cid.NewCIDFromBytes(rawMarshalled)
|
||||
|
||||
return &aclrecordproto.RawACLRecordWithId{
|
||||
return &aclrecordproto2.RawACLRecordWithId{
|
||||
Payload: rawMarshalled,
|
||||
Id: id,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) Head() (string, error) {
|
||||
l := len(t.records)
|
||||
if l > 0 {
|
||||
return t.rawRecords[l-1].Id, nil
|
||||
}
|
||||
return t.rawRoot.Id, nil
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) SetHead(headId string) error {
|
||||
panic("SetHead is not implemented")
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) Root() (*aclrecordproto2.RawACLRecordWithId, error) {
|
||||
return t.rawRoot, nil
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) GetRawRecord(ctx context.Context, id string) (*aclrecordproto2.RawACLRecordWithId, error) {
|
||||
recIdx, ok := t.indexes[id]
|
||||
if !ok {
|
||||
if id == t.rawRoot.Id {
|
||||
return t.rawRoot, nil
|
||||
}
|
||||
return nil, fmt.Errorf("no such record")
|
||||
}
|
||||
return t.rawRecords[recIdx], nil
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) AddRawRecord(ctx context.Context, rec *aclrecordproto2.RawACLRecordWithId) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) Id() string {
|
||||
return t.id
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) GetRawRecords() []*aclrecordproto2.RawACLRecordWithId {
|
||||
return t.rawRecords
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) GetKeychain() *YAMLKeychain {
|
||||
return t.keychain
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) Parse(l *YMLList) {
|
||||
func (t *ACLListStorageBuilder) Parse(tree *YMLList) {
|
||||
// Just to clarify - we are generating new identities for the ones that
|
||||
// are specified in the yml file, because our identities should be Ed25519
|
||||
// the same thing is happening for the encryption keys
|
||||
t.keychain.ParseKeys(&l.Keys)
|
||||
rawRoot := t.parseRoot(l.Root)
|
||||
var err error
|
||||
t.ListStorage, err = storage.NewInMemoryACLListStorage(rawRoot.Id, []*aclrecordproto.RawACLRecordWithId{rawRoot})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
prevId := rawRoot.Id
|
||||
for _, rec := range l.Records {
|
||||
t.keychain.ParseKeys(&tree.Keys)
|
||||
t.parseRoot(tree.Root)
|
||||
prevId := t.id
|
||||
for idx, rec := range tree.Records {
|
||||
newRecord := t.parseRecord(rec, prevId)
|
||||
rawRecord := t.createRaw(newRecord, newRecord.Identity)
|
||||
err = t.AddRawRecord(context.Background(), rawRecord)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
t.records = append(t.records, newRecord)
|
||||
t.rawRecords = append(t.rawRecords, rawRecord)
|
||||
t.indexes[rawRecord.Id] = idx
|
||||
prevId = rawRecord.Id
|
||||
}
|
||||
t.SetHead(prevId)
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) parseRecord(rec *Record, prevId string) *aclrecordproto.ACLRecord {
|
||||
func (t *ACLListStorageBuilder) parseRecord(rec *Record, prevId string) *aclrecordproto2.ACLRecord {
|
||||
k := t.keychain.GetKey(rec.ReadKey).(*SymKey)
|
||||
var aclChangeContents []*aclrecordproto.ACLContentValue
|
||||
var aclChangeContents []*aclrecordproto2.ACLContentValue
|
||||
for _, ch := range rec.AclChanges {
|
||||
aclChangeContent := t.parseACLChange(ch)
|
||||
aclChangeContents = append(aclChangeContents, aclChangeContent)
|
||||
}
|
||||
data := &aclrecordproto.ACLData{
|
||||
data := &aclrecordproto2.ACLData{
|
||||
AclContent: aclChangeContents,
|
||||
}
|
||||
bytes, _ := data.Marshal()
|
||||
|
||||
return &aclrecordproto.ACLRecord{
|
||||
return &aclrecordproto2.ACLRecord{
|
||||
PrevId: prevId,
|
||||
Identity: []byte(t.keychain.GetIdentity(rec.Identity)),
|
||||
Data: bytes,
|
||||
CurrentReadKeyHash: k.Hash,
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclrecordproto.ACLContentValue) {
|
||||
func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclrecordproto2.ACLContentValue) {
|
||||
switch {
|
||||
case ch.UserAdd != nil:
|
||||
add := ch.UserAdd
|
||||
@ -138,12 +178,12 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclrecord
|
||||
encKey := t.keychain.GetKey(add.EncryptionKey).(encryptionkey.PrivKey)
|
||||
rawKey, _ := encKey.GetPublic().Raw()
|
||||
|
||||
convCh = &aclrecordproto.ACLContentValue{
|
||||
Value: &aclrecordproto.ACLContentValue_UserAdd{
|
||||
UserAdd: &aclrecordproto.ACLUserAdd{
|
||||
convCh = &aclrecordproto2.ACLContentValue{
|
||||
Value: &aclrecordproto2.ACLContentValue_UserAdd{
|
||||
UserAdd: &aclrecordproto2.ACLUserAdd{
|
||||
Identity: []byte(t.keychain.GetIdentity(add.Identity)),
|
||||
EncryptionKey: rawKey,
|
||||
EncryptedReadKeys: t.encryptReadKeysWithPubKey(add.EncryptedReadKeys, encKey),
|
||||
EncryptedReadKeys: t.encryptReadKeys(add.EncryptedReadKeys, encKey),
|
||||
Permissions: t.convertPermission(add.Permission),
|
||||
},
|
||||
},
|
||||
@ -151,50 +191,52 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclrecord
|
||||
case ch.UserJoin != nil:
|
||||
join := ch.UserJoin
|
||||
|
||||
encKey := t.keychain.GetKey(join.EncryptionKey).(encryptionkey.PrivKey)
|
||||
encKey := t.keychain.
|
||||
GetKey(join.EncryptionKey).(encryptionkey.PrivKey)
|
||||
rawKey, _ := encKey.GetPublic().Raw()
|
||||
|
||||
idKey, _ := t.keychain.SigningKeysByYAMLName[join.Identity].GetPublic().Raw()
|
||||
signKey := t.keychain.GetKey(join.AcceptKey).(signingkey.PrivKey)
|
||||
idKey, _ := t.keychain.SigningKeysByYAMLIdentity[join.Identity].GetPublic().Raw()
|
||||
signKey := t.keychain.GetKey(join.AcceptSignature).(signingkey.PrivKey)
|
||||
signature, err := signKey.Sign(idKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
acceptPubKey, _ := signKey.GetPublic().Raw()
|
||||
|
||||
convCh = &aclrecordproto.ACLContentValue{
|
||||
Value: &aclrecordproto.ACLContentValue_UserJoin{
|
||||
UserJoin: &aclrecordproto.ACLUserJoin{
|
||||
convCh = &aclrecordproto2.ACLContentValue{
|
||||
Value: &aclrecordproto2.ACLContentValue_UserJoin{
|
||||
UserJoin: &aclrecordproto2.ACLUserJoin{
|
||||
Identity: []byte(t.keychain.GetIdentity(join.Identity)),
|
||||
EncryptionKey: rawKey,
|
||||
AcceptSignature: signature,
|
||||
AcceptPubKey: acceptPubKey,
|
||||
EncryptedReadKeys: t.encryptReadKeysWithPubKey(join.EncryptedReadKeys, encKey),
|
||||
InviteId: join.InviteId,
|
||||
EncryptedReadKeys: t.encryptReadKeys(join.EncryptedReadKeys, encKey),
|
||||
},
|
||||
},
|
||||
}
|
||||
case ch.UserInvite != nil:
|
||||
invite := ch.UserInvite
|
||||
rawAcceptKey, _ := t.keychain.GetKey(invite.AcceptKey).(signingkey.PrivKey).GetPublic().Raw()
|
||||
hash := t.keychain.GetKey(invite.EncryptionKey).(*SymKey).Hash
|
||||
encKey := t.keychain.ReadKeysByHash[hash]
|
||||
encKey := t.keychain.
|
||||
GetKey(invite.EncryptionKey).(encryptionkey.PrivKey)
|
||||
rawEncKey, _ := encKey.GetPublic().Raw()
|
||||
|
||||
convCh = &aclrecordproto.ACLContentValue{
|
||||
Value: &aclrecordproto.ACLContentValue_UserInvite{
|
||||
UserInvite: &aclrecordproto.ACLUserInvite{
|
||||
convCh = &aclrecordproto2.ACLContentValue{
|
||||
Value: &aclrecordproto2.ACLContentValue_UserInvite{
|
||||
UserInvite: &aclrecordproto2.ACLUserInvite{
|
||||
AcceptPublicKey: rawAcceptKey,
|
||||
EncryptSymKeyHash: hash,
|
||||
EncryptedReadKeys: t.encryptReadKeysWithSymKey(invite.EncryptedReadKeys, encKey.Key),
|
||||
EncryptPublicKey: rawEncKey,
|
||||
EncryptedReadKeys: t.encryptReadKeys(invite.EncryptedReadKeys, encKey),
|
||||
Permissions: t.convertPermission(invite.Permissions),
|
||||
InviteId: invite.InviteId,
|
||||
},
|
||||
},
|
||||
}
|
||||
case ch.UserPermissionChange != nil:
|
||||
permissionChange := ch.UserPermissionChange
|
||||
|
||||
convCh = &aclrecordproto.ACLContentValue{
|
||||
Value: &aclrecordproto.ACLContentValue_UserPermissionChange{
|
||||
UserPermissionChange: &aclrecordproto.ACLUserPermissionChange{
|
||||
convCh = &aclrecordproto2.ACLContentValue{
|
||||
Value: &aclrecordproto2.ACLContentValue_UserPermissionChange{
|
||||
UserPermissionChange: &aclrecordproto2.ACLUserPermissionChange{
|
||||
Identity: []byte(t.keychain.GetIdentity(permissionChange.Identity)),
|
||||
Permissions: t.convertPermission(permissionChange.Permission),
|
||||
},
|
||||
@ -205,24 +247,24 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclrecord
|
||||
|
||||
newReadKey := t.keychain.GetKey(remove.NewReadKey).(*SymKey)
|
||||
|
||||
var replaces []*aclrecordproto.ACLReadKeyReplace
|
||||
var replaces []*aclrecordproto2.ACLReadKeyReplace
|
||||
for _, id := range remove.IdentitiesLeft {
|
||||
encKey := t.keychain.EncryptionKeysByYAMLName[id]
|
||||
encKey := t.keychain.EncryptionKeysByYAMLIdentity[id]
|
||||
rawEncKey, _ := encKey.GetPublic().Raw()
|
||||
encReadKey, err := encKey.GetPublic().Encrypt(newReadKey.Key.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
replaces = append(replaces, &aclrecordproto.ACLReadKeyReplace{
|
||||
replaces = append(replaces, &aclrecordproto2.ACLReadKeyReplace{
|
||||
Identity: []byte(t.keychain.GetIdentity(id)),
|
||||
EncryptionKey: rawEncKey,
|
||||
EncryptedReadKey: encReadKey,
|
||||
})
|
||||
}
|
||||
|
||||
convCh = &aclrecordproto.ACLContentValue{
|
||||
Value: &aclrecordproto.ACLContentValue_UserRemove{
|
||||
UserRemove: &aclrecordproto.ACLUserRemove{
|
||||
convCh = &aclrecordproto2.ACLContentValue{
|
||||
Value: &aclrecordproto2.ACLContentValue_UserRemove{
|
||||
UserRemove: &aclrecordproto2.ACLUserRemove{
|
||||
Identity: []byte(t.keychain.GetIdentity(remove.RemovedIdentity)),
|
||||
ReadKeyReplaces: replaces,
|
||||
},
|
||||
@ -236,7 +278,7 @@ func (t *ACLListStorageBuilder) parseACLChange(ch *ACLChange) (convCh *aclrecord
|
||||
return convCh
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) encryptReadKeysWithPubKey(keys []string, encKey encryptionkey.PrivKey) (enc [][]byte) {
|
||||
func (t *ACLListStorageBuilder) encryptReadKeys(keys []string, encKey encryptionkey.PrivKey) (enc [][]byte) {
|
||||
for _, k := range keys {
|
||||
realKey := t.keychain.GetKey(k).(*SymKey).Key.Bytes()
|
||||
res, err := encKey.GetPublic().Encrypt(realKey)
|
||||
@ -249,47 +291,43 @@ func (t *ACLListStorageBuilder) encryptReadKeysWithPubKey(keys []string, encKey
|
||||
return
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) encryptReadKeysWithSymKey(keys []string, key *symmetric.Key) (enc [][]byte) {
|
||||
for _, k := range keys {
|
||||
realKey := t.keychain.GetKey(k).(*SymKey).Key.Bytes()
|
||||
res, err := key.Encrypt(realKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
enc = append(enc, res)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) convertPermission(perm string) aclrecordproto.ACLUserPermissions {
|
||||
func (t *ACLListStorageBuilder) convertPermission(perm string) aclrecordproto2.ACLUserPermissions {
|
||||
switch perm {
|
||||
case "admin":
|
||||
return aclrecordproto.ACLUserPermissions_Admin
|
||||
return aclrecordproto2.ACLUserPermissions_Admin
|
||||
case "writer":
|
||||
return aclrecordproto.ACLUserPermissions_Writer
|
||||
return aclrecordproto2.ACLUserPermissions_Writer
|
||||
case "reader":
|
||||
return aclrecordproto.ACLUserPermissions_Reader
|
||||
return aclrecordproto2.ACLUserPermissions_Reader
|
||||
default:
|
||||
panic(fmt.Sprintf("incorrect permission: %s", perm))
|
||||
}
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) traverseFromHead(f func(rec *aclrecordproto.ACLRecord, id string) error) (err error) {
|
||||
panic("this was removed, add if needed")
|
||||
func (t *ACLListStorageBuilder) traverseFromHead(f func(rec *aclrecordproto2.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 {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) parseRoot(root *Root) (rawRoot *aclrecordproto.RawACLRecordWithId) {
|
||||
rawSignKey, _ := t.keychain.SigningKeysByYAMLName[root.Identity].GetPublic().Raw()
|
||||
rawEncKey, _ := t.keychain.EncryptionKeysByYAMLName[root.Identity].GetPublic().Raw()
|
||||
readKey := t.keychain.ReadKeysByYAMLName[root.Identity]
|
||||
aclRoot := &aclrecordproto.ACLRoot{
|
||||
func (t *ACLListStorageBuilder) parseRoot(root *Root) {
|
||||
rawSignKey, _ := t.keychain.SigningKeysByYAMLIdentity[root.Identity].GetPublic().Raw()
|
||||
rawEncKey, _ := t.keychain.EncryptionKeysByYAMLIdentity[root.Identity].GetPublic().Raw()
|
||||
readKey, _ := aclrecordproto2.ACLReadKeyDerive(rawSignKey, rawEncKey)
|
||||
hasher := fnv.New64()
|
||||
hasher.Write(readKey.Bytes())
|
||||
t.root = &aclrecordproto2.ACLRoot{
|
||||
Identity: rawSignKey,
|
||||
EncryptionKey: rawEncKey,
|
||||
SpaceId: root.SpaceId,
|
||||
EncryptedReadKey: nil,
|
||||
DerivationScheme: "scheme",
|
||||
CurrentReadKeyHash: readKey.Hash,
|
||||
CurrentReadKeyHash: hasher.Sum64(),
|
||||
}
|
||||
return t.createRaw(aclRoot, rawSignKey)
|
||||
t.rawRoot = t.createRaw(t.root, rawSignKey)
|
||||
t.id = t.rawRoot.Id
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ package tree
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/common"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
|
||||
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/symmetric"
|
||||
@ -20,7 +20,7 @@ type ObjectTreeCreatePayload struct {
|
||||
Identity []byte
|
||||
}
|
||||
|
||||
func BuildObjectTree(treeStorage storage.TreeStorage, aclList list.ACLList) (ObjectTree, error) {
|
||||
func BuildObjectTree(treeStorage storage2.TreeStorage, aclList list.ACLList) (ObjectTree, error) {
|
||||
rootChange, err := treeStorage.Root()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -32,14 +32,14 @@ func BuildObjectTree(treeStorage storage.TreeStorage, aclList list.ACLList) (Obj
|
||||
func CreateDerivedObjectTree(
|
||||
payload ObjectTreeCreatePayload,
|
||||
aclList list.ACLList,
|
||||
createStorage storage.TreeStorageCreatorFunc) (objTree ObjectTree, err error) {
|
||||
createStorage storage2.TreeStorageCreatorFunc) (objTree ObjectTree, err error) {
|
||||
return createObjectTree(payload, 0, nil, aclList, createStorage)
|
||||
}
|
||||
|
||||
func CreateObjectTree(
|
||||
payload ObjectTreeCreatePayload,
|
||||
aclList list.ACLList,
|
||||
createStorage storage.TreeStorageCreatorFunc) (objTree ObjectTree, err error) {
|
||||
createStorage storage2.TreeStorageCreatorFunc) (objTree ObjectTree, err error) {
|
||||
bytes := make([]byte, 32)
|
||||
_, err = rand.Read(bytes)
|
||||
if err != nil {
|
||||
@ -53,7 +53,7 @@ func createObjectTree(
|
||||
timestamp int64,
|
||||
seed []byte,
|
||||
aclList list.ACLList,
|
||||
createStorage storage.TreeStorageCreatorFunc) (objTree ObjectTree, err error) {
|
||||
createStorage storage2.TreeStorageCreatorFunc) (objTree ObjectTree, err error) {
|
||||
aclList.RLock()
|
||||
aclHeadId := aclList.Head().Id
|
||||
aclList.RUnlock()
|
||||
@ -77,7 +77,8 @@ func createObjectTree(
|
||||
}
|
||||
|
||||
// create storage
|
||||
st, err := createStorage(storage.TreeStorageCreatePayload{
|
||||
st, err := createStorage(storage2.TreeStorageCreatePayload{
|
||||
TreeId: raw.Id,
|
||||
RootRawChange: raw,
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{raw},
|
||||
Heads: []string{raw.Id},
|
||||
@ -126,7 +127,8 @@ func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
|
||||
}
|
||||
}
|
||||
|
||||
objTree.id = objTree.treeStorage.ID()
|
||||
objTree.id = objTree.treeStorage.Id()
|
||||
|
||||
objTree.root, err = objTree.treeStorage.Root()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
111
node/acl/service.go
Normal file
111
node/acl/service.go
Normal file
@ -0,0 +1,111 @@
|
||||
package acl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusclient"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusproto"
|
||||
"time"
|
||||
)
|
||||
|
||||
const CName = "node.acl"
|
||||
|
||||
var log = logger.NewNamed(CName)
|
||||
|
||||
type Service interface {
|
||||
app.Component
|
||||
}
|
||||
|
||||
type service struct {
|
||||
consService consensusclient.Service
|
||||
account account.Service
|
||||
}
|
||||
|
||||
func (s *service) Init(a *app.App) (err error) {
|
||||
s.consService = a.MustComponent(consensusclient.CName).(consensusclient.Service)
|
||||
s.account = a.MustComponent(account.CName).(account.Service)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *service) Name() (name string) {
|
||||
return CName
|
||||
}
|
||||
|
||||
func (s *service) CreateLog(ctx context.Context, aclId string, rec *aclrecordproto.RawACLRecordWithId) (err error) {
|
||||
logId, err := cidToByte(aclId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
recId, err := cidToByte(rec.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
acc := s.account.Account()
|
||||
rec.AcceptorIdentity = acc.Identity
|
||||
if rec.AcceptorSignature, err = acc.SignKey.Sign(rec.Payload); err != nil {
|
||||
return
|
||||
}
|
||||
recPayload, err := rec.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return s.consService.AddLog(ctx, &consensusproto.Log{
|
||||
Id: logId,
|
||||
Records: []*consensusproto.Record{
|
||||
{
|
||||
Id: recId,
|
||||
Payload: recPayload,
|
||||
CreatedUnix: uint64(time.Now().Unix()),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *service) AddRecord(ctx context.Context, aclId string, rec *aclrecordproto.RawACLRecordWithId) (err error) {
|
||||
logId, err := cidToByte(aclId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
recId, err := cidToByte(rec.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
acc := s.account.Account()
|
||||
rec.AcceptorIdentity = acc.Identity
|
||||
if rec.AcceptorSignature, err = acc.SignKey.Sign(rec.Payload); err != nil {
|
||||
return
|
||||
}
|
||||
recPayload, err := rec.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return s.consService.AddRecord(ctx, logId, &consensusproto.Record{
|
||||
Id: recId,
|
||||
PrevId: nil, //TODO:
|
||||
Payload: recPayload,
|
||||
CreatedUnix: uint64(time.Now().Unix()),
|
||||
})
|
||||
}
|
||||
|
||||
func (s *service) Watch(ctx context.Context, spaceId, aclId string, h synchandler.SyncHandler) (err error) {
|
||||
w, err := newWatcher(spaceId, aclId, h)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = s.consService.Watch(w.logId, w); err != nil {
|
||||
return err
|
||||
}
|
||||
return w.Ready(ctx)
|
||||
}
|
||||
|
||||
func (s *service) UnWatch(aclId string) (err error) {
|
||||
logId, err := cidToByte(aclId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return s.consService.UnWatch(logId)
|
||||
}
|
||||
19
node/acl/util.go
Normal file
19
node/acl/util.go
Normal file
@ -0,0 +1,19 @@
|
||||
package acl
|
||||
|
||||
import "github.com/ipfs/go-cid"
|
||||
|
||||
func cidToString(b []byte) (s string, err error) {
|
||||
rcid, err := cid.Cast(b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return rcid.String(), nil
|
||||
}
|
||||
|
||||
func cidToByte(s string) (b []byte, err error) {
|
||||
rcid, err := cid.Decode(s)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return rcid.Bytes(), nil
|
||||
}
|
||||
16
node/acl/util_test.go
Normal file
16
node/acl/util_test.go
Normal file
@ -0,0 +1,16 @@
|
||||
package acl
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/cid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCIDLen(t *testing.T) {
|
||||
s, _ := cid.NewCIDFromBytes([]byte("some data"))
|
||||
t.Log(s, len(s))
|
||||
b, _ := cidToByte(s)
|
||||
t.Log(b, len(b))
|
||||
s2, _ := cidToString(b)
|
||||
assert.Equal(t, s, s2)
|
||||
}
|
||||
93
node/acl/watcher.go
Normal file
93
node/acl/watcher.go
Normal file
@ -0,0 +1,93 @@
|
||||
package acl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusproto"
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func newWatcher(spaceId, aclId string, h synchandler.SyncHandler) (w *watcher, err error) {
|
||||
w = &watcher{
|
||||
aclId: aclId,
|
||||
spaceId: spaceId,
|
||||
handler: h,
|
||||
ready: make(chan struct{}),
|
||||
}
|
||||
if w.logId, err = cidToByte(aclId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type watcher struct {
|
||||
spaceId string
|
||||
aclId string
|
||||
logId []byte
|
||||
handler synchandler.SyncHandler
|
||||
ready chan struct{}
|
||||
isReady sync.Once
|
||||
err error
|
||||
}
|
||||
|
||||
func (w *watcher) AddConsensusRecords(recs []*consensusproto.Record) {
|
||||
w.isReady.Do(func() {
|
||||
close(w.ready)
|
||||
})
|
||||
records := make([]*aclrecordproto.RawACLRecordWithId, 0, len(recs))
|
||||
|
||||
for _, rec := range recs {
|
||||
recId, err := cidToString(rec.Id)
|
||||
if err != nil {
|
||||
log.Error("received invalid id from consensus node", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
records = append(records, &aclrecordproto.RawACLRecordWithId{
|
||||
Payload: rec.Payload,
|
||||
Id: recId,
|
||||
})
|
||||
}
|
||||
|
||||
aclReq := &aclrecordproto.ACLSyncMessage{
|
||||
Content: &aclrecordproto.ACLSyncContentValue{
|
||||
Value: &aclrecordproto.ACLSyncContentValue_AddRecords{
|
||||
AddRecords: &aclrecordproto.ACLAddRecords{
|
||||
Records: records,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
payload, err := aclReq.Marshal()
|
||||
if err != nil {
|
||||
log.Error("acl payload marshal error", zap.Error(err))
|
||||
return
|
||||
}
|
||||
req := &spacesyncproto.ObjectSyncMessage{
|
||||
SpaceId: w.spaceId,
|
||||
Payload: payload,
|
||||
ObjectId: w.aclId,
|
||||
}
|
||||
|
||||
if err = w.handler.HandleMessage(context.TODO(), "", req); err != nil {
|
||||
log.Warn("handle message error", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watcher) AddConsensusError(err error) {
|
||||
w.isReady.Do(func() {
|
||||
w.err = err
|
||||
close(w.ready)
|
||||
})
|
||||
}
|
||||
|
||||
func (w *watcher) Ready(ctx context.Context) (err error) {
|
||||
select {
|
||||
case <-w.ready:
|
||||
return w.err
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
@ -82,7 +82,7 @@ func createListStorage(db *pogreb.DB, root *aclrecordproto.RawACLRecordWithId) (
|
||||
return
|
||||
}
|
||||
|
||||
func (l *listStorage) ID() string {
|
||||
func (l *listStorage) Id() string {
|
||||
return l.id
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
"go.uber.org/zap"
|
||||
"path"
|
||||
"sync"
|
||||
@ -22,7 +22,7 @@ type spaceStorage struct {
|
||||
spaceId string
|
||||
objDb *pogreb.DB
|
||||
keys spaceKeys
|
||||
aclStorage storage2.ListStorage
|
||||
aclStorage storage.ListStorage
|
||||
header *spacesyncproto.RawSpaceHeaderWithId
|
||||
mx sync.Mutex
|
||||
}
|
||||
@ -88,8 +88,8 @@ func createSpaceStorage(rootPath string, payload spacestorage.SpaceStorageCreate
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.With(zap.String("id", payload.SpaceHeaderWithId.Id), zap.Error(err)).Warn("failed to create storage")
|
||||
if err != nil {
|
||||
db.Close()
|
||||
}
|
||||
}()
|
||||
@ -129,15 +129,15 @@ func createSpaceStorage(rootPath string, payload spacestorage.SpaceStorageCreate
|
||||
return
|
||||
}
|
||||
|
||||
func (s *spaceStorage) ID() string {
|
||||
func (s *spaceStorage) Id() string {
|
||||
return s.spaceId
|
||||
}
|
||||
|
||||
func (s *spaceStorage) TreeStorage(id string) (storage2.TreeStorage, error) {
|
||||
func (s *spaceStorage) TreeStorage(id string) (storage.TreeStorage, error) {
|
||||
return newTreeStorage(s.objDb, id)
|
||||
}
|
||||
|
||||
func (s *spaceStorage) CreateTreeStorage(payload storage2.TreeStorageCreatePayload) (ts storage2.TreeStorage, err error) {
|
||||
func (s *spaceStorage) CreateTreeStorage(payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) {
|
||||
// we have mutex here, so we prevent overwriting the heads of a tree on concurrent creation
|
||||
s.mx.Lock()
|
||||
defer s.mx.Unlock()
|
||||
@ -145,7 +145,7 @@ func (s *spaceStorage) CreateTreeStorage(payload storage2.TreeStorageCreatePaylo
|
||||
return createTreeStorage(s.objDb, payload)
|
||||
}
|
||||
|
||||
func (s *spaceStorage) ACLStorage() (storage2.ListStorage, error) {
|
||||
func (s *spaceStorage) ACLStorage() (storage.ListStorage, error) {
|
||||
return s.aclStorage, nil
|
||||
}
|
||||
|
||||
@ -156,13 +156,13 @@ func (s *spaceStorage) SpaceHeader() (header *spacesyncproto.RawSpaceHeaderWithI
|
||||
func (s *spaceStorage) StoredIds() (ids []string, err error) {
|
||||
index := s.objDb.Items()
|
||||
|
||||
key, _, err := index.Next()
|
||||
key, val, err := index.Next()
|
||||
for err == nil {
|
||||
strKey := string(key)
|
||||
if isRootIdKey(strKey) {
|
||||
ids = append(ids, getRootId(strKey))
|
||||
ids = append(ids, string(val))
|
||||
}
|
||||
key, _, err = index.Next()
|
||||
key, val, err = index.Next()
|
||||
}
|
||||
|
||||
if err != pogreb.ErrIterationDone {
|
||||
|
||||
@ -3,7 +3,7 @@ package storage
|
||||
import (
|
||||
"context"
|
||||
"github.com/akrylysov/pogreb"
|
||||
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
|
||||
)
|
||||
|
||||
@ -48,7 +48,7 @@ func newTreeStorage(db *pogreb.DB, treeId string) (ts storage.TreeStorage, err e
|
||||
}
|
||||
|
||||
func createTreeStorage(db *pogreb.DB, payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) {
|
||||
keys := newTreeKeys(payload.RootRawChange.Id)
|
||||
keys := newTreeKeys(payload.TreeId)
|
||||
has, err := db.Has(keys.HeadsKey())
|
||||
if err != nil {
|
||||
return
|
||||
@ -86,7 +86,7 @@ func createTreeStorage(db *pogreb.DB, payload storage.TreeStorageCreatePayload)
|
||||
return
|
||||
}
|
||||
|
||||
func (t *treeStorage) ID() string {
|
||||
func (t *treeStorage) Id() string {
|
||||
return t.id
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user