// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Damn Vulnerable Go Application
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// WARNING: This is a DELIBERATELY VULNERABLE application for security training purposes
// DO NOT use this code in production environments!

package main

import (
	"crypto/md5"
	"database/sql"
	"encoding/hex"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

// Global variables (bad practice - race conditions)
var (
	db       *sql.DB
	sessions = make(map[string]string) // Insecure session storage
	apiKey   = "super-secret-api-key-123" // Hardcoded secret
)

// User struct with sensitive data exposure
type User struct {
	ID       int    `json:"id"`
	Username string `json:"username"`
	Password string `json:"password"` // Password exposed in JSON
	Email    string `json:"email"`
	IsAdmin  bool   `json:"is_admin"`
	SSN      string `json:"ssn"` // Sensitive data exposed
}

// Vulnerable authentication function
func authenticate(username, password string) (*User, error) {
	// SQL Injection vulnerability
	query := fmt.Sprintf("SELECT id, username, password, email, is_admin, ssn FROM users WHERE username = '%s' AND password = '%s'", username, password)
	
	row := db.QueryRow(query)
	
	user := &User{}
	err := row.Scan(&user.ID, &user.Username, &user.Password, &user.Email, &user.IsAdmin, &user.SSN)
	if err != nil {
		return nil, err
	}
	
	return user, nil
}

// Weak password hashing
func hashPassword(password string) string {
	// Using MD5 (cryptographically broken)
	hasher := md5.New()
	hasher.Write([]byte(password))
	return hex.EncodeToString(hasher.Sum(nil))
}

// Insecure session management
func createSession(userID string) string {
	// Predictable session ID
	sessionID := fmt.Sprintf("sess_%s_%d", userID, time.Now().Unix())
	sessions[sessionID] = userID
	return sessionID
}

// Path traversal vulnerability
func fileHandler(w http.ResponseWriter, r *http.Request) {
	filename := r.URL.Query().Get("file")
	if filename == "" {
		http.Error(w, "No file specified", http.StatusBadRequest)
		return
	}
	
	// No path validation - allows ../../../etc/passwd
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		http.Error(w, "File not found", http.StatusNotFound)
		return
	}
	
	w.Header().Set("Content-Type", "text/plain")
	w.Write(content)
}

// Command injection vulnerability
func pingHandler(w http.ResponseWriter, r *http.Request) {
	host := r.URL.Query().Get("host")
	if host == "" {
		http.Error(w, "No host specified", http.StatusBadRequest)
		return
	}
	
	// Direct command execution without sanitization
	cmd := exec.Command("ping", "-c", "4", host)
	output, err := cmd.Output()
	if err != nil {
		// Information disclosure
		http.Error(w, fmt.Sprintf("Command failed: %v", err), http.StatusInternalServerError)
		return
	}
	
	w.Header().Set("Content-Type", "text/plain")
	w.Write(output)
}

// XSS vulnerability
func searchHandler(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query().Get("q")
	
	// No HTML escaping - allows XSS
	html := fmt.Sprintf(`
	<html>
	<body>
		<h1>Search Results</h1>
		<p>You searched for: %s</p>
		<p>No results found.</p>
	</body>
	</html>`, query)
	
	w.Header().Set("Content-Type", "text/html")
	w.Write([]byte(html))
}

// CSRF vulnerability
func deleteUserHandler(w http.ResponseWriter, r *http.Request) {
	userID := r.URL.Query().Get("id")
	
	// No CSRF protection
	query := fmt.Sprintf("DELETE FROM users WHERE id = %s", userID)
	_, err := db.Exec(query)
	if err != nil {
		http.Error(w, "Failed to delete user", http.StatusInternalServerError)
		return
	}
	
	fmt.Fprintf(w, "User %s deleted successfully", userID)
}

// Information disclosure
func debugHandler(w http.ResponseWriter, r *http.Request) {
	// Exposing sensitive system information
	info := map[string]interface{}{
		"environment_variables": os.Environ(),
		"working_directory":     os.Getwd(),
		"process_id":           os.Getpid(),
		"api_key":              apiKey,
		"database_path":        "./vulnerable.db",
		"sessions":             sessions,
	}
	
	fmt.Fprintf(w, "Debug Info: %+v\n", info)
}

// Insecure file upload
func uploadHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}
	
	file, header, err := r.FormFile("file")
	if err != nil {
		http.Error(w, "No file uploaded", http.StatusBadRequest)
		return
	}
	defer file.Close()
	
	// No file type validation - allows executable uploads
	filename := header.Filename
	
	// No path sanitization
	dst, err := os.Create(filepath.Join("uploads", filename))
	if err != nil {
		http.Error(w, "Failed to create file", http.StatusInternalServerError)
		return
	}
	defer dst.Close()
	
	// Copy file content
	content, _ := ioutil.ReadAll(file)
	dst.Write(content)
	
	fmt.Fprintf(w, "File %s uploaded successfully", filename)
}

// Weak random number generation
func generateToken() string {
	// Using predictable time-based seed
	return fmt.Sprintf("token_%d", time.Now().UnixNano())
}

