diff --git a/internal/apps/flags/handlers.go b/internal/apps/flags/handlers.go index d98c534..2f7c430 100644 --- a/internal/apps/flags/handlers.go +++ b/internal/apps/flags/handlers.go @@ -169,7 +169,7 @@ func questionHandler(c *fiber.Ctx, newGame NullableUUID, prevError NullableStrin data["Errors"] = gameSession.QuestionsErrors data["PreviousError"] = prevError.String data["ShortcutKeys"] = []string{"d", "f", "h", "j", "k"} - return c.Render("apps/flags/question", data, "layouts/base") + return web.Render(c, "apps/flags/question", data, "layouts/base") } func sharedGameHandler(c *fiber.Ctx) error { @@ -242,7 +242,7 @@ func createSharedGameData(c *fiber.Ctx, tags []string, maxQuestions int, seconds data := *web.Common(c) data["Title"] = "tmp" data["ShareKey"] = shareKey - return c.Render("apps/flags/shared", data, "layouts/base") + return web.Render(c, "apps/flags/shared", data, "layouts/base") } func setupGame(c *fiber.Ctx, tags []string, maxQuestions int, seconds int, gameSeed NullableUUID) error { @@ -291,7 +291,7 @@ func gameEndHandler(c *fiber.Ctx) error { data := *web.Common(c) data["Title"] = "tmp" data["Errors"] = gameSession.QuestionsErrors - return c.Render("apps/flags/end", data, "layouts/base") + return web.Render(c, "apps/flags/end", data, "layouts/base") } @@ -304,5 +304,5 @@ func gameStartHandler(c *fiber.Ctx) error { data := *web.Common(c) data["Title"] = "Flags Game | tijl.dev" data["SupportedTags"] = supportedTags - return c.Render("apps/flags/start", data, "layouts/base") + return web.Render(c, "apps/flags/start", data, "layouts/base") } diff --git a/internal/apps/flags/locales/en.json b/internal/apps/flags/locales/en.json index 0478ece..8f06bcb 100644 --- a/internal/apps/flags/locales/en.json +++ b/internal/apps/flags/locales/en.json @@ -5,6 +5,8 @@ "max_questions": "Max Questions", "time_limit": "Time limit (seconds)", "share_game": "Save", + "deselect_all": "Deselect all", + "select_all": "Select all", "Asia": "Asia", "MiddleEast": "Middle East", "SoutheastAsia": "Southeast Asia", diff --git a/internal/apps/flags/locales/nl.json b/internal/apps/flags/locales/nl.json index 468ffc0..59a70ea 100644 --- a/internal/apps/flags/locales/nl.json +++ b/internal/apps/flags/locales/nl.json @@ -5,6 +5,8 @@ "time_limit": "Tijdlimit (seconden)", "max_questions": "Maximaal aantal vragen", "share_game": "Opslaan", + "deselect_all": "Alles deselecteren", + "select_all": "Alles selecteren", "Asia": "Aziƫ", "MiddleEast": "Midden-Oosten", "SoutheastAsia": "Zuidoost-Aziƫ", diff --git a/internal/apps/uploader/main.go b/internal/apps/uploader/main.go index a6c7f3a..05b4aa1 100644 --- a/internal/apps/uploader/main.go +++ b/internal/apps/uploader/main.go @@ -1,200 +1,200 @@ package uploader import ( - "context" - "database/sql" - "embed" - "encoding/hex" - "encoding/json" - "net/http" - "os" - "path/filepath" - "strconv" - "time" + "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" + "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") + i18n.RegisterTranslations(Embed, "locales") - var uploadDir string = filepath.Join(config.Config.DataLocation, "./uploader") + 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) - 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() + } - row, err := db.Queries.AppUploaderGet(context.TODO(), storageKey) - if err != nil { - return c.Next() - } + if row.Expire.UnixMilli() < time.Now().UnixMilli() { + 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 + } - 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() + } - 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()), + } - 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, + } + } - user, err := user.GetSession(c) - if err == nil { - createLog.Uid = sql.NullString{ - Valid: true, - String: user, - } - } + db.Queries.AppUploaderAccessCreate(context.TODO(), createLog) - db.Queries.AppUploaderAccessCreate(context.TODO(), createLog) + encryptedContent, err := os.ReadFile(filepath.Join(uploadDir, row.ID.String())) + if err != nil { + return err + } - 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 + } - 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 + } - decryptedContent, err := decryptData(encryptedContent, encryptionKey) - if err != nil { - return err - } + decryptedMetadata, err := decryptData(encryptedMetadata, 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") + } - 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)) - c.Set("Content-Disposition", "attachment; filename="+metadata["filename"].(string)) - c.Set("Content-Type", metadata["content_type"].(string)) + return c.Send(decryptedContent) + }) - 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") + } - a.Post("/app/uploader", func(c *fiber.Ctx) error { - uid, err := user.GetSession(c) - if err != nil { - return c.SendStatus(http.StatusUnauthorized) - } + src, err := file.Open() + if err != nil { + return c.Status(fiber.StatusInternalServerError).SendString("Failed to open file") + } + defer src.Close() - 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} + // 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") + } - file, err := c.FormFile("file") - if err != nil { - return c.Status(fiber.StatusBadRequest).SendString("Failed to read file") - } + // Generate encryption key + encryptionKey, err := generateEncryptionKey() + if err != nil { + return c.Status(fiber.StatusInternalServerError).SendString("Failed to generate encryption key") + } - src, err := file.Open() - if err != nil { - return c.Status(fiber.StatusInternalServerError).SendString("Failed to open file") - } - defer src.Close() + // Encrypt the file content + encryptedContent, err := encryptData(fileContent, encryptionKey) + if err != nil { + return c.Status(fiber.StatusInternalServerError).SendString("Failed to encrypt file content") + } - // 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") - } + storageKey := hashKey(encryptionKey) - // Generate encryption key - encryptionKey, err := generateEncryptionKey() - if err != nil { - return c.Status(fiber.StatusInternalServerError).SendString("Failed to generate encryption key") - } + 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 + } - // Encrypt the file content - encryptedContent, err := encryptData(fileContent, encryptionKey) - if err != nil { - return c.Status(fiber.StatusInternalServerError).SendString("Failed to encrypt file content") - } + // 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") + } - storageKey := hashKey(encryptionKey) + metadata := map[string]interface{}{ + "filename": file.Filename, + "content_type": file.Header.Get("Content-Type"), + } - 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 - } + metadataBytes, err := json.Marshal(metadata) + if err != nil { + return c.Status(fiber.StatusInternalServerError).SendString("Failed to marshal metadata") + } - // 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") - } + encryptedMetadata, err := encryptData(metadataBytes, encryptionKey) + if err != nil { + return c.Status(fiber.StatusInternalServerError).SendString("Failed to encrypt metadata") + } - metadata := map[string]interface{}{ - "filename": file.Filename, - "content_type": file.Header.Get("Content-Type"), - } + 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") + } - metadataBytes, err := json.Marshal(metadata) - if err != nil { - return c.Status(fiber.StatusInternalServerError).SendString("Failed to marshal metadata") - } + data := *web.Common(c) + data["Title"] = "tmp" + data["Key"] = hex.EncodeToString(encryptionKey) + return c.Render("apps/uploader/uploaded", data, "layouts/base") + }) - 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) + }, 1000) } diff --git a/internal/handlers/services.go b/internal/handlers/services.go index 83eaded..5d8d97e 100644 --- a/internal/handlers/services.go +++ b/internal/handlers/services.go @@ -9,6 +9,7 @@ import ( type Service struct { Name string + Slug string Description string Url string InfoUrl string @@ -16,38 +17,46 @@ type Service struct { Scale float64 } -var services = map[string]Service{ - "immich": { +var services = []Service{ + { Name: "Immich", + Slug: "immich", Description: "...", Url: "https://fotos.tijl.dev/photos", InfoUrl: "https://immich.app", Color: "white", Scale: 0, }, - "element": { + { Name: "Element", + Slug: "element", Description: "...", Url: "https://element.tijl.dev", InfoUrl: "https://matrix.org", Color: "#0DBD8B", Scale: 0.1, }, - "nextcloud": { + { Name: "Nextcloud", + Slug: "nextcloud", Description: "...", Url: "https://cloud.tijl.dev", InfoUrl: "https://nextcloud.com", Color: "#00679e", Scale: -0.2, }, + { + Name: "Gitea", + Slug: "gitea", + Description: "...", + Url: "https://git.tijl.dev", + InfoUrl: "https://about.gitea.com", + Color: "white", + Scale: -0.2, + }, } func servicesHandler(c *fiber.Ctx) error { - _, err := user.GetSession(c) - if err != nil { - return c.Next() - } data := *web.Common(c) data["Title"] = i18n.Translate(c, "services") data["Services"] = services @@ -59,9 +68,11 @@ func serviceHandler(c *fiber.Ctx) error { if err != nil { return c.Next() } - if services[c.Params("service")].Url != "" { - return c.Redirect(services[c.Params("service")].Url) - } + /* + if services[c.Params("service")].Url != "" { + return c.Redirect(services[c.Params("service")].Url) + } + */ return c.Next() } @@ -70,8 +81,10 @@ func serviceInfoHandler(c *fiber.Ctx) error { if err != nil { return c.Next() } - if services[c.Params("service")].Url != "" { - return c.Redirect(services[c.Params("service")].InfoUrl) - } + /* + if services[c.Params("service")].Url != "" { + return c.Redirect(services[c.Params("service")].InfoUrl) + } + */ return c.Next() } diff --git a/internal/service/main.go b/internal/service/main.go index 523738c..edf4920 100644 --- a/internal/service/main.go +++ b/internal/service/main.go @@ -70,6 +70,7 @@ func Listen() { app := fiber.New(fiber.Config{ Views: engine, DisableStartupMessage: true, + BodyLimit: 4 * 1024 * 1024 * 1024, }) app.Use(fiberzerolog.New(fiberzerolog.Config{ Logger: &log.Logger, diff --git a/modules/web/render.go b/modules/web/render.go new file mode 100644 index 0000000..0d7fd29 --- /dev/null +++ b/modules/web/render.go @@ -0,0 +1,10 @@ +package web + +import "github.com/gofiber/fiber/v2" + +func Render(c *fiber.Ctx, template string, data fiber.Map, layout string) error { + if c.Get("HX-Request") != "" && c.Get("HX-Target") == "main-content" { + return c.Render(template, data) + } + return c.Render(template, data, layout) +} diff --git a/web/views/apps/flags/end.html b/web/views/apps/flags/end.html index 3d2d29f..6f30c92 100644 --- a/web/views/apps/flags/end.html +++ b/web/views/apps/flags/end.html @@ -6,7 +6,7 @@
game is over
-
+
diff --git a/web/views/apps/flags/question.html b/web/views/apps/flags/question.html index 41ac312..b1a8bb1 100644 --- a/web/views/apps/flags/question.html +++ b/web/views/apps/flags/question.html @@ -18,7 +18,7 @@ {{.Flag}} -
+
{{range $index, $answer := .Answers}}
@@ -34,7 +34,7 @@ {{end}}
- + diff --git a/web/views/apps/flags/shared.html b/web/views/apps/flags/shared.html index 9de8846..deb9048 100644 --- a/web/views/apps/flags/shared.html +++ b/web/views/apps/flags/shared.html @@ -1,7 +1,7 @@
{{.ShareKey}}
-
+
diff --git a/web/views/apps/flags/start.html b/web/views/apps/flags/start.html index 67f5a30..7a8ae5c 100644 --- a/web/views/apps/flags/start.html +++ b/web/views/apps/flags/start.html @@ -1,4 +1,4 @@ -
+
diff --git a/web/views/apps/uploader/index.html b/web/views/apps/uploader/index.html index f357aae..c624b86 100644 --- a/web/views/apps/uploader/index.html +++ b/web/views/apps/uploader/index.html @@ -1,4 +1,4 @@ -
+