about summary refs log tree commit diff
path: root/src/bot.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/bot.go')
-rw-r--r--src/bot.go842
1 files changed, 842 insertions, 0 deletions
diff --git a/src/bot.go b/src/bot.go
new file mode 100644
index 0000000..1a0d342
--- /dev/null
+++ b/src/bot.go
@@ -0,0 +1,842 @@
+package main
+
+import (
+	"fmt"
+	"html/template"
+	"log"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/gorilla/mux"
+	"github.com/radareorg/r2pipe-go"
+)
+
+type Bot struct {
+	ID     int
+	Name   string
+	Source string
+	Users  []User
+
+	Archs []Arch
+	Bits  []Bit
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// GENERAL PURPOSE
+
+func BotCreate(name string, source string) (int, error) {
+	return globalState.InsertBot(Bot{Name: name, Source: source})
+}
+
+func BotUpdate(botid int, name string, source string) error {
+	return globalState.UpdateBot(Bot{ID: botid, Name: name, Source: source})
+}
+
+func BotGetById(id int) (Bot, error) {
+	return globalState.GetBotById(id)
+}
+
+func BotGetAll() ([]Bot, error) {
+	return globalState.GetAllBot()
+}
+
+func BotLinkArchIDs(botid int, archIDs []int) error {
+	return globalState.LinkArchIDsToBot(botid, archIDs)
+}
+
+func BotLinkBitIDs(botid int, bitIDs []int) error {
+	return globalState.LinkBitIDsToBot(botid, bitIDs)
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// DATABASE
+
+func (s *State) InsertBot(bot Bot) (int, error) {
+	res, err := s.db.Exec("INSERT INTO bots VALUES(NULL,?,?,?);", time.Now(), bot.Name, bot.Source)
+	if err != nil {
+		return 0, err
+	}
+
+	var id int64
+	if id, err = res.LastInsertId(); err != nil {
+		return 0, err
+	}
+	return int(id), nil
+}
+
+func (s *State) UpdateBot(bot Bot) error {
+	_, err := s.db.Exec("UPDATE bots SET name=?, source=? WHERE id=?", bot.Name, bot.Source, bot.ID)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (s *State) GetBotById(id int) (Bot, error) {
+	var botid int
+	var botname string
+	var botsource string
+
+	var ownerids string
+	var ownernames string
+
+	var archids string
+	var archnames string
+
+	var bitids string
+	var bitnames string
+
+	err := s.db.QueryRow(`
+	SELECT
+		bo.id, bo.name, bo.source,
+		COALESCE(group_concat(ub.user_id), ""),
+		COALESCE(group_concat(us.name), ""),
+		COALESCE(group_concat(ab.arch_id), ""),
+		COALESCE(group_concat(ar.name), ""),
+		COALESCE(group_concat(bb.bit_id), ""),
+		COALESCE(group_concat(bi.name), "")
+	FROM bots bo
+
+	LEFT JOIN user_bot_rel ub ON ub.bot_id = bo.id
+	LEFT JOIN users us ON us.id = ub.user_id
+
+	LEFT JOIN arch_bot_rel ab ON ab.bot_id = bo.id
+	LEFT JOIN archs ar ON ar.id = ab.arch_id
+
+	LEFT JOIN bit_bot_rel bb ON bb.bot_id = bo.id
+	LEFT JOIN bits bi ON bi.id = bb.bit_id
+
+	WHERE bo.id=?
+	GROUP BY bo.id;
+	`, id).Scan(&botid, &botname, &botsource, &ownerids, &ownernames, &archids, &archnames, &bitids, &bitnames)
+	if err != nil {
+		log.Println(err)
+		return Bot{}, err
+	}
+
+	// log.Println("botid: ", botid)
+	// log.Println("botname: ", botname)
+	// log.Println("botsource: ", botsource)
+	// log.Println("ownerids: ", ownerids)
+	// log.Println("ownernames: ", ownernames)
+	// log.Println("archid: ", archids)
+	// log.Println("archname: ", archnames)
+	// log.Println("bitid: ", bitids)
+	// log.Println("bitname: ", bitnames)
+
+	ownerIDList := strings.Split(ownerids, ",")
+	ownerNameList := strings.Split(ownernames, ",")
+
+	var users []User
+	for i, _ := range ownerIDList {
+		id, err := strconv.Atoi(ownerIDList[i])
+		if err != nil {
+			log.Println("ERR1: ", err)
+			return Bot{}, err
+		}
+		users = append(users, User{ID: id, Name: ownerNameList[i], PasswordHash: nil})
+	}
+
+	// assemble the archs
+	archIDList := strings.Split(archids, ",")
+	archNameList := strings.Split(archnames, ",")
+
+	var archs []Arch
+	if archIDList[0] != "" {
+		for i, _ := range archIDList {
+			id, err := strconv.Atoi(archIDList[i])
+			if err != nil {
+				log.Println("Err handling archs: ", err)
+				return Bot{}, err
+			}
+			archs = append(archs, Arch{id, archNameList[i], true})
+		}
+	} else {
+		archs = []Arch{}
+	}
+
+	// assemble the bits
+	bitIDList := strings.Split(bitids, ",")
+	bitNameList := strings.Split(bitnames, ",")
+
+	var bits []Bit
+	if bitIDList[0] != "" {
+		for i, _ := range bitIDList {
+			id, err := strconv.Atoi(bitIDList[i])
+			if err != nil {
+				log.Println("Err handling bits: ", err)
+				return Bot{}, err
+			}
+			bits = append(bits, Bit{id, bitNameList[i], true})
+		}
+	} else {
+		bits = []Bit{}
+	}
+
+	switch {
+	case err != nil:
+		log.Println("ERR4: ", err)
+		return Bot{}, err
+	default:
+		return Bot{botid, botname, botsource, users, archs, bits}, nil
+	}
+}
+
+func (s *State) UpdateBotSource(name string, source string) error {
+	_, err := s.db.Exec("UPDATE bots SET source=? WHERE name=?", source, name)
+	if err != nil {
+		return err
+	} else {
+		return nil
+	}
+}
+
+func (s *State) UpdateBotName(orig_name string, new_name string) error {
+	_, err := s.db.Exec("UPDATE bots SET name=? WHERE name=?", new_name, orig_name)
+	if err != nil {
+		return err
+	} else {
+		return nil
+	}
+}
+
+// Returns the users belonging to the given bot
+func (s *State) GetBotUsers(botid int) ([]User, error) {
+	rows, err := s.db.Query("SELECT id, name FROM users u LEFT JOIN user_bot_rel ub ON ub.user_id = u.id WHERE ub.bot_id=?", botid)
+	defer rows.Close()
+	if err != nil {
+		return nil, err
+	}
+
+	var users []User
+	for rows.Next() {
+		var user User
+		if err := rows.Scan(&user.ID, &user.Name); err != nil {
+			return users, err
+		}
+		users = append(users, user)
+	}
+	if err = rows.Err(); err != nil {
+		return users, err
+	}
+	return users, nil
+}
+
+// Returns the users belonging to the given bot
+func (s *State) GetAllBot() ([]Bot, error) {
+	rows, err := s.db.Query("SELECT id, name FROM bots;")
+	defer rows.Close()
+	if err != nil {
+		return nil, err
+	}
+
+	var bots []Bot
+	for rows.Next() {
+		var bot Bot
+		if err := rows.Scan(&bot.ID, &bot.Name); err != nil {
+			return bots, err
+		}
+		bots = append(bots, bot)
+	}
+	if err = rows.Err(); err != nil {
+		return bots, err
+	}
+	return bots, nil
+}
+
+// Returns the users belonging to the given bot
+func (s *State) GetAllBotsWithUsers() ([]Bot, error) {
+	rows, err := s.db.Query(`SELECT
+		b.id, b.name, b.source, group_concat(ub.user_id), group_concat(u.name)
+	FROM bots b
+	LEFT JOIN user_bot_rel ub ON ub.bot_id = b.id
+	LEFT JOIN users u ON ub.user_id = u.id
+	GROUP BY b.id;`)
+	defer rows.Close()
+	if err != nil {
+		return nil, err
+	}
+
+	var bots []Bot
+	for rows.Next() {
+		var bot Bot
+		var userIDListString string
+		var usernameListString string
+
+		err := rows.Scan(&bot.ID, &bot.Name, &bot.Source, &userIDListString, &usernameListString)
+		if err != nil {
+			return nil, err
+		}
+
+		userIDList := strings.Split(userIDListString, ",")
+		usernameList := strings.Split(usernameListString, ",")
+
+		var users []User
+		for i, _ := range userIDList {
+			id, err := strconv.Atoi(userIDList[i])
+			if err != nil {
+				return nil, err
+			}
+			users = append(users, User{ID: id, Name: usernameList[i], PasswordHash: nil})
+		}
+		bot.Users = users
+
+		bots = append(bots, bot)
+	}
+	if err = rows.Err(); err != nil {
+		return bots, err
+	}
+	return bots, nil
+}
+
+func (s *State) LinkArchIDsToBot(botid int, archIDs []int) error {
+	// delete preexisting links
+	_, err := s.db.Exec("DELETE FROM arch_bot_rel WHERE bot_id=?;", botid)
+	if err != nil {
+		log.Println("Error deleting old arch bot link: ", err)
+		return err
+	}
+
+	// yes, we're building this by hand, but as we only insert int's I'm just confident that whoever
+	// gets some sqli here just deserves it :D
+	query := "INSERT INTO arch_bot_rel (arch_id, bot_id) VALUES"
+	for idx, id := range archIDs {
+		query += fmt.Sprintf("(%d, %d)", id, botid)
+		if idx != len(archIDs)-1 {
+			query += ", "
+		}
+	}
+	query += ";"
+	log.Println(query)
+
+	_, err = s.db.Exec(query)
+	if err != nil {
+		log.Println("LinkArchIDsToBot err: ", err)
+		return err
+	} else {
+		return nil
+	}
+}
+
+func (s *State) LinkBitIDsToBot(botid int, bitIDs []int) error {
+	// delete preexisting links
+	_, err := s.db.Exec("DELETE FROM bit_bot_rel WHERE bot_id=?;", botid)
+	if err != nil {
+		log.Println("Error deleting old bit bot link: ", err)
+		return err
+	}
+
+	// yes, we're building this by hand, but as we only insert int's I'm just confident that whoever
+	// gets some sqli here just deserves it :D
+	query := "INSERT INTO bit_bot_rel (bit_id, bot_id) VALUES"
+	for idx, id := range bitIDs {
+		query += fmt.Sprintf("(%d, %d)", id, botid)
+		if idx != len(bitIDs)-1 {
+			query += ", "
+		}
+	}
+	query += ";"
+	log.Println(query)
+
+	_, err = s.db.Exec(query)
+	if err != nil {
+		log.Println("LinkBitIDsToBot err: ", err)
+		return err
+	} else {
+		return nil
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// HTTP
+
+func botsHandler(w http.ResponseWriter, r *http.Request) {
+	switch r.Method {
+	case "GET":
+		// define data
+		data := map[string]interface{}{}
+
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"]
+		data["pagelink1"] = Link{"bot", "/bot"}
+		data["pagelink1options"] = []Link{
+			{Name: "user", Target: "/user"},
+			{Name: "battle", Target: "/battle"},
+		}
+		data["pagelinknext"] = []Link{
+			{Name: "new", Target: "/new"},
+		}
+
+		if username == nil {
+			http.Redirect(w, r, "/login", http.StatusMethodNotAllowed)
+		}
+
+		user, err := UserGetUserFromUsername(username.(string))
+		if err != nil {
+			data["err"] = "Could not fetch the user"
+		} else {
+			data["user"] = user
+		}
+
+		bots, err := globalState.GetAllBotsWithUsers()
+		data["bots"] = bots
+
+		// get the template
+		t, err := template.ParseGlob("./templates/*.html")
+		if err != nil {
+			w.WriteHeader(http.StatusInternalServerError)
+			w.Write([]byte("500 - Error reading template file"))
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		// exec!
+		t.ExecuteTemplate(w, "bots", data)
+	default:
+		http.Redirect(w, r, "/", http.StatusMethodNotAllowed)
+	}
+}
+
+func botSingleHandler(w http.ResponseWriter, r *http.Request) {
+	vars := mux.Vars(r)
+	botid, err := strconv.Atoi(vars["id"])
+	if err != nil {
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Write([]byte("500 - Invalid bot id"))
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	switch r.Method {
+	case "GET":
+		// define data
+		data := map[string]interface{}{}
+		data["pagelink1"] = Link{"bot", "/bot"}
+		data["pagelink1options"] = []Link{
+			{Name: "user", Target: "/user"},
+			{Name: "battle", Target: "/battle"},
+		}
+
+		// display errors passed via query parameters
+		log.Println("[d] Getting previous results")
+		queryres := r.URL.Query().Get("res")
+		if queryres != "" {
+			data["res"] = queryres
+		}
+
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"].(string)
+
+		viewer, err := UserGetUserFromUsername(username)
+		if err != nil {
+			data["err"] = "Could not get the id four your username... Please contact an admin"
+		}
+
+		bot, err := BotGetById(int(botid))
+		data["bot"] = bot
+		data["user"] = viewer
+
+		// open radare without input for building the bot
+		r2p1, err := r2pipe.NewPipe("--")
+		if err != nil {
+			panic(err)
+		}
+		defer r2p1.Close()
+
+		src := strings.ReplaceAll(bot.Source, "\r\n", "; ")
+		radareCommand := fmt.Sprintf("rasm2 -a %s -b %s \"%+v\"", bot.Archs[0].Name, bot.Bits[0].Name, src)
+		bytecode, err := r2cmd(r2p1, radareCommand)
+		if err != nil {
+			data["err"] = "Error assembling the bot"
+			http.Redirect(w, r, fmt.Sprintf("/bot/%d", botid), http.StatusSeeOther)
+			return
+		}
+		data["bytecode_r2cmd"] = radareCommand
+		data["bytecode"] = bytecode
+
+		radareCommand = fmt.Sprintf("rasm2 -a %s -b %s -D %+v", bot.Archs[0].Name, bot.Bits[0].Name, bytecode)
+		disasm, err := r2cmd(r2p1, radareCommand)
+		if err != nil {
+			data["err"] = "Error disassembling the bot"
+			http.Redirect(w, r, fmt.Sprintf("/bot/%d", botid), http.StatusSeeOther)
+			return
+		}
+		data["err"] = "Could not get the id four your username... Please contact an admin"
+
+		data["disasm_r2cmd"] = radareCommand
+		data["disasm"] = disasm
+
+		// define the breadcrumbs
+		data["pagelink2"] = Link{bot.Name, fmt.Sprintf("/%d", bot.ID)}
+
+		allBotNames, err := BotGetAll()
+		var opts []Link
+		for _, bot := range allBotNames {
+			opts = append(opts, Link{Name: bot.Name, Target: fmt.Sprintf("/%d", bot.ID)})
+		}
+		data["pagelink2options"] = opts
+
+		editable := false
+		for _, user := range bot.Users {
+			if user.ID == viewer.ID {
+				editable = true
+			}
+		}
+		if editable == true {
+			data["editable"] = true
+		}
+
+		// get all architectures and set the enable flag on the ones that are enabled in the battle
+		archs, err := ArchGetAll()
+		if err != nil {
+			data["err"] = "Could not fetch the archs"
+		} else {
+			data["archs"] = archs
+		}
+
+		for i, a := range archs {
+			for _, b := range bot.Archs {
+				if a.ID == b.ID {
+					archs[i].Enabled = true
+				}
+			}
+		}
+
+		// get all bits and set the enable flag on the ones that are enabled in the battle
+		bits, err := BitGetAll()
+		if err != nil {
+			data["err"] = "Could not fetch the bits"
+		} else {
+			data["bits"] = bits
+		}
+
+		for i, a := range bits {
+			for _, b := range bot.Bits {
+				if a.ID == b.ID {
+					bits[i].Enabled = true
+				}
+			}
+		}
+
+		// get the template
+		t, err := template.ParseGlob("./templates/*.html")
+		if err != nil {
+			w.WriteHeader(http.StatusInternalServerError)
+			w.Write([]byte("500 - Error reading template file"))
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		// exec!
+		t.ExecuteTemplate(w, "botSingle", data)
+
+	case "POST":
+		// checking if the user submitting the bot information is allowed to do so
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"].(string)
+
+		// get the user submitting
+		log.Println("Getting the user submitting the change request...")
+		requesting_user, err := UserGetUserFromUsername(username)
+		if err != nil {
+			log.Println("err: ", err)
+			http.Redirect(w, r, fmt.Sprintf("/bot/%d", botid), http.StatusSeeOther)
+			return
+		}
+
+		// get the users the bot belongs
+		log.Println("Getting the user the bot belongs to...")
+		orig_bot, err := BotGetById(int(botid))
+		if err != nil {
+			log.Println("err: ", err)
+			http.Redirect(w, r, fmt.Sprintf("/bot/%d", botid), http.StatusSeeOther)
+			return
+		}
+
+		// check if the user submitting the change request is within the users the bot belongs to
+		log.Println("Checking if edit is allowed...")
+		allowed_to_edit := false
+		for _, user := range orig_bot.Users {
+			if user.ID == requesting_user.ID {
+				allowed_to_edit = true
+			}
+		}
+
+		if allowed_to_edit == false {
+			http.Redirect(w, r, fmt.Sprintf("/bot/%d", botid), http.StatusSeeOther)
+			return
+		}
+
+		// at this point, we're sure the user is allowed to edit the bot
+		r.ParseForm()
+		name := r.Form.Get("name")
+		source := r.Form.Get("source")
+
+		var archIDs []int
+		var bitIDs []int
+
+		for k, _ := range r.Form {
+			if strings.HasPrefix(k, "arch-") {
+				id, err := strconv.Atoi(strings.TrimPrefix(k, "arch-"))
+				if err != nil {
+					msg := "ERROR: Invalid arch id"
+					http.Redirect(w, r, fmt.Sprintf("/bot/%d?res=%s", botid, msg), http.StatusSeeOther)
+					return
+				}
+				archIDs = append(archIDs, id)
+			}
+			if strings.HasPrefix(k, "bit-") {
+				id, err := strconv.Atoi(strings.TrimPrefix(k, "bit-"))
+				if err != nil {
+					msg := "ERROR: Invalid bit id"
+					http.Redirect(w, r, fmt.Sprintf("/bot/%d?res=%s", botid, msg), http.StatusSeeOther)
+					return
+				}
+				bitIDs = append(bitIDs, id)
+			}
+		}
+
+		if len(archIDs) == 0 {
+			msg := "ERROR: Please select an architecture"
+			http.Redirect(w, r, fmt.Sprintf("/bot/%d?res=%s", botid, msg), http.StatusSeeOther)
+			return
+		}
+		if len(archIDs) >= 2 {
+			msg := "ERROR: Please select ONE architecture"
+			http.Redirect(w, r, fmt.Sprintf("/bot/%d?res=%s", botid, msg), http.StatusSeeOther)
+			return
+		}
+
+		if len(bitIDs) == 0 {
+			msg := "ERROR: Please select one of the bits"
+			http.Redirect(w, r, fmt.Sprintf("/bot/%d?res=%s", botid, msg), http.StatusSeeOther)
+			return
+		}
+		if len(bitIDs) >= 2 {
+			msg := "ERROR: Please select ONE of the bits"
+			http.Redirect(w, r, fmt.Sprintf("/bot/%d?res=%s", botid, msg), http.StatusSeeOther)
+			return
+		}
+
+		// link archs to battle
+		err = BotLinkArchIDs(botid, archIDs)
+		if err != nil {
+			log.Println("Error linking the arch ids to the battle: ", err)
+			msg := "ERROR: Could not create due to internal reasons"
+			http.Redirect(w, r, fmt.Sprintf("/bot/%d?res=%s", botid, msg), http.StatusSeeOther)
+			return
+		}
+
+		// link bits to battle
+		err = BotLinkBitIDs(botid, bitIDs)
+		if err != nil {
+			log.Println("Error linking the bit ids to the battle: ", err)
+			msg := "ERROR: Could not create due to internal reasons"
+			http.Redirect(w, r, fmt.Sprintf("/bot/%d?res=%s", botid, msg), http.StatusSeeOther)
+			return
+		}
+
+		if name != "" {
+			if source != "" {
+				log.Println("Updating bot...")
+				err := BotUpdate(botid, name, source)
+				if err != nil {
+					log.Println("err: ", err)
+					w.WriteHeader(http.StatusInternalServerError)
+					w.Write([]byte("500 - Error inserting bot into db"))
+					http.Error(w, err.Error(), http.StatusInternalServerError)
+					return
+				}
+			}
+		}
+
+		http.Redirect(w, r, fmt.Sprintf("/bot/%d", botid), http.StatusSeeOther)
+
+	default:
+		http.Redirect(w, r, "/", http.StatusMethodNotAllowed)
+	}
+}
+
+func botNewHandler(w http.ResponseWriter, r *http.Request) {
+	switch r.Method {
+	case "GET":
+		// define data
+		data := map[string]interface{}{}
+
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"].(string)
+		data["pagelink1"] = Link{Name: "bot", Target: "/bot"}
+		data["pagelink1options"] = []Link{
+			{Name: "user", Target: "/user"},
+			{Name: "battle", Target: "/battle"},
+		}
+		data["pagelink2"] = Link{Name: "new", Target: "/new"}
+		data["pagelink2options"] = []Link{
+			{Name: "list", Target: ""},
+		}
+
+		// display errors passed via query parameters
+		log.Println("[d] Getting previous results")
+		queryres := r.URL.Query().Get("res")
+		if queryres != "" {
+			data["res"] = queryres
+		}
+
+		user, err := UserGetUserFromUsername(username)
+		if err != nil {
+			data["err"] = "Could not fetch the user"
+		} else {
+			data["user"] = user
+		}
+
+		archs, err := ArchGetAll()
+		if err != nil {
+			data["err"] = "Could not fetch the archs"
+		} else {
+			data["archs"] = archs
+		}
+
+		bits, err := BitGetAll()
+		if err != nil {
+			data["err"] = "Could not fetch the bits"
+		} else {
+			data["bits"] = bits
+		}
+
+		// get the template
+		t, err := template.ParseGlob("./templates/*.html")
+		if err != nil {
+			w.WriteHeader(http.StatusInternalServerError)
+			w.Write([]byte("500 - Error reading template file"))
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		// exec!
+		t.ExecuteTemplate(w, "botNew", data)
+
+	case "POST":
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"].(string)
+
+		// parse the post parameters
+		r.ParseForm()
+		log.Println("---")
+		log.Println(r.Form)
+		log.Println("---")
+
+		name := r.Form.Get("name")
+		source := r.Form.Get("source")
+
+		if name == "" {
+			msg := "ERROR: Please provide a name"
+			http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		if source == "" {
+			msg := "ERROR: Please provide some source"
+			http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		var archIDs []int
+		var bitIDs []int
+
+		for k, _ := range r.Form {
+			if strings.HasPrefix(k, "arch-") {
+				id, err := strconv.Atoi(strings.TrimPrefix(k, "arch-"))
+				if err != nil {
+					msg := "ERROR: Invalid arch id"
+					http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+					return
+				}
+				archIDs = append(archIDs, id)
+			}
+			if strings.HasPrefix(k, "bit-") {
+				id, err := strconv.Atoi(strings.TrimPrefix(k, "bit-"))
+				if err != nil {
+					msg := "ERROR: Invalid bit id"
+					http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+					return
+				}
+				bitIDs = append(bitIDs, id)
+			}
+		}
+
+		if len(archIDs) == 0 {
+			msg := "ERROR: Please select an architecture"
+			http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+		if len(archIDs) >= 2 {
+			msg := "ERROR: Please select ONE architecture"
+			http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		if len(bitIDs) == 0 {
+			msg := "ERROR: Please select one of the bits"
+			http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+		if len(bitIDs) >= 2 {
+			msg := "ERROR: Please select ONE of the bits"
+			http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		botid, err := BotCreate(name, source)
+		if err != nil {
+			log.Println("Error creating the bot: ", err)
+			msg := "ERROR: Could not create bot"
+			http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		err = UserLinkBot(username, botid)
+		if err != nil {
+			w.WriteHeader(http.StatusInternalServerError)
+			w.Write([]byte("500 - Error adding the bot to the user"))
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		if len(archIDs) == 0 {
+			msg := "ERROR: Please select an architecture"
+			http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		// link archs to battle
+		err = BotLinkArchIDs(botid, archIDs)
+		if err != nil {
+			log.Println("Error linking the arch ids to the bot: ", err)
+			msg := "ERROR: Could not create due to internal reasons"
+			http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		if len(bitIDs) == 0 {
+			msg := "ERROR: Please select an bits"
+			http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		// link bits to battle
+		err = BotLinkBitIDs(botid, bitIDs)
+		if err != nil {
+			log.Println("Error linking the bit ids to the bot: ", err)
+			msg := "ERROR: Could not create due to internal reasons"
+			http.Redirect(w, r, fmt.Sprintf("/bot/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		http.Redirect(w, r, "/bot", http.StatusSeeOther)
+		return
+	default:
+		http.Redirect(w, r, "/", http.StatusMethodNotAllowed)
+	}
+}