github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/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  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/mattermost/mattermost-server/v5/model"
    17  	"github.com/mattermost/mattermost-server/v5/utils/fileutils"
    18  )
    19  
    20  func TestGeneratePublicLinkHash(t *testing.T) {
    21  	filename1 := model.NewId() + "/" + model.NewRandomString(16) + ".txt"
    22  	filename2 := model.NewId() + "/" + model.NewRandomString(16) + ".txt"
    23  	salt1 := model.NewRandomString(32)
    24  	salt2 := model.NewRandomString(32)
    25  
    26  	hash1 := GeneratePublicLinkHash(filename1, salt1)
    27  	hash2 := GeneratePublicLinkHash(filename2, salt1)
    28  	hash3 := GeneratePublicLinkHash(filename1, salt2)
    29  
    30  	hash := GeneratePublicLinkHash(filename1, salt1)
    31  	assert.Equal(t, hash, hash1, "hash should be equal for the same file name and salt")
    32  
    33  	assert.NotEqual(t, hash1, hash2, "hashes for different files should not be equal")
    34  
    35  	assert.NotEqual(t, hash1, hash3, "hashes for the same file with different salts should not be equal")
    36  }
    37  
    38  func TestDoUploadFile(t *testing.T) {
    39  	th := Setup(t)
    40  	defer th.TearDown()
    41  
    42  	teamId := model.NewId()
    43  	channelId := model.NewId()
    44  	userId := model.NewId()
    45  	filename := "test"
    46  	data := []byte("abcd")
    47  
    48  	info1, err := th.App.DoUploadFile(time.Date(2007, 2, 4, 1, 2, 3, 4, time.Local), teamId, channelId, userId, filename, data)
    49  	require.Nil(t, err, "DoUploadFile should succeed with valid data")
    50  	defer func() {
    51  		th.App.Srv().Store.FileInfo().PermanentDelete(info1.Id)
    52  		th.App.RemoveFile(info1.Path)
    53  	}()
    54  
    55  	value := fmt.Sprintf("20070204/teams/%v/channels/%v/users/%v/%v/%v", teamId, channelId, userId, info1.Id, filename)
    56  	assert.Equal(t, value, info1.Path, "stored file at incorrect path")
    57  
    58  	info2, err := th.App.DoUploadFile(time.Date(2007, 2, 4, 1, 2, 3, 4, time.Local), teamId, channelId, userId, filename, data)
    59  	require.Nil(t, err, "DoUploadFile should succeed with valid data")
    60  	defer func() {
    61  		th.App.Srv().Store.FileInfo().PermanentDelete(info2.Id)
    62  		th.App.RemoveFile(info2.Path)
    63  	}()
    64  
    65  	value = fmt.Sprintf("20070204/teams/%v/channels/%v/users/%v/%v/%v", teamId, channelId, userId, info2.Id, filename)
    66  	assert.Equal(t, value, info2.Path, "stored file at incorrect path")
    67  
    68  	info3, err := th.App.DoUploadFile(time.Date(2008, 3, 5, 1, 2, 3, 4, time.Local), teamId, channelId, userId, filename, data)
    69  	require.Nil(t, err, "DoUploadFile should succeed with valid data")
    70  	defer func() {
    71  		th.App.Srv().Store.FileInfo().PermanentDelete(info3.Id)
    72  		th.App.RemoveFile(info3.Path)
    73  	}()
    74  
    75  	value = fmt.Sprintf("20080305/teams/%v/channels/%v/users/%v/%v/%v", teamId, channelId, userId, info3.Id, filename)
    76  	assert.Equal(t, value, info3.Path, "stored file at incorrect path")
    77  
    78  	info4, err := th.App.DoUploadFile(time.Date(2009, 3, 5, 1, 2, 3, 4, time.Local), "../../"+teamId, "../../"+channelId, "../../"+userId, "../../"+filename, data)
    79  	require.Nil(t, err, "DoUploadFile should succeed with valid data")
    80  	defer func() {
    81  		th.App.Srv().Store.FileInfo().PermanentDelete(info4.Id)
    82  		th.App.RemoveFile(info4.Path)
    83  	}()
    84  
    85  	value = fmt.Sprintf("20090305/teams/%v/channels/%v/users/%v/%v/%v", teamId, channelId, userId, info4.Id, filename)
    86  	assert.Equal(t, value, info4.Path, "stored file at incorrect path")
    87  }
    88  
    89  func TestUploadFile(t *testing.T) {
    90  	th := Setup(t).InitBasic()
    91  	defer th.TearDown()
    92  
    93  	channelId := th.BasicChannel.Id
    94  	filename := "test"
    95  	data := []byte("abcd")
    96  
    97  	info1, err := th.App.UploadFile(data, "wrong", filename)
    98  	require.Error(t, err, "Wrong Channel ID.")
    99  	require.Nil(t, info1, "Channel ID does not exist.")
   100  
   101  	info1, err = th.App.UploadFile(data, "", filename)
   102  	require.Nil(t, err, "empty channel IDs should be valid")
   103  
   104  	info1, err = th.App.UploadFile(data, channelId, filename)
   105  	require.Nil(t, err, "UploadFile should succeed with valid data")
   106  	defer func() {
   107  		th.App.Srv().Store.FileInfo().PermanentDelete(info1.Id)
   108  		th.App.RemoveFile(info1.Path)
   109  	}()
   110  
   111  	value := fmt.Sprintf("%v/teams/noteam/channels/%v/users/nouser/%v/%v",
   112  		time.Now().Format("20060102"), channelId, info1.Id, filename)
   113  	assert.Equal(t, value, info1.Path, "Stored file at incorrect path")
   114  }
   115  
   116  func TestParseOldFilenames(t *testing.T) {
   117  	th := Setup(t).InitBasic()
   118  	defer th.TearDown()
   119  
   120  	fileId := model.NewId()
   121  
   122  	tests := []struct {
   123  		description string
   124  		filenames   []string
   125  		channelId   string
   126  		userId      string
   127  		expected    [][]string
   128  	}{
   129  		{
   130  			description: "Empty input should result in empty output",
   131  			filenames:   []string{},
   132  			channelId:   th.BasicChannel.Id,
   133  			userId:      th.BasicUser.Id,
   134  			expected:    [][]string{},
   135  		},
   136  		{
   137  			description: "Filename with invalid format should not parse",
   138  			filenames:   []string{"/path/to/some/file.png"},
   139  			channelId:   th.BasicChannel.Id,
   140  			userId:      th.BasicUser.Id,
   141  			expected:    [][]string{},
   142  		},
   143  		{
   144  			description: "ChannelId in Filename should not match",
   145  			filenames: []string{
   146  				fmt.Sprintf("/%v/%v/%v/file.png", model.NewId(), th.BasicUser.Id, fileId),
   147  			},
   148  			channelId: th.BasicChannel.Id,
   149  			userId:    th.BasicUser.Id,
   150  			expected:  [][]string{},
   151  		},
   152  		{
   153  			description: "UserId in Filename should not match",
   154  			filenames: []string{
   155  				fmt.Sprintf("/%v/%v/%v/file.png", th.BasicChannel.Id, model.NewId(), fileId),
   156  			},
   157  			channelId: th.BasicChannel.Id,
   158  			userId:    th.BasicUser.Id,
   159  			expected:  [][]string{},
   160  		},
   161  		{
   162  			description: "../ in filename should not parse",
   163  			filenames: []string{
   164  				fmt.Sprintf("/%v/%v/%v/../../../file.png", th.BasicChannel.Id, th.BasicUser.Id, fileId),
   165  			},
   166  			channelId: th.BasicChannel.Id,
   167  			userId:    th.BasicUser.Id,
   168  			expected:  [][]string{},
   169  		},
   170  		{
   171  			description: "Should only parse valid filenames",
   172  			filenames: []string{
   173  				fmt.Sprintf("/%v/%v/%v/../otherfile.png", th.BasicChannel.Id, th.BasicUser.Id, fileId),
   174  				fmt.Sprintf("/%v/%v/%v/file.png", th.BasicChannel.Id, th.BasicUser.Id, fileId),
   175  			},
   176  			channelId: th.BasicChannel.Id,
   177  			userId:    th.BasicUser.Id,
   178  			expected: [][]string{
   179  				{
   180  					th.BasicChannel.Id,
   181  					th.BasicUser.Id,
   182  					fileId,
   183  					"file.png",
   184  				},
   185  			},
   186  		},
   187  		{
   188  			description: "Valid Filename should parse",
   189  			filenames: []string{
   190  				fmt.Sprintf("/%v/%v/%v/file.png", th.BasicChannel.Id, th.BasicUser.Id, fileId),
   191  			},
   192  			channelId: th.BasicChannel.Id,
   193  			userId:    th.BasicUser.Id,
   194  			expected: [][]string{
   195  				{
   196  					th.BasicChannel.Id,
   197  					th.BasicUser.Id,
   198  					fileId,
   199  					"file.png",
   200  				},
   201  			},
   202  		},
   203  	}
   204  
   205  	for _, test := range tests {
   206  		t.Run(test.description, func(tt *testing.T) {
   207  			result := parseOldFilenames(test.filenames, test.channelId, test.userId)
   208  			require.Equal(tt, result, test.expected)
   209  		})
   210  	}
   211  }
   212  
   213  func TestGetInfoForFilename(t *testing.T) {
   214  	th := Setup(t).InitBasic()
   215  	defer th.TearDown()
   216  
   217  	post := th.BasicPost
   218  	teamId := th.BasicTeam.Id
   219  
   220  	info := th.App.getInfoForFilename(post, teamId, post.ChannelId, post.UserId, "someid", "somefile.png")
   221  	assert.Nil(t, info, "Test non-existent file")
   222  }
   223  
   224  func TestFindTeamIdForFilename(t *testing.T) {
   225  	th := Setup(t).InitBasic()
   226  	defer th.TearDown()
   227  
   228  	teamId := th.App.findTeamIdForFilename(th.BasicPost, "someid", "somefile.png")
   229  	assert.Equal(t, th.BasicTeam.Id, teamId)
   230  
   231  	_, 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)
   232  	require.Nil(t, err)
   233  
   234  	teamId = th.App.findTeamIdForFilename(th.BasicPost, "someid", "somefile.png")
   235  	assert.Equal(t, "", teamId)
   236  }
   237  
   238  func TestMigrateFilenamesToFileInfos(t *testing.T) {
   239  	th := Setup(t).InitBasic()
   240  	defer th.TearDown()
   241  
   242  	post := th.BasicPost
   243  	infos := th.App.MigrateFilenamesToFileInfos(post)
   244  	assert.Equal(t, 0, len(infos))
   245  
   246  	post.Filenames = []string{fmt.Sprintf("/%v/%v/%v/blargh.png", th.BasicChannel.Id, th.BasicUser.Id, "someid")}
   247  	infos = th.App.MigrateFilenamesToFileInfos(post)
   248  	assert.Equal(t, 0, len(infos))
   249  
   250  	path, _ := fileutils.FindDir("tests")
   251  	file, fileErr := os.Open(filepath.Join(path, "test.png"))
   252  	require.Nil(t, fileErr)
   253  	defer file.Close()
   254  
   255  	fileId := model.NewId()
   256  	fpath := fmt.Sprintf("/teams/%v/channels/%v/users/%v/%v/test.png", th.BasicTeam.Id, th.BasicChannel.Id, th.BasicUser.Id, fileId)
   257  	_, err := th.App.WriteFile(file, fpath)
   258  	require.Nil(t, err)
   259  	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)
   260  	require.Nil(t, err)
   261  
   262  	infos = th.App.MigrateFilenamesToFileInfos(rpost)
   263  	assert.Equal(t, 1, len(infos))
   264  
   265  	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)
   266  	require.Nil(t, err)
   267  
   268  	infos = th.App.MigrateFilenamesToFileInfos(rpost)
   269  	assert.Equal(t, 0, len(infos))
   270  }
   271  
   272  func TestCopyFileInfos(t *testing.T) {
   273  	th := Setup(t)
   274  	defer th.TearDown()
   275  
   276  	teamId := model.NewId()
   277  	channelId := model.NewId()
   278  	userId := model.NewId()
   279  	filename := "test"
   280  	data := []byte("abcd")
   281  
   282  	info1, err := th.App.DoUploadFile(time.Date(2007, 2, 4, 1, 2, 3, 4, time.Local), teamId, channelId, userId, filename, data)
   283  	require.Nil(t, err)
   284  	defer func() {
   285  		th.App.Srv().Store.FileInfo().PermanentDelete(info1.Id)
   286  		th.App.RemoveFile(info1.Path)
   287  	}()
   288  
   289  	infoIds, err := th.App.CopyFileInfos(userId, []string{info1.Id})
   290  	require.Nil(t, err)
   291  
   292  	info2, err := th.App.GetFileInfo(infoIds[0])
   293  	require.Nil(t, err)
   294  	defer func() {
   295  		th.App.Srv().Store.FileInfo().PermanentDelete(info2.Id)
   296  		th.App.RemoveFile(info2.Path)
   297  	}()
   298  
   299  	assert.NotEqual(t, info1.Id, info2.Id, "should not be equal")
   300  	assert.Equal(t, info2.PostId, "", "should be empty string")
   301  }