199 lines
4.7 KiB
Go
199 lines
4.7 KiB
Go
package bucket
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
internal_s3utils "git.makerforce.io/photos/photos/internal/s3utils"
|
|
"github.com/minio/minio-go/v6/pkg/s3utils"
|
|
"github.com/minio/minio-go/v6/pkg/signer"
|
|
)
|
|
|
|
type Signer struct {
|
|
accessKey string
|
|
secretKey string
|
|
regionName string
|
|
bucketSecure bool
|
|
expirations Expirations
|
|
}
|
|
|
|
type Expirations struct {
|
|
// Expiration time for list and read in time.Duration
|
|
Read time.Duration
|
|
// Expiration time for write in time.Duration
|
|
Write time.Duration
|
|
}
|
|
|
|
var ErrorExpirationTooLow = errors.New("expiration time too low")
|
|
|
|
func NewSigner(accessKey, secretKey, regionName string, bucketSecure bool, expirations Expirations) (*Signer, error) {
|
|
if expirations.Read == 0 {
|
|
expirations.Read = 30 * time.Minute
|
|
}
|
|
if expirations.Write == 0 {
|
|
expirations.Write = 5 * time.Minute
|
|
}
|
|
if expirations.Read < time.Second || expirations.Write < time.Second {
|
|
return nil, ErrorExpirationTooLow
|
|
}
|
|
signer := &Signer{
|
|
accessKey: accessKey,
|
|
secretKey: secretKey,
|
|
regionName: regionName,
|
|
bucketSecure: bucketSecure,
|
|
expirations: expirations,
|
|
}
|
|
return signer, nil
|
|
}
|
|
|
|
func NewSignerFromEnv() (*Signer, error) {
|
|
accessKey := os.Getenv("MINIO_ACCESS_KEY")
|
|
secretKey := os.Getenv("MINIO_SECRET_KEY")
|
|
regionName := os.Getenv("MINIO_REGION_NAME")
|
|
bucketSecure := os.Getenv("BUCKET_SECURE") == "true"
|
|
expirationRead, _ := strconv.Atoi(os.Getenv("EXPIRATION_READ"))
|
|
expirationWrite, _ := strconv.Atoi(os.Getenv("EXPIRATION_WRITE"))
|
|
expirations := Expirations{Read: time.Duration(expirationRead), Write: time.Duration(expirationWrite)}
|
|
return NewSigner(accessKey, secretKey, regionName, bucketSecure, expirations)
|
|
}
|
|
|
|
func (s *Signer) baseBucket(b Bucket) url.URL {
|
|
url := url.URL{
|
|
Scheme: "http",
|
|
Host: b.String(),
|
|
Path: "/",
|
|
}
|
|
if s.bucketSecure {
|
|
url.Scheme = "https"
|
|
}
|
|
return url
|
|
}
|
|
|
|
func (s *Signer) preSignV4(req http.Request) http.Request {
|
|
domain := os.Getenv("MINIO_DOMAIN")
|
|
|
|
// Validate host
|
|
host, _, err := net.SplitHostPort(req.Host)
|
|
if err != nil {
|
|
host = req.Host
|
|
}
|
|
originalPath := req.URL.Path
|
|
|
|
if len(domain) < 1 {
|
|
// If we are using domains, rewrite the host into path
|
|
req.URL.Path = internal_s3utils.PathFromHost(req.URL.Path, host)
|
|
}
|
|
// If we are using subdomains, sign the direct URL
|
|
signedReq := signer.PreSignV4(
|
|
req,
|
|
s.accessKey, s.secretKey, "",
|
|
"sgp1",
|
|
int64(s.expirations.Read/time.Second),
|
|
)
|
|
signedReq.URL.Path = originalPath
|
|
return *signedReq
|
|
}
|
|
|
|
func listBucketParams(prefix, startAfter string, maxKeys int) url.Values {
|
|
params := make(url.Values)
|
|
params.Set("list-type", "2")
|
|
params.Set("metadata", "true")
|
|
params.Set("encoding-type", "url")
|
|
params.Set("prefix", prefix)
|
|
params.Set("delimiter", "")
|
|
params.Set("max-keys", strconv.Itoa(maxKeys))
|
|
params.Set("start-after", startAfter)
|
|
return params
|
|
}
|
|
|
|
func (s *Signer) GetBucketPhotos(b Bucket, startAfter string, maxKeys int) (string, error) {
|
|
err := b.Validate()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
url := s.baseBucket(b)
|
|
url.Path += "/"
|
|
params := listBucketParams(photoPrefix, startAfter, maxKeys)
|
|
url.RawQuery = s3utils.QueryEncode(params)
|
|
|
|
req, err := http.NewRequest("GET", url.String(), nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
signedReq := s.preSignV4(*req)
|
|
return signedReq.URL.String(), nil
|
|
}
|
|
|
|
func (s *Signer) GetPhoto(b Bucket, p Photo) (string, error) {
|
|
err := b.Validate()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
err = p.Validate()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
url := s.baseBucket(b)
|
|
url.Path += p.Path()
|
|
|
|
req, err := http.NewRequest("GET", url.String(), nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
signedReq := signer.PreSignV4(*req, s.accessKey, s.secretKey, "", "sgp1", int64(s.expirations.Read/time.Second))
|
|
return signedReq.URL.String(), nil
|
|
}
|
|
|
|
func (s *Signer) PutPhoto(b Bucket, p Photo) (string, error) {
|
|
err := b.Validate()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
err = p.Validate()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
url := s.baseBucket(b)
|
|
url.Path += p.Path()
|
|
|
|
req, err := http.NewRequest("PUT", url.String(), nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
signedReq := signer.PreSignV4(*req, s.accessKey, s.secretKey, "", "sgp1", int64(s.expirations.Write/time.Second))
|
|
return signedReq.URL.String(), nil
|
|
}
|
|
|
|
func (s *Signer) GetPreview(b Bucket, p Preview) (string, error) {
|
|
err := b.Validate()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
err = p.Validate()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
url := s.baseBucket(b)
|
|
url.Path += p.Path()
|
|
|
|
req, err := http.NewRequest("GET", url.String(), nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
signedReq := signer.PreSignV4(*req, s.accessKey, s.secretKey, "", "sgp1", int64(s.expirations.Read/time.Second))
|
|
return signedReq.URL.String(), nil
|
|
}
|