// Race condition vulnerability
var counter int

func counterHandler(w http.ResponseWriter, r *http.Request) {
	// Race condition - not thread safe
	counter++
	fmt.Fprintf(w, "Counter: %d", counter)
}

// Integer overflow vulnerability
func calculateHandler(w http.ResponseWriter, r *http.Request) {
	aStr := r.URL.Query().Get("a")
	bStr := r.URL.Query().Get("b")
	
	a, _ := strconv.Atoi(aStr) // No error handling
	b, _ := strconv.Atoi(bStr)
	
	// No overflow checking
	result := a * b
	fmt.Fprintf(w, "Result: %d", result)
}

// Template injection vulnerability
func templateHandler(w http.ResponseWriter, r *http.Request) {
	userInput := r.URL.Query().Get("template")
	
	// Direct template execution with user input
	tmpl, err := template.New("user").Parse(userInput)
	if err != nil {
		http.Error(w, "Template error", http.StatusBadRequest)
		return
	}
	
	tmpl.Execute(w, nil)
}

// Insecure deserialization (simulated)
func deserializeHandler(w http.ResponseWriter, r *http.Request) {
	data := r.URL.Query().Get("data")
	
	// Simulated unsafe deserialization
	if strings.Contains(data, "exec") {
		// This would execute arbitrary code in a real scenario
		fmt.Fprintf(w, "Executing: %s", data)
	} else {
		fmt.Fprintf(w, "Data processed: %s", data)
	}
}

// Initialize vulnerable database
func initDB() {
	var err error
	db, err = sql.Open("sqlite3", "./vulnerable.db")
	if err != nil {
		log.Fatal(err)
	}
	
	// Create users table with weak schema
	createTable := `
	CREATE TABLE IF NOT EXISTS users (
		id INTEGER PRIMARY KEY,
		username TEXT,
		password TEXT, -- Plain text passwords
		email TEXT,
		is_admin BOOLEAN DEFAULT FALSE,
		ssn TEXT -- Sensitive data without encryption
	);`
	
	_, err = db.Exec(createTable)
	if err != nil {
		log.Fatal(err)
	}
	
	// Insert default admin user with weak credentials
	insertAdmin := `
	INSERT OR IGNORE INTO users (id, username, password, email, is_admin, ssn) 
	VALUES (1, 'admin', 'password123', 'admin@vulnerable.com', TRUE, '123-45-6789');`
	
	db.Exec(insertAdmin)
}

func main() {
	// Initialize vulnerable database
	initDB()
	
	// Create uploads directory
	os.MkdirAll("uploads", 0777) // Overly permissive permissions
	
	// Vulnerable route handlers
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Welcome to the Damn Vulnerable Go Application!")
	})
	
	http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
		username := r.URL.Query().Get("username")
		password := r.URL.Query().Get("password")
		
		user, err := authenticate(username, password)
		if err != nil {
			http.Error(w, "Login failed", http.StatusUnauthorized)
			return
		}
		
		sessionID := createSession(strconv.Itoa(user.ID))
		
		// Insecure cookie settings
		http.SetCookie(w, &http.Cookie{
			Name:     "session",
			Value:    sessionID,
			HttpOnly: false, // Allows XSS access
			Secure:   false, // Allows transmission over HTTP
			SameSite: http.SameSiteNoneMode, // No CSRF protection
		})
		
		fmt.Fprintf(w, "Welcome %s! Session: %s", user.Username, sessionID)
	})
	
	http.HandleFunc("/file", fileHandler)
	http.HandleFunc("/ping", pingHandler)
	http.HandleFunc("/search", searchHandler)
	http.HandleFunc("/delete", deleteUserHandler)
	http.HandleFunc("/debug", debugHandler)
	http.HandleFunc("/upload", uploadHandler)
	http.HandleFunc("/counter", counterHandler)
	http.HandleFunc("/calculate", calculateHandler)
	http.HandleFunc("/template", templateHandler)
	http.HandleFunc("/deserialize", deserializeHandler)
	
	fmt.Println("🚨 DAMN VULNERABLE GO APPLICATION STARTED 🚨")
	fmt.Println("⚠️  WARNING: This application contains intentional security vulnerabilities!")
	fmt.Println("🔓 Server running on http://localhost:8080")
	fmt.Println("")
	fmt.Println("🎯 Available vulnerable endpoints:")
	fmt.Println("   /login?username=admin&password=password123")
	fmt.Println("   /file?file=../../../etc/passwd")
	fmt.Println("   /ping?host=google.com;cat /etc/passwd")
	fmt.Println("   /search?q=<script>alert('XSS')</script>")
	fmt.Println("   /delete?id=1")
	fmt.Println("   /debug")
	fmt.Println("   /upload (POST)")
	fmt.Println("   /counter")
	fmt.Println("   /calculate?a=999999999&b=999999999")
	fmt.Println("   /template?template={{.}}")
	fmt.Println("   /deserialize?data=exec:rm -rf /")
	
	// Insecure server configuration
	log.Fatal(http.ListenAndServe(":8080", nil)) // No TLS, no timeouts
}