MM-58577 Check remote ownership for posts and reactions (#27317)
* - ensure that posts and reactions can only be added via sync when coming from a remote that the target channel is shared with. - ensure that posts and reactions are only modified/deleted by the remote that owns them. * check that reaction belongs to post that belongs to channel that is shared with remote; check that posts belong to channel shared with remote * check for correct error type in unit test * tweak unit test
Этот коммит содержится в:
@@ -198,6 +198,36 @@ func (_m *ReactionStore) GetForPostSince(postId string, since int64, excludeRemo
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetSingle provides a mock function with given fields: userID, postID, remoteID, emojiName
|
||||
func (_m *ReactionStore) GetSingle(userID string, postID string, remoteID string, emojiName string) (*model.Reaction, error) {
|
||||
ret := _m.Called(userID, postID, remoteID, emojiName)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetSingle")
|
||||
}
|
||||
|
||||
var r0 *model.Reaction
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(string, string, string, string) (*model.Reaction, error)); ok {
|
||||
return rf(userID, postID, remoteID, emojiName)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(string, string, string, string) *model.Reaction); ok {
|
||||
r0 = rf(userID, postID, remoteID, emojiName)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Reaction)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(string, string, string, string) error); ok {
|
||||
r1 = rf(userID, postID, remoteID, emojiName)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetUniqueCountForPost provides a mock function with given fields: postId
|
||||
func (_m *ReactionStore) GetUniqueCountForPost(postId string) (int, error) {
|
||||
ret := _m.Called(postId)
|
||||
|
||||
@@ -31,6 +31,7 @@ func TestReactionStore(t *testing.T, rctx request.CTX, ss store.Store, s SqlStor
|
||||
t.Run("ReactionDeadlock", func(t *testing.T) { testReactionDeadlock(t, rctx, ss) })
|
||||
t.Run("ExistsOnPost", func(t *testing.T) { testExistsOnPost(t, rctx, ss) })
|
||||
t.Run("GetUniqueCountForPost", func(t *testing.T) { testGetUniqueCountForPost(t, rctx, ss) })
|
||||
t.Run("ReactionGetSingle", func(t *testing.T) { testReactionGetSingle(t, rctx, ss) })
|
||||
}
|
||||
|
||||
func testReactionSave(t *testing.T, rctx request.CTX, ss store.Store) {
|
||||
@@ -938,3 +939,85 @@ func testGetUniqueCountForPost(t *testing.T, rctx request.CTX, ss store.Store) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, count)
|
||||
}
|
||||
|
||||
func testReactionGetSingle(t *testing.T, rctx request.CTX, ss store.Store) {
|
||||
var (
|
||||
testUserID = model.NewId()
|
||||
testEmojiName = "smile"
|
||||
testRemoteID = model.NewId()
|
||||
)
|
||||
|
||||
t.Run("get without remoteId", func(t *testing.T) {
|
||||
post, err := ss.Post().Save(rctx, &model.Post{
|
||||
ChannelId: model.NewId(),
|
||||
UserId: testUserID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
reaction := &model.Reaction{
|
||||
UserId: testUserID,
|
||||
PostId: post.Id,
|
||||
EmojiName: testEmojiName,
|
||||
}
|
||||
|
||||
_, nErr := ss.Reaction().Save(reaction)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
reactionFound, err := ss.Reaction().GetSingle(testUserID, post.Id, "", testEmojiName)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testUserID, reactionFound.UserId)
|
||||
assert.Equal(t, post.Id, reactionFound.PostId)
|
||||
assert.Equal(t, "", reactionFound.GetRemoteID())
|
||||
assert.Equal(t, testEmojiName, reactionFound.EmojiName)
|
||||
})
|
||||
|
||||
t.Run("get with remoteId", func(t *testing.T) {
|
||||
post, err := ss.Post().Save(rctx, &model.Post{
|
||||
ChannelId: model.NewId(),
|
||||
UserId: testUserID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
reaction := &model.Reaction{
|
||||
UserId: testUserID,
|
||||
PostId: post.Id,
|
||||
EmojiName: testEmojiName,
|
||||
RemoteId: model.NewString(testRemoteID),
|
||||
}
|
||||
|
||||
_, nErr := ss.Reaction().Save(reaction)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
reactionFound, err := ss.Reaction().GetSingle(testUserID, post.Id, testRemoteID, testEmojiName)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testUserID, reactionFound.UserId)
|
||||
assert.Equal(t, post.Id, reactionFound.PostId)
|
||||
assert.Equal(t, testRemoteID, reactionFound.GetRemoteID())
|
||||
assert.Equal(t, testEmojiName, reactionFound.EmojiName)
|
||||
})
|
||||
|
||||
t.Run("not found - wrong remoteID", func(t *testing.T) {
|
||||
post, err := ss.Post().Save(rctx, &model.Post{
|
||||
ChannelId: model.NewId(),
|
||||
UserId: testUserID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
reaction := &model.Reaction{
|
||||
UserId: testUserID,
|
||||
PostId: post.Id,
|
||||
EmojiName: testEmojiName,
|
||||
RemoteId: model.NewString(testRemoteID),
|
||||
}
|
||||
|
||||
_, nErr := ss.Reaction().Save(reaction)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
reactionFound, err := ss.Reaction().GetSingle(testUserID, post.Id, "bogus-remoteId", testEmojiName)
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, reactionFound)
|
||||
|
||||
var errNotFound *store.ErrNotFound
|
||||
assert.ErrorAs(t, err, &errNotFound)
|
||||
})
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user