301 lines
6.0 KiB
Go
301 lines
6.0 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"database/sql"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"math/big"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
)
|
|
|
|
type User struct {
|
|
UserID string `json:"user_id"`
|
|
Username string `json:"username"`
|
|
}
|
|
|
|
type RegistrationResponse struct {
|
|
UserID string `json:"user_id"`
|
|
}
|
|
|
|
type ProfileRequest struct {
|
|
UserID string `json:"user_id"`
|
|
}
|
|
|
|
type ProfileResponse struct {
|
|
Username string `json:"username"`
|
|
}
|
|
|
|
var db *sql.DB
|
|
|
|
func generateUsername() (string, error) {
|
|
adjectives := []string{
|
|
"freaky",
|
|
"suspicious",
|
|
"malicious",
|
|
"supersticious",
|
|
"handsome",
|
|
"ugly",
|
|
"crazy",
|
|
"demonic",
|
|
"peeping",
|
|
"slippery",
|
|
"mysterious",
|
|
"spooky",
|
|
"creepy",
|
|
"sinister",
|
|
"ghoulish",
|
|
"macabre",
|
|
"eerie",
|
|
"pessimistic",
|
|
"frightening",
|
|
"grotesque",
|
|
"haunted",
|
|
"infernal",
|
|
"menacing",
|
|
"morose",
|
|
"nefarious",
|
|
"nightmarish",
|
|
"obscure",
|
|
"ominous",
|
|
"phantasmagoric",
|
|
"pallid",
|
|
"perilous",
|
|
"phantom",
|
|
"aberrant",
|
|
"bizarre",
|
|
"chilling",
|
|
"cryptic",
|
|
"dark",
|
|
"dreadful",
|
|
"obsolete",
|
|
"greasy",
|
|
"bald",
|
|
"putrid",
|
|
"old",
|
|
}
|
|
words := []string{
|
|
"magician",
|
|
"welder",
|
|
"wizard",
|
|
"criminal",
|
|
"rat",
|
|
"castle",
|
|
"droid",
|
|
"robot",
|
|
"cyborg",
|
|
"joe",
|
|
"bob",
|
|
"tom",
|
|
"builder",
|
|
"architect",
|
|
"troll",
|
|
"ogre",
|
|
"nomad",
|
|
"bohemian",
|
|
"skeleton",
|
|
"goblin",
|
|
"monster",
|
|
"engineer",
|
|
"dude",
|
|
"guy",
|
|
"mob",
|
|
"creep",
|
|
"juice",
|
|
"smoke",
|
|
"potion",
|
|
"fart",
|
|
"mage",
|
|
"vermin",
|
|
"crook",
|
|
"flunkey",
|
|
"insect",
|
|
"bug",
|
|
"handyman",
|
|
}
|
|
|
|
index1Big, err := rand.Int(rand.Reader, big.NewInt(int64(len(adjectives))))
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to generate random index for array1: %w", err)
|
|
}
|
|
index1 := int(index1Big.Int64())
|
|
|
|
index2Big, err := rand.Int(rand.Reader, big.NewInt(int64(len(words))))
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to generate random index for array2: %w", err)
|
|
}
|
|
index2 := int(index2Big.Int64())
|
|
|
|
randomNumberBig, err := rand.Int(rand.Reader, big.NewInt(101))
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to generate random number: %w", err)
|
|
}
|
|
randomNumber := randomNumberBig.Int64()
|
|
|
|
username := fmt.Sprintf("%s_%s%d", adjectives[index1], words[index2], randomNumber)
|
|
|
|
return username, nil
|
|
}
|
|
|
|
func generateSecureUserID() (string, error) {
|
|
b := make([]byte, 8)
|
|
_, err := rand.Read(b)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return hex.EncodeToString(b), nil
|
|
}
|
|
|
|
//func validateUsername(username string) error {
|
|
// if len(username) < 3 || len(username) > 32 {
|
|
// return fmt.Errorf("[-] username must be between 3 and 32 characters")
|
|
// }
|
|
//
|
|
// pattern := `^[a-zA-Z0-9_]+$`
|
|
// match, err := regexp.MatchString(pattern, username)
|
|
// if err != nil {
|
|
// return fmt.Errorf("[-] error validating username")
|
|
// }
|
|
// if !match {
|
|
// return fmt.Errorf("[-] username can only contain letters, numbers, and underscores")
|
|
// }
|
|
//
|
|
// return nil
|
|
//}
|
|
|
|
func InitDB(dbPath string) (*sql.DB, error) {
|
|
db, err := sql.Open("sqlite3", dbPath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open db: %v", err)
|
|
}
|
|
_, err = db.Exec(`
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
user_id TEXT PRIMARY KEY CHECK(length(user_id) = 16),
|
|
username TEXT NOT NULL UNIQUE CHECK(length(username) >= 3 AND length(username) <= 32),
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`)
|
|
if err != nil {
|
|
db.Close()
|
|
return nil, fmt.Errorf("failed to create users table: %v", err)
|
|
}
|
|
|
|
return db, nil
|
|
}
|
|
|
|
func greet(w http.ResponseWriter, r *http.Request) {
|
|
println("[+] ping")
|
|
fmt.Fprintf(w, "[+] enxos server %s", time.Now())
|
|
}
|
|
|
|
func u_profile(w http.ResponseWriter, r *http.Request) {
|
|
println("[+] u_profile")
|
|
if r.Method != http.MethodPost {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
var profRequest ProfileRequest
|
|
err := json.NewDecoder(r.Body).Decode(&profRequest)
|
|
if err != nil {
|
|
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
profRequest.UserID = strings.TrimSpace(profRequest.UserID)
|
|
|
|
var username string
|
|
err = db.QueryRow("SELECT username FROM users WHERE user_id = ?", profRequest.UserID).Scan(&username)
|
|
if err != nil {
|
|
http.Error(w, "Database error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if strings.Compare(strings.TrimSpace(username), "") == 0 {
|
|
http.Error(w, "UserID not found", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
response := ProfileResponse{
|
|
Username: username,
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusCreated)
|
|
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
func u_register(w http.ResponseWriter, r *http.Request) {
|
|
println("[+] u_register")
|
|
if r.Method != http.MethodPost {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
username, err := generateUsername()
|
|
if err != nil {
|
|
http.Error(w, "Failed to generate username", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
userid, err := generateSecureUserID()
|
|
if err != nil {
|
|
http.Error(w, "Failed to generate user ID", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
_, err = db.Exec("INSERT INTO users (user_id, username) VALUES (?, ?)", userid, username)
|
|
if err != nil {
|
|
http.Error(w, "Failed to create user", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
response := RegistrationResponse{
|
|
UserID: userid,
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusCreated)
|
|
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
func main() {
|
|
const dbPath = "./users.db"
|
|
|
|
var err error
|
|
|
|
db, err = InitDB(dbPath)
|
|
if err != nil {
|
|
log.Fatalf("DB Initialization failed: %v", err)
|
|
}
|
|
|
|
err = db.Ping()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
http.HandleFunc("/", greet)
|
|
http.HandleFunc("/u/profile", u_profile)
|
|
http.HandleFunc("/u/register", u_register)
|
|
//http.ListenAndServe(":8801", nil)
|
|
|
|
server := &http.Server{
|
|
Addr: ":8801",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
}
|
|
|
|
log.Printf("[+] enxos server starting on %s", server.Addr)
|
|
|
|
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
log.Fatalf("[-] server failed to start: %v", err)
|
|
}
|
|
}
|