// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Vulnerable Go 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"
	"html/template"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"

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

// User represents a user in the system
type User struct {
	ID       int
	Username string
	Password string
	Email    string
	IsAdmin  bool
}

// Global variables - potential security issues
var (
	db       *sql.DB
	apiKey   = "sk-1234567890abcdef" // Hardcoded API key - VULNERABILITY
	dbPass   = "admin123"            // Hardcoded database password - VULNERABILITY
	adminKey = "supersecret"         // Hardcoded admin key - VULNERABILITY
)

// Database connection with hardcoded credentials - VULNERABILITY
func initDB() {
	var err error
	// SQL injection vulnerable connection string
	connStr := fmt.Sprintf("root:%s@tcp(localhost:3306)/testdb", dbPass)
	db, err = sql.Open("mysql", connStr)
	if err != nil {
		log.Fatal(err)
	}
}

// Vulnerable login handler - SQL Injection
func loginHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.ServeFile(w, r, "login.html")
		return
	}

	username := r.FormValue("username")
	password := r.FormValue("password")

	// VULNERABILITY: SQL Injection - direct string concatenation
	query := fmt.Sprintf("SELECT id, username, password, email, is_admin FROM users WHERE username='%s' AND password='%s'", username, password)
	
	var user User
	err := db.QueryRow(query).Scan(&user.ID, &user.Username, &user.Password, &user.Email, &user.IsAdmin)
	if err != nil {
		http.Error(w, "Invalid credentials", http.StatusUnauthorized)
		return
	}

	// VULNERABILITY: Weak password hashing (MD5)
	hashedPassword := fmt.Sprintf("%x", md5.Sum([]byte(password)))
	if user.Password != hashedPassword {
		http.Error(w, "Invalid credentials", http.StatusUnauthorized)
		return
	}

	// Set insecure cookie - VULNERABILITY
	http.SetCookie(w, &http.Cookie{
		Name:     "session",
		Value:    user.Username,
		HttpOnly: false, // VULNERABILITY: Not HttpOnly
		Secure:   false, // VULNERABILITY: Not Secure
	})

	fmt.Fprintf(w, "Welcome %s!", user.Username)
}

// Vulnerable file upload handler - Path Traversal
func uploadHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	filename := r.FormValue("filename")
	content := r.FormValue("content")

	// VULNERABILITY: Path traversal - no validation of filename
	filepath := "/uploads/" + filename
	
	file, err := os.Create(filepath)
	if err != nil {
		http.Error(w, "Cannot create file", http.StatusInternalServerError)
		return
	}
	defer file.Close()

	file.WriteString(content)
	fmt.Fprintf(w, "File %s uploaded successfully", filename)
}

// Vulnerable command execution - Command Injection
func execHandler(w http.ResponseWriter, r *http.Request) {
	command := r.URL.Query().Get("cmd")
	
	// VULNERABILITY: Command injection - direct execution of user input
	cmd := exec.Command("sh", "-c", command)
	output, err := cmd.Output()
	if err != nil {
		http.Error(w, "Command execution failed", http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, "Output: %s", string(output))
}

// Vulnerable template rendering - XSS
func profileHandler(w http.ResponseWriter, r *http.Request) {
	username := r.URL.Query().Get("user")
	
	// VULNERABILITY: XSS - unsafe template rendering
	tmplStr := fmt.Sprintf("<h1>Profile for %s</h1><p>Welcome back!</p>", username)
	tmpl := template.Must(template.New("profile").Parse(tmplStr))
	tmpl.Execute(w, nil)
}

// Vulnerable user search - Information disclosure
func searchHandler(w http.ResponseWriter, r *http.Request) {
	searchTerm := r.URL.Query().Get("q")
	
	// VULNERABILITY: SQL Injection in search
	query := fmt.Sprintf("SELECT username, email FROM users WHERE username LIKE '%%%s%%'", searchTerm)
	
	rows, err := db.Query(query)
	if err != nil {
		http.Error(w, "Search failed", http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	var results []string
	for rows.Next() {
		var username, email string
		rows.Scan(&username, &email)
		// VULNERABILITY: Information disclosure - exposing email addresses
		results = append(results, fmt.Sprintf("%s (%s)", username, email))
	}

	fmt.Fprintf(w, "Search results: %s", strings.Join(results, ", "))
}

// Vulnerable admin panel - Insecure Direct Object Reference
func adminHandler(w http.ResponseWriter, r *http.Request) {
	userID := r.URL.Query().Get("id")
	
	// VULNERABILITY: No authorization check
	id, _ := strconv.Atoi(userID)
	
	// VULNERABILITY: SQL Injection
	query := fmt.Sprintf("SELECT * FROM users WHERE id = %d", id)
	
	var user User
	err := db.QueryRow(query).Scan(&user.ID, &user.Username, &user.Password, &user.Email, &user.IsAdmin)
	if err != nil {
		http.Error(w, "User not found", http.StatusNotFound)
		return
	}

	// VULNERABILITY: Exposing sensitive information including passwords
	fmt.Fprintf(w, "User Details: ID=%d, Username=%s, Password=%s, Email=%s, IsAdmin=%t", 
		user.ID, user.Username, user.Password, user.Email, user.IsAdmin)
}

// Vulnerable password reset - Weak token generation
func resetPasswordHandler(w http.ResponseWriter, r *http.Request) {
	email := r.FormValue("email")
	
	// VULNERABILITY: Weak random token generation
	token := fmt.Sprintf("%x", md5.Sum([]byte(email)))
	
	// VULNERABILITY: Logging sensitive information
	log.Printf("Password reset token for %s: %s", email, token)
	
	fmt.Fprintf(w, "Password reset token sent to %s", email)
}

// Vulnerable file read - Local File Inclusion
func readFileHandler(w http.ResponseWriter, r *http.Request) {
	filename := r.URL.Query().Get("file")
	
	// VULNERABILITY: Local File Inclusion - no path validation
	content, err := os.ReadFile(filename)
	if err != nil {
		http.Error(w, "Cannot read file", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "text/plain")
	w.Write(content)
}

func main() {
	// Initialize database connection
	initDB()
	defer db.Close()

	// VULNERABILITY: No HTTPS enforcement
	http.HandleFunc("/login", loginHandler)
	http.HandleFunc("/upload", uploadHandler)
	http.HandleFunc("/exec", execHandler)
	http.HandleFunc("/profile", profileHandler)
	http.HandleFunc("/search", searchHandler)
	http.HandleFunc("/admin", adminHandler)
	http.HandleFunc("/reset", resetPasswordHandler)
	http.HandleFunc("/read", readFileHandler)

	// VULNERABILITY: Server running without security headers
	log.Println("Server starting on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}