package main import ( "crypto/tls" "embed" "fmt" "io/fs" "log" "net/http" "os" "time" "github.com/cloudlena/adapters/logging" "github.com/cloudlena/s3manager/internal/app/s3manager" "github.com/gorilla/mux" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "github.com/spf13/viper" ) const serverTimeout = 5 * time.Second //go:embed web/template var templateFS embed.FS //go:embed web/static var staticFS embed.FS func main() { var accessKeyID, secretAccessKey, iamEndpoint string viper.AutomaticEnv() viper.SetDefault("ENDPOINT", "s3.amazonaws.com") endpoint := viper.GetString("ENDPOINT") useIam := viper.GetBool("USE_IAM") if useIam { iamEndpoint = viper.GetString("IAM_ENDPOINT") } else { accessKeyID = viper.GetString("ACCESS_KEY_ID") if len(accessKeyID) == 0 { log.Fatal("please provide ACCESS_KEY_ID") } secretAccessKey = viper.GetString("SECRET_ACCESS_KEY") if len(secretAccessKey) == 0 { log.Fatal("please provide SECRET_ACCESS_KEY") } } region := viper.GetString("REGION") viper.SetDefault("ALLOW_DELETE", true) allowDelete := viper.GetBool("ALLOW_DELETE") viper.SetDefault("FORCE_DOWNLOAD", true) forceDownload := viper.GetBool("FORCE_DOWNLOAD") viper.SetDefault("USE_SSL", true) useSSL := viper.GetBool("USE_SSL") viper.SetDefault("SKIP_SSL_VERIFICATION", false) skipSSLVerification := viper.GetBool("SKIP_SSL_VERIFICATION") listRecursive := viper.GetBool("LIST_RECURSIVE") viper.SetDefault("PORT", "8080") port := viper.GetString("PORT") viper.SetDefault("SSE_TYPE", "") viper.SetDefault("SSE_KEY", "") sseType := s3manager.SSEType{Type: viper.GetString("SSE_TYPE"), Key: viper.GetString("SSE_KEY")} // Set up templates templates, err := fs.Sub(templateFS, "web/template") if err != nil { log.Fatal(err) } // Set up statics statics, err := fs.Sub(staticFS, "web/static") if err != nil { log.Fatal(err) } // Set up S3 client opts := &minio.Options{ Secure: useSSL, } if useIam { opts.Creds = credentials.NewIAM(iamEndpoint) } else { opts.Creds = credentials.NewStaticV4(accessKeyID, secretAccessKey, "") } if region != "" { opts.Region = region } if useSSL && skipSSLVerification { opts.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} //nolint:gosec } s3, err := minio.New(endpoint, opts) if err != nil { log.Fatalln(fmt.Errorf("error creating s3 client: %w", err)) } // Set up router r := mux.NewRouter() r.Handle("/", http.RedirectHandler("/buckets", http.StatusPermanentRedirect)).Methods(http.MethodGet) r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.FS(statics)))).Methods(http.MethodGet) r.Handle("/buckets", s3manager.HandleBucketsView(s3, templates, allowDelete)).Methods(http.MethodGet) r.Handle("/buckets/{bucketName}", s3manager.HandleBucketView(s3, templates, allowDelete, listRecursive)).Methods(http.MethodGet) r.Handle("/api/buckets", s3manager.HandleCreateBucket(s3)).Methods(http.MethodPost) if allowDelete { r.Handle("/api/buckets/{bucketName}", s3manager.HandleDeleteBucket(s3)).Methods(http.MethodDelete) } r.Handle("/api/buckets/{bucketName}/objects", s3manager.HandleCreateObject(s3, sseType)).Methods(http.MethodPost) r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleGetObject(s3, forceDownload)).Methods(http.MethodGet) if allowDelete { r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleDeleteObject(s3)).Methods(http.MethodDelete) } lr := logging.Handler(os.Stdout)(r) srv := &http.Server{ Addr: ":" + port, Handler: lr, ReadTimeout: serverTimeout, WriteTimeout: serverTimeout, } log.Fatal(srv.ListenAndServe()) }