webclient: allow to download multiple files as zip

This commit is contained in:
Nicola Murino
2021-05-30 23:07:46 +02:00
parent fc7066a25c
commit 423d8306be
18 changed files with 1869 additions and 139 deletions

View File

@@ -22,6 +22,7 @@ import (
"github.com/go-chi/chi/v5"
"github.com/go-chi/jwtauth/v5"
"github.com/klauspost/compress/zip"
"github.com/lestrrat-go/jwx/jwa"
"github.com/lestrrat-go/jwx/jwt"
"github.com/rs/xid"
@@ -263,6 +264,19 @@ xr5cb9VBRBtB9aOKVfuRhpatAfS2Pzm2Htae9lFn7slGPUmu2hkjDw==
-----END RSA PRIVATE KEY-----`
)
type failingWriter struct {
}
func (r *failingWriter) Write(p []byte) (n int, err error) {
return 0, errors.New("write error")
}
func (r *failingWriter) WriteHeader(statusCode int) {}
func (r *failingWriter) Header() http.Header {
return make(http.Header)
}
func TestShouldBind(t *testing.T) {
c := Conf{
Bindings: []Binding{
@@ -1088,6 +1102,119 @@ func TestProxyHeaders(t *testing.T) {
assert.NoError(t, err)
}
func TestRecoverer(t *testing.T) {
recoveryPath := "/recovery"
b := Binding{
Address: "",
Port: 8080,
EnableWebAdmin: true,
EnableWebClient: false,
}
server := newHttpdServer(b, "../static")
server.initializeRouter()
server.router.Get(recoveryPath, func(w http.ResponseWriter, r *http.Request) {
panic("panic")
})
testServer := httptest.NewServer(server.router)
defer testServer.Close()
req, err := http.NewRequest(http.MethodGet, recoveryPath, nil)
assert.NoError(t, err)
rr := httptest.NewRecorder()
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusInternalServerError, rr.Code, rr.Body.String())
server.router = chi.NewRouter()
server.router.Use(recoverer)
server.router.Get(recoveryPath, func(w http.ResponseWriter, r *http.Request) {
panic("panic")
})
testServer = httptest.NewServer(server.router)
defer testServer.Close()
req, err = http.NewRequest(http.MethodGet, recoveryPath, nil)
assert.NoError(t, err)
rr = httptest.NewRecorder()
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusInternalServerError, rr.Code, rr.Body.String())
}
func TestCompressorAbortHandler(t *testing.T) {
defer func() {
rcv := recover()
assert.Equal(t, http.ErrAbortHandler, rcv)
}()
connection := &Connection{
BaseConnection: common.NewBaseConnection(xid.New().String(), common.ProtocolHTTP, dataprovider.User{}),
request: nil,
}
renderCompressedFiles(&failingWriter{}, connection, "", nil)
}
func TestZipErrors(t *testing.T) {
user := dataprovider.User{
HomeDir: filepath.Clean(os.TempDir()),
}
user.Permissions = make(map[string][]string)
user.Permissions["/"] = []string{dataprovider.PermAny}
connection := &Connection{
BaseConnection: common.NewBaseConnection(xid.New().String(), common.ProtocolHTTP, user),
request: nil,
}
testDir := filepath.Join(os.TempDir(), "testDir")
err := os.MkdirAll(testDir, os.ModePerm)
assert.NoError(t, err)
wr := zip.NewWriter(&failingWriter{})
err = wr.Close()
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "write error")
}
err = addZipEntry(wr, connection, "/"+filepath.Base(testDir), "/")
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "write error")
}
testFilePath := filepath.Join(testDir, "ziptest.zip")
err = os.WriteFile(testFilePath, utils.GenerateRandomBytes(65535), os.ModePerm)
assert.NoError(t, err)
err = addZipEntry(wr, connection, path.Join("/", filepath.Base(testDir), filepath.Base(testFilePath)),
"/"+filepath.Base(testDir))
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "write error")
}
connection.User.Permissions["/"] = []string{dataprovider.PermListItems}
err = addZipEntry(wr, connection, path.Join("/", filepath.Base(testDir), filepath.Base(testFilePath)),
"/"+filepath.Base(testDir))
assert.ErrorIs(t, err, os.ErrPermission)
// creating a virtual folder to a missing path stat is ok but readdir fails
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
BaseVirtualFolder: vfs.BaseVirtualFolder{
MappedPath: filepath.Join(os.TempDir(), "mapped"),
},
VirtualPath: "/vpath",
})
connection.User = user
wr = zip.NewWriter(bytes.NewBuffer(make([]byte, 0)))
err = addZipEntry(wr, connection, user.VirtualFolders[0].VirtualPath, "/")
assert.Error(t, err)
user.Filters.FilePatterns = append(user.Filters.FilePatterns, dataprovider.PatternsFilter{
Path: "/",
DeniedPatterns: []string{"*.zip"},
})
err = addZipEntry(wr, connection, "/"+filepath.Base(testDir), "/")
assert.ErrorIs(t, err, os.ErrPermission)
err = os.RemoveAll(testDir)
assert.NoError(t, err)
}
func TestWebAdminRedirect(t *testing.T) {
b := Binding{
Address: "",
@@ -1312,6 +1439,8 @@ func TestHTTPDFile(t *testing.T) {
assert.Error(t, err)
err = httpdFile.Close()
assert.ErrorIs(t, err, common.ErrTransferClosed)
err = os.Remove(p)
assert.NoError(t, err)
}
func TestChangeUserPwd(t *testing.T) {
@@ -1359,6 +1488,13 @@ func TestGetFilesInvalidClaims(t *testing.T) {
handleClientGetDirContents(rr, req)
assert.Equal(t, http.StatusForbidden, rr.Code)
assert.Contains(t, rr.Body.String(), "invalid token claims")
rr = httptest.NewRecorder()
req, _ = http.NewRequest(http.MethodGet, webClientDownloadPath, nil)
req.Header.Set("Cookie", fmt.Sprintf("jwt=%v", token["access_token"]))
handleWebClientDownload(rr, req)
assert.Equal(t, http.StatusForbidden, rr.Code)
assert.Contains(t, rr.Body.String(), "Invalid token claims")
}
func TestManageKeysInvalidClaims(t *testing.T) {