Skip to content

Commit

Permalink
added signup endpoint for web access
Browse files Browse the repository at this point in the history
  • Loading branch information
yakuter committed Jun 6, 2020
1 parent a178969 commit 734d4ec
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 28 deletions.
77 changes: 77 additions & 0 deletions internal/api/signup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package api

import (
"encoding/json"
"net/http"

"github.com/go-playground/validator/v10"
"github.com/pass-wall/passwall-server/internal/app"
"github.com/pass-wall/passwall-server/internal/storage"
"github.com/pass-wall/passwall-server/model"
)

const (
SignupSuccess = "User created successfully"
)

// Signup ...
func Signup(s storage.Store) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {

userDTO := new(model.UserDTO)

// 1. Decode request body to userDTO object
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&userDTO); err != nil {
RespondWithError(w, http.StatusBadRequest, "Invalid resquest payload")
return
}
defer r.Body.Close()

// 2. Run validator according to model.UserDTO validator tags
validate := validator.New()
validateError := validate.Struct(userDTO)
if validateError != nil {
errs := GetErrors(validateError.(validator.ValidationErrors))
RespondWithErrors(w, http.StatusBadRequest, InvalidRequestPayload, errs)
return
}

// 3. Check if user exist in database
_, err := s.Users().FindByEmail(userDTO.Email)
if err == nil {
errs := []string{"This email is already used!"}
message := "User couldn't created!"
RespondWithErrors(w, http.StatusBadRequest, message, errs)
return
}

// 4. Create new user
createdUser, err := app.CreateUser(s, userDTO)
if err != nil {
RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}

// 5. Update user once to generate schema
updatedUser, err := app.UpdateUser(s, createdUser, userDTO, false)
if err != nil {
RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}

// 6. Migrate user specific tables in user's schema
err = s.Users().Migrate(updatedUser.Schema)
if err != nil {
RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}

response := model.Response{
Code: http.StatusOK,
Status: Success,
Message: SignupSuccess,
}
RespondWithJSON(w, http.StatusOK, response)
}
}
26 changes: 2 additions & 24 deletions internal/api/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ package api

import (
"encoding/json"
"fmt"
"net/http"
"strconv"

"github.com/go-playground/validator/v10"
"github.com/pass-wall/passwall-server/internal/app"
"github.com/pass-wall/passwall-server/internal/storage"
"github.com/pass-wall/passwall-server/model"
uuid "github.com/satori/go.uuid"

"github.com/gorilla/mux"
)
Expand Down Expand Up @@ -94,28 +92,14 @@ func CreateUser(s storage.Store) http.HandlerFunc {
}

// 4. Create new user
// Hasing the master password with SHA256
userDTO.MasterPassword = app.NewSHA256([]byte(userDTO.MasterPassword))

// All new users are free member and Member (not Admin)
userDTO.Plan = "Free"
userDTO.Role = "Member"

// Generate new UUID for user
userDTO.UUID = uuid.NewV4()

createdUser, err := app.CreateUser(s, userDTO)
if err != nil {
RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}

// 5. Generate Schema and update user Schema field
// TODO: I am not sure if we need this schema field
isAuthorized := r.Context().Value("authorized").(bool)
userDTO.Schema = fmt.Sprintf("user%d", createdUser.ID)
fmt.Println(userDTO.Schema)
updatedUser, err := app.UpdateUser(s, createdUser, userDTO, isAuthorized)
// 5. Update user once to generate schema
updatedUser, err := app.UpdateUser(s, createdUser, userDTO, true)
if err != nil {
RespondWithError(w, http.StatusInternalServerError, err.Error())
return
Expand All @@ -132,7 +116,6 @@ func CreateUser(s storage.Store) http.HandlerFunc {
}
}

// TODO:
// UpdateUser ...
func UpdateUser(s storage.Store) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -161,11 +144,6 @@ func UpdateUser(s storage.Store) http.HandlerFunc {
return
}

// claims := token.Claims.(jwt.MapClaims)
// fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])

// atClaims["authorized"] = true

// Check if user exist in database with new email address
if userDTO.Email != user.Email {
_, err := s.Users().FindByEmail(userDTO.Email)
Expand Down
21 changes: 18 additions & 3 deletions internal/app/user.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
package app

import (
"fmt"

"github.com/pass-wall/passwall-server/internal/storage"
"github.com/pass-wall/passwall-server/model"
uuid "github.com/satori/go.uuid"
)

// CreateUser creates a user and saves it to the store
func CreateUser(s storage.Store, dto *model.UserDTO) (*model.User, error) {
func CreateUser(s storage.Store, userDTO *model.UserDTO) (*model.User, error) {

// Hasing the master password with SHA256
userDTO.MasterPassword = NewSHA256([]byte(userDTO.MasterPassword))

// New user's plan is Free and role is Member (not Admin)
userDTO.Plan = "Free"
userDTO.Role = "Member"

createdUser, err := s.Users().Save(model.ToUser(dto))
// Generate new UUID for user
userDTO.UUID = uuid.NewV4()

createdUser, err := s.Users().Save(model.ToUser(userDTO))
if err != nil {
return nil, err
}
Expand All @@ -27,7 +40,9 @@ func UpdateUser(s storage.Store, user *model.User, userDTO *model.UserDTO, isAut
user.Name = userDTO.Name
user.Email = userDTO.Email
user.MasterPassword = userDTO.MasterPassword
user.Schema = userDTO.Schema

// This never changes
user.Schema = fmt.Sprintf("user%d", user.ID)

// Only Admin's can change plan and role
if isAuthorized {
Expand Down
10 changes: 9 additions & 1 deletion internal/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ func (r *Router) initRoutes() {
authRouter.HandleFunc("/refresh", api.RefreshToken(r.store))
authRouter.HandleFunc("/check", api.CheckToken(r.store))

// Web public endpoints
webRouter := mux.NewRouter().PathPrefix("/web").Subrouter()
webRouter.HandleFunc("/signup", api.Signup(r.store)).Methods(http.MethodPost)

n := negroni.Classic()
n.Use(negroni.HandlerFunc(CORS))
n.Use(negroni.HandlerFunc(Secure))
Expand All @@ -106,11 +110,15 @@ func (r *Router) initRoutes() {
))

r.router.PathPrefix("/auth").Handler(n.With(

LimitHandler(),
negroni.Wrap(authRouter),
))

r.router.PathPrefix("/web").Handler(n.With(
LimitHandler(),
negroni.Wrap(webRouter),
))

// Insecure endpoints
r.router.HandleFunc("/health", api.HealthCheck(r.store)).Methods(http.MethodGet)

Expand Down

0 comments on commit 734d4ec

Please sign in to comment.