diff --git a/lib/handlers/scionic/utils.go b/lib/handlers/scionic/utils.go index 60d949f..1625128 100644 --- a/lib/handlers/scionic/utils.go +++ b/lib/handlers/scionic/utils.go @@ -3,11 +3,15 @@ package scionic import ( "fmt" "io" + "log" + "path/filepath" "slices" "strconv" + "strings" "time" "github.com/fxamacker/cbor/v2" + "github.com/spf13/viper" merkle_dag "github.com/HORNET-Storage/scionic-merkletree/dag" @@ -134,3 +138,79 @@ func WriteMessageToStream[T any](stream types.Stream, message T) error { return nil } + +// Function to check file permission based on RelaySettings, loading settings internally +func IsFilePermitted(filename string) bool { + // Load relay settings + settings, err := LoadRelaySettings() + if err != nil { + log.Fatalf("Failed to load relay settings: %v", err) + return false + } + + // Extract the file extension and make it lowercase for case-insensitive comparison + fileExtension := strings.ToLower(strings.TrimPrefix(filepath.Ext(filename), ".")) + + // Check mode setting + if settings.Mode == "smart" { + // Smart mode: Check if the file extension is explicitly allowed + + if settings.IsPhotosActive && contains(settings.PhotoTypes, fileExtension) { + return true + } + if settings.IsVideosActive && contains(settings.VideoTypes, fileExtension) { + return true + } + if settings.IsAudioActive && contains(settings.AudioTypes, fileExtension) { + return true + } + + // Miscellaneous case: If the file type is not in the known lists but also not blocked, allow it + if !contains(settings.Photos, fileExtension) && + !contains(settings.Videos, fileExtension) && + !contains(settings.Audio, fileExtension) { + return true // Permit miscellaneous files in smart mode if they are not explicitly blocked + } + + return false // File type is not permitted in "smart" mode if it doesn't match any active or miscellaneous type + } else if settings.Mode == "unlimited" { + // Unlimited mode: Allow everything except explicitly blocked types + + if contains(settings.Photos, fileExtension) || contains(settings.Videos, fileExtension) || contains(settings.Audio, fileExtension) { + return false // File type is explicitly blocked in "unlimited" mode + } + + return true // File type is permitted in "unlimited" mode + } + + return false // Default to false if the mode is not recognized +} + +// Helper function to check if a slice contains a given string +func contains(list []string, item string) bool { + for _, element := range list { + if element == item { + return true + } + } + return false +} + +func LoadRelaySettings() (*types.RelaySettings, error) { + viper.SetConfigName("config") // Name of config file (without extension) + viper.SetConfigType("json") // Type of the config file + viper.AddConfigPath(".") // Path to look for the config file in + + if err := viper.ReadInConfig(); err != nil { + log.Fatalf("Error reading config file: %s", err) + return nil, err + } + + var settings types.RelaySettings + if err := viper.UnmarshalKey("relay_settings", &settings); err != nil { + log.Fatalf("Error unmarshaling config into struct: %s (nostr/utils)", err) + return nil, err + } + + return &settings, nil +} diff --git a/lib/stores/stats_stores/statistics_store_gorm.go b/lib/stores/stats_stores/statistics_store_gorm.go index aa3bd8d..cc39d2c 100644 --- a/lib/stores/stats_stores/statistics_store_gorm.go +++ b/lib/stores/stats_stores/statistics_store_gorm.go @@ -479,7 +479,7 @@ func (store *GormStatisticsStore) FetchProfilesTimeSeriesData(startDate, endDate COUNT(CASE WHEN dht_key THEN 1 ELSE NULL END) as dht_key, COUNT(CASE WHEN lightning_addr AND dht_key THEN 1 ELSE NULL END) as lightning_and_dht FROM user_profiles - WHERE strftime('%Y-%m', timestamp) >= ? AND strftime('%Y-%m', timestamp) < ? + WHERE strftime('%Y-%m', timestamp) >= ? AND strftime('%Y-%m', timestamp) <= ? GROUP BY month ORDER BY month ASC; `, startDate, endDate).Scan(&data).Error diff --git a/lib/types.go b/lib/types.go index b092bad..a7e9148 100644 --- a/lib/types.go +++ b/lib/types.go @@ -169,23 +169,27 @@ type BitcoinRate struct { } type RelaySettings struct { - Mode string `json:"mode"` - Protocol []string `json:"protocol"` - Chunked []string `json:"chunked"` - Chunksize string `json:"chunksize"` - MaxFileSize int `json:"maxFileSize"` - MaxFileSizeUnit string `json:"maxFileSizeUnit"` - Kinds []string `json:"kinds"` - DynamicKinds []string `json:"dynamicKinds"` - Photos []string `json:"photos"` - Videos []string `json:"videos"` - GitNestr []string `json:"gitNestr"` - Audio []string `json:"audio"` - IsKindsActive bool `json:"isKindsActive"` - IsPhotosActive bool `json:"isPhotosActive"` - IsVideosActive bool `json:"isVideosActive"` - IsGitNestrActive bool `json:"isGitNestrActive"` - IsAudioActive bool `json:"isAudioActive"` + Mode string `json:"mode"` + Protocol []string `json:"protocol"` + Kinds []string `json:"kinds"` + DynamicKinds []string `json:"dynamicKinds"` + Photos []string `json:"photos"` + Videos []string `json:"videos"` + GitNestr []string `json:"gitNestr"` + Audio []string `json:"audio"` + IsKindsActive bool `json:"isKindsActive"` + IsPhotosActive bool `json:"isPhotosActive"` + IsVideosActive bool `json:"isVideosActive"` + IsGitNestrActive bool `json:"isGitNestrActive"` + IsAudioActive bool `json:"isAudioActive"` + IsFileStorageActive bool `json:"isFileStorageActive"` + AppBuckets []string `json:"appBuckets"` + DynamicAppBuckets []string `json:"dynamicAppBuckets"` + + // New fields for the file type lists + PhotoTypes []string `json:"photoTypes"` + VideoTypes []string `json:"videoTypes"` + AudioTypes []string `json:"audioTypes"` } type TimeSeriesData struct { diff --git a/lib/web/handler_relay_settings.go b/lib/web/handler_relay_settings.go index 1b6d215..a6fdf60 100644 --- a/lib/web/handler_relay_settings.go +++ b/lib/web/handler_relay_settings.go @@ -17,8 +17,6 @@ func updateRelaySettings(c *fiber.Ctx) error { return c.Status(400).SendString(err.Error()) } - log.Println("Received data:", data) - relaySettingsData, ok := data["relay_settings"] if !ok { log.Println("Relay settings data not provided") @@ -32,46 +30,77 @@ func updateRelaySettings(c *fiber.Ctx) error { return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error") } - log.Println("Received relay settings JSON:", string(relaySettingsJSON)) - if err := json.Unmarshal(relaySettingsJSON, &relaySettings); err != nil { log.Println("Error unmarshaling relay settings:", err) return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error") } - // Check boolean flags and set corresponding arrays to empty if false - if !relaySettings.IsKindsActive { - relaySettings.Kinds = []string{} - relaySettings.DynamicKinds = []string{} + // Apply logic for boolean flags + applyBooleanFlags(&relaySettings) + + // Update Viper configuration + if err := updateViperConfig(relaySettings); err != nil { + log.Printf("Error updating config: %s", err) + return c.Status(fiber.StatusInternalServerError).SendString("Failed to update settings") + } + + log.Println("Stored relay settings:", relaySettings) + + return c.SendStatus(fiber.StatusOK) +} + +func applyBooleanFlags(settings *types.RelaySettings) { + if !settings.IsKindsActive { + settings.Kinds = []string{} + settings.DynamicKinds = []string{} } - if !relaySettings.IsPhotosActive { - relaySettings.Photos = []string{} + if !settings.IsPhotosActive { + settings.Photos = []string{} } - if !relaySettings.IsVideosActive { - relaySettings.Videos = []string{} + if !settings.IsVideosActive { + settings.Videos = []string{} } - if !relaySettings.IsGitNestrActive { - relaySettings.GitNestr = []string{} + if !settings.IsGitNestrActive { + settings.GitNestr = []string{} } - if !relaySettings.IsAudioActive { - relaySettings.Audio = []string{} + if !settings.IsAudioActive { + settings.Audio = []string{} } - if relaySettings.Mode == "smart" { - relaySettings.DynamicKinds = []string{} + + if settings.AppBuckets == nil { + settings.AppBuckets = []string{} } - // Store in Viper - viper.Set("relay_settings", relaySettings) + log.Println("Dynamic app buckets: ", settings.DynamicAppBuckets) - // Save the changes to the configuration file - if err := viper.WriteConfig(); err != nil { - log.Printf("Error writing config: %s", err) - return c.Status(fiber.StatusInternalServerError).SendString("Failed to update settings") + if settings.DynamicAppBuckets == nil { + settings.DynamicAppBuckets = []string{} } - log.Println("Stored relay settings:", relaySettings) + if settings.Mode == "smart" { + settings.DynamicKinds = []string{} + } +} - return c.SendStatus(fiber.StatusOK) +func updateViperConfig(settings types.RelaySettings) error { + viper.Set("relay_settings.Mode", settings.Mode) + viper.Set("relay_settings.IsKindsActive", settings.IsKindsActive) + viper.Set("relay_settings.IsPhotosActive", settings.IsPhotosActive) + viper.Set("relay_settings.IsVideosActive", settings.IsVideosActive) + viper.Set("relay_settings.IsGitNestrActive", settings.IsGitNestrActive) + viper.Set("relay_settings.IsAudioActive", settings.IsAudioActive) + viper.Set("relay_settings.IsFileStorageActive", settings.IsFileStorageActive) + viper.Set("relay_settings.Kinds", settings.Kinds) + viper.Set("relay_settings.DynamicKinds", settings.DynamicKinds) + viper.Set("relay_settings.Photos", settings.Photos) + viper.Set("relay_settings.Videos", settings.Videos) + viper.Set("relay_settings.GitNestr", settings.GitNestr) + viper.Set("relay_settings.Audio", settings.Audio) + viper.Set("relay_settings.Protocol", settings.Protocol) + viper.Set("relay_settings.AppBuckets", settings.AppBuckets) + viper.Set("relay_settings.DynamicAppBuckets", settings.DynamicAppBuckets) + + return viper.WriteConfig() } func getRelaySettings(c *fiber.Ctx) error { @@ -86,12 +115,16 @@ func getRelaySettings(c *fiber.Ctx) error { return c.Status(fiber.StatusInternalServerError).SendString("Failed to fetch settings") } - // Ensure Protocol and Chunked are arrays if relaySettings.Protocol == nil { relaySettings.Protocol = []string{} } - if relaySettings.Chunked == nil { - relaySettings.Chunked = []string{} + + if relaySettings.AppBuckets == nil { + relaySettings.AppBuckets = []string{} + } + + if relaySettings.DynamicAppBuckets == nil { + relaySettings.DynamicAppBuckets = []string{} } log.Println("Fetched relay settings:", relaySettings) diff --git a/services/server/port/main.go b/services/server/port/main.go index ef0c0cb..a046d45 100644 --- a/services/server/port/main.go +++ b/services/server/port/main.go @@ -88,22 +88,37 @@ func init() { // Set default relay settings (including Mode) viper.SetDefault("relay_settings", map[string]interface{}{ - "Mode": "smart", // Default mode to "smart" - "IsKindsActive": false, // Default to false for activity flags - "IsPhotosActive": false, - "IsVideosActive": false, - "IsGitNestrActive": false, - "IsAudioActive": false, - "Kinds": []string{}, // Default empty arrays for list fields - "DynamicKinds": []string{}, - "Photos": []string{}, - "Videos": []string{}, - "GitNestr": []string{}, - "Audio": []string{}, - "Protocol": []string{}, // Default empty Protocol and Chunked lists - "Chunked": []string{}, + "Mode": "smart", // Default mode to "smart" + "IsKindsActive": false, // Default to false for activity flags + "IsPhotosActive": false, + "IsVideosActive": false, + "IsGitNestrActive": false, + "IsAudioActive": false, + "isFileStorageActive": false, + "Kinds": []string{}, // Default empty arrays for list fields + "DynamicKinds": []string{}, + "Photos": []string{}, + "Videos": []string{}, + "GitNestr": []string{}, + "Audio": []string{}, + "Protocol": []string{}, // Default empty Protocol and Chunked lists + "AppBuckets": []string{}, + "DynamicAppBuckets": []string{}, + + // New default file type lists for Photos, Videos, and Audio + "PhotoFileTypes": []string{ + "jpeg", "jpg", "png", "gif", "bmp", "tiff", "raw", "svg", + "eps", "psd", "ai", "pdf", "webp", + }, + "VideoFileTypes": []string{ + "avi", "mp4", "mov", "wmv", "mkv", "flv", "mpeg", + "3gp", "webm", "ogg", + }, + "AudioFileTypes": []string{ + "mp3", "wav", "ogg", "flac", "aac", "wma", "m4a", + "opus", "m4b", "midi", "mp4", "webm", "3gp", + }, }) - // Generate a random wallet API key apiKey, err := generateRandomAPIKey() if err != nil {