79 lines
1.8 KiB
Go
79 lines
1.8 KiB
Go
package storage
|
|
|
|
import (
|
|
"mime"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mlogclub/simple/common/strs"
|
|
)
|
|
|
|
func GenerateStorageKey(info UploadInfo) (assetID string, storageKey string) {
|
|
assetID = strs.UUID()
|
|
var (
|
|
env = currentAssetEnv()
|
|
prefix = normalizeAssetPrefix(info.Prefix)
|
|
datePath = time.Now().Format("2006/01/02")
|
|
ext = getExt(info)
|
|
)
|
|
|
|
storageKey = filepath.Join(
|
|
env,
|
|
prefix,
|
|
datePath,
|
|
assetID+ext,
|
|
)
|
|
storageKey = strings.TrimLeft(filepath.ToSlash(storageKey), "/")
|
|
return
|
|
}
|
|
|
|
func getExt(info UploadInfo) string {
|
|
ext := normalizeExt(filepath.Ext(strings.TrimSpace(info.Filename)))
|
|
if ext == "" || IsBlockedExtension(ext) {
|
|
ext = normalizeExt(getExtByMimeType(info.MimeType))
|
|
}
|
|
if ext == "" || IsBlockedExtension(ext) {
|
|
// The stored extension decides the Content-Type this origin serves. A
|
|
// browser-active extension must never reach the key, and no extension at
|
|
// all would leave the server to sniff the payload and announce whatever
|
|
// it finds, so both cases settle on an inert binary type.
|
|
return ".bin"
|
|
}
|
|
return ext
|
|
}
|
|
|
|
func getExtByMimeType(mimeType string) string {
|
|
if strs.IsBlank(mimeType) {
|
|
return ""
|
|
}
|
|
|
|
mediaType, _, _ := mime.ParseMediaType(mimeType)
|
|
if mediaType == "" {
|
|
return ""
|
|
}
|
|
|
|
return safeExtensionForMediaType(mediaType)
|
|
}
|
|
|
|
func normalizeAssetPrefix(prefix string) string {
|
|
prefix = strings.TrimSpace(prefix)
|
|
prefix = strings.Trim(prefix, "/")
|
|
prefix = strings.ReplaceAll(prefix, "..", "")
|
|
prefix = filepath.ToSlash(prefix)
|
|
for strings.Contains(prefix, "//") {
|
|
prefix = strings.ReplaceAll(prefix, "//", "/")
|
|
}
|
|
return strings.Trim(prefix, "/")
|
|
}
|
|
|
|
func currentAssetEnv() string {
|
|
for _, key := range []string{"APP_ENV", "GO_ENV"} {
|
|
if value := strings.TrimSpace(os.Getenv(key)); value != "" {
|
|
return value
|
|
}
|
|
}
|
|
return ""
|
|
}
|