From eedabbd8f75cf877cbf1cc619ab9595e45579fc2 Mon Sep 17 00:00:00 2001 From: Marc Ole Bulling Date: Tue, 8 Mar 2022 13:17:39 +0100 Subject: [PATCH] Added tests and comments --- internal/encryption/Encryption.go | 17 +++++- internal/storage/FileServing_test.go | 86 +++++++++++++++++++++++++++- internal/test/TestHelper.go | 9 +++ internal/webserver/Webserver_test.go | 4 -- 4 files changed, 109 insertions(+), 7 deletions(-) diff --git a/internal/encryption/Encryption.go b/internal/encryption/Encryption.go index 96a9293..178c366 100644 --- a/internal/encryption/Encryption.go +++ b/internal/encryption/Encryption.go @@ -17,12 +17,22 @@ import ( "time" ) -// NoEncryption setup value is fo +// NoEncryption means all files are stored in plaintext const NoEncryption = 0 + +// LocalEncryptionStored means remote files are stored in plaintext, cipher for local files is in plaintext const LocalEncryptionStored = 1 + +// LocalEncryptionInput means remote files are stored in plaintext, password needs to be entered on startup const LocalEncryptionInput = 2 + +// FullEncryptionStored means all files are encrypted, cipher for local files is in plaintext const FullEncryptionStored = 3 + +// FullEncryptionInput means all files are encrypted, password needs to be entered on startup const FullEncryptionInput = 4 + +// EndToEndEncryption means all files are encrypted and decrypted client-side const EndToEndEncryption = 5 var encryptedKey, ramCipher []byte @@ -265,3 +275,8 @@ func getRandomData(size int) ([]byte, error) { func GetRandomCipher() ([]byte, error) { return getRandomData(blockSize) } + +// GetRandomNonce a 12 byte long array with random data +func GetRandomNonce() ([]byte, error) { + return getRandomData(nonceSize) +} diff --git a/internal/storage/FileServing_test.go b/internal/storage/FileServing_test.go index 56b60d4..0e9adf0 100644 --- a/internal/storage/FileServing_test.go +++ b/internal/storage/FileServing_test.go @@ -8,6 +8,7 @@ import ( "github.com/forceu/gokapi/internal/configuration" "github.com/forceu/gokapi/internal/configuration/cloudconfig" "github.com/forceu/gokapi/internal/configuration/datastorage" + "github.com/forceu/gokapi/internal/encryption" "github.com/forceu/gokapi/internal/models" "github.com/forceu/gokapi/internal/storage/cloudstorage/aws" "github.com/forceu/gokapi/internal/test" @@ -79,9 +80,21 @@ func TestAddHotlink(t *testing.T) { link, ok := datastorage.GetHotlink(file.HotlinkId) test.IsEqualBool(t, ok, true) test.IsEqualString(t, link, "testId") + file = models.File{Name: "test.jpg", Id: "testId", ExpireAt: time.Now().Add(time.Hour).Unix()} + file.Encryption.IsEncrypted = true + file.AwsBucket = "test" + addHotlink(&file) + test.IsEqualString(t, file.HotlinkId, "") } -func TestNewFile(t *testing.T) { +type testFile struct { + File models.File + Request models.UploadRequest + Header multipart.FileHeader + Content []byte +} + +func createTestFile() (testFile, error) { os.Setenv("TZ", "UTC") content := []byte("This is a file for testing purposes") mimeHeader := make(textproto.MIMEHeader) @@ -100,6 +113,22 @@ func TestNewFile(t *testing.T) { DataDir: "test/data", } file, err := NewFile(bytes.NewReader(content), &header, request) + return testFile{ + File: file, + Request: request, + Header: header, + Content: content, + }, err +} + +func TestNewFile(t *testing.T) { + + newFile, err := createTestFile() + file := newFile.File + request := newFile.Request + content := newFile.Content + header := newFile.Header + test.IsNil(t, err) retrievedFile, ok := datastorage.GetMetaDataById(file.Id) test.IsEqualBool(t, ok, true) @@ -132,7 +161,7 @@ func TestNewFile(t *testing.T) { createBigFile("bigfile", 20) bigFile, _ := os.Open("bigfile") - mimeHeader = make(textproto.MIMEHeader) + mimeHeader := make(textproto.MIMEHeader) mimeHeader.Set("Content-Disposition", "form-data; name=\"file\"; filename=\"bigfile\"") mimeHeader.Set("Content-Type", "application/binary") header = multipart.FileHeader{ @@ -189,6 +218,24 @@ func TestNewFile(t *testing.T) { bigFile.Close() os.Remove("bigfile") + configuration.Get().Encryption.Level = 1 + previousSalt := configuration.Get().Authentication.SaltFiles + configuration.Get().Authentication.SaltFiles = "testsaltfiles" + cipher, err := encryption.GetRandomCipher() + test.IsNil(t, err) + encryption.Init(models.Configuration{Encryption: models.Encryption{ + Level: encryption.LocalEncryptionStored, + Cipher: cipher, + }}) + + newFile, err = createTestFile() + test.IsNil(t, err) + retrievedFile, ok = datastorage.GetMetaDataById(newFile.File.Id) + test.IsEqualBool(t, ok, true) + test.IsEqualString(t, retrievedFile.SHA256, "5bbfa18805eb12c678cfd284c956718d57039e37") + configuration.Get().Authentication.SaltFiles = previousSalt + configuration.Get().Encryption.Level = 0 + if aws.IsIncludedInBuild { header = multipart.FileHeader{ Filename: "bigfile", @@ -216,6 +263,7 @@ func TestNewFile(t *testing.T) { test.IsEqualString(t, retrievedFile.Size, "20.0 MB") testconfiguration.DisableS3() } + } func TestServeFile(t *testing.T) { @@ -252,6 +300,25 @@ func TestServeFile(t *testing.T) { } testconfiguration.DisableS3() } + newFile, err := createTestFile() + test.IsNotNil(t, err) + file = newFile.File + datastorage.SaveMetaData(file) + r = httptest.NewRequest("GET", "/upload", nil) + w = httptest.NewRecorder() + cipher, err := encryption.GetRandomCipher() + test.IsNil(t, err) + nonce, err := encryption.GetRandomNonce() + test.IsNil(t, err) + encryption.Init(models.Configuration{Encryption: models.Encryption{ + Level: encryption.LocalEncryptionStored, + Cipher: cipher, + }}) + file.Encryption.IsEncrypted = true + file.Encryption.DecryptionKey = cipher + file.Encryption.Nonce = nonce + defer test.ExpectPanic(t) + ServeFile(file, w, r, true) } func TestCleanUp(t *testing.T) { @@ -460,3 +527,18 @@ func TestDeleteAllEncrypted(t *testing.T) { test.IsEqualBool(t, ok, true) test.IsEqualBool(t, data.UnlimitedTime, true) } + +func TestWriteDownloadHeaders(t *testing.T) { + file := models.File{Name: "testname", ContentType: "testtype"} + w, _ := test.GetRecorder("GET", "/test", nil, nil, nil) + writeDownloadHeaders(file, w, true) + test.IsEqualString(t, w.Result().Header.Get("Content-Disposition"), "attachment; filename=\"testname\"") + w, _ = test.GetRecorder("GET", "/test", nil, nil, nil) + writeDownloadHeaders(file, w, false) + test.IsEqualString(t, w.Result().Header.Get("Content-Disposition"), "inline; filename=\"testname\"") + test.IsEqualString(t, w.Result().Header.Get("Content-Type"), "testtype") + file.Encryption.IsEncrypted = true + w, _ = test.GetRecorder("GET", "/test", nil, nil, nil) + writeDownloadHeaders(file, w, false) + test.IsEqualString(t, w.Result().Header.Get("Accept-Ranges"), "bytes") +} diff --git a/internal/test/TestHelper.go b/internal/test/TestHelper.go index 5b707ad..2660fff 100644 --- a/internal/test/TestHelper.go +++ b/internal/test/TestHelper.go @@ -31,6 +31,14 @@ func IsEqualString(t MockT, got, want string) { } } +// ContainsString fails test if got does not contain want +func ContainsString(t MockT, got, want string) { + t.Helper() + if !strings.Contains(got, want) { + t.Errorf("Assertion failed, GOT: %s, WANT: %s.", got, want) + } +} + // ResponseBodyContains fails test if http response does contain string func ResponseBodyContains(t MockT, got *httptest.ResponseRecorder, want string) { t.Helper() @@ -383,6 +391,7 @@ func GetRecorder(method, target string, cookies []Cookie, headers []Header, body func ExpectPanic(t MockT) { r := recover() + t.Helper() if r == nil { t.Errorf("The code did not panic") } diff --git a/internal/webserver/Webserver_test.go b/internal/webserver/Webserver_test.go index 942dc1e..5fe53a5 100644 --- a/internal/webserver/Webserver_test.go +++ b/internal/webserver/Webserver_test.go @@ -11,7 +11,6 @@ import ( "github.com/forceu/gokapi/internal/test/testconfiguration" "github.com/forceu/gokapi/internal/webserver/authentication" "html/template" - "io" "io/fs" "os" "strings" @@ -653,9 +652,6 @@ func TestResponseError(t *testing.T) { err := errors.New("testerror") defer test.ExpectPanic(t) responseError(w, err) - output, err := io.ReadAll(w.Result().Body) - test.IsNil(t, err) - test.IsEqualString(t, string(output), "{\"Result\":\"error\",\"ErrorMessage\":\""+err.Error()+"\"}") } func TestShowErrorAuth(t *testing.T) {