Add first ACL list test and other refactoring
This commit is contained in:
parent
a17b102756
commit
0dcb95fbcd
@ -56,12 +56,13 @@ func newACLStateWithIdentity(
|
||||
}
|
||||
}
|
||||
|
||||
func newACLState() *ACLState {
|
||||
func newACLState(decoder keys.Decoder) *ACLState {
|
||||
return &ACLState{
|
||||
userReadKeys: make(map[uint64]*symmetric.Key),
|
||||
userStates: make(map[string]*aclpb.ACLChangeUserState),
|
||||
userInvites: make(map[string]*aclpb.ACLChangeUserInvite),
|
||||
permissionsAtRecord: make(map[string][]UserPermissionPair),
|
||||
signingPubKeyDecoder: decoder,
|
||||
userReadKeys: make(map[uint64]*symmetric.Key),
|
||||
userStates: make(map[string]*aclpb.ACLChangeUserState),
|
||||
userInvites: make(map[string]*aclpb.ACLChangeUserInvite),
|
||||
permissionsAtRecord: make(map[string][]UserPermissionPair),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -20,8 +20,10 @@ func newACLStateBuilderWithIdentity(decoder keys.Decoder, accountData *account.A
|
||||
}
|
||||
}
|
||||
|
||||
func newACLStateBuilder() *aclStateBuilder {
|
||||
return &aclStateBuilder{}
|
||||
func newACLStateBuilder(decoder keys.Decoder) *aclStateBuilder {
|
||||
return &aclStateBuilder{
|
||||
decoder: decoder,
|
||||
}
|
||||
}
|
||||
|
||||
func (sb *aclStateBuilder) Build(records []*Record) (*ACLState, error) {
|
||||
@ -30,10 +32,10 @@ func (sb *aclStateBuilder) Build(records []*Record) (*ACLState, error) {
|
||||
state *ACLState
|
||||
)
|
||||
|
||||
if sb.decoder != nil {
|
||||
if sb.key != nil {
|
||||
state = newACLStateWithIdentity(sb.identity, sb.key, sb.decoder)
|
||||
} else {
|
||||
state = newACLState()
|
||||
state = newACLState(sb.decoder)
|
||||
}
|
||||
for _, rec := range records {
|
||||
err = state.applyChangeAndUpdate(rec)
|
||||
|
||||
@ -6,6 +6,7 @@ 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/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@ -44,11 +45,24 @@ type aclList struct {
|
||||
|
||||
func BuildACLListWithIdentity(acc *account.AccountData, storage storage.ListStorage) (ACLList, error) {
|
||||
builder := newACLStateBuilderWithIdentity(acc.Decoder, acc)
|
||||
return buildWithACLStateBuilder(builder, storage)
|
||||
}
|
||||
|
||||
func BuildACLList(decoder keys.Decoder, storage storage.ListStorage) (ACLList, error) {
|
||||
return buildWithACLStateBuilder(newACLStateBuilder(decoder), storage)
|
||||
}
|
||||
|
||||
func buildWithACLStateBuilder(builder *aclStateBuilder, storage storage.ListStorage) (ACLList, error) {
|
||||
header, err := storage.Header()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id, err := storage.ID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawRecord, err := storage.Head()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -94,6 +108,7 @@ func BuildACLListWithIdentity(acc *account.AccountData, storage storage.ListStor
|
||||
indexes: indexes,
|
||||
builder: builder,
|
||||
aclState: state,
|
||||
id: id,
|
||||
RWMutex: sync.RWMutex{},
|
||||
}, nil
|
||||
}
|
||||
@ -114,7 +129,7 @@ func (a *aclList) IsAfter(first string, second string) (bool, error) {
|
||||
firstRec, okFirst := a.indexes[first]
|
||||
secondRec, okSecond := a.indexes[second]
|
||||
if !okFirst || !okSecond {
|
||||
return false, fmt.Errorf("not all entries are there: first (%b), second (%b)", okFirst, okSecond)
|
||||
return false, fmt.Errorf("not all entries are there: first (%t), second (%t)", okFirst, okSecond)
|
||||
}
|
||||
return firstRec >= secondRec, nil
|
||||
}
|
||||
|
||||
46
pkg/acl/list/list_test.go
Normal file
46
pkg/acl/list/list_test.go
Normal file
@ -0,0 +1,46 @@
|
||||
package list
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/testutils/acllistbuilder"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAclList_ACLState_UserInviteAndJoin(t *testing.T) {
|
||||
st, err := acllistbuilder.NewListStorageWithTestName("userjoinexample.yml")
|
||||
require.NoError(t, err, "building storage should not result in error")
|
||||
|
||||
keychain := st.(*acllistbuilder.ACLListStorageBuilder).GetKeychain()
|
||||
|
||||
aclList, err := BuildACLList(signingkey.NewEDPubKeyDecoder(), st)
|
||||
require.NoError(t, err, "building acl list should be without error")
|
||||
|
||||
idA := keychain.GetIdentity("A")
|
||||
idB := keychain.GetIdentity("B")
|
||||
idC := keychain.GetIdentity("C")
|
||||
|
||||
// checking final state
|
||||
assert.Equal(t, aclList.ACLState().GetUserStates()[idA].Permissions, aclpb.ACLChange_Admin)
|
||||
assert.Equal(t, aclList.ACLState().GetUserStates()[idB].Permissions, aclpb.ACLChange_Writer)
|
||||
assert.Equal(t, aclList.ACLState().GetUserStates()[idC].Permissions, aclpb.ACLChange_Reader)
|
||||
assert.Equal(t, aclList.ACLState().CurrentReadKeyHash(), aclList.Head().Content.CurrentReadKeyHash)
|
||||
var records []*Record
|
||||
aclList.Iterate(func(record *Record) (IsContinue bool) {
|
||||
records = append(records, record)
|
||||
return true
|
||||
})
|
||||
|
||||
// checking permissions at specific records
|
||||
assert.Equal(t, 3, len(records))
|
||||
_, err = aclList.ACLState().PermissionsAtRecord(records[1].Id, idB)
|
||||
assert.Error(t, err, "B should have no permissions at record 1")
|
||||
perm, err := aclList.ACLState().PermissionsAtRecord(records[2].Id, idB)
|
||||
assert.NoError(t, err, "should have no error with permissions of B in the record 2")
|
||||
assert.Equal(t, perm, UserPermissionPair{
|
||||
Identity: idB,
|
||||
Permission: aclpb.ACLChange_Writer,
|
||||
})
|
||||
}
|
||||
@ -50,8 +50,8 @@ func (k *Keychain) ParseKeys(keys *Keys) {
|
||||
}
|
||||
}
|
||||
|
||||
func (k *Keychain) AddEncryptionKey(name string) {
|
||||
if _, exists := k.EncryptionKeys[name]; exists {
|
||||
func (k *Keychain) AddEncryptionKey(key *Key) {
|
||||
if _, exists := k.EncryptionKeys[key.Name]; exists {
|
||||
return
|
||||
}
|
||||
newPrivKey, _, err := encryptionkey.GenerateRandomRSAKeyPair(2048)
|
||||
@ -59,11 +59,11 @@ func (k *Keychain) AddEncryptionKey(name string) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
k.EncryptionKeys[name] = newPrivKey
|
||||
k.EncryptionKeys[key.Name] = newPrivKey
|
||||
}
|
||||
|
||||
func (k *Keychain) AddSigningKey(name string) {
|
||||
if _, exists := k.SigningKeys[name]; exists {
|
||||
func (k *Keychain) AddSigningKey(key *Key) {
|
||||
if _, exists := k.SigningKeys[key.Name]; exists {
|
||||
return
|
||||
}
|
||||
newPrivKey, pubKey, err := signingkey.GenerateRandomEd25519KeyPair()
|
||||
@ -71,48 +71,47 @@ func (k *Keychain) AddSigningKey(name string) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
k.SigningKeys[name] = newPrivKey
|
||||
k.SigningKeys[key.Name] = newPrivKey
|
||||
res, err := k.coder.EncodeToString(pubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
k.SigningKeysByIdentity[res] = newPrivKey
|
||||
k.GeneratedIdentities[name] = res
|
||||
k.GeneratedIdentities[key.Name] = res
|
||||
}
|
||||
|
||||
func (k *Keychain) AddReadKey(name string) {
|
||||
if _, exists := k.ReadKeys[name]; exists {
|
||||
func (k *Keychain) AddReadKey(key *Key) {
|
||||
if _, exists := k.ReadKeys[key.Name]; exists {
|
||||
return
|
||||
}
|
||||
key, _ := symmetric.NewRandom()
|
||||
rkey, _ := symmetric.NewRandom()
|
||||
|
||||
hasher := fnv.New64()
|
||||
hasher.Write(key.Bytes())
|
||||
hasher.Write(rkey.Bytes())
|
||||
|
||||
k.ReadKeys[name] = &SymKey{
|
||||
k.ReadKeys[key.Name] = &SymKey{
|
||||
Hash: hasher.Sum64(),
|
||||
Key: key,
|
||||
Key: rkey,
|
||||
}
|
||||
k.ReadKeysByHash[hasher.Sum64()] = &SymKey{
|
||||
Hash: hasher.Sum64(),
|
||||
Key: key,
|
||||
Key: rkey,
|
||||
}
|
||||
}
|
||||
|
||||
func (k *Keychain) AddKey(key string) {
|
||||
parts := strings.Split(key, ".")
|
||||
func (k *Keychain) AddKey(key *Key) {
|
||||
parts := strings.Split(key.Name, ".")
|
||||
if len(parts) != 3 {
|
||||
panic("cannot parse a key")
|
||||
}
|
||||
name := parts[2]
|
||||
|
||||
switch parts[1] {
|
||||
case "Sign":
|
||||
k.AddSigningKey(name)
|
||||
k.AddSigningKey(key)
|
||||
case "Enc":
|
||||
k.AddEncryptionKey(name)
|
||||
k.AddEncryptionKey(key)
|
||||
case "Read":
|
||||
k.AddReadKey(name)
|
||||
k.AddReadKey(key)
|
||||
default:
|
||||
panic("incorrect format")
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/testutils/yamltests"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/encryptionkey"
|
||||
@ -34,7 +35,7 @@ func NewACLListStorageBuilder(keychain *Keychain) *ACLListStorageBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
func NewACLListStorageBuilderWithTestName(name string) (*ACLListStorageBuilder, error) {
|
||||
func NewListStorageWithTestName(name string) (storage.ListStorage, error) {
|
||||
filePath := path.Join(yamltests.Path(), name)
|
||||
return NewACLListStorageBuilderFromFile(filePath)
|
||||
}
|
||||
@ -89,7 +90,7 @@ func (t *ACLListStorageBuilder) Header() (*aclpb.Header, error) {
|
||||
return t.header, nil
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) GetRecord(ctx context.Context, id string) (*aclpb.RawRecord, error) {
|
||||
func (t *ACLListStorageBuilder) GetRawRecord(ctx context.Context, id string) (*aclpb.RawRecord, error) {
|
||||
recIdx, ok := t.indexes[id]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no such record")
|
||||
@ -97,7 +98,7 @@ func (t *ACLListStorageBuilder) GetRecord(ctx context.Context, id string) (*aclp
|
||||
return t.getRecord(recIdx), nil
|
||||
}
|
||||
|
||||
func (t *ACLListStorageBuilder) AddRecord(ctx context.Context, rec *aclpb.Record) error {
|
||||
func (t *ACLListStorageBuilder) AddRawRecord(ctx context.Context, rec *aclpb.RawRecord) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
package acllistbuilder
|
||||
|
||||
type Key struct {
|
||||
Name string `yaml:"name"`
|
||||
Value string `yaml:"value"`
|
||||
}
|
||||
|
||||
type Keys struct {
|
||||
Enc []string `yaml:"Enc"`
|
||||
Sign []string `yaml:"Sign"`
|
||||
Read []string `yaml:"Read"`
|
||||
Enc []*Key `yaml:"Enc"`
|
||||
Sign []*Key `yaml:"Sign"`
|
||||
Read []*Key `yaml:"Read"`
|
||||
}
|
||||
|
||||
type ACLChange struct {
|
||||
@ -50,8 +55,7 @@ type ACLChange struct {
|
||||
type Record struct {
|
||||
Identity string `yaml:"identity"`
|
||||
AclChanges []*ACLChange `yaml:"aclChanges"`
|
||||
|
||||
ReadKey string `yaml:"readKey"`
|
||||
ReadKey string `yaml:"readKey"`
|
||||
}
|
||||
|
||||
type Header struct {
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_YamlParse(t *testing.T) {
|
||||
tb, _ := NewACLListStorageBuilderWithTestName("userjoinexampleupdate.yml")
|
||||
tb, _ := NewListStorageWithTestName("userjoinexampleupdate.yml")
|
||||
gr, _ := tb.Graph()
|
||||
fmt.Println(gr)
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
list:
|
||||
author: A
|
||||
records:
|
||||
- identity: A
|
||||
aclChanges:
|
||||
@ -16,7 +14,7 @@ records:
|
||||
encryptionKey: key.Enc.Onetime1
|
||||
encryptedReadKeys: [key.Read.1]
|
||||
permissions: writer
|
||||
inviteIdx: A.1.2
|
||||
inviteId: A.1.2
|
||||
- userAdd:
|
||||
identity: C
|
||||
permission: reader
|
||||
|
||||
@ -77,48 +77,27 @@ type docTree struct {
|
||||
}
|
||||
|
||||
func BuildDocTreeWithIdentity(t storage.TreeStorage, acc *account.AccountData, listener TreeUpdateListener, aclList list.ACLList) (DocTree, error) {
|
||||
treeBuilder := newTreeBuilder(t, acc.Decoder)
|
||||
validator := newTreeValidator()
|
||||
|
||||
docTree := &docTree{
|
||||
treeStorage: t,
|
||||
accountData: acc,
|
||||
tree: nil,
|
||||
treeBuilder: treeBuilder,
|
||||
validator: validator,
|
||||
updateListener: listener,
|
||||
tmpChangesBuf: make([]*Change, 0, 10),
|
||||
difSnapshotBuf: make([]*aclpb.RawChange, 0, 10),
|
||||
notSeenIdxBuf: make([]int, 0, 10),
|
||||
identityKeys: make(map[string]signingkey.PubKey),
|
||||
}
|
||||
err := docTree.rebuildFromStorage(aclList, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
docTree.id, err = t.ID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
docTree.header, err = t.Header()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if listener != nil {
|
||||
listener.Rebuild(docTree)
|
||||
}
|
||||
|
||||
return docTree, nil
|
||||
return buildDocTreeWithAccount(t, acc, acc.Decoder, listener, aclList)
|
||||
}
|
||||
|
||||
func BuildDocTree(t storage.TreeStorage, decoder keys.Decoder, listener TreeUpdateListener, aclList list.ACLList) (DocTree, error) {
|
||||
return buildDocTreeWithAccount(t, nil, decoder, listener, aclList)
|
||||
}
|
||||
|
||||
func buildDocTreeWithAccount(
|
||||
t storage.TreeStorage,
|
||||
acc *account.AccountData,
|
||||
decoder keys.Decoder,
|
||||
listener TreeUpdateListener,
|
||||
aclList list.ACLList) (DocTree, error) {
|
||||
|
||||
treeBuilder := newTreeBuilder(t, decoder)
|
||||
validator := newTreeValidator()
|
||||
|
||||
docTree := &docTree{
|
||||
treeStorage: t,
|
||||
tree: nil,
|
||||
accountData: acc,
|
||||
treeBuilder: treeBuilder,
|
||||
validator: validator,
|
||||
updateListener: listener,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user