From 0f23e11414f8a9cf90d0009ec2dc73fd7b8e8b84 Mon Sep 17 00:00:00 2001
From: Vikas
Date: Sun, 2 Jun 2024 19:42:26 +0530
Subject: [PATCH] Add ability to configure the application; reset db; better
logging
---
.gitignore | 1 +
config/config.go | 8 ++++++++
db/db.go | 17 ++++-------------
db/utils.go | 36 ++++++++++++++++++++++++++++++++++++
main.go | 15 +++++++++++++--
views/base.templ | 8 +++++---
views/base_templ.go | 32 ++++++++++++++++++++++++++++++--
views/decrypt.templ | 2 +-
views/decrypt_templ.go | 4 ++--
views/index.templ | 4 ++--
views/index_templ.go | 2 +-
web/handlers.go | 12 ++++++++++--
12 files changed, 113 insertions(+), 28 deletions(-)
create mode 100644 config/config.go
create mode 100644 db/utils.go
diff --git a/.gitignore b/.gitignore
index 079f556..8d65f16 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@
*.dll
*.so
*.dylib
+bin/
# Test binary, built with `go test -c`
*.test
diff --git a/config/config.go b/config/config.go
new file mode 100644
index 0000000..ed7d686
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,8 @@
+package config
+
+var (
+ ServerAddr = ":8080"
+ AppName = "PastePass"
+ DBPath = "pastes.boltdb"
+ ResetDB = false
+)
diff --git a/db/db.go b/db/db.go
index 2867d94..53a8540 100644
--- a/db/db.go
+++ b/db/db.go
@@ -3,7 +3,7 @@ package db
import (
"errors"
"fmt"
- "log"
+ "log/slog"
"time"
"encoding/json"
@@ -26,15 +26,6 @@ type DB struct {
boltDB *bolt.DB
}
-func NewDB(name string) (*DB, error) {
- boltDB, err := bolt.Open(name, 0600, &bolt.Options{Timeout: 1 * time.Second})
- if err != nil {
- return nil, err
- }
-
- return &DB{boltDB: boltDB}, nil
-}
-
func (d *DB) Close() error {
return d.boltDB.Close()
}
@@ -106,7 +97,7 @@ func (d *DB) Get(id string) (*Paste, error) {
func (d *DB) Decrypt(id string, key string) (string, error) {
// delete paste if expired
- if _, err := d.Get(id); err == ErrPasteExpired {
+ if _, err := d.Get(id); errors.Is(err, ErrPasteExpired) {
return "", d.Delete(id)
}
@@ -186,7 +177,7 @@ func (d *DB) DeleteExpired() error {
for _, id := range expiredPastes {
if err := d.Delete(id); err != nil {
- log.Println(fmt.Errorf("error deleting expired paste %s: %v", id, err))
+ slog.Error("error_deleting_expired_paste", "id", id, "error", err)
}
}
@@ -199,7 +190,7 @@ func (d *DB) DeleteExpiredPeriodically(interval time.Duration) {
for range ticker.C {
if err := d.DeleteExpired(); err != nil {
- log.Println(fmt.Errorf("error deleting expired pastes: %v", err))
+ slog.Error("error_starting_expired_paste_job", "error", err)
}
}
}
diff --git a/db/utils.go b/db/utils.go
new file mode 100644
index 0000000..0aa8dfa
--- /dev/null
+++ b/db/utils.go
@@ -0,0 +1,36 @@
+package db
+
+import (
+ "github.com/boltdb/bolt"
+ "log/slog"
+ "os"
+ "time"
+)
+
+func NewDB(path string, reset bool) (*DB, error) {
+ if reset {
+ removeDB(path)
+ }
+
+ boltDB, err := bolt.Open(path, 0600, &bolt.Options{Timeout: 1 * time.Second})
+ if err != nil {
+ return nil, err
+ }
+
+ return &DB{boltDB: boltDB}, nil
+}
+
+func removeDB(path string) {
+ slog.Info("resetting_db", "path", path)
+ if _, err := os.Stat(path); err != nil && os.IsNotExist(err) {
+ slog.Error("db_does_not_exist", "path", path, "error", err)
+ return
+ }
+
+ if err := os.Remove(path); err != nil {
+ slog.Error("error_removing_db", "path", path, "error", err)
+ return
+ }
+
+ slog.Info("db_removed", "path", path)
+}
diff --git a/main.go b/main.go
index 9e0352d..fc459b0 100644
--- a/main.go
+++ b/main.go
@@ -1,7 +1,10 @@
package main
import (
+ "flag"
+ "github.com/v1k45/pastepass/config"
"log"
+ "log/slog"
"net/http"
"time"
@@ -10,14 +13,22 @@ import (
)
func main() {
+ flag.StringVar(&config.ServerAddr, "server-addr", config.ServerAddr, "The server address to listen on")
+ flag.StringVar(&config.AppName, "app-name", config.AppName, "The name of the application (e.g. ACME PastePass)")
+ flag.StringVar(&config.DBPath, "db-path", config.DBPath, "The path to the database file")
+ flag.BoolVar(&config.ResetDB, "reset-db", config.ResetDB, "Reset the database on startup")
+ flag.Parse()
+
// Open the database
- boltdb, err := db.NewDB("pastes.boltdb")
+ boltdb, err := db.NewDB(config.DBPath, config.ResetDB)
if err != nil {
log.Fatalf("failed to open database: %v", err)
}
go boltdb.DeleteExpiredPeriodically(time.Minute * 5)
+ slog.Info("starting_server", "server_addr", config.ServerAddr, "app_name", config.AppName, "db_name", config.DBPath)
+
// Start the web server
handler := web.NewHandler(boltdb)
- http.ListenAndServe(":8080", handler.Router())
+ http.ListenAndServe(config.ServerAddr, handler.Router())
}
diff --git a/views/base.templ b/views/base.templ
index c9ef498..9446a8f 100644
--- a/views/base.templ
+++ b/views/base.templ
@@ -1,5 +1,7 @@
package views
+import "github.com/v1k45/pastepass/config"
+
templ base() {
@@ -8,14 +10,14 @@ templ base() {
- Paste
+ { config.AppName } - secure, one-time paste bin.
@@ -25,7 +27,7 @@ templ base() {
-
{text}
+
{text}
diff --git a/views/decrypt_templ.go b/views/decrypt_templ.go
index ac80039..1787959 100644
--- a/views/decrypt_templ.go
+++ b/views/decrypt_templ.go
@@ -29,14 +29,14 @@ func Decrypt(text string) templ.Component {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
View Paste
Please make sure to save the content before closing this page. This paste has been deleted and will no longer be available for viewing again.
")
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("View Paste
Please make sure to save the content before closing this page. This paste has been deleted and will no longer be available for viewing again.
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/decrypt.templ`, Line: 16, Col: 87}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/decrypt.templ`, Line: 16, Col: 106}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
diff --git a/views/index.templ b/views/index.templ
index 0688d6c..8dc6151 100644
--- a/views/index.templ
+++ b/views/index.templ
@@ -5,8 +5,8 @@ templ Index() {
")
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/web/handlers.go b/web/handlers.go
index 9c56e5a..a6ccaae 100644
--- a/web/handlers.go
+++ b/web/handlers.go
@@ -3,6 +3,7 @@ package web
import (
"context"
"fmt"
+ "log/slog"
"net/http"
"github.com/v1k45/pastepass/db"
@@ -26,18 +27,21 @@ func (h *Handler) Index(w http.ResponseWriter, r *http.Request) {
func (h *Handler) Paste(w http.ResponseWriter, r *http.Request) {
pastedText := r.FormValue("text")
if pastedText == "" {
+ slog.Error("validation_error", "error", "paste content is required")
errorResponse(w, http.StatusBadRequest, "Invalid Data", "Paste content is required.")
return
}
expiresAt, err := getExpiresAt(r.FormValue("expiration"))
if err != nil {
+ slog.Error("validation_error", "error", err)
errorResponse(w, http.StatusBadRequest, "Invalid Data", "Invalid expiration time.")
return
}
paste, err := h.DB.NewPaste(pastedText, expiresAt)
if err != nil {
+ slog.Error("cannot_create_paste", "error", err)
errorResponse(w, http.StatusInternalServerError, "Internal Server Error", "Failed to create paste, please try again later.")
return
}
@@ -55,7 +59,9 @@ func (h *Handler) Paste(w http.ResponseWriter, r *http.Request) {
}
func (h *Handler) View(w http.ResponseWriter, r *http.Request) {
- if _, err := h.DB.Get(r.PathValue("id")); err != nil {
+ id := r.PathValue("id")
+ if _, err := h.DB.Get(id); err != nil {
+ slog.Error("cannot_view_paste", "error", err, "id", id)
errorResponse(w, http.StatusNotFound, "Not Found", "The paste you are looking for is either expired or does not exist.")
return
}
@@ -65,8 +71,10 @@ func (h *Handler) View(w http.ResponseWriter, r *http.Request) {
}
func (h *Handler) Decrypt(w http.ResponseWriter, r *http.Request) {
- decryptedText, err := h.DB.Decrypt(r.PathValue("id"), r.PathValue("key"))
+ id, key := r.PathValue("id"), r.PathValue("key")
+ decryptedText, err := h.DB.Decrypt(id, key)
if err != nil {
+ slog.Error("cannot_decrypt_paste", "error", err, "id", id)
errorResponse(
w, http.StatusInternalServerError,
"Internal Server Error", "The paste you are looking for is either expired, corrputed or does not exist.")