201 lines
5.5 KiB
Go
201 lines
5.5 KiB
Go
package uploader
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"embed"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"time"
|
|
|
|
"git.tijl.dev/tijl/tijl.dev-core/internal/config"
|
|
"git.tijl.dev/tijl/tijl.dev-core/internal/queries"
|
|
"git.tijl.dev/tijl/tijl.dev-core/internal/user"
|
|
"git.tijl.dev/tijl/tijl.dev-core/modules/db"
|
|
"git.tijl.dev/tijl/tijl.dev-core/modules/i18n"
|
|
"git.tijl.dev/tijl/tijl.dev-core/modules/web"
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
//go:embed locales/*
|
|
var Embed embed.FS
|
|
|
|
func Setup() {
|
|
i18n.RegisterTranslations(Embed, "locales")
|
|
|
|
var uploadDir string = filepath.Join(config.Config.DataLocation, "./uploader")
|
|
|
|
web.RegisterAppSetupFunc(func(a *fiber.App) {
|
|
a.Get("/app/uploader", func(c *fiber.Ctx) error {
|
|
_, err := user.GetSession(c)
|
|
if err != nil {
|
|
return c.Redirect("/auth?redirect=" + c.Path())
|
|
}
|
|
data := *web.Common(c)
|
|
data["Title"] = "tmp"
|
|
return c.Render("apps/uploader/index", data, "layouts/base")
|
|
})
|
|
a.Get("/app/uploader/:key", func(c *fiber.Ctx) error {
|
|
encryptionKey, err := hex.DecodeString(c.Params("key"))
|
|
if err != nil {
|
|
return c.Next()
|
|
}
|
|
storageKey := hashKey(encryptionKey)
|
|
|
|
row, err := db.Queries.AppUploaderGet(context.TODO(), storageKey)
|
|
if err != nil {
|
|
return c.Next()
|
|
}
|
|
|
|
if row.Expire.UnixMilli() < time.Now().UnixMilli() {
|
|
return c.Next()
|
|
}
|
|
|
|
accessCount, err := db.Queries.AppUploaderAccessCount(context.TODO(), row.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if accessCount == int64(row.MaxVisits) || accessCount > int64(row.MaxVisits) {
|
|
return c.Next()
|
|
}
|
|
|
|
createLog := queries.AppUploaderAccessCreateParams{
|
|
FileID: row.ID,
|
|
IpAddress: c.IP(),
|
|
Agent: string(c.Context().UserAgent()),
|
|
}
|
|
|
|
user, err := user.GetSession(c)
|
|
if err == nil {
|
|
createLog.Uid = sql.NullString{
|
|
Valid: true,
|
|
String: user,
|
|
}
|
|
}
|
|
|
|
db.Queries.AppUploaderAccessCreate(context.TODO(), createLog)
|
|
|
|
encryptedContent, err := os.ReadFile(filepath.Join(uploadDir, row.ID.String()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
encryptedMetadata, err := os.ReadFile(filepath.Join(uploadDir, row.ID.String()+".meta"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
decryptedContent, err := decryptData(encryptedContent, encryptionKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
decryptedMetadata, err := decryptData(encryptedMetadata, encryptionKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var metadata map[string]interface{}
|
|
if err := json.Unmarshal(decryptedMetadata, &metadata); err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString("Failed to parse metadata")
|
|
}
|
|
|
|
c.Set("Content-Disposition", "attachment; filename="+metadata["filename"].(string))
|
|
c.Set("Content-Type", metadata["content_type"].(string))
|
|
|
|
return c.Send(decryptedContent)
|
|
})
|
|
|
|
a.Post("/app/uploader", func(c *fiber.Ctx) error {
|
|
uid, err := user.GetSession(c)
|
|
if err != nil {
|
|
return c.SendStatus(http.StatusUnauthorized)
|
|
}
|
|
expireDays, err := strconv.Atoi(c.FormValue("expire_days"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
maxDownloads, err := strconv.Atoi(c.FormValue("max_downloads"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
file, err := c.FormFile("file")
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).SendString("Failed to read file")
|
|
}
|
|
|
|
src, err := file.Open()
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString("Failed to open file")
|
|
}
|
|
defer src.Close()
|
|
|
|
// Read file content into a byte slice
|
|
fileContent := make([]byte, file.Size)
|
|
if _, err := src.Read(fileContent); err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString("Failed to read file content")
|
|
}
|
|
|
|
// Generate encryption key
|
|
encryptionKey, err := generateEncryptionKey()
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString("Failed to generate encryption key")
|
|
}
|
|
|
|
// Encrypt the file content
|
|
encryptedContent, err := encryptData(fileContent, encryptionKey)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString("Failed to encrypt file content")
|
|
}
|
|
|
|
storageKey := hashKey(encryptionKey)
|
|
|
|
id, err := db.Queries.AppUploaderCreate(context.TODO(), queries.AppUploaderCreateParams{
|
|
Uid: uid,
|
|
FileCrypto: storageKey,
|
|
Expire: time.Now().AddDate(0, 0, expireDays),
|
|
MaxVisits: int32(maxDownloads),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Save encrypted file content
|
|
if err := os.WriteFile(filepath.Join(uploadDir, id.String()), encryptedContent, 0644); err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString("Failed to save encrypted file")
|
|
}
|
|
|
|
metadata := map[string]interface{}{
|
|
"filename": file.Filename,
|
|
"content_type": file.Header.Get("Content-Type"),
|
|
}
|
|
|
|
metadataBytes, err := json.Marshal(metadata)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString("Failed to marshal metadata")
|
|
}
|
|
|
|
encryptedMetadata, err := encryptData(metadataBytes, encryptionKey)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString("Failed to encrypt metadata")
|
|
}
|
|
|
|
if err := os.WriteFile(filepath.Join(uploadDir, id.String()+".meta"), encryptedMetadata, 0644); err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString("Failed to save encrypted metadata")
|
|
}
|
|
|
|
data := *web.Common(c)
|
|
data["Title"] = "tmp"
|
|
data["Key"] = hex.EncodeToString(encryptionKey)
|
|
return c.Render("apps/uploader/uploaded", data, "layouts/base")
|
|
})
|
|
|
|
}, 1000)
|
|
}
|