diff --git a/cmd/gokapi/Main.go b/cmd/gokapi/Main.go index e411c00..97e2fd4 100644 --- a/cmd/gokapi/Main.go +++ b/cmd/gokapi/Main.go @@ -33,7 +33,7 @@ import ( // versionGokapi is the current version in readable form. // Other version numbers can be modified in /build/go-generate/updateVersionNumbers.go -const versionGokapi = "1.9.0-beta" +const versionGokapi = "1.9.0" // The following calls update the version numbers, update documentation, minify Js/CSS and build the WASM modules //go:generate go run "../../build/go-generate/updateVersionNumbers.go" diff --git a/internal/configuration/configupgrade/Upgrade_test.go b/internal/configuration/configupgrade/Upgrade_test.go index 637f381..9519ae0 100644 --- a/internal/configuration/configupgrade/Upgrade_test.go +++ b/internal/configuration/configupgrade/Upgrade_test.go @@ -36,8 +36,12 @@ func TestUpgradeDb(t *testing.T) { exitCode = 0 oldConfigFile.ConfigVersion = 17 + oldConfigFile.Authentication.OAuthUsers = []string{"test"} + oldConfigFile.MaxMemory = 40 upgradeDone = DoUpgrade(&oldConfigFile, &env) test.IsEqualBool(t, upgradeDone, true) + test.IsEqualString(t, oldConfigFile.Authentication.OAuthUserScope, "email") + test.IsEqualInt(t, oldConfigFile.MaxMemory, 50) test.IsEqualInt(t, exitCode, 0) exitCode = 0 diff --git a/internal/configuration/database/provider/redis/Redis_test.go b/internal/configuration/database/provider/redis/Redis_test.go index 7747d6b..0126cd8 100644 --- a/internal/configuration/database/provider/redis/Redis_test.go +++ b/internal/configuration/database/provider/redis/Redis_test.go @@ -53,6 +53,10 @@ func TestDatabaseProvider_GetType(t *testing.T) { test.IsEqualInt(t, dbInstance.GetType(), 1) } +func TestDatabaseProvider_GetSchemaVersion(t *testing.T) { + test.IsEqualInt(t, dbInstance.GetSchemaVersion(), DatabaseSchemeVersion) +} + func TestDatabaseProvider_Upgrade(t *testing.T) { var err error dbInstance, err = New(config) diff --git a/internal/configuration/database/provider/sqlite/Sqlite_test.go b/internal/configuration/database/provider/sqlite/Sqlite_test.go index c168b72..8c863fd 100644 --- a/internal/configuration/database/provider/sqlite/Sqlite_test.go +++ b/internal/configuration/database/provider/sqlite/Sqlite_test.go @@ -64,6 +64,10 @@ func TestDatabaseProvider_GetDbVersion(t *testing.T) { dbInstance.SetDbVersion(DatabaseSchemeVersion) } +func TestDatabaseProvider_GetSchemaVersion(t *testing.T) { + test.IsEqualInt(t, dbInstance.GetSchemaVersion(), DatabaseSchemeVersion) +} + func TestMetaData(t *testing.T) { files := dbInstance.GetAllMetadata() test.IsEqualInt(t, len(files), 0) diff --git a/internal/encryption/Encryption_test.go b/internal/encryption/Encryption_test.go index 67d8d84..aee939b 100644 --- a/internal/encryption/Encryption_test.go +++ b/internal/encryption/Encryption_test.go @@ -2,10 +2,20 @@ package encryption import ( "bytes" + "crypto/rand" + "crypto/sha256" + "encoding/hex" + "github.com/forceu/gokapi/internal/models" "github.com/forceu/gokapi/internal/test" + "io" + "os" "testing" + + "golang.org/x/crypto/scrypt" ) +// Note: most of these tests are written by AI + func TestGetRandomCipher(t *testing.T) { cipher1, err := GetRandomCipher() test.IsNil(t, err) @@ -16,8 +26,37 @@ func TestGetRandomCipher(t *testing.T) { test.IsEqualBool(t, isEqual != 0, true) } +func TestInit(t *testing.T) { + config := models.Configuration{ + Encryption: models.Encryption{ + Level: NoEncryption, + Cipher: []byte("01234567890123456789012345678901"), + }, + } + Init(config) + // Testing for no encryption, nothing should change + + config.Encryption.Level = LocalEncryptionStored + Init(config) + test.IsNotNil(t, ramCipher) + test.IsNotNil(t, encryptedKey) + + config.Encryption.Level = FullEncryptionStored + Init(config) + test.IsNotNil(t, ramCipher) + test.IsNotNil(t, encryptedKey) +} + func TestPasswordChecksum(t *testing.T) { - checksum := PasswordChecksum("testpw", "testsalt") + password := "securepassword" + salt := "somesalt" + checksum := PasswordChecksum(password, salt) + expectedChecksum, err := scrypt.Key([]byte(password), []byte(salt), 1048576, 8, 1, blockSize) + test.IsNil(t, err) + hasher := sha256.New() + hasher.Write(expectedChecksum) + test.IsEqualString(t, hex.EncodeToString(hasher.Sum(nil)), checksum) + checksum = PasswordChecksum("testpw", "testsalt") test.IsEqualString(t, checksum, "30161cdf03347d6d3f99743532b8523e03e79d4d91ddd3a623be414519ee9ca9") checksum = PasswordChecksum("testpw", "test") test.IsEqualString(t, checksum, "41d1781205837071affbf2268588b3f2e755f0365cfe16aff6136155c1013029") @@ -26,3 +65,148 @@ func TestPasswordChecksum(t *testing.T) { checksum = PasswordChecksum("test", "testsalt") test.IsEqualString(t, checksum, "2dbcdfd0989dd2e1be0eea54f176c102e891fd4cb8182544fa4c9dba45307846") } + +func TestEncryptDecryptBytes(t *testing.T) { + key := make([]byte, 32) + _, err := rand.Read(key) + test.IsNil(t, err) + + nonce := make([]byte, 12) + _, err = rand.Read(nonce) + test.IsNil(t, err) + + plaintext := []byte("this is some plaintext") + + ciphertext, err := EncryptDecryptBytes(plaintext, key, nonce, true) + test.IsNil(t, err) + + decrypted, err := EncryptDecryptBytes(ciphertext, key, nonce, false) + test.IsNil(t, err) + test.IsEqualByteSlice(t, plaintext, decrypted) +} + +func TestGenerateNewFileKey(t *testing.T) { + encInfo := &models.EncryptionInfo{} + key, err := generateNewFileKey(encInfo) + test.IsNil(t, err) + test.IsEqualInt(t, 32, len(key)) + test.IsEqualInt(t, 12, len(encInfo.Nonce)) + test.IsEqualBool(t, encInfo.IsEncrypted, true) + test.IsEqualInt(t, 48, len(encInfo.DecryptionKey)) +} + +func TestEncryptDecrypt(t *testing.T) { + plaintext := []byte("this is some plaintext") + input := bytes.NewReader(plaintext) + var encrypted bytes.Buffer + encInfo := &models.EncryptionInfo{} + + err := Encrypt(encInfo, input, &encrypted) + test.IsNil(t, err) + + var decrypted bytes.Buffer + err = DecryptReader(*encInfo, &encrypted, &decrypted) + test.IsNil(t, err) + test.IsEqualByteSlice(t, plaintext, decrypted.Bytes()) +} + +func TestGetRandomData(t *testing.T) { + data, err := getRandomData(32) + test.IsNil(t, err) + test.IsEqualInt(t, 32, len(data)) +} + +func TestCalculateEncryptedFilesize(t *testing.T) { + size := int64(1024) + encryptedSize := CalculateEncryptedFilesize(size) + test.IsEqualBool(t, encryptedSize > size, true) +} + +func TestGetStream(t *testing.T) { + key, err := GetRandomCipher() + test.IsNil(t, err) + stream := getStream(key) + test.IsNotNil(t, stream) +} + +func TestStoreMasterKey(t *testing.T) { + key := make([]byte, 32) + _, err := rand.Read(key) + test.IsNil(t, err) + + storeMasterKey(key) + test.IsNotNil(t, ramCipher) + test.IsNotNil(t, encryptedKey) +} + +func TestFileCipherEncryptDecrypt(t *testing.T) { + input := []byte("testdata") + nonce, err := GetRandomNonce() + test.IsNil(t, err) + + encrypted, err := fileCipherEncrypt(input, nonce) + test.IsNil(t, err) + + decrypted, err := fileCipherDecrypt(encrypted, nonce) + test.IsNil(t, err) + test.IsEqualByteSlice(t, input, decrypted) +} + +func TestGetCipherFromFile(t *testing.T) { + // Initialize the encryption key and nonce + encInfo := &models.EncryptionInfo{ + DecryptionKey: make([]byte, 32), + Nonce: make([]byte, 12), + } + _, err := rand.Read(encInfo.DecryptionKey) + test.IsNil(t, err) + _, err = rand.Read(encInfo.Nonce) + test.IsNil(t, err) + + // Set the master key and ram cipher + key := make([]byte, 32) + _, err = rand.Read(key) + test.IsNil(t, err) + storeMasterKey(key) + + // Encrypt a sample key to store in encInfo.DecryptionKey + encKey, err := fileCipherEncrypt(key, encInfo.Nonce) + test.IsNil(t, err) + encInfo.DecryptionKey = encKey + + // Retrieve the cipher from the file info + retrievedKey, err := GetCipherFromFile(*encInfo) + test.IsNil(t, err) + test.IsEqualInt(t, 32, len(retrievedKey)) + test.IsEqualByteSlice(t, key, retrievedKey) +} + +func TestIsCorrectKey(t *testing.T) { + // Create a temporary file for testing + file, err := os.CreateTemp("", "testfile") + test.IsNil(t, err) + defer os.Remove(file.Name()) + + // Write some encrypted data to the file + encInfo := &models.EncryptionInfo{ + DecryptionKey: make([]byte, 32), + Nonce: make([]byte, 12), + } + _, err = rand.Read(encInfo.DecryptionKey) + test.IsNil(t, err) + _, err = rand.Read(encInfo.Nonce) + test.IsNil(t, err) + + plaintext := []byte("this is some plaintext") + input := bytes.NewReader(plaintext) + err = Encrypt(encInfo, input, file) + test.IsNil(t, err) + + // Re-open the file for reading + _, err = file.Seek(0, io.SeekStart) + test.IsNil(t, err) + + // Test if the key is correct + isCorrect := IsCorrectKey(*encInfo, file) + test.IsEqualBool(t, isCorrect, true) +} diff --git a/internal/helper/OS_test.go b/internal/helper/OS_test.go index 8d57be0..02ca1c3 100644 --- a/internal/helper/OS_test.go +++ b/internal/helper/OS_test.go @@ -65,3 +65,10 @@ func TestCheck(t *testing.T) { err = errors.New("test") Check(err) } + +func TestCheckIgnoreTimeout(t *testing.T) { + CheckIgnoreTimeout(nil) + CheckIgnoreTimeout(os.ErrDeadlineExceeded) + defer test.ExpectPanic(t) + CheckIgnoreTimeout(errors.New("other")) +} diff --git a/internal/storage/processingstatus/ProcessingStatus.go b/internal/storage/processingstatus/ProcessingStatus.go index 7e18b6b..cbb0f8b 100644 --- a/internal/storage/processingstatus/ProcessingStatus.go +++ b/internal/storage/processingstatus/ProcessingStatus.go @@ -29,6 +29,6 @@ func Set(id string, status int) { if ok && oldStatus.CurrentStatus > newStatus.CurrentStatus { return } - passNewStatus(newStatus) database.SaveUploadStatus(newStatus) + go passNewStatus(newStatus) } diff --git a/internal/storage/processingstatus/ProcessingStatus_test.go b/internal/storage/processingstatus/ProcessingStatus_test.go index 6b3e8f1..6f8cbaf 100644 --- a/internal/storage/processingstatus/ProcessingStatus_test.go +++ b/internal/storage/processingstatus/ProcessingStatus_test.go @@ -3,12 +3,10 @@ package processingstatus import ( "github.com/forceu/gokapi/internal/configuration" "github.com/forceu/gokapi/internal/configuration/database" - "github.com/forceu/gokapi/internal/models" "github.com/forceu/gokapi/internal/test" "github.com/forceu/gokapi/internal/test/testconfiguration" "os" "testing" - "time" ) func TestMain(m *testing.M) { @@ -21,38 +19,19 @@ func TestMain(m *testing.M) { } func TestSetStatus(t *testing.T) { + const id = "testchunk" + status, ok := database.GetUploadStatus(id) + test.IsEqualBool(t, ok, false) + test.IsEmpty(t, status.ChunkId) + Set(id, 2) + status, ok = database.GetUploadStatus(id) + test.IsEqualBool(t, ok, true) + test.IsEqualString(t, status.ChunkId, id) + test.IsEqualInt(t, status.CurrentStatus, 2) + Set(id, 1) + status, ok = database.GetUploadStatus(id) + test.IsEqualBool(t, ok, true) + test.IsEqualString(t, status.ChunkId, id) + test.IsEqualInt(t, status.CurrentStatus, 2) - chunkID := "testChunkID" - testCases := []struct { - name string - initialStatus int - newStatus int - }{ - {"SetNewStatus", -1, StatusHashingOrEncrypting}, - {"SetSameStatus", StatusUploading, StatusUploading}, - // Add more test cases as needed - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - // Set the initial status for the chunk ID - initialStatus := models.UploadStatus{ - ChunkId: chunkID, - CurrentStatus: tc.initialStatus, - } - database.SaveUploadStatus(initialStatus) - - // Set the new status - Set(chunkID, tc.newStatus) - - // Wait for SSE event to be published - time.Sleep(100 * time.Millisecond) - - // Retrieve the updated status from the database - updatedStatus, _ := database.GetUploadStatus(chunkID) - - // Check if the status was updated - test.IsEqualInt(t, tc.newStatus, updatedStatus.CurrentStatus) - }) - } } diff --git a/internal/webserver/web/templates/string_constants.tmpl b/internal/webserver/web/templates/string_constants.tmpl index e9aad95..a10cbf0 100644 --- a/internal/webserver/web/templates/string_constants.tmpl +++ b/internal/webserver/web/templates/string_constants.tmpl @@ -1,5 +1,5 @@ // Change these for rebranding -{{define "version"}}1.9.0-beta{{end}} +{{define "version"}}1.9.0{{end}} // Specifies the version of JS files, so that the browser doesn't // use a cached version, if the file has been updated