diff --git a/frontend/assets/css/register-blocked.css b/frontend/assets/css/register-blocked.css new file mode 100644 index 0000000..3a117d2 --- /dev/null +++ b/frontend/assets/css/register-blocked.css @@ -0,0 +1,108 @@ +:root { + --bg: #111827; + --card: #1f2937; + --border: #374151; + --text: #f9fafb; + --text-muted: #9ca3af; + --accent: #3b82f6; + --accent-hover: #2563eb; + --success: #10b981; + --error: #ef4444; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + min-height: 100vh; + background: var(--bg); + color: var(--text); + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + display: flex; + flex-direction: column; +} + +body:not(.dashboard-layout) { + justify-content: center; + align-items: center; + padding: 1rem; +} + +.card { + width: 100%; + max-width: 400px; + background: var(--card); + border: 1px solid var(--border); + border-radius: 16px; + padding: 2.5rem 2rem; + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -4px rgba(0, 0, 0, 0.3); + text-align: center; +} + +.card h1 { + margin: 0 0 0.5rem 0; + font-size: 1.75rem; + font-weight: 700; + letter-spacing: -0.025em; +} + +.card .subtitle { + color: var(--text-muted); + font-size: 0.95rem; + margin-bottom: 2rem; +} + +.btn { + display: inline-flex; + justify-content: center; + align-items: center; + width: 100%; + padding: 0.85rem; + font-size: 1rem; + font-weight: 600; + border-radius: 10px; + border: none; + cursor: pointer; + text-decoration: none; + transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.1s ease; +} + +.btn:active { + transform: scale(0.98); +} + +.btn-secondary { + background: #1f2937; + color: white; + border: 1px solid var(--border); +} + +.btn-secondary:hover { + background: var(--accent); + border-color: var(--accent); +} + +.footer-text { + margin-top: 1.5rem; + font-size: 0.9rem; + color: var(--text-muted); +} + +.message { + margin-top: 1.25rem; + padding: 0.85rem 1rem; + border-radius: 10px; + font-size: 0.9rem; + line-height: 1.4; + text-align: left; +} + +.message.error { + background: rgba(239, 68, 68, 0.1); + border: 1px solid rgba(239, 68, 68, 0.2); + color: var(--error); + display: block; +} \ No newline at end of file diff --git a/frontend/assets/js/auth.js b/frontend/assets/js/auth.js index 5f43a5c..a844166 100644 --- a/frontend/assets/js/auth.js +++ b/frontend/assets/js/auth.js @@ -13,20 +13,15 @@ return null; } - const cookieAccessToken = getCookie("access_token"); - const cookieRefreshToken = getCookie("refresh_token"); - - const localAccessToken = localStorage.getItem("access_token"); - const localRefreshToken = localStorage.getItem("refresh_token"); - - const accessToken = cookieAccessToken || localAccessToken; - const refreshToken = cookieRefreshToken || localRefreshToken; - - if (!accessToken && !refreshToken) { - return; + function clearAllAuth() { + console.log("Clearing all auth remnants from cookies and localStorage..."); + localStorage.removeItem("access_token"); + localStorage.removeItem("refresh_token"); + document.cookie = "access_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;"; + document.cookie = "refresh_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;"; } - async function tryTokenRefresh() { + async function tryTokenRefresh(refreshToken) { if (!refreshToken) return false; try { @@ -51,19 +46,28 @@ console.error("Refresh request failed:", err); } - document.cookie = "access_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;"; - document.cookie = "refresh_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;"; return false; } async function checkAuth() { + const cookieAccessToken = getCookie("access_token"); + const cookieRefreshToken = getCookie("refresh_token"); + const localAccessToken = localStorage.getItem("access_token"); + const localRefreshToken = localStorage.getItem("refresh_token"); + + const accessToken = cookieAccessToken || localAccessToken; + const refreshToken = cookieRefreshToken || localRefreshToken; + console.log("Auth check started..."); console.log("AccessToken present:", !!accessToken); console.log("RefreshToken present:", !!refreshToken); - if (!cookieAccessToken && accessToken) { - console.log("Access token cookie missing, but present in localStorage. Forcing refresh..."); - } else if (accessToken) { + if (!accessToken && !refreshToken) { + console.log("No tokens found. User is guest."); + return; + } + + if (accessToken) { try { console.log("Attempting ping with access token..."); const response = await fetch("/api/ping", { @@ -76,7 +80,7 @@ window.location.href = "/dashboard"; return; } else { - console.log("Ping failed. Status:", response.status); + console.log("Ping failed. Token might be expired. Status:", response.status); } } catch (err) { console.error("Network error during ping:", err); @@ -85,24 +89,21 @@ if (refreshToken) { console.log("Starting token refresh to rebuild cookies..."); - const refreshSuccessful = await tryTokenRefresh(); + const refreshSuccessful = await tryTokenRefresh(refreshToken); if (refreshSuccessful) { console.log("Refresh successful! Redirecting to dashboard..."); window.location.href = "/dashboard"; return; } else { - console.log("Refresh failed. Staying on login."); + console.log("Refresh failed. Refresh token is invalid/expired."); } } else { - console.log("No refresh token present. User must log in normally."); + console.log("No refresh token present."); } - console.log("Authentication completely failed. Clearing remnants..."); - localStorage.removeItem("access_token"); - localStorage.removeItem("refresh_token"); - document.cookie = "access_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;"; - document.cookie = "refresh_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;"; + clearAllAuth(); + console.log("Authentication completely failed. Staying on current guest page."); } checkAuth(); diff --git a/frontend/handler.go b/frontend/handler.go index 0521f51..aecea49 100644 --- a/frontend/handler.go +++ b/frontend/handler.go @@ -3,8 +3,13 @@ package frontend import ( "html/template" "net/http" + "os" "path/filepath" "strings" + + "github.com/tdewolff/minify/v2" + "github.com/tdewolff/minify/v2/css" + "github.com/tdewolff/minify/v2/js" ) var dashboard = template.Must(template.ParseFiles( @@ -116,7 +121,50 @@ func Projects(w http.ResponseWriter, r *http.Request) { } } +var minifier *minify.M + +func init() { + minifier = minify.New() + // Füge die Minifier für CSS und JS hinzu + minifier.AddFunc("text/css", css.Minify) + minifier.AddFunc("text/javascript", js.Minify) +} + func Assets(w http.ResponseWriter, r *http.Request) { path := strings.TrimPrefix(r.URL.Path, "/assets/") - http.ServeFile(w, r, filepath.Join("frontend/assets", path)) + fullPath := filepath.Join("frontend/assets", path) + + w.Header().Set("Cache-Control", "public, max-age=3600") + + var mimeType string + if strings.HasSuffix(path, ".min.js") { + mimeType = "text/javascript" + fullPath = strings.Replace(fullPath, ".min.js", ".js", 1) + } else if strings.HasSuffix(path, ".min.css") { + mimeType = "text/css" + fullPath = strings.Replace(fullPath, ".min.css", ".css", 1) + } + + info, err := os.Stat(fullPath) + if err != nil || info.IsDir() { + http.Error(w, "Asset not found", http.StatusNotFound) + return + } + + if mimeType != "" { + content, err := os.ReadFile(fullPath) + if err != nil { + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + + minifiedContent, err := minifier.Bytes(mimeType, content) + if err == nil { + w.Header().Set("Content-Type", mimeType) + w.Write(minifiedContent) + return + } + } + + http.ServeFile(w, r, fullPath) } diff --git a/frontend/htmx/404.html b/frontend/htmx/404.html index 5507027..706579f 100644 --- a/frontend/htmx/404.html +++ b/frontend/htmx/404.html @@ -4,8 +4,8 @@ 404 - Page Not Found | MiauInv - - + + diff --git a/frontend/htmx/contents/dash/base.html b/frontend/htmx/contents/dash/base.html index b4903eb..6fde30d 100644 --- a/frontend/htmx/contents/dash/base.html +++ b/frontend/htmx/contents/dash/base.html @@ -5,9 +5,9 @@ {{ .Title }} | MiauInv - - - + + + diff --git a/frontend/htmx/home.html b/frontend/htmx/home.html index 2b1767d..f993eff 100644 --- a/frontend/htmx/home.html +++ b/frontend/htmx/home.html @@ -5,8 +5,8 @@ MiauInv | Private Instance - - + + diff --git a/frontend/htmx/login.html b/frontend/htmx/login.html index 17527a8..6fbbf8d 100644 --- a/frontend/htmx/login.html +++ b/frontend/htmx/login.html @@ -5,10 +5,10 @@ Sign In | MiauInv - - + + - + diff --git a/frontend/htmx/register-blocked.html b/frontend/htmx/register-blocked.html new file mode 100644 index 0000000..9953952 --- /dev/null +++ b/frontend/htmx/register-blocked.html @@ -0,0 +1,26 @@ + + + + + + Registration Disabled - MiauInv + + + + + +
+

Registration

+
Create a new account
+ +
+ Access Denied: Public registration is currently disabled for this system. Please contact your system administrator to request an account. +
+ + +
+ + + \ No newline at end of file diff --git a/frontend/htmx/register.html b/frontend/htmx/register.html index d7f8742..646d99d 100644 --- a/frontend/htmx/register.html +++ b/frontend/htmx/register.html @@ -4,8 +4,9 @@ Register | MiauInv - - + + + @@ -36,6 +37,5 @@

- \ No newline at end of file diff --git a/frontend/htmx/register_blocked.html b/frontend/htmx/register_blocked.html deleted file mode 100644 index 360f9f1..0000000 --- a/frontend/htmx/register_blocked.html +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - Registration Disabled - MiauInv - - - - -
-

Registration

-
Create a new account
- -
- Access Denied: Public registration is currently disabled for this system. Please contact your system administrator to request an account. -
- - -
- - - \ No newline at end of file diff --git a/frontend/htmx/under-construction.html b/frontend/htmx/under-construction.html index f2e472f..c4ed2e7 100644 --- a/frontend/htmx/under-construction.html +++ b/frontend/htmx/under-construction.html @@ -4,8 +4,8 @@ Feature Under Development | MiauInv - - + + diff --git a/go.mod b/go.mod index 9359228..b8461b1 100644 --- a/go.mod +++ b/go.mod @@ -5,15 +5,17 @@ go 1.26 require ( github.com/glebarez/go-sqlite v1.22.0 github.com/golang-jwt/jwt/v5 v5.3.1 + github.com/google/uuid v1.5.0 + github.com/tdewolff/minify/v2 v2.24.13 golang.org/x/crypto v0.52.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/dustin/go-humanize v1.0.1 // indirect - github.com/google/uuid v1.5.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/tdewolff/parse/v2 v2.8.12 // indirect golang.org/x/sys v0.45.0 // indirect modernc.org/libc v1.37.6 // indirect modernc.org/mathutil v1.6.0 // indirect diff --git a/go.sum b/go.sum index 864d7a6..9a82097 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,13 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/tdewolff/minify/v2 v2.24.13 h1:xrcF7gKDnUszseEY9WX9mUlZII2v2Go/QAcAwRASw58= +github.com/tdewolff/minify/v2 v2.24.13/go.mod h1:emvwoYeIl8bfAKqRU5ww95LX9Gpggpqv/naal9a8Yq0= +github.com/tdewolff/parse/v2 v2.8.12 h1:5BBjfaCv482v3nltlS0u6wH1xJaxjR6ofDrWttNvROg= +github.com/tdewolff/parse/v2 v2.8.12/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLBLd6dlIXYqo= +github.com/tdewolff/test v1.0.11/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= +github.com/tdewolff/test v1.0.12 h1:7F21DqIajswxuche0geHdrUZRCWE4oko4b7bcmkkrxk= +github.com/tdewolff/test v1.0.12/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/server/server.go b/server/server.go index 65531d8..886069b 100644 --- a/server/server.go +++ b/server/server.go @@ -75,7 +75,7 @@ func (this *Server) Run() { if this.AllowRegistration { mux.HandleFunc("/register", utils.RenderFile("frontend/htmx/register.html")) } else { - mux.HandleFunc("/register", utils.RenderFile("frontend/htmx/register_blocked.html")) + mux.HandleFunc("/register", utils.RenderFile("frontend/htmx/register-blocked.html")) } //