diff --git a/.gitignore b/.gitignore index 148d85e..67da780 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,7 @@ /go.sum /ImageMagick wordlist.txt -*.db \ No newline at end of file +*.db + +/app_build/README.md +/app_build/tailwindcss-linux-x64 \ No newline at end of file diff --git a/README.md b/README.md index 97217f5..2340ebe 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,21 @@ -# Email Header Analyzer - Build & Usage Instructions +# GoNetKit +- Go Web App where you can find many usefull IT tools +- These tools should provide simple and nice way for user to get what they need without requiring signing up or sharing details with 3rd parties. ## Building a Single-File Executable (Windows & Linux) This app uses Go's `embed` package to bundle all static files (web UI, icons, CSS, etc.) into a single executable. You do **not** need to distribute the `web/` folder separately. +- You will need C building package, especially on Windows as this app using SQLITE, if you do not need password pushser, then remove it and you will not need it to make windows built. +- built scripts are in `app_build` folder, but may need fixing as the app is in development still and I built it on few computers when i have time. ### Prerequisites -- [Go 1.16+](https://golang.org/dl/) (required for `embed`) +- [Go 1.24+](https://golang.org/dl/) (required for `embed`) - (Optional) [Python 3](https://www.python.org/) with Pillow for icon conversion ```go -go mod init headeranalyzer +go mod init gonetkit go mod tidy ``` -### 1. Prepare Icons +### 1. Prepare Icons (custom icon Optional) - Place your tray icon and favicon in `web/icon.png` and `web/favicon.png`. - For Windows tray icon, you **must** use a `.ico` file. Use the provided script: @@ -20,6 +24,7 @@ go mod tidy python web/convert_icon.py web/icon.png web/icon.ico # using ImageMagick convertor magick envelope.jpg -define icon:auto-resize=16,32,48,64 favicon.ico +# https://github.com/ImageMagick/ImageMagick/releases ImageMagick\magick.exe web\icon.png -define icon:auto-resize=16,32,48,64 web\favicon.ico ImageMagick\magick.exe identify web\favicon.ico # App Icon: @@ -37,19 +42,19 @@ go clean -cache #### Windows (from Windows PowerShell or Command Prompt): ```powershell # PowerShell (set environment variables before the command) -$env:GOOS="windows"; $env:GOARCH="amd64"; go build -ldflags "-H=windowsgui" -o headeranalyzer.exe main.go +$env:GOOS="windows"; $env:GOARCH="amd64"; go build -ldflags "-H=windowsgui" -o GoNetKit.exe main.go ``` ```cmd REM Command Prompt (set environment variables before the command) set GOOS=windows set GOARCH=amd64 -go build -ldflags "-H=windowsgui" -o headeranalyzer.exe main.go +go build -ldflags "-H=windowsgui" -o GoNetKit.exe main.go ``` #### Linux/macOS (from Bash): ```sh # Build 64-bit Linux executable -GOOS=linux GOARCH=amd64 go build -o headeranalyzer main.go +GOOS=linux GOARCH=amd64 go build -o goNetKit main.go ``` - The resulting executable contains all static files and icons. @@ -74,13 +79,13 @@ By default, Go does not embed an icon in the .exe. To add your tray/web icon as #### Windows (from Windows PowerShell or Command Prompt): ```powershell # PowerShell (set environment variables before the command) -$env:GOOS="windows"; $env:GOARCH="amd64"; go build -ldflags "-H=windowsgui" -o headeranalyzer.exe main.go +$env:GOOS="windows"; $env:GOARCH="amd64"; go build -ldflags "-H=windowsgui" -o GoNetKit.exe main.go ``` ```cmd REM Command Prompt (set environment variables before the command) set GOOS=windows set GOARCH=amd64 -go build -ldflags "-H=windowsgui" -o headeranalyzer.exe main.go +go build -ldflags "-H=windowsgui" -o GoNetKit.exe main.go ``` - The `-ldflags "-H=windowsgui"` flag prevents a console window from opening when you run the app. @@ -89,7 +94,7 @@ go build -ldflags "-H=windowsgui" -o headeranalyzer.exe main.go #### Linux/macOS (from Bash): ```sh # Build 64-bit Linux executable -GOOS=linux GOARCH=amd64 go build -o headeranalyzer main.go +GOOS=linux GOARCH=amd64 go build -o goNetKit main.go ``` - The resulting executable contains all static files and icons. @@ -97,9 +102,9 @@ GOOS=linux GOARCH=amd64 go build -o headeranalyzer main.go ### 3. Run the App - Double-click or run from terminal: - - On Windows: `headeranalyzer.exe` - - On Linux: `./headeranalyzer` -- The app will start a web server (default: http://localhost:8080) and show a system tray icon. + - On Windows: `GoNetKit.exe` + - On Linux: `./goNetKit` +- The app will start a web server (default: http://localhost:5555) and show a system tray icon. - Use the tray menu to open the web UI or quit the app. ### 4. Usage Notes @@ -123,8 +128,8 @@ If you followed all steps and the icon still does not appear: - **Try building without cross-compiling:** If you are cross-compiling, try building directly on Windows. - **Try go build without -ldflags:** Rarely, the `-ldflags` flag can interfere. Try building with and without it: ```powershell - go build -o headeranalyzer.exe main.go - go build -ldflags "-H=windowsgui" -o headeranalyzer.exe main.go + go build -o GoNetKit.exe main.go + go build -ldflags "-H=windowsgui" -o GoNetKit.exe main.go ``` - **Try go generate:** If you use `go generate`, ensure it does not overwrite or remove `icon.syso`. diff --git a/build-linux.sh b/app_build/build-linux.sh similarity index 100% rename from build-linux.sh rename to app_build/build-linux.sh diff --git a/build-resource.bat b/app_build/build-resource.bat similarity index 100% rename from build-resource.bat rename to app_build/build-resource.bat diff --git a/build-resource.sh b/app_build/build-resource.sh similarity index 100% rename from build-resource.sh rename to app_build/build-resource.sh diff --git a/app_build/build-tailwind.bat b/app_build/build-tailwind.bat new file mode 100644 index 0000000..ddfe320 --- /dev/null +++ b/app_build/build-tailwind.bat @@ -0,0 +1,71 @@ +@echo off +REM Tailwind CSS Build Script for Header Analyzer (Windows) +REM This script downloads Tailwind CLI and generates CSS for production + +setlocal enabledelayedexpansion + +set "PROJECT_ROOT=%~dp0.." +set "TAILWIND_CLI=%PROJECT_ROOT%\app_build\tailwindcss-windows-x64.exe" +set "INPUT_CSS=%PROJECT_ROOT%\web\style-custom.css" +set "OUTPUT_CSS=%PROJECT_ROOT%\web\style-compiled.css" +set "CONFIG_FILE=%PROJECT_ROOT%\tailwind.config.js" + +echo 🎨 Building Tailwind CSS for Header Analyzer... +echo Project root: %PROJECT_ROOT% + +REM Download Tailwind CLI if it doesn't exist +if not exist "%TAILWIND_CLI%" ( + echo đŸ“Ĩ Downloading Tailwind CSS CLI... + curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-windows-x64.exe + move tailwindcss-windows-x64.exe "%TAILWIND_CLI%" + echo ✅ Tailwind CLI downloaded +) + +REM Create tailwind.config.js if it doesn't exist +if not exist "%CONFIG_FILE%" ( + echo âš™ī¸ Creating tailwind.config.js... + ( + echo /** @type {import('tailwindcss'^).Config} */ + echo module.exports = { + echo content: [ + echo "./web/**/*.html", + echo "./web/**/*.js" + echo ], + echo theme: { + echo extend: { + echo colors: { + echo 'header-blue': '#007cba', + echo 'header-dark': '#1a1a1a' + echo } + echo }, + echo }, + echo plugins: [], + echo } + ) > "%CONFIG_FILE%" + echo ✅ Created tailwind.config.js +) + +REM Build CSS +echo 🔨 Building Tailwind CSS... +if "%1"=="--watch" ( + echo 👀 Starting watch mode... + "%TAILWIND_CLI%" -i "%INPUT_CSS%" -o "%OUTPUT_CSS%" --watch +) else if "%1"=="--dev" ( + echo đŸ› ī¸ Building development CSS... + "%TAILWIND_CLI%" -i "%INPUT_CSS%" -o "%OUTPUT_CSS%" +) else ( + echo đŸ“Ļ Building production CSS ^(minified^)... + "%TAILWIND_CLI%" -i "%INPUT_CSS%" -o "%OUTPUT_CSS%" --minify +) + +echo ✅ Tailwind CSS build complete! +echo 📍 Output: %OUTPUT_CSS% + +REM Show file size +if exist "%OUTPUT_CSS%" ( + for %%F in ("%OUTPUT_CSS%") do ( + echo 📊 Generated CSS size: %%~zF bytes + ) +) + +pause diff --git a/app_build/build-tailwind.sh b/app_build/build-tailwind.sh new file mode 100755 index 0000000..17b8650 --- /dev/null +++ b/app_build/build-tailwind.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# Tailwind CSS Build Script for Header Analyzer +# This script downloads Tailwind CLI and generates CSS for production + +set -e + +PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +TAILWIND_CLI="$PROJECT_ROOT/app_build/tailwindcss-linux-x64" +INPUT_CSS="$PROJECT_ROOT/web/style-input.css" +OUTPUT_CSS="$PROJECT_ROOT/web/style-tailwind.css" +CONFIG_FILE="$PROJECT_ROOT/tailwind.config.js" + +echo "🎨 Building Tailwind CSS for Header Analyzer..." +echo "Project root: $PROJECT_ROOT" + +# Download Tailwind CLI if it doesn't exist +if [ ! -f "$TAILWIND_CLI" ]; then + echo "đŸ“Ĩ Downloading Tailwind CSS CLI..." + curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 + mv tailwindcss-linux-x64 "$TAILWIND_CLI" + chmod +x "$TAILWIND_CLI" + echo "✅ Tailwind CLI downloaded" +fi + +# Create tailwind.config.js if it doesn't exist +if [ ! -f "$CONFIG_FILE" ]; then + echo "âš™ī¸ Creating tailwind.config.js..." + cat > "$CONFIG_FILE" << 'EOF' +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./web/**/*.html", + "./web/**/*.js" + ], + theme: { + extend: { + colors: { + 'header-blue': '#007cba', + 'header-dark': '#1a1a1a' + } + }, + }, + plugins: [], +} +EOF + echo "✅ Created tailwind.config.js" +fi + +# Build CSS +echo "🔨 Building Tailwind CSS..." +if [ "$1" = "--watch" ]; then + echo "👀 Starting watch mode..." + "$TAILWIND_CLI" -i "$INPUT_CSS" -o "$OUTPUT_CSS" --watch +elif [ "$1" = "--dev" ]; then + echo "đŸ› ī¸ Building development CSS..." + "$TAILWIND_CLI" -i "$INPUT_CSS" -o "$OUTPUT_CSS" +else + echo "đŸ“Ļ Building production CSS (minified)..." + "$TAILWIND_CLI" -i "$INPUT_CSS" -o "$OUTPUT_CSS" --minify +fi + +echo "✅ Tailwind CSS build complete!" +echo "📍 Output: $OUTPUT_CSS" + +# Show file size +if [ -f "$OUTPUT_CSS" ]; then + SIZE=$(du -h "$OUTPUT_CSS" | cut -f1) + echo "📊 Generated CSS size: $SIZE" +fi diff --git a/build-windows.bat b/app_build/build-windows.bat similarity index 100% rename from build-windows.bat rename to app_build/build-windows.bat diff --git a/app_build/build.sh b/app_build/build.sh new file mode 100755 index 0000000..758542d --- /dev/null +++ b/app_build/build.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# Main Build Script for Header Analyzer +# Builds Tailwind CSS and compiles the Go application + +set -e + +PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +BUILD_DIR="$PROJECT_ROOT/app_build" + +echo "🚀 Building Header Analyzer..." +echo "Project root: $PROJECT_ROOT" + +# Build Tailwind CSS first +echo "📝 Step 1: Building Tailwind CSS..." +"$BUILD_DIR/build-tailwind.sh" + +# Build Go application +echo "📝 Step 2: Building Go application..." +cd "$PROJECT_ROOT" + +# Set build variables +VERSION=$(git describe --tags --always --dirty 2>/dev/null || echo "dev") +BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") +COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown") + +echo "Version: $VERSION" +echo "Build time: $BUILD_TIME" +echo "Commit: $COMMIT" + +# Build for current platform +echo "🔨 Compiling for current platform..." +go build -ldflags "-X main.version=$VERSION -X main.buildTime=$BUILD_TIME -X main.commit=$COMMIT" \ + -o headeranalyzer . + +echo "✅ Build complete!" +echo "📍 Binary: $PROJECT_ROOT/headeranalyzer" + +# Show binary size +if [ -f "$PROJECT_ROOT/headeranalyzer" ]; then + SIZE=$(du -h "$PROJECT_ROOT/headeranalyzer" | cut -f1) + echo "📊 Binary size: $SIZE" +fi diff --git a/web/style.css b/app_build/style.css similarity index 98% rename from web/style.css rename to app_build/style.css index 46bcd5b..76c6869 100644 --- a/web/style.css +++ b/app_build/style.css @@ -1,6 +1,3 @@ -/* Import Tailwind CSS */ -@import url('https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css'); - :root { --bg-color: #0f172a; --text-color: #e2e8f0; @@ -22,6 +19,34 @@ .text-dark-muted { color: var(--dark-muted); } .border-dark-border { border-color: var(--dark-border); } +/* Custom animations and styles */ +@keyframes slideInRight { + from { transform: translateX(100%); opacity: 0; } + to { transform: translateX(0); opacity: 1; } +} + +@keyframes slideOutRight { + from { transform: translateX(0); opacity: 1; } + to { transform: translateX(100%); opacity: 0; } +} + +.animate-slide-in-right { + animation: slideInRight 0.3s ease-out forwards; +} + +.animate-slide-out-right { + animation: slideOutRight 0.3s ease-in forwards; +} + +/* Backdrop blur for popup */ +.backdrop-blur-popup { + backdrop-filter: blur(8px); +} + +/* Floating button styles */ +.floating-nav { + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); +} /* Password Generator Styles */ .password-generator { max-width: 56rem; diff --git a/main.go b/main.go index db83702..24655a1 100644 --- a/main.go +++ b/main.go @@ -16,11 +16,11 @@ import ( "syscall" "time" - "headeranalyzer/landingpage" - "headeranalyzer/parser" - "headeranalyzer/passwordgenerator" - "headeranalyzer/pwpusher" - "headeranalyzer/resolver" + "gonetkit/landingpage" + "gonetkit/parser" + "gonetkit/passwordgenerator" + "gonetkit/pwpusher" + "gonetkit/resolver" "github.com/getlantern/systray" ) @@ -174,6 +174,17 @@ func main() { w.Write(data) }) + // Serve Tailwind CSS file with correct MIME type + http.HandleFunc("/style-tailwind.css", func(w http.ResponseWriter, r *http.Request) { + data, err := fs.ReadFile(staticFS, "style-tailwind.css") + if err != nil { + http.NotFound(w, r) + return + } + w.Header().Set("Content-Type", "text/css") + w.Write(data) + }) + http.Handle("/", landingHandler) http.Handle("/analyze", indexHandler) diff --git a/parser/analyzer.go b/parser/analyzer.go index bf016c5..d1d7702 100644 --- a/parser/analyzer.go +++ b/parser/analyzer.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "headeranalyzer/resolver" + "gonetkit/resolver" ) type Report struct { diff --git a/parser/handler.go b/parser/handler.go index 12e19ce..58e1b21 100644 --- a/parser/handler.go +++ b/parser/handler.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "headeranalyzer/security" + "gonetkit/security" ) type Handler struct { @@ -73,6 +73,44 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Validate CSRF token csrfToken := r.FormValue("csrf_token") if !h.csrf.ValidateToken(csrfToken) { + // If CSRF validation fails, check if this looks like a refresh attempt + // by seeing if we have headers data + headers := r.FormValue("headers") + if headers != "" { + // This appears to be a refresh attempt with stale CSRF token + // Generate a new token and re-analyze + log.Printf("DEBUG: CSRF validation failed, but reanalyzing with fresh token for refresh") + freshCSRFToken, err := h.csrf.GenerateToken() + if err != nil { + http.Redirect(w, r, "/?error="+url.QueryEscape("Security token generation failed"), http.StatusSeeOther) + return + } + + validatedHeaders, err := h.validator.ValidateEmailHeaders(headers) + if err != nil { + log.Printf("DEBUG: Validation failed on refresh: %v", err) + http.Redirect(w, r, "/?error="+url.QueryEscape("Invalid input provided"), http.StatusSeeOther) + return + } + + report := Analyze(validatedHeaders) + data := struct { + *Report + CurrentPage string + CSRFToken string + OriginalHeaders string + }{ + Report: report, + CurrentPage: "home", + CSRFToken: freshCSRFToken, + OriginalHeaders: validatedHeaders, + } + + h.templates.ExecuteTemplate(w, "headeranalyzer.html", data) + return + } + + // Regular CSRF failure - redirect to home http.Redirect(w, r, "/?error="+url.QueryEscape("Invalid security token. Please try again."), http.StatusSeeOther) return } @@ -95,13 +133,26 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { log.Printf("DEBUG: Headers validated successfully") report := Analyze(validatedHeaders) log.Printf("DEBUG: Analysis completed, From field: '%s'", report.From) - // Create a wrapper struct to include current page info + + // Generate a fresh CSRF token for the result page + freshCSRFToken, err := h.csrf.GenerateToken() + if err != nil { + log.Printf("ERROR: Failed to generate fresh CSRF token: %v", err) + http.Redirect(w, r, "/?error="+url.QueryEscape("Security token generation failed"), http.StatusSeeOther) + return + } + + // Create a wrapper struct to include current page info and fresh CSRF token data := struct { *Report - CurrentPage string + CurrentPage string + CSRFToken string + OriginalHeaders string }{ - Report: report, - CurrentPage: "home", + Report: report, + CurrentPage: "home", + CSRFToken: freshCSRFToken, + OriginalHeaders: validatedHeaders, } log.Printf("DEBUG: About to render template with data") diff --git a/passwordgenerator/api.go b/passwordgenerator/api.go index 84e43d7..54a78ae 100644 --- a/passwordgenerator/api.go +++ b/passwordgenerator/api.go @@ -5,7 +5,7 @@ import ( "net/http" "strings" - "headeranalyzer/security" + "gonetkit/security" ) var validator = security.NewInputValidator() diff --git a/passwordgenerator/handler.go b/passwordgenerator/handler.go index ebf8c04..ac64a7b 100644 --- a/passwordgenerator/handler.go +++ b/passwordgenerator/handler.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "headeranalyzer/security" + "gonetkit/security" ) type Handler struct { diff --git a/pwpusher/pwpusher.go b/pwpusher/pwpusher.go index c6b2182..52d90fd 100644 --- a/pwpusher/pwpusher.go +++ b/pwpusher/pwpusher.go @@ -20,7 +20,7 @@ import ( "strings" "time" - "headeranalyzer/security" + "gonetkit/security" _ "github.com/mattn/go-sqlite3" "golang.org/x/crypto/bcrypt" @@ -605,9 +605,18 @@ func (p *PWPusher) handleCreatePush(w http.ResponseWriter, r *http.Request) { // Prepare response URL with new format scheme := "http" + + // Check for HTTPS in multiple ways if r.TLS != nil { scheme = "https" + } else if r.Header.Get("X-Forwarded-Proto") == "https" { + scheme = "https" + } else if r.Header.Get("X-Forwarded-Ssl") == "on" { + scheme = "https" + } else if strings.HasPrefix(r.Header.Get("Referer"), "https://") { + scheme = "https" } + fullURL := fmt.Sprintf("%s://%s/s/%s?k=%s", scheme, r.Host, id, additionalKey) // Save to user's history if tracking is enabled @@ -632,6 +641,7 @@ func (p *PWPusher) handleCreatePush(w http.ResponseWriter, r *http.Request) { "PushURL": fullURL, "ID": id, "ExpiresAt": expiresAt.Format("2006-01-02 15:04:05"), + "MaxViews": req.MaxViews, "CurrentPage": "pwpush", }) } diff --git a/resolver/dns_api.go b/resolver/dns_api.go index 61fb753..201084b 100644 --- a/resolver/dns_api.go +++ b/resolver/dns_api.go @@ -7,7 +7,7 @@ import ( "net/http" "strings" - "headeranalyzer/security" + "gonetkit/security" "github.com/miekg/dns" ) diff --git a/resolver/handler.go b/resolver/handler.go index 226d6da..9c0b147 100644 --- a/resolver/handler.go +++ b/resolver/handler.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "headeranalyzer/security" + "gonetkit/security" ) type Handler struct { diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..a290955 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,9 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./web/*.{html,js}", + "./**/*.go" + ], + safelist: [], + plugins: [], +} diff --git a/web/base.html b/web/base.html index 4c945f7..ed214c3 100644 --- a/web/base.html +++ b/web/base.html @@ -4,62 +4,35 @@ {{block "title" .}}{{end}} - - - - + + {{block "head" .}}{{end}} -
+
-