Add first ACL list test and other refactoring

This commit is contained in:
mcrakhman 2022-08-21 15:23:47 +02:00 committed by Mikhail Iudin
parent a17b102756
commit 0dcb95fbcd
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0
10 changed files with 120 additions and 75 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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