From cae6d8f6bce5c55d853b1951a90658cf04c728d3 Mon Sep 17 00:00:00 2001 From: AnastasiaShemyakinskaya Date: Fri, 11 Apr 2025 11:39:30 +0200 Subject: [PATCH] GO-5297: remove store Signed-off-by: AnastasiaShemyakinskaya --- core/anytype/bootstrap.go | 2 - core/pushnotification/service.go | 112 ++++++----- core/pushnotification/service_test.go | 185 ------------------ .../aclobjectmanager/aclobjectmanager.go | 37 +++- 4 files changed, 96 insertions(+), 240 deletions(-) delete mode 100644 core/pushnotification/service_test.go diff --git a/core/anytype/bootstrap.go b/core/anytype/bootstrap.go index c68e2f201..fcc4a1afc 100644 --- a/core/anytype/bootstrap.go +++ b/core/anytype/bootstrap.go @@ -113,7 +113,6 @@ import ( "github.com/anyproto/anytype-heart/space/spacecore/oldstorage" "github.com/anyproto/anytype-heart/space/spacecore/peermanager" "github.com/anyproto/anytype-heart/space/spacecore/peerstore" - "github.com/anyproto/anytype-heart/space/spacecore/spacekeystore" "github.com/anyproto/anytype-heart/space/spacecore/storage" "github.com/anyproto/anytype-heart/space/spacecore/storage/migrator" "github.com/anyproto/anytype-heart/space/spacecore/storage/migratorfinisher" @@ -325,7 +324,6 @@ func Bootstrap(a *app.App, components ...app.Component) { Register(spaceview.New()). Register(api.New()). Register(client.NewPushClient()). - Register(spacekeystore.New()). Register(pushnotification.New()) } diff --git a/core/pushnotification/service.go b/core/pushnotification/service.go index b7f74009b..8db0d16e0 100644 --- a/core/pushnotification/service.go +++ b/core/pushnotification/service.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/anyproto/any-sync/app" + "github.com/anyproto/any-sync/commonspace/object/acl/list" "github.com/anyproto/any-sync/util/crypto" "github.com/anyproto/anytype-push-server/pushclient/pushapi" "github.com/cheggaaa/mb/v3" @@ -15,7 +16,8 @@ import ( "github.com/anyproto/anytype-heart/core/wallet" "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pkg/lib/logging" - "github.com/anyproto/anytype-heart/space/spacecore/spacekeystore" + "github.com/anyproto/anytype-heart/space" + "github.com/anyproto/anytype-heart/space/spacecore/spacekey" ) const CName = "core.pushnotification.service" @@ -42,7 +44,6 @@ func New() Service { type service struct { pushClient client.Client wallet wallet.Wallet - spaceKeyStore spacekeystore.Store cfg *config.Config started bool activeSubscriptions map[string]TopicSet @@ -50,6 +51,7 @@ type service struct { ctx context.Context cancel context.CancelFunc batcher *mb.MB[newSubscription] + spaceService space.Service } func (s *service) SubscribeToTopics(ctx context.Context, spaceId string, topics []string) { @@ -84,8 +86,8 @@ func (s *service) Init(a *app.App) (err error) { s.cfg = app.MustComponent[*config.Config](a) s.pushClient = app.MustComponent[client.Client](a) s.wallet = app.MustComponent[wallet.Wallet](a) - s.spaceKeyStore = app.MustComponent[spacekeystore.Store](a) s.batcher = mb.New[newSubscription](0) + s.spaceService = app.MustComponent[space.Service](a) return } @@ -121,9 +123,10 @@ func (s *service) subscribeAll(ctx context.Context) error { func (s *service) buildPushTopics() []*pushapi.Topic { s.activeSubscriptionsLock.Lock() defer s.activeSubscriptionsLock.Unlock() + var allTopics []*pushapi.Topic - for spaceKey, topicsSet := range s.activeSubscriptions { - spaceTopics, err := s.createTopicsForSpace(spaceKey, topicsSet.Slice()) + for spaceId, topicsSet := range s.activeSubscriptions { + spaceTopics, err := s.createTopicsForSpace(spaceId, topicsSet.Slice()) if err != nil { continue } @@ -132,14 +135,23 @@ func (s *service) buildPushTopics() []*pushapi.Topic { return allTopics } -func (s *service) createTopicsForSpace(spaceKey string, topicNames []string) ([]*pushapi.Topic, error) { - privKey, err := s.spaceKeyStore.SignKeyByKeyId(spaceKey) +func (s *service) createTopicsForSpace(spaceId string, topicNames []string) ([]*pushapi.Topic, error) { + space, err := s.spaceService.Get(s.ctx, spaceId) if err != nil { - return nil, fmt.Errorf("failed to get encryption key for space %s: %w", spaceKey, err) + return nil, err } - topics, err := s.makeTopics(privKey, topicNames) + state := space.CommonSpace().Acl().AclState() + firstMetadataKey, err := state.FirstMetadataKey() if err != nil { - return nil, fmt.Errorf("failed to make topics for space %s: %w", spaceKey, err) + return nil, err + } + _, signKey, err := spacekey.DeriveSpaceKey(firstMetadataKey) + if err != nil { + return nil, fmt.Errorf("failed to get key for space %s: %w", spaceId, err) + } + topics, err := s.makeTopics(signKey, topicNames) + if err != nil { + return nil, fmt.Errorf("failed to make topics for space %s: %w", spaceId, err) } return topics, nil } @@ -148,15 +160,24 @@ func (s *service) CreateSpace(ctx context.Context, spaceId string) (err error) { if !s.started { return nil } - spaceKey, err := s.spaceKeyStore.SignKeyBySpaceId(spaceId) + space, err := s.spaceService.Get(s.ctx, spaceId) if err != nil { return err } - signature, err := spaceKey.Sign([]byte(s.wallet.GetAccountPrivkey().GetPublic().Account())) + state := space.CommonSpace().Acl().AclState() + firstMetadataKey, err := state.FirstMetadataKey() if err != nil { return err } - pubKey := spaceKey.GetPublic() + _, signKey, err := spacekey.DeriveSpaceKey(firstMetadataKey) + if err != nil { + return err + } + signature, err := signKey.Sign([]byte(s.wallet.GetAccountPrivkey().GetPublic().Account())) + if err != nil { + return err + } + pubKey := signKey.GetPublic() rawKey, err := pubKey.Raw() if err != nil { return err @@ -172,15 +193,24 @@ func (s *service) Notify(ctx context.Context, spaceId string, topic []string, pa if !s.started { return nil } - topics, err := s.makeTopicsBySpaceId(spaceId, topic) + space, err := s.spaceService.Get(s.ctx, spaceId) if err != nil { return err } - keyId, err := s.spaceKeyStore.KeyBySpaceId(spaceId) + state := space.CommonSpace().Acl().AclState() + firstMetadataKey, err := state.FirstMetadataKey() if err != nil { return err } - encryptedJson, err := s.prepareEncryptedJson(keyId, payload) + keyId, signKey, err := spacekey.DeriveSpaceKey(firstMetadataKey) + if err != nil { + return err + } + topics, err := s.makeTopics(signKey, topic) + if err != nil { + return err + } + encryptedJson, err := s.prepareEncryptedPayload(state, payload) if err != nil { return err } @@ -194,12 +224,28 @@ func (s *service) Notify(ctx context.Context, spaceId string, topic []string, pa Signature: signature, } _, err = s.pushClient.Notify(ctx, &pushapi.NotifyRequest{ - Topics: topics, + Topics: &pushapi.Topics{Topics: topics}, Message: p, }) return err } +func (s *service) prepareEncryptedPayload(state *list.AclState, payload []byte) ([]byte, error) { + symKey, err := state.CurrentReadKey() + if err != nil { + return nil, err + } + encryptionKey, err := spacekey.DeriveEncryptionKey(symKey) + if err != nil { + return nil, err + } + encryptedJson, err := encryptionKey.Encrypt(payload) + if err != nil { + return nil, err + } + return encryptedJson, nil +} + func (s *service) fillSubscriptions(ctx context.Context) (err error) { if !s.started { return nil @@ -224,30 +270,6 @@ func (s *service) fillSubscriptions(ctx context.Context) (err error) { return nil } -func (s *service) prepareEncryptedJson(keyId string, payload []byte) ([]byte, error) { - symKey, err := s.spaceKeyStore.EncryptionKeyBySpaceId(keyId) - if err != nil { - return nil, err - } - encryptedJson, err := symKey.Encrypt(payload) - if err != nil { - return nil, err - } - return encryptedJson, nil -} - -func (s *service) makeTopicsBySpaceId(spaceId string, topics []string) (*pushapi.Topics, error) { - spaceKey, err := s.spaceKeyStore.SignKeyBySpaceId(spaceId) - if err != nil { - return nil, err - } - pushApiTopics, err := s.makeTopics(spaceKey, topics) - if err != nil { - return nil, err - } - return &pushapi.Topics{Topics: pushApiTopics}, nil -} - func (s *service) makeTopics(spaceKey crypto.PrivKey, topics []string) ([]*pushapi.Topic, error) { pushApiTopics := make([]*pushapi.Topic, 0, len(topics)) pubKey := spaceKey.GetPublic() @@ -313,13 +335,9 @@ func (s *service) run() { } func (s *service) addNewSubscription(sub newSubscription) (shouldUpdate bool, err error) { - keyId, err := s.spaceKeyStore.KeyBySpaceId(sub.SpaceId) - if err != nil { - return false, err - } s.activeSubscriptionsLock.Lock() defer s.activeSubscriptionsLock.Unlock() - activeTopics, ok := s.activeSubscriptions[keyId] + activeTopics, ok := s.activeSubscriptions[sub.SpaceId] if !ok { activeTopics = NewTopicSet() } @@ -328,6 +346,6 @@ func (s *service) addNewSubscription(sub newSubscription) (shouldUpdate bool, er shouldUpdate = true } } - s.activeSubscriptions[keyId] = activeTopics + s.activeSubscriptions[sub.SpaceId] = activeTopics return shouldUpdate, nil } diff --git a/core/pushnotification/service_test.go b/core/pushnotification/service_test.go deleted file mode 100644 index 0eb06c59d..000000000 --- a/core/pushnotification/service_test.go +++ /dev/null @@ -1,185 +0,0 @@ -package pushnotification - -import ( - "context" - "crypto/rand" - "encoding/json" - "testing" - - "github.com/anyproto/any-sync/app" - "github.com/anyproto/any-sync/util/crypto" - "github.com/anyproto/anytype-push-server/pushclient/pushapi" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - - "github.com/anyproto/anytype-heart/core/event/mock_event" - "github.com/anyproto/anytype-heart/core/wallet/mock_wallet" - "github.com/anyproto/anytype-heart/pb" - "github.com/anyproto/anytype-heart/space/spacecore/spacekeystore" - "github.com/anyproto/anytype-heart/tests/testutil" -) - -const ( - spaceId = "spaceId" - topic = "test" - aclRecordId = "aclRecordId" -) - -type testPayload struct { - Text string `json:"text"` -} - -type mockPushClient struct { - t *testing.T - expectedNotify *pushapi.NotifyRequest - expectedTokenReq *pushapi.SetTokenRequest -} - -func (m *mockPushClient) Subscriptions(ctx context.Context, req *pushapi.SubscriptionsRequest) (resp *pushapi.SubscriptionsResponse, err error) { - return &pushapi.SubscriptionsResponse{}, nil -} - -func (m *mockPushClient) Init(a *app.App) (err error) { - return nil -} - -func (m *mockPushClient) Name() (name string) { - return "mockPushClient" -} - -func (m *mockPushClient) SetToken(ctx context.Context, req *pushapi.SetTokenRequest) (resp *pushapi.Ok, err error) { - m.expectedTokenReq = req - return &pushapi.Ok{}, nil -} - -func (m *mockPushClient) SubscribeAll(ctx context.Context, req *pushapi.SubscribeAllRequest) (resp *pushapi.Ok, err error) { - return &pushapi.Ok{}, nil -} - -func (m *mockPushClient) CreateSpace(ctx context.Context, req *pushapi.CreateSpaceRequest) (resp *pushapi.Ok, err error) { - return &pushapi.Ok{}, nil -} - -func (m *mockPushClient) Notify(ctx context.Context, req *pushapi.NotifyRequest) (resp *pushapi.Ok, err error) { - m.expectedNotify = req - return &pushapi.Ok{}, nil -} - -func TestNotify(t *testing.T) { - t.Run("success", func(t *testing.T) { - // given - wallet := mock_wallet.NewMockWallet(t) - accKey, _, err := crypto.GenerateEd25519Key(rand.Reader) - wallet.EXPECT().GetAccountPrivkey().Return(accKey) - - sender := mock_event.NewMockSender(t) - a := &app.App{} - a.Register(testutil.PrepareMock(context.TODO(), a, sender)) - store := spacekeystore.New() - err = store.Init(a) - assert.NoError(t, err) - readKey := crypto.NewAES() - privKey, _, err := crypto.GenerateEd25519Key(rand.Reader) - assert.NoError(t, err) - sender.EXPECT().Broadcast(mock.Anything).Return() - store.SyncKeysFromAclState(spaceId, aclRecordId, privKey, readKey) - - pushClient := &mockPushClient{t: t} - s := &service{ - started: true, - pushClient: pushClient, - wallet: wallet, - spaceKeyStore: store, - } - tp := &testPayload{Text: "test"} - payload, err := json.Marshal(tp) - assert.NoError(t, err) - - // when - err = s.Notify(context.TODO(), spaceId, []string{topic}, payload) - - // then - assert.NoError(t, err) - assert.Len(t, pushClient.expectedNotify.Topics.Topics, 1) - assert.Equal(t, topic, pushClient.expectedNotify.Topics.Topics[0].Topic) - - spaceKey, err := store.SignKeyBySpaceId(spaceId) - raw, err := spaceKey.GetPublic().Raw() - assert.NoError(t, err) - assert.Equal(t, raw, pushClient.expectedNotify.Topics.Topics[0].SpaceKey) - verify, err := spaceKey.GetPublic().Verify([]byte(topic), pushClient.expectedNotify.Topics.Topics[0].Signature) - assert.NoError(t, err) - assert.True(t, verify) - - keyBySpaceId, err := store.KeyBySpaceId(spaceId) - assert.NoError(t, err) - assert.Equal(t, keyBySpaceId, pushClient.expectedNotify.Message.KeyId) - - symKey, err := store.EncryptionKeyBySpaceId(keyBySpaceId) - assert.NoError(t, err) - decryptedJson, err := symKey.Decrypt(pushClient.expectedNotify.Message.Payload) - assert.NoError(t, err) - - expectedMsg := &testPayload{} - err = json.Unmarshal(decryptedJson, expectedMsg) - assert.NoError(t, err) - assert.Equal(t, expectedMsg.Text, tp.Text) - }) - t.Run("error not found", func(t *testing.T) { - // given - wallet := mock_wallet.NewMockWallet(t) - store := spacekeystore.New() - pushClient := &mockPushClient{t: t} - s := &service{ - pushClient: pushClient, - wallet: wallet, - spaceKeyStore: store, - } - tp := &testPayload{Text: "test"} - payload, err := json.Marshal(tp) - assert.NoError(t, err) - - // when - err = s.Notify(context.TODO(), spaceId, []string{topic}, payload) - - // then - assert.ErrorIs(t, err, spacekeystore.ErrNotFound) - }) -} - -func TestRegisterToken(t *testing.T) { - t.Run("success", func(t *testing.T) { - // given - wallet := mock_wallet.NewMockWallet(t) - pushClient := &mockPushClient{t: t} - s := &service{ - pushClient: pushClient, - wallet: wallet, - spaceKeyStore: spacekeystore.New(), - } - - // when - err := s.RegisterToken(context.TODO(), &pb.RpcPushNotificationRegisterTokenRequest{ - Token: "token", - Platform: pb.RpcPushNotificationRegisterToken_IOS, - }) - - // then - assert.NoError(t, err) - assert.Equal(t, "token", pushClient.expectedTokenReq.Token) - assert.Equal(t, pushapi.Platform_IOS, pushClient.expectedTokenReq.Platform) - }) - t.Run("token empty", func(t *testing.T) { - // given - s := &service{} - - // when - err := s.RegisterToken(context.TODO(), &pb.RpcPushNotificationRegisterTokenRequest{ - Token: "", - Platform: pb.RpcPushNotificationRegisterToken_IOS, - }) - - // then - assert.Error(t, err) - }) -} diff --git a/space/internal/components/aclobjectmanager/aclobjectmanager.go b/space/internal/components/aclobjectmanager/aclobjectmanager.go index 9c730d83f..0e2600b68 100644 --- a/space/internal/components/aclobjectmanager/aclobjectmanager.go +++ b/space/internal/components/aclobjectmanager/aclobjectmanager.go @@ -18,13 +18,15 @@ import ( "go.uber.org/zap" "github.com/anyproto/anytype-heart/core/block/chats/push" + "github.com/anyproto/anytype-heart/core/event" + "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/space/clientspace" "github.com/anyproto/anytype-heart/space/internal/components/aclnotifications" "github.com/anyproto/anytype-heart/space/internal/components/invitemigrator" "github.com/anyproto/anytype-heart/space/internal/components/participantwatcher" "github.com/anyproto/anytype-heart/space/internal/components/spaceloader" "github.com/anyproto/anytype-heart/space/internal/components/spacestatus" - "github.com/anyproto/anytype-heart/space/spacecore/spacekeystore" + "github.com/anyproto/anytype-heart/space/spacecore/spacekey" "github.com/anyproto/anytype-heart/space/spaceinfo" ) @@ -62,7 +64,6 @@ type aclObjectManager struct { spaceLoaderListener SpaceLoaderListener participantWatcher participantwatcher.ParticipantWatcher inviteMigrator invitemigrator.InviteMigrator - spaceKeyStore spacekeystore.Store accountService accountservice.Service pushNotificationService pushNotificationService @@ -70,6 +71,7 @@ type aclObjectManager struct { lastIndexed string guestKey crypto.PrivKey mx sync.Mutex + eventSender event.Sender } type SpaceLoaderListener interface { @@ -119,8 +121,8 @@ func (a *aclObjectManager) Init(ap *app.App) (err error) { a.statService.AddProvider(a) a.waitLoad = make(chan struct{}) a.wait = make(chan struct{}) - a.spaceKeyStore = app.MustComponent[spacekeystore.Store](ap) a.pushNotificationService = app.MustComponent[pushNotificationService](ap) + a.eventSender = app.MustComponent[event.Sender](ap) return nil } @@ -268,10 +270,10 @@ func (a *aclObjectManager) processAcl() (err error) { a.mx.Lock() defer a.mx.Unlock() a.lastIndexed = acl.Head().Id - return a.updateSpaceKeyStore(aclState, common) + return a.broadcastKeyUpdate(aclState, common) } -func (a *aclObjectManager) updateSpaceKeyStore(aclState *list.AclState, common commonspace.Space) error { +func (a *aclObjectManager) broadcastKeyUpdate(aclState *list.AclState, common commonspace.Space) error { firstMetadataKey, err := aclState.FirstMetadataKey() if err != nil { return err @@ -280,7 +282,30 @@ func (a *aclObjectManager) updateSpaceKeyStore(aclState *list.AclState, common c if err != nil { return err } - a.spaceKeyStore.SyncKeysFromAclState(common.Id(), aclState.CurrentReadKeyId(), firstMetadataKey, readKey) + spaceKey, _, err := spacekey.DeriveSpaceKey(firstMetadataKey) + if err != nil { + return err + } + encryptionKey, err := spacekey.DeriveEncryptionKey(readKey) + if err != nil { + return err + } + raw, err := encryptionKey.Raw() + if err != nil { + return err + } + a.eventSender.Broadcast(&pb.Event{ + Messages: []*pb.EventMessage{ + { + SpaceId: common.Id(), + Value: &pb.EventMessageValueOfKeyUpdate{KeyUpdate: &pb.EventKeyUpdate{ + SpaceKeyId: spaceKey, + EncryptionKeyId: aclState.CurrentReadKeyId(), + EncryptionKey: raw, + }}, + }, + }, + }) return nil }