package controllers import ( "fmt" "multitenantStack/models" companydb "multitenantStack/services/companydb" "strings" constants "multitenantStack/constants" tokenTools "multitenantStack/services/tokenTools" "time" "github.com/astaxie/beego/orm" jwt "github.com/dgrijalva/jwt-go" "github.com/kennygrant/sanitize" ) // AuthController operations for Auth type AuthController struct { BaseController } // AuthResponse the format for all responses from auth type AuthResponse struct { Status int `json:"status"` Jwt string `json:"jwt"` User models.CompanyUser `json:"user"` } // URLMapping ... func (c *AuthController) URLMapping() { // This block is used to drastically speed up the annotation -> lookup process c.Mapping("Login", c.Login) c.Mapping("Register", c.Register) } // Login Get a JWT token for the user // @Title Create // @Description create Auth // @Param body body models.Auth true "body for Auth content" // @Success 201 {object} models.Auth // @Failure 403 body is empty // @router /login [post] func (c *AuthController) Login() { if c.Ctx.Input.Method() != "POST" { c.ServeJSONError("Method not allowed") return } tokenHeader := c.Ctx.Request.Header.Get("X-JWTtoken") if tokenHeader != "" { valid, _ := tokenTools.Validate(tokenHeader) if valid { c.ServeJSONError("You are already logged in") return } } email := c.GetString("email") password := c.GetString("password") if email == "" || password == "" { c.ServeJSONError("Email/Password missing") return } systemdb := companydb.GetSystemDatabase() if systemdb == nil { c.ServeJSONError("Error retrieving User") return } o, err := orm.NewOrmWithDB("postgres", "default", systemdb) if err != nil { c.ServeJSONError("Error retrieving User") return } userCompanyMapping, err := models.GetUserCompanyMapByEmail(o, email) if err != nil { c.ServeJSONError("Error retrieving User") return } if !tokenTools.CheckPasswordHash(password, userCompanyMapping.PasswordHash) { c.ServeJSONError("Email/Password incorrect") return } companyName := userCompanyMapping.Company companyUserID := userCompanyMapping.CompanyUserID db, err := companydb.GetDatabaseWithName(companyName) if err != nil { c.ServeJSONError("Error retrieving Company") return } o, err = orm.NewOrmWithDB("postgres", "default", db) if err != nil { c.ServeJSONError("Error retrieving CompanyData") return } companyUser, err := models.GetCompanyUserById(o, int(companyUserID)) if err != nil { c.ServeJSONError("Error retrieving Company User") return } tokenString := "" // The jwtClaims are our trusted clientside session tokenString = tokenTools.CreateToken(jwt.MapClaims{ "email": email, "companyName": companyName, "companyUserID": companyUserID, "exp": time.Now().Unix() + 3600, }) json := AuthResponse{200, tokenString, *companyUser} c.Data["json"] = &json c.ServeJSON() } // Register Register a new company and user, create DB and so on // @Title Create // @Description create Auth // @Param body body models.Auth true "body for Auth content" // @Success 201 {object} models.Auth // @Failure 403 body is empty // @router /register [post] func (c *AuthController) Register() { // can be called without jwt token set // needed data: // email // password // companyname // optional: username // Tasks: // create database // create user_company_map entry // create company user // return jwt token and user profile if c.Ctx.Input.Method() != "POST" { c.ServeJSONError("Method not allowed") return } tokenHeader := c.Ctx.Request.Header.Get("X-JWTtoken") if tokenHeader != "" { valid, _ := tokenTools.Validate(tokenHeader) if valid { c.ServeJSONError("You are already logged in") return } } email := c.GetString("email") password := c.GetString("password") username := c.GetString("username") companyname := c.GetString("companyname") companyname = sanitize.BaseName(companyname) companyname = strings.ToLower(companyname) companyname = fmt.Sprintf("company_%s", companyname) if email == "" || password == "" || companyname == "" || username == "" { c.ServeJSONError("Email/Password/Companyname missing") return } systemdb := companydb.GetSystemDatabase() if systemdb == nil { c.ServeJSONError("Error retrieving data") return } o, err := orm.NewOrmWithDB("postgres", "default", systemdb) if err != nil { c.ServeJSONError("Error retrieving data") return } ucmExists, err := models.GetUserCompanyMapByEmail(o, email) if ucmExists != nil { fmt.Println(ucmExists) c.ServeJSONError("Error: Email exists!") return } if companydb.HasDatabase(companyname) { c.ServeJSONError("Error: Company exists!") return } var userCompanyMapping models.UserCompanyMap newHash, _ := tokenTools.HashPassword(password) userCompanyMapping.PasswordHash = newHash userCompanyMapping.Company = companyname userCompanyMapping.Email = email ucmID, err := models.AddUserCompanyMap(o, &userCompanyMapping) if err != nil { c.ServeJSONErrorWithError("Error on saving user", err) return } // Create company newDB, err := companydb.CreateDatabase(companyname) if err != nil { c.ServeJSONErrorWithError("Error on creating DB", err) return } newO, err := orm.NewOrmWithDB("postgres", "default", newDB) if err != nil { c.ServeJSONErrorWithError("Error retrieving company data", err) return } var companyUser models.CompanyUser companyUser.Name = username companyUser.Profile = "{}" companyUser.Role = constants.RoleOwner userID, err := models.AddCompanyUser(newO, &companyUser) if err != nil { c.ServeJSONError("Error on saving company user") return } // edit usermapping userCompanyMapping.ID = int(ucmID) userCompanyMapping.CompanyUserID = int16(userID) if err := models.UpdateUserCompanyMapById(o, &userCompanyMapping); err != nil { c.ServeJSONError("Error on saving user") return } tokenString := "" tokenString = tokenTools.CreateToken(jwt.MapClaims{ "email": email, "companyName": companyname, "companyUserID": userCompanyMapping.CompanyUserID, "exp": time.Now().Unix() + 3600, }) json := AuthResponse{200, tokenString, companyUser} c.Data["json"] = &json c.ServeJSON() }