mirror of
https://github.com/databasus/databasus.git
synced 2026-04-06 00:32:03 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2815cc3752 | ||
|
|
189573fa1b | ||
|
|
81f77760c9 | ||
|
|
63e23b2489 |
@@ -144,6 +144,27 @@ func (r *RcloneStorage) Validate(encryptor encryption.FieldEncryptor) error {
|
||||
return errors.New("rclone config content is required")
|
||||
}
|
||||
|
||||
configContent, err := encryptor.Decrypt(r.StorageID, r.ConfigContent)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt rclone config content: %w", err)
|
||||
}
|
||||
|
||||
parsedConfig, err := parseConfigContent(configContent)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse rclone config: %w", err)
|
||||
}
|
||||
|
||||
if len(parsedConfig) == 0 {
|
||||
return errors.New("rclone config must contain at least one remote section")
|
||||
}
|
||||
|
||||
if len(parsedConfig) > 1 {
|
||||
return fmt.Errorf(
|
||||
"rclone config must contain exactly one remote section, but found %d; create a separate storage for each remote",
|
||||
len(parsedConfig),
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -230,6 +251,13 @@ func (r *RcloneStorage) getFs(
|
||||
return nil, errors.New("rclone config must contain at least one remote section")
|
||||
}
|
||||
|
||||
if len(parsedConfig) > 1 {
|
||||
return nil, fmt.Errorf(
|
||||
"rclone config must contain exactly one remote section, but found %d; create a separate storage for each remote",
|
||||
len(parsedConfig),
|
||||
)
|
||||
}
|
||||
|
||||
var remoteName string
|
||||
for section, values := range parsedConfig {
|
||||
remoteName = section
|
||||
|
||||
118
backend/internal/features/storages/models/rclone/model_test.go
Normal file
118
backend/internal/features/storages/models/rclone/model_test.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package rclone_storage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_ParseConfigContent_SingleRemote_ParsedCorrectly(t *testing.T) {
|
||||
content := `[myremote]
|
||||
type = s3
|
||||
provider = AWS
|
||||
access_key_id = AKIAIOSFODNN7EXAMPLE
|
||||
secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
|
||||
region = us-east-1`
|
||||
|
||||
sections, err := parseConfigContent(content)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, sections, 1)
|
||||
assert.Equal(t, "s3", sections["myremote"]["type"])
|
||||
assert.Equal(t, "AWS", sections["myremote"]["provider"])
|
||||
assert.Equal(t, "AKIAIOSFODNN7EXAMPLE", sections["myremote"]["access_key_id"])
|
||||
assert.Equal(t, "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", sections["myremote"]["secret_access_key"])
|
||||
assert.Equal(t, "us-east-1", sections["myremote"]["region"])
|
||||
}
|
||||
|
||||
func Test_ParseConfigContent_MultipleRemotes_AllParsed(t *testing.T) {
|
||||
content := `[remote1]
|
||||
type = s3
|
||||
region = us-east-1
|
||||
|
||||
[remote2]
|
||||
type = drive
|
||||
client_id = abc123`
|
||||
|
||||
sections, err := parseConfigContent(content)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, sections, 2)
|
||||
assert.Equal(t, "s3", sections["remote1"]["type"])
|
||||
assert.Equal(t, "us-east-1", sections["remote1"]["region"])
|
||||
assert.Equal(t, "drive", sections["remote2"]["type"])
|
||||
assert.Equal(t, "abc123", sections["remote2"]["client_id"])
|
||||
}
|
||||
|
||||
func Test_ParseConfigContent_EmptyContent_ReturnsEmptyMap(t *testing.T) {
|
||||
sections, err := parseConfigContent("")
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, sections)
|
||||
}
|
||||
|
||||
func Test_ParseConfigContent_CommentsAndBlankLines_Ignored(t *testing.T) {
|
||||
content := `# This is a comment
|
||||
; Another comment
|
||||
|
||||
[myremote]
|
||||
type = s3
|
||||
|
||||
# inline comment line
|
||||
region = eu-west-1`
|
||||
|
||||
sections, err := parseConfigContent(content)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, sections, 1)
|
||||
assert.Equal(t, "s3", sections["myremote"]["type"])
|
||||
assert.Equal(t, "eu-west-1", sections["myremote"]["region"])
|
||||
}
|
||||
|
||||
func Test_ParseConfigContent_ValueWithEqualsSign_PreservesFullValue(t *testing.T) {
|
||||
content := `[myremote]
|
||||
type = s3
|
||||
secret_access_key = abc=def=ghi`
|
||||
|
||||
sections, err := parseConfigContent(content)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "abc=def=ghi", sections["myremote"]["secret_access_key"])
|
||||
}
|
||||
|
||||
func Test_ParseConfigContent_KeyWithoutValue_EmptyString(t *testing.T) {
|
||||
content := `[myremote]
|
||||
type =
|
||||
provider = AWS`
|
||||
|
||||
sections, err := parseConfigContent(content)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "", sections["myremote"]["type"])
|
||||
assert.Equal(t, "AWS", sections["myremote"]["provider"])
|
||||
}
|
||||
|
||||
func Test_ParseConfigContent_KeyValueOutsideSection_Ignored(t *testing.T) {
|
||||
content := `orphan_key = orphan_value
|
||||
[myremote]
|
||||
type = s3`
|
||||
|
||||
sections, err := parseConfigContent(content)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, sections, 1)
|
||||
assert.Equal(t, "s3", sections["myremote"]["type"])
|
||||
}
|
||||
|
||||
func Test_ParseConfigContent_WhitespaceAroundKeysAndValues_Trimmed(t *testing.T) {
|
||||
content := `[myremote]
|
||||
type = s3
|
||||
region = us-west-2 `
|
||||
|
||||
sections, err := parseConfigContent(content)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "s3", sections["myremote"]["type"])
|
||||
assert.Equal(t, "us-west-2", sections["myremote"]["region"])
|
||||
}
|
||||
@@ -34,7 +34,7 @@ export function AuthNavbarComponent() {
|
||||
|
||||
{!IS_CLOUD && (
|
||||
<a
|
||||
className="!text-black hover:opacity-80 dark:!text-gray-200"
|
||||
className="!text-black !underline !decoration-blue-600 !decoration-2 underline-offset-2 hover:opacity-80 dark:!text-gray-200"
|
||||
href="https://databasus.com/cloud"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
|
||||
@@ -232,7 +232,7 @@ export const MainScreenComponent = () => {
|
||||
|
||||
{!IS_CLOUD && (
|
||||
<a
|
||||
className="!text-black hover:opacity-80 dark:!text-gray-200"
|
||||
className="!text-black !underline !decoration-blue-600 !decoration-2 underline-offset-2 hover:opacity-80 dark:!text-gray-200"
|
||||
href="https://databasus.com/cloud"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
|
||||
Reference in New Issue
Block a user