github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/extract_plugin_tar_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  	"archive/tar"
     8  	"bytes"
     9  	"compress/gzip"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"path/filepath"
    14  	"sort"
    15  	"strings"
    16  	"testing"
    17  
    18  	"github.com/stretchr/testify/assert"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  func assertDirectoryContents(t *testing.T, dir string, expectedFiles []string) {
    23  	var files []string
    24  	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
    25  		require.NoError(t, err)
    26  		file := strings.TrimPrefix(path, dir)
    27  		file = strings.TrimPrefix(file, "/")
    28  		files = append(files, file)
    29  		return nil
    30  	})
    31  	require.NoError(t, err)
    32  
    33  	sort.Strings(files)
    34  	sort.Strings(expectedFiles)
    35  	assert.Equal(t, expectedFiles, files)
    36  }
    37  
    38  func TestExtractTarGz(t *testing.T) {
    39  	makeArchive := func(t *testing.T, files []*tar.Header) bytes.Buffer {
    40  		// Build an in-memory archive with the specified files, writing the path as each
    41  		// file's contents when applicable.
    42  		var archive bytes.Buffer
    43  		archiveGzWriter := gzip.NewWriter(&archive)
    44  		archiveWriter := tar.NewWriter(archiveGzWriter)
    45  		for _, file := range files {
    46  			if file.Typeflag == tar.TypeReg {
    47  				contents := []byte(file.Name)
    48  				file.Size = int64(len(contents))
    49  				err := archiveWriter.WriteHeader(file)
    50  				require.NoError(t, err)
    51  
    52  				var written int
    53  				written, err = archiveWriter.Write(contents)
    54  				require.NoError(t, err)
    55  				require.EqualValues(t, len(contents), written)
    56  			} else {
    57  				err := archiveWriter.WriteHeader(file)
    58  				require.NoError(t, err)
    59  			}
    60  		}
    61  		err := archiveWriter.Close()
    62  		require.NoError(t, err)
    63  		err = archiveGzWriter.Close()
    64  		require.NoError(t, err)
    65  
    66  		return archive
    67  	}
    68  
    69  	t.Run("empty dst", func(t *testing.T) {
    70  		archive := makeArchive(t, nil)
    71  		err := extractTarGz(&archive, "")
    72  		require.Error(t, err)
    73  	})
    74  
    75  	testCases := []struct {
    76  		Files         []*tar.Header
    77  		ExpectedError bool
    78  		ExpectedFiles []string
    79  	}{
    80  		{
    81  			[]*tar.Header{{Name: "../test/path", Typeflag: tar.TypeDir}},
    82  			true,
    83  			nil,
    84  		},
    85  		{
    86  			[]*tar.Header{{Name: "../../test/path", Typeflag: tar.TypeDir}},
    87  			true,
    88  			nil,
    89  		},
    90  		{
    91  			[]*tar.Header{{Name: "../../test/../path", Typeflag: tar.TypeDir}},
    92  			true,
    93  			nil,
    94  		},
    95  		{
    96  			[]*tar.Header{{Name: "test/../../path", Typeflag: tar.TypeDir}},
    97  			true,
    98  			nil,
    99  		},
   100  		{
   101  			[]*tar.Header{{Name: "test/path/../..", Typeflag: tar.TypeDir}},
   102  			false,
   103  			[]string{""},
   104  		},
   105  		{
   106  			[]*tar.Header{{Name: "test", Typeflag: tar.TypeDir}},
   107  			false,
   108  			[]string{"", "test"},
   109  		},
   110  		{
   111  			[]*tar.Header{
   112  				{Name: "test", Typeflag: tar.TypeDir},
   113  				{Name: "test/path", Typeflag: tar.TypeDir},
   114  			},
   115  			false,
   116  			[]string{"", "test", "test/path"},
   117  		},
   118  		{
   119  			[]*tar.Header{
   120  				{Name: "test", Typeflag: tar.TypeDir},
   121  				{Name: "test/path/", Typeflag: tar.TypeDir},
   122  			},
   123  			false,
   124  			[]string{"", "test", "test/path"},
   125  		},
   126  		{
   127  			[]*tar.Header{
   128  				{Name: "test", Typeflag: tar.TypeDir},
   129  				{Name: "test/path", Typeflag: tar.TypeDir},
   130  				{Name: "test/path/file.ext", Typeflag: tar.TypeReg},
   131  			},
   132  			false,
   133  			[]string{"", "test", "test/path", "test/path/file.ext"},
   134  		},
   135  		{
   136  			[]*tar.Header{
   137  				{Name: "/../../file.ext", Typeflag: tar.TypeReg},
   138  			},
   139  			true,
   140  			nil,
   141  		},
   142  		{
   143  			[]*tar.Header{
   144  				{Name: "/../../link", Typeflag: tar.TypeLink},
   145  			},
   146  			false,
   147  			[]string{""},
   148  		},
   149  		{
   150  			[]*tar.Header{
   151  				{Name: "..file", Typeflag: tar.TypeReg},
   152  			},
   153  			false,
   154  			[]string{"", "..file"},
   155  		},
   156  	}
   157  
   158  	for i, testCase := range testCases {
   159  		t.Run(fmt.Sprintf("test-%d", i), func(t *testing.T) {
   160  			dst, err := ioutil.TempDir("", "TestExtractTarGz")
   161  			require.NoError(t, err)
   162  			defer os.RemoveAll(dst)
   163  
   164  			archive := makeArchive(t, testCase.Files)
   165  			err = extractTarGz(&archive, dst)
   166  			if testCase.ExpectedError {
   167  				require.Error(t, err)
   168  			} else {
   169  				require.NoError(t, err)
   170  				assertDirectoryContents(t, dst, testCase.ExpectedFiles)
   171  			}
   172  		})
   173  	}
   174  }