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  }