123 lines
3.7 KiB
Go
123 lines
3.7 KiB
Go
// This file is part of MinIO Console Server
|
|
// Copyright (c) 2024 MinIO, Inc.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package api
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/go-openapi/runtime"
|
|
"github.com/go-openapi/runtime/middleware"
|
|
"github.com/go-openapi/swag"
|
|
"github.com/minio/console/api/operations"
|
|
"github.com/minio/console/api/operations/public"
|
|
xnet "github.com/minio/pkg/v3/net"
|
|
)
|
|
|
|
func registerPublicObjectsHandlers(api *operations.ConsoleAPI) {
|
|
api.PublicDownloadSharedObjectHandler = public.DownloadSharedObjectHandlerFunc(func(params public.DownloadSharedObjectParams) middleware.Responder {
|
|
resp, err := getDownloadPublicObjectResponse(params)
|
|
if err != nil {
|
|
return public.NewDownloadSharedObjectDefault(err.Code).WithPayload(err.APIError)
|
|
}
|
|
return resp
|
|
})
|
|
}
|
|
|
|
func getDownloadPublicObjectResponse(params public.DownloadSharedObjectParams) (middleware.Responder, *CodedAPIError) {
|
|
ctx := params.HTTPRequest.Context()
|
|
|
|
inputURLDecoded, err := checkMinIOStringURL(params.URL)
|
|
if err != nil {
|
|
return nil, ErrorWithContext(ctx, err)
|
|
}
|
|
if inputURLDecoded == nil {
|
|
return nil, ErrorWithContext(ctx, ErrDefault, fmt.Errorf("decoded url is null"))
|
|
}
|
|
|
|
req, err := http.NewRequest(http.MethodGet, *inputURLDecoded, nil)
|
|
if err != nil {
|
|
return nil, ErrorWithContext(ctx, err)
|
|
}
|
|
|
|
clnt := PrepareConsoleHTTPClient(getClientIP(params.HTTPRequest))
|
|
resp, err := clnt.Do(req)
|
|
if err != nil {
|
|
return nil, ErrorWithContext(ctx, err)
|
|
}
|
|
|
|
return middleware.ResponderFunc(func(rw http.ResponseWriter, _ runtime.Producer) {
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
http.Error(rw, resp.Status, resp.StatusCode)
|
|
return
|
|
}
|
|
|
|
urlObj, err := url.Parse(*inputURLDecoded)
|
|
if err != nil {
|
|
http.Error(rw, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Add the filename
|
|
_, objectName := url2BucketAndObject(urlObj)
|
|
escapedName := url.PathEscape(objectName)
|
|
rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", escapedName))
|
|
|
|
_, err = io.Copy(rw, resp.Body)
|
|
if err != nil {
|
|
http.Error(rw, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}), nil
|
|
}
|
|
|
|
// checkMinIOStringURL decodes url and validates is a MinIO url endpoint
|
|
func checkMinIOStringURL(inputURL string) (*string, error) {
|
|
// Validate input URL
|
|
parsedURL, err := xnet.ParseHTTPURL(inputURL)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Ensure incoming url points to MinIO Server
|
|
minIOHost := getMinIOEndpoint()
|
|
if parsedURL.Host != minIOHost {
|
|
return nil, ErrForbidden
|
|
}
|
|
return swag.String(inputURL), nil
|
|
}
|
|
|
|
func url2BucketAndObject(u *url.URL) (bucketName, objectName string) {
|
|
tokens := splitStr(u.Path, "/", 3)
|
|
return tokens[1], tokens[2]
|
|
}
|
|
|
|
// splitStr splits a string into n parts, empty strings are added
|
|
// if we are not able to reach n elements
|
|
func splitStr(path, sep string, n int) []string {
|
|
splits := strings.SplitN(path, sep, n)
|
|
// Add empty strings if we found elements less than nr
|
|
for i := n - len(splits); i > 0; i-- {
|
|
splits = append(splits, "")
|
|
}
|
|
return splits
|
|
}
|