// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Vulnerable Go App Demo
//
// 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.

package main

import (
	"crypto/md5"
	"database/sql"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"

	_ "github.com/go-sql-driver/mysql"
)

// Hardcoded credentials - VULNERABILITY 1
const (
	DB_PASSWORD = "admin123"
	API_KEY     = "sk-1234567890abcdef"
	SECRET_KEY  = "my-super-secret-key"
)

// Global variables without proper synchronization - VULNERABILITY 2
var (
	userCount    int
	isProcessing bool
)

// Vulnerable user struct with sensitive data
type User struct {
	ID       int
	Username string
	Password string // Plain text password - VULNERABILITY 3
	SSN      string // Sensitive data without encryption
	Email    string
}

// SQL Injection vulnerability - VULNERABILITY 4
func getUserByID(db *sql.DB, userID string) (*User, error) {
	// Direct string concatenation in SQL query
	query := "SELECT id, username, password, ssn, email FROM users WHERE id = " + userID
	
	row := db.QueryRow(query)
	
	user := &User{}
	err := row.Scan(&user.ID, &user.Username, &user.Password, &user.SSN, &user.Email)
	if err != nil {
		return nil, err
	}
	
	return user, nil
}

// Command Injection vulnerability - VULNERABILITY 5
func executeCommand(w http.ResponseWriter, r *http.Request) {
	command := r.URL.Query().Get("cmd")
	if command == "" {
		http.Error(w, "No command provided", http.StatusBadRequest)
		return
	}
	
	// Direct execution of user input
	cmd := exec.Command("sh", "-c", command)
	output, err := cmd.Output()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	
	w.Write(output)
}

// Weak cryptographic hash - VULNERABILITY 6
func hashPassword(password string) string {
	hasher := md5.New()
	hasher.Write([]byte(password))
	return fmt.Sprintf("%x", hasher.Sum(nil))
}

// Path traversal vulnerability - VULNERABILITY 7
func serveFile(w http.ResponseWriter, r *http.Request) {
	filename := r.URL.Query().Get("file")
	if filename == "" {
		http.Error(w, "No file specified", http.StatusBadRequest)
		return
	}
	
	// No validation of file path
	content, err := os.ReadFile(filename)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	
	w.Write(content)
}

// Race condition vulnerability - VULNERABILITY 8
func incrementCounter(w http.ResponseWriter, r *http.Request) {
	// No synchronization for concurrent access
	userCount++
	isProcessing = true
	
	// Simulate some processing time
	for i := 0; i < 1000; i++ {
		userCount += i
	}
	
	isProcessing = false
	fmt.Fprintf(w, "Counter: %d", userCount)
}

// Information disclosure - VULNERABILITY 9
func debugInfo(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain")
	
	// Exposing sensitive system information
	fmt.Fprintf(w, "Database Password: %s\n", DB_PASSWORD)
	fmt.Fprintf(w, "API Key: %s\n", API_KEY)
	fmt.Fprintf(w, "Secret Key: %s\n", SECRET_KEY)
	fmt.Fprintf(w, "Environment Variables:\n")
	
	for _, env := range os.Environ() {
		fmt.Fprintf(w, "%s\n", env)
	}
}

// Improper error handling - VULNERABILITY 10
func loginUser(w http.ResponseWriter, r *http.Request) {
	username := r.FormValue("username")
	password := r.FormValue("password")
	
	db, err := sql.Open("mysql", "user:"+DB_PASSWORD+"@tcp(localhost:3306)/mydb")
	if err != nil {
		// Exposing internal error details
		http.Error(w, "Database connection failed: "+err.Error(), http.StatusInternalServerError)
		return
	}
	defer db.Close()
	
	// SQL injection vulnerability in login
	query := fmt.Sprintf("SELECT id FROM users WHERE username='%s' AND password='%s'", username, password)
	
	var userID int
	err = db.QueryRow(query).Scan(&userID)
	if err != nil {
		// Information disclosure through error messages
		http.Error(w, "Login failed: "+err.Error(), http.StatusUnauthorized)
		return
	}
	
	fmt.Fprintf(w, "Login successful for user ID: %d", userID)
}

// Insecure random number generation - VULNERABILITY 11
func generateToken() string {
	// Using predictable random source
	token := ""
	for i := 0; i < 10; i++ {
		token += strconv.Itoa(i % 10)
	}
	return token
}

// Buffer overflow potential - VULNERABILITY 12
func processData(data string) string {
	// Fixed size buffer without bounds checking
	buffer := make([]byte, 100)
	copy(buffer, []byte(data)) // No length validation
	return string(buffer)
}

// Insecure HTTP headers - VULNERABILITY 13
func insecureHandler(w http.ResponseWriter, r *http.Request) {
	// Missing security headers
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "*")
	w.Header().Set("Access-Control-Allow-Headers", "*")
	
	// No CSRF protection
	action := r.FormValue("action")
	if action == "delete" {
		fmt.Fprintf(w, "Deleted user account")
	}
}

// Memory leak potential - VULNERABILITY 14
func memoryLeakHandler(w http.ResponseWriter, r *http.Request) {
	// Creating large slices without proper cleanup
	data := make([]byte, 1024*1024) // 1MB allocation
	
	// Storing in global variable (memory leak)
	globalData = append(globalData, data...)
	
	fmt.Fprintf(w, "Data processed: %d bytes", len(data))
}

var globalData []byte

// Denial of Service vulnerability - VULNERABILITY 15
func dosHandler(w http.ResponseWriter, r *http.Request) {
	iterations := r.URL.Query().Get("iterations")
	if iterations == "" {
		iterations = "1000000"
	}
	
	count, _ := strconv.Atoi(iterations)
	
	// No limit on iterations - can cause DoS
	result := 0
	for i := 0; i < count; i++ {
		result += i * i
	}
	
	fmt.Fprintf(w, "Result: %d", result)
}

func main() {
	// Insecure server configuration
	http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
		db, _ := sql.Open("mysql", "user:"+DB_PASSWORD+"@tcp(localhost:3306)/mydb")
		defer db.Close()
		
		userID := r.URL.Query().Get("id")
		user, err := getUserByID(db, userID)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		
		fmt.Fprintf(w, "User: %+v", user)
	})
	
	http.HandleFunc("/exec", executeCommand)
	http.HandleFunc("/file", serveFile)
	http.HandleFunc("/counter", incrementCounter)
	http.HandleFunc("/debug", debugInfo)
	http.HandleFunc("/login", loginUser)
	http.HandleFunc("/insecure", insecureHandler)
	http.HandleFunc("/memory", memoryLeakHandler)
	http.HandleFunc("/dos", dosHandler)
	
	fmt.Println("Starting vulnerable server on :8080")
	
	// Insecure server configuration - no TLS, no timeouts
	log.Fatal(http.ListenAndServe(":8080", nil))
}