tijl.dev-core/internal/apps/uploader/main.go
tijl 5ad1da76b1
All checks were successful
build / build (push) Successful in 28s
release-tag / release-image (push) Successful in 17m36s
updates
2024-09-04 23:03:23 +02:00

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=/app/uploader", http.StatusUnauthorized)
}
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)
}