package api import ( "context" "crypto/sha256" "database/sql" "encoding/hex" "encoding/json" "log" "time" "code.lila.network/adoralaura/go-urlsh/internal/constants" "code.lila.network/adoralaura/go-urlsh/internal/db" "code.lila.network/adoralaura/go-urlsh/internal/misc" "code.lila.network/adoralaura/go-urlsh/models" "github.com/gofiber/fiber/v2" ) func (am APIRouteManager) HandleUserPost(c *fiber.Ctx) error { var newuser models.LoginRequest err := json.Unmarshal(c.Body(), &newuser) if err != nil { log.Println(err.Error()) return fiber.NewError(fiber.StatusBadRequest, "400 Bad Request") } usercount, err := am.db.NewSelect().Model((*models.User)(nil)).Count(context.Background()) if err != nil { log.Printf("[POST /api/v1/users] Error querying database for users: %v\n", err.Error()) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } if usercount != 0 { log.Printf("[POST /api/v1/users] someone trying to create user but user already exists\n") return fiber.NewError(fiber.StatusUnauthorized, "401 Unauthorized") } else { salt := misc.RandomString(15) created := time.Now() hashbytes := sha256.Sum256([]byte(salt + newuser.Password)) hash := hex.EncodeToString(hashbytes[:]) user := new(models.User) user.UserName = newuser.Username user.PasswordSalt = salt user.PasswordHash = hash user.Created = created _, err = am.db.NewInsert().Model(user).Exec(context.Background()) if err != nil { log.Printf("[POST /api/v1/users] Error adding user %v to database : %v\n", newuser.Username, err.Error()) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } userresponse := models.UserResponse{UserName: newuser.Username, Created: created, MFAEnabled: false} c.Status(fiber.StatusCreated) err = c.JSON(userresponse) if err != nil { log.Println(err) } return nil } } func (am APIRouteManager) HandleUserMe(c *fiber.Ctx) error { if !db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) && !db.IsApiKeyValid(c.GetRespHeader("x-api-key", "")) { return fiber.NewError(fiber.StatusUnauthorized, "401 Unauthorized") } cookie := c.Cookies(constants.LoginCookieName, "") apikey := c.GetRespHeader("x-api-key", "") var authmethod string var user models.User if cookie != "" { authmethod = "cookie" } else { authmethod = "apikey" } switch authmethod { case "cookie": var session models.Session err := am.db.NewSelect().Model(&session).Where("cookie = ?", cookie).Scan(context.Background()) if err != nil { if err == sql.ErrNoRows { log.Printf("[GET /api/v1/users/me] Session %v not found\n", cookie) } else { log.Printf("[GET /api/v1/users/me] Error querying session %v from database: %v\n", cookie, err) } return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } err = am.db.NewSelect().Model(&user).Where("username = ?", session.UserName).Scan(context.Background()) if err != nil { log.Printf("[GET /api/v1/users/me] Error querying user %v from database: %v\n", session.UserName, err) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } case "apikey": var key models.ApiKey err := am.db.NewSelect().Model(&key).Where("key = ?", apikey).Scan(context.Background()) if err != nil { if err == sql.ErrNoRows { log.Printf("[GET /api/v1/users/me] ApiKey %v not found\n", apikey) } else { log.Printf("[GET /api/v1/users/me] Error querying apikey %v from database: %v\n", apikey, err) } return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } err = am.db.NewSelect().Model(&user).Where("username = ?", key.UserName).Scan(context.Background()) if err != nil { log.Printf("[GET /api/v1/users/me] Error querying user %v from database: %v\n", key.UserName, err) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } } var userresponse = new(models.UserResponse) userresponse.UserName = user.UserName userresponse.Created = user.Created hasmfa, err := db.UserHasMFA(user) if err != nil { log.Printf("[GET /api/v1/users/me] Error checking MFA status: %q\n", err) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } userresponse.MFAEnabled = hasmfa err = c.JSON(userresponse) if err != nil { log.Printf("[GET /api/v1/users/me] Error marshaling JSON response: %q\n", err) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } return nil }