Exemple #1
0
// ValidateAuth validates that the user cookie is set up before calling the
// handler passed as parameter.
func ValidateAuth(h httputils.ContextHandler) httputils.ContextHandler {
	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		var (
			sessionData *httputils.SessionData
			err         error
			ok          bool
			cookieStore *sessions.CookieStore
			session     *sessions.Session
			cfg         = ctx.Value("config").(*config.Config)
		)

		cookieStore, ok = ctx.Value("cookieStore").(*sessions.CookieStore)

		if !ok {
			httputils.WriteError(w, http.StatusInternalServerError, "")
			return fmt.Errorf("validate auth: could not cast value as cookie store: %s", ctx.Value("cookieStore"))
		}

		session, err = cookieStore.Get(r, cfg.SessionCookieName)

		if err != nil {
			log.Println(err)
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
			return nil
		}

		sessionData, ok = session.Values["data"].(*httputils.SessionData)

		if !ok || sessionData.IsInvalid() {
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
			return nil
		} else if time.Now().After(sessionData.ExpiresAt) {
			session.Options.MaxAge = -1
			session.Save(r, w)
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)

			return nil
		}

		// Extend the session's lifetime.
		cfg, ok = ctx.Value("config").(*config.Config)

		if !ok {
			httputils.WriteError(w, http.StatusInternalServerError, "")
			return fmt.Errorf("validate auth: error casting config object: %s", ctx.Value("config"))
		}

		// Save session only if the session was extended.
		if extendSessionLifetime(sessionData, cfg.SessionLifeTime) {
			sessionData.ExpiresAt = time.Now().Add(cfg.SessionLifeTime)
			session.Save(r, w)
		}

		authenticatedContext := context.WithValue(ctx, "sessionData", sessionData)
		return h(authenticatedContext, w, r)
	}
}
Exemple #2
0
// FindByIDNumber finds student by honduran Id number or passport number.
func (h *handler) FindByIDNumber(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	var (
		err      error
		idNumber string
		vars     = mux.Vars(r)
	)

	type MappedStudent struct {
		ID           int       `json:"id"`
		IDNumber     string    `json:"idNumber"`
		FirstName    string    `json:"firstName"`
		LastName     string    `json:"lastName"`
		Email        string    `json:"email"`
		Status       int       `json:"status"`
		PlaceOfBirth string    `json:"placeOfBirth"`
		Address      string    `json:"address"`
		Birthdate    time.Time `json:"birthdate"`
		Gender       bool      `json:"gender"`
		Nationality  string    `json:"nationality"`
		PhoneNumber  string    `json:"phoneNumber"`
	}

	idNumber = vars["idNumber"]

	if idNumber == "" {
		httputils.WriteError(w, http.StatusBadRequest, "")
		return err
	}

	student, err := h.studentService.FindByIDNumber(idNumber)

	if err != nil {
		return err
	} else if student == nil {
		httputils.WriteError(w, http.StatusNotFound, "")
		return nil
	}

	response := &MappedStudent{
		ID:           student.ID,
		IDNumber:     student.IDNumber,
		FirstName:    student.FirstName,
		LastName:     student.LastName,
		Email:        student.Email,
		Status:       student.Status,
		PlaceOfBirth: student.PlaceOfBirth,
		Address:      student.Address,
		Birthdate:    student.Birthdate,
		Gender:       student.Gender,
		Nationality:  student.Nationality,
		PhoneNumber:  student.PhoneNumber,
	}

	return httputils.WriteJSON(w, http.StatusOK, response)
}
Exemple #3
0
// Edit a student.
func (h *handler) Edit(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	var (
		err error

		payload struct {
			ID           int
			IDNumber     string
			FirstName    string
			LastName     string
			Email        string
			PlaceOfBirth string
			Address      string
			Birthdate    time.Time
			Gender       bool
			Nationality  string
			PhoneNumber  string
		}
	)

	type Response struct {
		Success      bool   `json:"success"`
		ErrorMessage string `json:"errorMessage"`
	}

	if err = httputils.DecodeJSON(r.Body, &payload); err != nil {
		httputils.WriteError(w, http.StatusBadRequest, "")
		return nil
	}

	student := &models.Student{
		ID:           payload.ID,
		IDNumber:     payload.IDNumber,
		FirstName:    payload.FirstName,
		LastName:     payload.LastName,
		Email:        payload.Email,
		PlaceOfBirth: payload.PlaceOfBirth,
		Address:      payload.Address,
		Birthdate:    payload.Birthdate,
		Gender:       payload.Gender,
		Nationality:  payload.Nationality,
		PhoneNumber:  payload.PhoneNumber,
	}

	err = h.studentService.Edit(student)
	if err != nil {
		if err == services.ErrDuplicatedStudentIDNumber {
			return httputils.WriteJSON(w, http.StatusOK, &Response{
				Success:      false,
				ErrorMessage: "El número de cédula o pasaporte ya existe!",
			})
		}

		return err
	}

	return httputils.WriteJSON(w, http.StatusOK, &Response{
		Success: true,
	})
}
Exemple #4
0
// FindByID finds a single user by UserID.
func (h *handler) FindByID(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	var (
		err    error
		userID int
		vars   = mux.Vars(r)
	)

	type MappedUser struct {
		ID        int    `json:"id"`
		Username  string `json:"username"`
		Email     string `json:"email"`
		FirstName string `json:"firstName"`
		LastName  string `json:"lastName"`
		Status    int    `json:"status"`
		IsAdmin   bool   `json:"isAdmin"`
		IsTeacher bool   `json:"isTeacher"`
	}

	userID, err = strconv.Atoi(vars["id"])

	if err != nil {
		httputils.WriteError(w, http.StatusBadRequest, "")
		return err
	}

	user, err := h.userService.FindByID(userID)
	if err != nil {
		return err
	} else if user == nil {
		httputils.WriteError(w, http.StatusNotFound, "")
		return nil
	}

	response := &MappedUser{
		ID:        user.ID,
		Username:  user.Username,
		Email:     user.Email,
		FirstName: user.FirstName,
		LastName:  user.LastName,
		Status:    user.Status,
		IsAdmin:   user.IsAdmin,
		IsTeacher: user.IsTeacher,
	}

	return httputils.WriteJSON(w, http.StatusOK, response)
}
Exemple #5
0
// FindByID finds a Student by Id.
func (h *handler) FindByID(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	var (
		err       error
		studentID int
		vars      = mux.Vars(r)
	)

	type MappedStudent struct {
		ID        int       `json:"id"`
		Email     string    `json:"email"`
		FirstName string    `json:"firstName"`
		LastName  string    `json:"lastName"`
		Status    int       `json:"status"`
		CreatedAt time.Time `json:"createdAt"`
	}

	studentID, err = strconv.Atoi(vars["id"])

	if err != nil {
		httputils.WriteError(w, http.StatusBadRequest, "")
		return nil
	}

	student, err := h.studentService.FindByID(studentID)
	if err != nil {
		return err
	} else if student == nil {
		httputils.WriteError(w, http.StatusNotFound, "")
		return nil
	}

	response := &MappedStudent{
		ID:        student.ID,
		Email:     student.Email,
		FirstName: student.FirstName,
		LastName:  student.LastName,
		Status:    student.Status,
		CreatedAt: student.CreatedAt,
	}

	return httputils.WriteJSON(w, http.StatusOK, response)
}
Exemple #6
0
// HandleHTTPError sets the appropriate headers to the response if a http
// handler returned an error. This might be used in the future if different
// types of errors are returned.
func HandleHTTPError(h httputils.ContextHandler) httputils.ContextHandler {
	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		err := h(ctx, w, r)

		if err != nil {
			httputils.WriteError(w, http.StatusInternalServerError, "")
		}

		return err
	}
}
Exemple #7
0
// Authorize validates privileges for the current user. Each route must have
// an array of privileges that point which users can make a call to it.
//
// Note:
//
// It is assumed that ValidateAuth was called before this function, or at
// least some other session check was done before this.
func Authorize(h httputils.ContextHandler) httputils.ContextHandler {
	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		var (
			requiredRoles []string
			sessionData   *httputils.SessionData
			route         routes.Route
			ok            bool
		)

		sessionData, ok = ctx.Value("sessionData").(*httputils.SessionData)

		if !ok {
			httputils.WriteError(w, http.StatusInternalServerError, "")
			return fmt.Errorf("authorize: could not cast value as session data: %s", ctx.Value("sessionData"))
		}

		route, ok = ctx.Value("route").(routes.Route)

		if !ok {
			httputils.WriteError(w, http.StatusInternalServerError, "")
			return fmt.Errorf("authorize: could not cast value as route: %s", ctx.Value("route"))
		}

		requiredRoles = route.RequiredRoles()

		if len(requiredRoles) == 0 {
			return h(ctx, w, r)
		}

		for _, role := range requiredRoles {
			if role == "ADMIN" && sessionData.IsAdmin {
				return h(ctx, w, r)
			} else if role == "TEACHER" && sessionData.IsTeacher {
				return h(ctx, w, r)
			}
		}

		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
		return nil
	}
}
Exemple #8
0
// Edit a user.
func (h *handler) Edit(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	var (
		err error

		payload struct {
			ID        int
			Username  string
			Email     string
			FirstName string
			LastName  string
			Status    int
			IsAdmin   bool
			IsTeacher bool
		}
	)

	type Response struct {
		Success      bool   `json:"success"`
		ErrorMessage string `json:"errorMessage"`
	}

	if err = httputils.DecodeJSON(r.Body, &payload); err != nil {
		httputils.WriteError(w, http.StatusBadRequest, "")
		return nil
	}

	user := &models.User{
		ID:        payload.ID,
		Username:  payload.Username,
		Email:     payload.Email,
		FirstName: payload.FirstName,
		LastName:  payload.LastName,
		Status:    payload.Status,
		IsAdmin:   payload.IsAdmin,
		IsTeacher: payload.IsTeacher,
	}

	err = h.userService.Edit(user)
	if err != nil {
		if err == services.ErrDuplicatedUsername {
			return httputils.WriteJSON(w, http.StatusOK, &Response{
				Success:      false,
				ErrorMessage: "El nombre de usuario ya existe!",
			})
		}

		return err
	}

	return httputils.WriteJSON(w, http.StatusOK, &Response{
		Success: true,
	})
}
Exemple #9
0
// Login does basic email/password login.
// Checks:
// 		- User must exist
//		- Passwords match
//		- User's status is Active
//
// If the checks pass, it sets up a session cookie.
func (h *handler) Login(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	var (
		cookieStore = ctx.Value("cookieStore").(*sessions.CookieStore)
		err         error

		loginForm struct {
			Identifier string
			Password   string
		}
	)

	if err = httputils.DecodeJSON(r.Body, &loginForm); err != nil {
		httputils.WriteError(w, http.StatusBadRequest, "")
		return nil
	}

	user, err := h.authService.BasicAuth(loginForm.Identifier, loginForm.Password)

	if err != nil {
		httputils.WriteError(w, http.StatusInternalServerError, "")
		return nil
	} else if user == nil {
		httputils.WriteError(w, http.StatusUnauthorized, "Usuario/clave inválidos")
		return nil
	}

	session, _ := cookieStore.New(r, h.cfg.SessionCookieName)
	session.Values["data"] = &httputils.SessionData{
		UserID:    user.ID,
		Email:     user.Email,
		IsAdmin:   user.IsAdmin,
		IsTeacher: user.IsTeacher,
		ExpiresAt: time.Now().Add(h.cfg.SessionLifeTime),
	}

	return session.Save(r, w)
}
Exemple #10
0
// Delete user.
func (h *handler) Delete(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	var (
		err error

		payload struct {
			UserID int
		}
	)

	if err = httputils.DecodeJSON(r.Body, &payload); err != nil {
		httputils.WriteError(w, http.StatusBadRequest, "")
		return nil
	}

	err = h.userService.Delete(payload.UserID)
	if err != nil {
		return err
	}

	return httputils.WriteJSON(w, http.StatusOK, nil)
}
Exemple #11
0
// ChangePasswordForCurrentUser changes the logged user's password.
func (h *handler) ChangePasswordForCurrentUser(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	var (
		err            error
		sessionData, _ = ctx.Value("sessionData").(*httputils.SessionData)

		payload struct {
			NewPassword string
		}
	)

	if err = httputils.DecodeJSON(r.Body, &payload); err != nil {
		httputils.WriteError(w, http.StatusBadRequest, "")
		return nil
	}

	err = h.userService.ChangePassword(sessionData.UserID, payload.NewPassword)
	if err != nil && err != services.ErrRecordNotFound {
		return err
	}

	return httputils.WriteJSON(w, http.StatusOK, nil)
}
Exemple #12
0
// ChangePassword changes a user's password.
func (h *handler) ChangePassword(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	var (
		err error

		payload struct {
			UserID      int
			NewPassword string
		}
	)

	if err = httputils.DecodeJSON(r.Body, &payload); err != nil {
		httputils.WriteError(w, http.StatusBadRequest, "")
		return nil
	}

	err = h.userService.ChangePassword(payload.UserID, payload.NewPassword)
	if err != nil && err != services.ErrRecordNotFound {
		return err
	}

	return httputils.WriteJSON(w, http.StatusOK, nil)
}
Exemple #13
0
// GetProfileForCurrentUser retrieves the logged user's information.
func (h *handler) GetProfileForCurrentUser(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	sessionData, _ := ctx.Value("sessionData").(*httputils.SessionData)

	type Response struct {
		ID        int    `json:"id"`
		Username  string `json:"username"`
		Email     string `json:"email"`
		FirstName string `json:"firstName"`
		LastName  string `json:"lastName"`
		Status    int    `json:"status"`
		IsAdmin   bool   `json:"isAdmin"`
		IsTeacher bool   `json:"isTeacher"`
	}

	user, err := h.userService.FindByID(sessionData.UserID)

	if err != nil {
		return err
	} else if user == nil {
		httputils.WriteError(w, http.StatusNotFound, "")
		return nil
	}

	response := &Response{
		ID:        user.ID,
		Username:  user.Username,
		Email:     user.Email,
		FirstName: user.FirstName,
		LastName:  user.LastName,
		Status:    user.Status,
		IsAdmin:   user.IsAdmin,
		IsTeacher: user.IsTeacher,
	}

	return httputils.WriteJSON(w, http.StatusOK, response)
}