github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/app/file_test.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "errors" 8 "fmt" 9 "image" 10 "os" 11 "path/filepath" 12 "testing" 13 "time" 14 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 18 "github.com/mattermost/mattermost-server/v5/model" 19 "github.com/mattermost/mattermost-server/v5/plugin/plugintest/mock" 20 "github.com/mattermost/mattermost-server/v5/services/filesstore/mocks" 21 "github.com/mattermost/mattermost-server/v5/utils/fileutils" 22 ) 23 24 func TestGeneratePublicLinkHash(t *testing.T) { 25 filename1 := model.NewId() + "/" + model.NewRandomString(16) + ".txt" 26 filename2 := model.NewId() + "/" + model.NewRandomString(16) + ".txt" 27 salt1 := model.NewRandomString(32) 28 salt2 := model.NewRandomString(32) 29 30 hash1 := GeneratePublicLinkHash(filename1, salt1) 31 hash2 := GeneratePublicLinkHash(filename2, salt1) 32 hash3 := GeneratePublicLinkHash(filename1, salt2) 33 34 hash := GeneratePublicLinkHash(filename1, salt1) 35 assert.Equal(t, hash, hash1, "hash should be equal for the same file name and salt") 36 37 assert.NotEqual(t, hash1, hash2, "hashes for different files should not be equal") 38 39 assert.NotEqual(t, hash1, hash3, "hashes for the same file with different salts should not be equal") 40 } 41 42 func TestDoUploadFile(t *testing.T) { 43 th := Setup(t) 44 defer th.TearDown() 45 46 teamID := model.NewId() 47 channelId := model.NewId() 48 userID := model.NewId() 49 filename := "test" 50 data := []byte("abcd") 51 52 info1, err := th.App.DoUploadFile(time.Date(2007, 2, 4, 1, 2, 3, 4, time.Local), teamID, channelId, userID, filename, data) 53 require.Nil(t, err, "DoUploadFile should succeed with valid data") 54 defer func() { 55 th.App.Srv().Store.FileInfo().PermanentDelete(info1.Id) 56 th.App.RemoveFile(info1.Path) 57 }() 58 59 value := fmt.Sprintf("20070204/teams/%v/channels/%v/users/%v/%v/%v", teamID, channelId, userID, info1.Id, filename) 60 assert.Equal(t, value, info1.Path, "stored file at incorrect path") 61 62 info2, err := th.App.DoUploadFile(time.Date(2007, 2, 4, 1, 2, 3, 4, time.Local), teamID, channelId, userID, filename, data) 63 require.Nil(t, err, "DoUploadFile should succeed with valid data") 64 defer func() { 65 th.App.Srv().Store.FileInfo().PermanentDelete(info2.Id) 66 th.App.RemoveFile(info2.Path) 67 }() 68 69 value = fmt.Sprintf("20070204/teams/%v/channels/%v/users/%v/%v/%v", teamID, channelId, userID, info2.Id, filename) 70 assert.Equal(t, value, info2.Path, "stored file at incorrect path") 71 72 info3, err := th.App.DoUploadFile(time.Date(2008, 3, 5, 1, 2, 3, 4, time.Local), teamID, channelId, userID, filename, data) 73 require.Nil(t, err, "DoUploadFile should succeed with valid data") 74 defer func() { 75 th.App.Srv().Store.FileInfo().PermanentDelete(info3.Id) 76 th.App.RemoveFile(info3.Path) 77 }() 78 79 value = fmt.Sprintf("20080305/teams/%v/channels/%v/users/%v/%v/%v", teamID, channelId, userID, info3.Id, filename) 80 assert.Equal(t, value, info3.Path, "stored file at incorrect path") 81 82 info4, err := th.App.DoUploadFile(time.Date(2009, 3, 5, 1, 2, 3, 4, time.Local), "../../"+teamID, "../../"+channelId, "../../"+userID, "../../"+filename, data) 83 require.Nil(t, err, "DoUploadFile should succeed with valid data") 84 defer func() { 85 th.App.Srv().Store.FileInfo().PermanentDelete(info4.Id) 86 th.App.RemoveFile(info4.Path) 87 }() 88 89 value = fmt.Sprintf("20090305/teams/%v/channels/%v/users/%v/%v/%v", teamID, channelId, userID, info4.Id, filename) 90 assert.Equal(t, value, info4.Path, "stored file at incorrect path") 91 } 92 93 func TestUploadFile(t *testing.T) { 94 th := Setup(t).InitBasic() 95 defer th.TearDown() 96 97 channelId := th.BasicChannel.Id 98 filename := "test" 99 data := []byte("abcd") 100 101 info1, err := th.App.UploadFile(data, "wrong", filename) 102 require.NotNil(t, err, "Wrong Channel ID.") 103 require.Nil(t, info1, "Channel ID does not exist.") 104 105 info1, err = th.App.UploadFile(data, "", filename) 106 require.Nil(t, err, "empty channel IDs should be valid") 107 108 info1, err = th.App.UploadFile(data, channelId, filename) 109 require.Nil(t, err, "UploadFile should succeed with valid data") 110 defer func() { 111 th.App.Srv().Store.FileInfo().PermanentDelete(info1.Id) 112 th.App.RemoveFile(info1.Path) 113 }() 114 115 value := fmt.Sprintf("%v/teams/noteam/channels/%v/users/nouser/%v/%v", 116 time.Now().Format("20060102"), channelId, info1.Id, filename) 117 assert.Equal(t, value, info1.Path, "Stored file at incorrect path") 118 } 119 120 func TestParseOldFilenames(t *testing.T) { 121 th := Setup(t).InitBasic() 122 defer th.TearDown() 123 124 fileId := model.NewId() 125 126 tests := []struct { 127 description string 128 filenames []string 129 channelId string 130 userID string 131 expected [][]string 132 }{ 133 { 134 description: "Empty input should result in empty output", 135 filenames: []string{}, 136 channelId: th.BasicChannel.Id, 137 userID: th.BasicUser.Id, 138 expected: [][]string{}, 139 }, 140 { 141 description: "Filename with invalid format should not parse", 142 filenames: []string{"/path/to/some/file.png"}, 143 channelId: th.BasicChannel.Id, 144 userID: th.BasicUser.Id, 145 expected: [][]string{}, 146 }, 147 { 148 description: "ChannelId in Filename should not match", 149 filenames: []string{ 150 fmt.Sprintf("/%v/%v/%v/file.png", model.NewId(), th.BasicUser.Id, fileId), 151 }, 152 channelId: th.BasicChannel.Id, 153 userID: th.BasicUser.Id, 154 expected: [][]string{}, 155 }, 156 { 157 description: "UserId in Filename should not match", 158 filenames: []string{ 159 fmt.Sprintf("/%v/%v/%v/file.png", th.BasicChannel.Id, model.NewId(), fileId), 160 }, 161 channelId: th.BasicChannel.Id, 162 userID: th.BasicUser.Id, 163 expected: [][]string{}, 164 }, 165 { 166 description: "../ in filename should not parse", 167 filenames: []string{ 168 fmt.Sprintf("/%v/%v/%v/../../../file.png", th.BasicChannel.Id, th.BasicUser.Id, fileId), 169 }, 170 channelId: th.BasicChannel.Id, 171 userID: th.BasicUser.Id, 172 expected: [][]string{}, 173 }, 174 { 175 description: "Should only parse valid filenames", 176 filenames: []string{ 177 fmt.Sprintf("/%v/%v/%v/../otherfile.png", th.BasicChannel.Id, th.BasicUser.Id, fileId), 178 fmt.Sprintf("/%v/%v/%v/file.png", th.BasicChannel.Id, th.BasicUser.Id, fileId), 179 }, 180 channelId: th.BasicChannel.Id, 181 userID: th.BasicUser.Id, 182 expected: [][]string{ 183 { 184 th.BasicChannel.Id, 185 th.BasicUser.Id, 186 fileId, 187 "file.png", 188 }, 189 }, 190 }, 191 { 192 description: "Valid Filename should parse", 193 filenames: []string{ 194 fmt.Sprintf("/%v/%v/%v/file.png", th.BasicChannel.Id, th.BasicUser.Id, fileId), 195 }, 196 channelId: th.BasicChannel.Id, 197 userID: th.BasicUser.Id, 198 expected: [][]string{ 199 { 200 th.BasicChannel.Id, 201 th.BasicUser.Id, 202 fileId, 203 "file.png", 204 }, 205 }, 206 }, 207 } 208 209 for _, test := range tests { 210 t.Run(test.description, func(tt *testing.T) { 211 result := parseOldFilenames(test.filenames, test.channelId, test.userID) 212 require.Equal(tt, result, test.expected) 213 }) 214 } 215 } 216 217 func TestGetInfoForFilename(t *testing.T) { 218 th := Setup(t).InitBasic() 219 defer th.TearDown() 220 221 post := th.BasicPost 222 teamID := th.BasicTeam.Id 223 224 info := th.App.getInfoForFilename(post, teamID, post.ChannelId, post.UserId, "someid", "somefile.png") 225 assert.Nil(t, info, "Test non-existent file") 226 } 227 228 func TestFindTeamIdForFilename(t *testing.T) { 229 th := Setup(t).InitBasic() 230 defer th.TearDown() 231 232 teamID := th.App.findTeamIdForFilename(th.BasicPost, "someid", "somefile.png") 233 assert.Equal(t, th.BasicTeam.Id, teamID) 234 235 _, err := th.App.CreateTeamWithUser(&model.Team{Email: th.BasicUser.Email, Name: "zz" + model.NewId(), DisplayName: "Joram's Test Team", Type: model.TEAM_OPEN}, th.BasicUser.Id) 236 require.Nil(t, err) 237 238 teamID = th.App.findTeamIdForFilename(th.BasicPost, "someid", "somefile.png") 239 assert.Equal(t, "", teamID) 240 } 241 242 func TestMigrateFilenamesToFileInfos(t *testing.T) { 243 th := Setup(t).InitBasic() 244 defer th.TearDown() 245 246 post := th.BasicPost 247 infos := th.App.MigrateFilenamesToFileInfos(post) 248 assert.Equal(t, 0, len(infos)) 249 250 post.Filenames = []string{fmt.Sprintf("/%v/%v/%v/blargh.png", th.BasicChannel.Id, th.BasicUser.Id, "someid")} 251 infos = th.App.MigrateFilenamesToFileInfos(post) 252 assert.Equal(t, 0, len(infos)) 253 254 path, _ := fileutils.FindDir("tests") 255 file, fileErr := os.Open(filepath.Join(path, "test.png")) 256 require.NoError(t, fileErr) 257 defer file.Close() 258 259 fileId := model.NewId() 260 fpath := fmt.Sprintf("/teams/%v/channels/%v/users/%v/%v/test.png", th.BasicTeam.Id, th.BasicChannel.Id, th.BasicUser.Id, fileId) 261 _, err := th.App.WriteFile(file, fpath) 262 require.Nil(t, err) 263 rpost, err := th.App.CreatePost(&model.Post{UserId: th.BasicUser.Id, ChannelId: th.BasicChannel.Id, Filenames: []string{fmt.Sprintf("/%v/%v/%v/test.png", th.BasicChannel.Id, th.BasicUser.Id, fileId)}}, th.BasicChannel, false, true) 264 require.Nil(t, err) 265 266 infos = th.App.MigrateFilenamesToFileInfos(rpost) 267 assert.Equal(t, 1, len(infos)) 268 269 rpost, err = th.App.CreatePost(&model.Post{UserId: th.BasicUser.Id, ChannelId: th.BasicChannel.Id, Filenames: []string{fmt.Sprintf("/%v/%v/%v/../../test.png", th.BasicChannel.Id, th.BasicUser.Id, fileId)}}, th.BasicChannel, false, true) 270 require.Nil(t, err) 271 272 infos = th.App.MigrateFilenamesToFileInfos(rpost) 273 assert.Equal(t, 0, len(infos)) 274 } 275 276 func TestCreateZipFileAndAddFiles(t *testing.T) { 277 th := Setup(t) 278 defer th.TearDown() 279 280 mockBackend := mocks.FileBackend{} 281 mockBackend.On("WriteFile", mock.Anything, "directory-to-heaven/zip-file-name-to-heaven.zip").Return(int64(666), errors.New("Only those who dare to fail greatly can ever achieve greatly")) 282 283 err := th.App.CreateZipFileAndAddFiles(&mockBackend, []model.FileData{}, "zip-file-name-to-heaven.zip", "directory-to-heaven") 284 require.Error(t, err) 285 require.Equal(t, err.Error(), "Only those who dare to fail greatly can ever achieve greatly") 286 287 mockBackend = mocks.FileBackend{} 288 mockBackend.On("WriteFile", mock.Anything, "directory-to-heaven/zip-file-name-to-heaven.zip").Return(int64(666), nil) 289 err = th.App.CreateZipFileAndAddFiles(&mockBackend, []model.FileData{}, "zip-file-name-to-heaven.zip", "directory-to-heaven") 290 require.NoError(t, err) 291 } 292 293 func TestCopyFileInfos(t *testing.T) { 294 th := Setup(t) 295 defer th.TearDown() 296 297 teamID := model.NewId() 298 channelId := model.NewId() 299 userID := model.NewId() 300 filename := "test" 301 data := []byte("abcd") 302 303 info1, err := th.App.DoUploadFile(time.Date(2007, 2, 4, 1, 2, 3, 4, time.Local), teamID, channelId, userID, filename, data) 304 require.Nil(t, err) 305 defer func() { 306 th.App.Srv().Store.FileInfo().PermanentDelete(info1.Id) 307 th.App.RemoveFile(info1.Path) 308 }() 309 310 infoIds, err := th.App.CopyFileInfos(userID, []string{info1.Id}) 311 require.Nil(t, err) 312 313 info2, err := th.App.GetFileInfo(infoIds[0]) 314 require.Nil(t, err) 315 defer func() { 316 th.App.Srv().Store.FileInfo().PermanentDelete(info2.Id) 317 th.App.RemoveFile(info2.Path) 318 }() 319 320 assert.NotEqual(t, info1.Id, info2.Id, "should not be equal") 321 assert.Equal(t, info2.PostId, "", "should be empty string") 322 } 323 324 func TestGenerateThumbnailImage(t *testing.T) { 325 t.Run("test generating thumbnail image", func(t *testing.T) { 326 // given 327 th := Setup(t) 328 defer th.TearDown() 329 img := createDummyImage() 330 dataPath, _ := fileutils.FindDir("data") 331 thumbailName := "thumb.jpg" 332 thumbnailPath := filepath.Join(dataPath, thumbailName) 333 334 // when 335 th.App.generateThumbnailImage(img, thumbailName) 336 defer os.Remove(thumbnailPath) 337 338 // then 339 outputImage, err := os.Stat(thumbnailPath) 340 assert.NoError(t, err) 341 assert.Equal(t, int64(957), outputImage.Size()) 342 }) 343 } 344 345 func createDummyImage() *image.RGBA { 346 width := 200 347 height := 100 348 upperLeftCorner := image.Point{0, 0} 349 lowerRightCorner := image.Point{width, height} 350 return image.NewRGBA(image.Rectangle{upperLeftCorner, lowerRightCorner}) 351 }