mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-08 05:57:03 +09:00
aclService: OwnerId, Permissions
This commit is contained in:
parent
19798f2295
commit
151dd9508d
5 changed files with 231 additions and 8 deletions
17
acl/acl.go
17
acl/acl.go
|
@ -1,3 +1,4 @@
|
||||||
|
//go:generate mockgen -destination mock_acl/mock_acl.go github.com/anyproto/any-sync/acl AclService
|
||||||
package acl
|
package acl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -21,13 +22,15 @@ const CName = "coordinator.acl"
|
||||||
|
|
||||||
var log = logger.NewNamed(CName)
|
var log = logger.NewNamed(CName)
|
||||||
|
|
||||||
func New() Acl {
|
func New() AclService {
|
||||||
return &aclService{}
|
return &aclService{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Acl interface {
|
type AclService interface {
|
||||||
AddRecord(ctx context.Context, spaceId string, rec *consensusproto.RawRecord) (result *consensusproto.RawRecordWithId, err error)
|
AddRecord(ctx context.Context, spaceId string, rec *consensusproto.RawRecord) (result *consensusproto.RawRecordWithId, err error)
|
||||||
RecordsAfter(ctx context.Context, spaceId, aclHead string) (result []*consensusproto.RawRecordWithId, err error)
|
RecordsAfter(ctx context.Context, spaceId, aclHead string) (result []*consensusproto.RawRecordWithId, err error)
|
||||||
|
Permissions(ctx context.Context, identity crypto.PubKey, spaceId string) (res list.AclPermissions, err error)
|
||||||
|
OwnerPubKey(ctx context.Context, spaceId string) (ownerIdentity crypto.PubKey, err error)
|
||||||
app.ComponentRunnable
|
app.ComponentRunnable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +99,16 @@ func (as *aclService) RecordsAfter(ctx context.Context, spaceId, aclHead string)
|
||||||
return acl.RecordsAfter(ctx, aclHead)
|
return acl.RecordsAfter(ctx, aclHead)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (as *aclService) OwnerPubKey(ctx context.Context, spaceId string) (ownerIdentity crypto.PubKey, err error) {
|
||||||
|
acl, err := as.get(ctx, spaceId)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
acl.RLock()
|
||||||
|
defer acl.RUnlock()
|
||||||
|
return acl.AclState().OwnerPubKey()
|
||||||
|
}
|
||||||
|
|
||||||
func (as *aclService) Permissions(ctx context.Context, identity crypto.PubKey, spaceId string) (res list.AclPermissions, err error) {
|
func (as *aclService) Permissions(ctx context.Context, identity crypto.PubKey, spaceId string) (res list.AclPermissions, err error) {
|
||||||
acl, err := as.get(ctx, spaceId)
|
acl, err := as.get(ctx, spaceId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -103,13 +103,45 @@ func TestAclService_RecordsAfter(t *testing.T) {
|
||||||
assert.Len(t, res, 1)
|
assert.Len(t, res, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAclService(t *testing.T) {
|
||||||
|
ownerKeys, err := accountdata.NewRandom()
|
||||||
|
require.NoError(t, err)
|
||||||
|
spaceId := "spaceId"
|
||||||
|
ownerAcl, err := list.NewTestDerivedAcl(spaceId, ownerKeys)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
fx := newFixture(t)
|
||||||
|
defer fx.finish(t)
|
||||||
|
|
||||||
|
fx.consCl.EXPECT().Watch(spaceId, gomock.Any()).DoAndReturn(func(spaceId string, w consensusclient.Watcher) error {
|
||||||
|
go func() {
|
||||||
|
w.AddConsensusRecords([]*consensusproto.RawRecordWithId{
|
||||||
|
ownerAcl.Root(),
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
fx.consCl.EXPECT().UnWatch(spaceId)
|
||||||
|
|
||||||
|
t.Run("permissions", func(t *testing.T) {
|
||||||
|
res, err := fx.Permissions(ctx, ownerKeys.SignKey.GetPublic(), spaceId)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, res.IsOwner())
|
||||||
|
})
|
||||||
|
t.Run("ownerPUbKey", func(t *testing.T) {
|
||||||
|
res, err := fx.OwnerPubKey(ctx, spaceId)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, ownerKeys.SignKey.GetPublic().Account(), res.Account())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func newFixture(t *testing.T) *fixture {
|
func newFixture(t *testing.T) *fixture {
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
fx := &fixture{
|
fx := &fixture{
|
||||||
a: new(app.App),
|
a: new(app.App),
|
||||||
ctrl: ctrl,
|
ctrl: ctrl,
|
||||||
consCl: mock_consensusclient.NewMockService(ctrl),
|
consCl: mock_consensusclient.NewMockService(ctrl),
|
||||||
Acl: New(),
|
AclService: New(),
|
||||||
}
|
}
|
||||||
|
|
||||||
fx.consCl.EXPECT().Name().Return(consensusclient.CName).AnyTimes()
|
fx.consCl.EXPECT().Name().Return(consensusclient.CName).AnyTimes()
|
||||||
|
@ -117,7 +149,7 @@ func newFixture(t *testing.T) *fixture {
|
||||||
fx.consCl.EXPECT().Run(gomock.Any()).AnyTimes()
|
fx.consCl.EXPECT().Run(gomock.Any()).AnyTimes()
|
||||||
fx.consCl.EXPECT().Close(gomock.Any()).AnyTimes()
|
fx.consCl.EXPECT().Close(gomock.Any()).AnyTimes()
|
||||||
|
|
||||||
fx.a.Register(fx.consCl).Register(fx.Acl).Register(&accounttest.AccountTestService{})
|
fx.a.Register(fx.consCl).Register(fx.AclService).Register(&accounttest.AccountTestService{})
|
||||||
|
|
||||||
require.NoError(t, fx.a.Start(ctx))
|
require.NoError(t, fx.a.Start(ctx))
|
||||||
return fx
|
return fx
|
||||||
|
@ -127,7 +159,7 @@ type fixture struct {
|
||||||
a *app.App
|
a *app.App
|
||||||
ctrl *gomock.Controller
|
ctrl *gomock.Controller
|
||||||
consCl *mock_consensusclient.MockService
|
consCl *mock_consensusclient.MockService
|
||||||
Acl
|
AclService
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fx *fixture) finish(t *testing.T) {
|
func (fx *fixture) finish(t *testing.T) {
|
||||||
|
|
160
acl/mock_acl/mock_acl.go
Normal file
160
acl/mock_acl/mock_acl.go
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
|
// Source: github.com/anyproto/any-sync/acl (interfaces: AclService)
|
||||||
|
//
|
||||||
|
// Generated by this command:
|
||||||
|
//
|
||||||
|
// mockgen -destination mock_acl/mock_acl.go github.com/anyproto/any-sync/acl AclService
|
||||||
|
//
|
||||||
|
|
||||||
|
// Package mock_acl is a generated GoMock package.
|
||||||
|
package mock_acl
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
|
app "github.com/anyproto/any-sync/app"
|
||||||
|
list "github.com/anyproto/any-sync/commonspace/object/acl/list"
|
||||||
|
consensusproto "github.com/anyproto/any-sync/consensus/consensusproto"
|
||||||
|
crypto "github.com/anyproto/any-sync/util/crypto"
|
||||||
|
gomock "go.uber.org/mock/gomock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockAclService is a mock of AclService interface.
|
||||||
|
type MockAclService struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockAclServiceMockRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockAclServiceMockRecorder is the mock recorder for MockAclService.
|
||||||
|
type MockAclServiceMockRecorder struct {
|
||||||
|
mock *MockAclService
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockAclService creates a new mock instance.
|
||||||
|
func NewMockAclService(ctrl *gomock.Controller) *MockAclService {
|
||||||
|
mock := &MockAclService{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockAclServiceMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
|
func (m *MockAclService) EXPECT() *MockAclServiceMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRecord mocks base method.
|
||||||
|
func (m *MockAclService) AddRecord(arg0 context.Context, arg1 string, arg2 *consensusproto.RawRecord) (*consensusproto.RawRecordWithId, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "AddRecord", arg0, arg1, arg2)
|
||||||
|
ret0, _ := ret[0].(*consensusproto.RawRecordWithId)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRecord indicates an expected call of AddRecord.
|
||||||
|
func (mr *MockAclServiceMockRecorder) AddRecord(arg0, arg1, arg2 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRecord", reflect.TypeOf((*MockAclService)(nil).AddRecord), arg0, arg1, arg2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close mocks base method.
|
||||||
|
func (m *MockAclService) Close(arg0 context.Context) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Close", arg0)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close indicates an expected call of Close.
|
||||||
|
func (mr *MockAclServiceMockRecorder) Close(arg0 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockAclService)(nil).Close), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init mocks base method.
|
||||||
|
func (m *MockAclService) Init(arg0 *app.App) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Init", arg0)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init indicates an expected call of Init.
|
||||||
|
func (mr *MockAclServiceMockRecorder) Init(arg0 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockAclService)(nil).Init), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name mocks base method.
|
||||||
|
func (m *MockAclService) Name() string {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Name")
|
||||||
|
ret0, _ := ret[0].(string)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name indicates an expected call of Name.
|
||||||
|
func (mr *MockAclServiceMockRecorder) Name() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockAclService)(nil).Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// OwnerPubKey mocks base method.
|
||||||
|
func (m *MockAclService) OwnerPubKey(arg0 context.Context, arg1 string) (crypto.PubKey, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "OwnerPubKey", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(crypto.PubKey)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// OwnerPubKey indicates an expected call of OwnerPubKey.
|
||||||
|
func (mr *MockAclServiceMockRecorder) OwnerPubKey(arg0, arg1 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OwnerPubKey", reflect.TypeOf((*MockAclService)(nil).OwnerPubKey), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permissions mocks base method.
|
||||||
|
func (m *MockAclService) Permissions(arg0 context.Context, arg1 crypto.PubKey, arg2 string) (list.AclPermissions, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Permissions", arg0, arg1, arg2)
|
||||||
|
ret0, _ := ret[0].(list.AclPermissions)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permissions indicates an expected call of Permissions.
|
||||||
|
func (mr *MockAclServiceMockRecorder) Permissions(arg0, arg1, arg2 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Permissions", reflect.TypeOf((*MockAclService)(nil).Permissions), arg0, arg1, arg2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordsAfter mocks base method.
|
||||||
|
func (m *MockAclService) RecordsAfter(arg0 context.Context, arg1, arg2 string) ([]*consensusproto.RawRecordWithId, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "RecordsAfter", arg0, arg1, arg2)
|
||||||
|
ret0, _ := ret[0].([]*consensusproto.RawRecordWithId)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordsAfter indicates an expected call of RecordsAfter.
|
||||||
|
func (mr *MockAclServiceMockRecorder) RecordsAfter(arg0, arg1, arg2 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordsAfter", reflect.TypeOf((*MockAclService)(nil).RecordsAfter), arg0, arg1, arg2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run mocks base method.
|
||||||
|
func (m *MockAclService) Run(arg0 context.Context) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Run", arg0)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run indicates an expected call of Run.
|
||||||
|
func (mr *MockAclServiceMockRecorder) Run(arg0 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockAclService)(nil).Run), arg0)
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ var (
|
||||||
ErrIncorrectRoot = errors.New("incorrect root")
|
ErrIncorrectRoot = errors.New("incorrect root")
|
||||||
ErrIncorrectRecordSequence = errors.New("incorrect prev id of a record")
|
ErrIncorrectRecordSequence = errors.New("incorrect prev id of a record")
|
||||||
ErrMetadataTooLarge = errors.New("metadata size too large")
|
ErrMetadataTooLarge = errors.New("metadata size too large")
|
||||||
|
ErrOwnerNotFound = errors.New("owner not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
const MaxMetadataLen = 1024
|
const MaxMetadataLen = 1024
|
||||||
|
@ -844,6 +845,15 @@ func (st *AclState) LastRecordId() string {
|
||||||
return st.lastRecordId
|
return st.lastRecordId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (st *AclState) OwnerPubKey() (ownerIdentity crypto.PubKey, err error) {
|
||||||
|
for _, aState := range st.accountStates {
|
||||||
|
if aState.Permissions.IsOwner() {
|
||||||
|
return aState.PubKey, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, ErrOwnerNotFound
|
||||||
|
}
|
||||||
|
|
||||||
func (st *AclState) deriveKey() (crypto.SymKey, error) {
|
func (st *AclState) deriveKey() (crypto.SymKey, error) {
|
||||||
keyBytes, err := st.key.Raw()
|
keyBytes, err := st.key.Raw()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/accountdata"
|
"github.com/anyproto/any-sync/commonspace/object/accountdata"
|
||||||
|
@ -395,3 +396,10 @@ func TestAclList_RequestRemove(t *testing.T) {
|
||||||
require.Nil(t, accountState().keys[removeRec.Id].ReadKey)
|
require.Nil(t, accountState().keys[removeRec.Id].ReadKey)
|
||||||
require.NotEmpty(t, accountState().keys[fx.ownerAcl.Id()])
|
require.NotEmpty(t, accountState().keys[fx.ownerAcl.Id()])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAclState_OwnerPubKey(t *testing.T) {
|
||||||
|
fx := newFixture(t)
|
||||||
|
pubKey, err := fx.ownerAcl.AclState().OwnerPubKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, fx.ownerKeys.SignKey.GetPublic().Account(), pubKey.Account())
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue