package acltree import ( "testing" "github.com/anytypeio/go-anytype-infrastructure-experiments/account" "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb" "github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/threadbuilder" "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" "github.com/stretchr/testify/assert" ) type ACLContext struct { Tree *Tree ACLState *aclState } func createTreeFromThread(t thread.Thread, fromStart bool) (*Tree, error) { treeBuilder := NewTreeBuilder(t, keys.NewEd25519Decoder()) treeBuilder.Init() return treeBuilder.Build(fromStart) } func createACLStateFromThread( t thread.Thread, identity string, key keys.EncryptionPrivKey, decoder keys.SigningPubKeyDecoder, fromStart bool) (*ACLContext, error) { tree, err := createTreeFromThread(t, fromStart) if err != nil { return nil, err } accountData := &account.AccountData{ Identity: identity, EncKey: key, } aclTreeBuilder := NewACLTreeBuilder(t, decoder) aclTreeBuilder.Init() aclTree, err := aclTreeBuilder.Build() if err != nil { return nil, err } if !fromStart { snapshotValidator := NewSnapshotValidator(decoder, accountData) snapshotValidator.Init(aclTree) valid, err := snapshotValidator.ValidateSnapshot(tree.root) if err != nil { return nil, err } if !valid { // TODO: think about what to do if the snapshot is invalid - should we rebuild the tree without it return createACLStateFromThread(t, identity, key, decoder, true) } } aclBuilder := NewACLStateBuilder(decoder, accountData) err = aclBuilder.Init(tree) if err != nil { return nil, err } aclState, err := aclBuilder.Build() if err != nil { return nil, err } return &ACLContext{ Tree: tree, ACLState: aclState, }, nil } func TestACLStateBuilder_UserJoinBuild(t *testing.T) { thread, err := threadbuilder.NewThreadBuilderFromFile("threadbuilder/userjoinexample.yml") if err != nil { t.Fatal(err) } keychain := thread.GetKeychain() ctx, err := createACLStateFromThread( thread, keychain.GetIdentity("A"), keychain.EncryptionKeys["A"], keys.NewEd25519Decoder(), false) if err != nil { t.Fatalf("should build acl aclState without err: %v", err) } aclState := ctx.ACLState //fmt.Println(ctx.Tree.Graph()) aId := keychain.GeneratedIdentities["A"] bId := keychain.GeneratedIdentities["B"] cId := keychain.GeneratedIdentities["C"] assert.Equal(t, aclState.identity, aId) assert.Equal(t, aclState.userStates[aId].Permissions, pb.ACLChange_Admin) assert.Equal(t, aclState.userStates[bId].Permissions, pb.ACLChange_Writer) assert.Equal(t, aclState.userStates[cId].Permissions, pb.ACLChange_Reader) var changeIds []string ctx.Tree.iterate(ctx.Tree.root, func(c *Change) (isContinue bool) { changeIds = append(changeIds, c.Id) return true }) assert.Equal(t, changeIds, []string{"A.1.1", "A.1.2", "B.1.1", "B.1.2"}) } func TestACLStateBuilder_UserRemoveBuild(t *testing.T) { thread, err := threadbuilder.NewThreadBuilderFromFile("threadbuilder/userremoveexample.yml") if err != nil { t.Fatal(err) } keychain := thread.GetKeychain() ctx, err := createACLStateFromThread( thread, keychain.GetIdentity("A"), keychain.EncryptionKeys["A"], keys.NewEd25519Decoder(), false) if err != nil { t.Fatalf("should build acl aclState without err: %v", err) } aclState := ctx.ACLState //fmt.Println(ctx.Tree.Graph()) aId := keychain.GeneratedIdentities["A"] assert.Equal(t, aclState.identity, aId) assert.Equal(t, aclState.userStates[aId].Permissions, pb.ACLChange_Admin) var changeIds []string ctx.Tree.iterate(ctx.Tree.root, func(c *Change) (isContinue bool) { changeIds = append(changeIds, c.Id) return true }) assert.Equal(t, changeIds, []string{"A.1.1", "A.1.2", "B.1.1", "A.1.3", "A.1.4"}) } func TestACLStateBuilder_UserRemoveBeforeBuild(t *testing.T) { thread, err := threadbuilder.NewThreadBuilderFromFile("threadbuilder/userremovebeforeexample.yml") if err != nil { t.Fatal(err) } keychain := thread.GetKeychain() ctx, err := createACLStateFromThread( thread, keychain.GetIdentity("A"), keychain.EncryptionKeys["A"], keys.NewEd25519Decoder(), false) if err != nil { t.Fatalf("should build acl aclState without err: %v", err) } aclState := ctx.ACLState //fmt.Println(ctx.Tree.Graph()) for _, s := range []string{"A", "C", "E"} { assert.Equal(t, aclState.userStates[keychain.GetIdentity(s)].Permissions, pb.ACLChange_Admin) } assert.Equal(t, aclState.identity, keychain.GetIdentity("A")) assert.Nil(t, aclState.userStates[keychain.GetIdentity("B")]) var changeIds []string ctx.Tree.iterate(ctx.Tree.root, func(c *Change) (isContinue bool) { changeIds = append(changeIds, c.Id) return true }) assert.Equal(t, changeIds, []string{"A.1.1", "B.1.1", "A.1.2", "A.1.3"}) } func TestACLStateBuilder_InvalidSnapshotBuild(t *testing.T) { thread, err := threadbuilder.NewThreadBuilderFromFile("threadbuilder/invalidsnapshotexample.yml") if err != nil { t.Fatal(err) } keychain := thread.GetKeychain() ctx, err := createACLStateFromThread( thread, keychain.GetIdentity("A"), keychain.EncryptionKeys["A"], keys.NewEd25519Decoder(), false) if err != nil { t.Fatalf("should build acl aclState without err: %v", err) } aclState := ctx.ACLState //fmt.Println(ctx.Tree.Graph()) for _, s := range []string{"A", "B", "C", "D", "E", "F"} { assert.Equal(t, aclState.userStates[keychain.GetIdentity(s)].Permissions, pb.ACLChange_Admin) } assert.Equal(t, aclState.identity, keychain.GetIdentity("A")) var changeIds []string ctx.Tree.iterate(ctx.Tree.root, func(c *Change) (isContinue bool) { changeIds = append(changeIds, c.Id) return true }) assert.Equal(t, []string{"A.1.1", "B.1.1", "A.1.2", "A.1.3", "B.1.2"}, changeIds) } func TestACLStateBuilder_ValidSnapshotBuild(t *testing.T) { thread, err := threadbuilder.NewThreadBuilderFromFile("threadbuilder/validsnapshotexample.yml") if err != nil { t.Fatal(err) } keychain := thread.GetKeychain() ctx, err := createACLStateFromThread( thread, keychain.GetIdentity("A"), keychain.EncryptionKeys["A"], keys.NewEd25519Decoder(), false) if err != nil { t.Fatalf("should build acl aclState without err: %v", err) } aclState := ctx.ACLState //fmt.Println(ctx.Tree.Graph()) for _, s := range []string{"A", "B", "C", "D", "E", "F"} { assert.Equal(t, aclState.userStates[keychain.GetIdentity(s)].Permissions, pb.ACLChange_Admin) } assert.Equal(t, aclState.identity, keychain.GetIdentity("A")) var changeIds []string ctx.Tree.iterate(ctx.Tree.root, func(c *Change) (isContinue bool) { changeIds = append(changeIds, c.Id) return true }) assert.Equal(t, []string{"A.1.2", "A.1.3", "B.1.2"}, changeIds) }