diff --git a/config.sample.toml b/config.sample.toml index 31f8ac483efc0dc613d5e122334f93f0bf3cc37e..472fea3f14c49c5722019405fbeba9bf1a1ca020 100644 --- a/config.sample.toml +++ b/config.sample.toml @@ -20,3 +20,12 @@ tempLocation = "/var/data/buckets/_temp" storageLocation = "/var/data/buckets/data" quarantineLocation = "/var/data/buckets/_quarantine" +[fileWebhook] +# URL will receive POST with JSON body containing only a `sha256_hash` key for each NEW file +enable = false +url = "http://localhost:3100/scan" + +[ratelimiter] +enable = true +redisURL = "redis://localhost:6379/0" + diff --git a/lib/routes/uploadpomf.go b/lib/routes/uploadpomf.go index e5aaac4f9b99e758dc0e61eb01291662ce835ed6..8140feac33ea024bb18c01aca3d3d249758a98b4 100644 --- a/lib/routes/uploadpomf.go +++ b/lib/routes/uploadpomf.go @@ -1,9 +1,11 @@ package routes import ( + "bytes" "crypto/md5" "crypto/sha256" "encoding/hex" + "encoding/json" "io" "net/http" "os" @@ -68,6 +70,11 @@ type fullResponse struct { Files []fileResponse `json:"files"` } +// fileWebhookRequest represents the data submitted in a file webhook request. +type fileWebhookRequest struct { + SHA256Hash string `json:"sha256_hash"` +} + // UploadPomf handles Pomf multipart/form-data upload requests. func UploadPomf(associateObjectsWithUser bool) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -270,6 +277,27 @@ func UploadPomf(associateObjectsWithUser bool) func(http.ResponseWriter, *http.R Name: file.Filename, }) } + + // Fire fileWebhook in goroutine + if viper.GetBool("fileWebhook.enable") { + go func() { + reqData := fileWebhookRequest{hex.EncodeToString(sha256Bytes)} + m, err := json.Marshal(reqData) + if err != nil { + log.Warn().Err(err).Msg("failed to marshal reqData in fileWebhook goroutine") + return + } + buf := bytes.NewBuffer(m) + resp, err := http.Post(viper.GetString("fileWebhook.url"), "application/json", buf) + if err != nil { + log.Warn().Err(err).Msg("failed to send request in fileWebhook goroutine") + return + } + if resp.StatusCode < 200 || resp.StatusCode > 399 { + log.Warn().Msgf("got unexpected status code from fileWebhook url: %v", resp.StatusCode) + } + }() + } } else { // Delete temporary file err = os.Remove(tempPath) diff --git a/main.go b/main.go index 066e3c5de6bde3a58b80ba9b23b4f85fd371970c..65d84f1e1867f61649dcdff36ea9417114f1c710 100644 --- a/main.go +++ b/main.go @@ -73,6 +73,7 @@ func init() { viper.SetDefault("ratelimiter.listObjectsCost", ratelimiter.ListObjectsCost) viper.SetDefault("ratelimiter.objectCost", ratelimiter.ObjectCost) viper.SetDefault("ratelimiter.deleteObjectCost", ratelimiter.DeleteObjectCost) + viper.SetDefault("fileWebhook.enable", false) // Load configuration file viper.SetConfigType("toml") @@ -138,6 +139,9 @@ func init() { if viper.GetBool("ratelimiter.enable") && viper.GetString("ratelimiter.redisURL") == "" { log.Fatal().Msg("Configuration: ratelimiter.redisURL is required when ratelimiter is enabled") } + if viper.GetBool("fileWebhook.enable") && viper.GetString("fileWebhook.url") == "" { + log.Fatal().Msg("Configuration: fileWebhook.url is required when fileWebhook is enabled") + } } func main() {