207 lines
4.8 KiB
Go
207 lines
4.8 KiB
Go
/* Copyright © INFINI Ltd. All rights reserved.
|
|
* web: https://infinilabs.com
|
|
* mail: hello#infini.ltd */
|
|
|
|
package api
|
|
|
|
import (
|
|
"fmt"
|
|
"golang.org/x/crypto/bcrypt"
|
|
rbac "infini.sh/console/core/security"
|
|
"infini.sh/console/modules/security/realm"
|
|
"infini.sh/framework/core/api"
|
|
httprouter "infini.sh/framework/core/api/router"
|
|
"infini.sh/framework/core/util"
|
|
"net/http"
|
|
)
|
|
|
|
const userInSession = "user_session:"
|
|
|
|
// const SSOProvider = "sso"
|
|
const NativeProvider = "native"
|
|
|
|
//const LDAPProvider = "ldap"
|
|
|
|
func (h APIHandler) Logout(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
reqUser, err := rbac.FromUserContext(r.Context())
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
|
|
rbac.DeleteUserToken(reqUser.UserId)
|
|
h.WriteOKJSON(w, util.MapStr{
|
|
"status": "ok",
|
|
})
|
|
}
|
|
|
|
func (h APIHandler) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
reqUser, err := rbac.FromUserContext(r.Context())
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
|
|
if reqUser.Provider == NativeProvider {
|
|
user, err := h.User.Get(reqUser.UserId)
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
if user.Nickname == "" {
|
|
user.Nickname = user.Username
|
|
}
|
|
|
|
u := util.MapStr{
|
|
"user_id": user.ID,
|
|
"name": user.Username,
|
|
"email": user.Email,
|
|
"nick_name": user.Nickname,
|
|
"phone": user.Phone,
|
|
}
|
|
|
|
h.WriteOKJSON(w, api.FoundResponse(reqUser.UserId, u))
|
|
} else {
|
|
|
|
//TODO fetch external profile
|
|
|
|
u := util.MapStr{
|
|
"user_id": reqUser.UserId,
|
|
"name": reqUser.Username,
|
|
"email": "", //TOOD, save user profile come from SSO
|
|
"nick_name": reqUser.Username, //TODO
|
|
"phone": "", //TODO
|
|
}
|
|
h.WriteOKJSON(w, api.FoundResponse(reqUser.UserId, u))
|
|
}
|
|
|
|
}
|
|
|
|
func (h APIHandler) UpdatePassword(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
reqUser, err := rbac.FromUserContext(r.Context())
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
var req struct {
|
|
OldPassword string `json:"old_password"`
|
|
NewPassword string `json:"new_password"`
|
|
}
|
|
err = h.DecodeJSON(r, &req)
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
|
|
user, err := h.User.Get(reqUser.UserId)
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.OldPassword))
|
|
if err == bcrypt.ErrMismatchedHashAndPassword {
|
|
h.ErrorInternalServer(w, "old password is not correct")
|
|
return
|
|
}
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
user.Password = string(hash)
|
|
err = h.User.Update(&user)
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
h.WriteOKJSON(w, api.UpdateResponse(reqUser.UserId))
|
|
return
|
|
}
|
|
|
|
func (h APIHandler) UpdateProfile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
reqUser, err := rbac.FromUserContext(r.Context())
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
var req struct {
|
|
Name string `json:"name"`
|
|
Phone string `json:"phone"`
|
|
Email string `json:"email"`
|
|
}
|
|
err = h.DecodeJSON(r, &req)
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
user, err := h.User.Get(reqUser.UserId)
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
user.Username = req.Name
|
|
user.Email = req.Email
|
|
user.Phone = req.Phone
|
|
err = h.User.Update(&user)
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
h.WriteOKJSON(w, api.UpdateResponse(reqUser.UserId))
|
|
return
|
|
}
|
|
|
|
func (h APIHandler) Login(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
var req struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
err := h.DecodeJSON(r, &req)
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, err.Error())
|
|
return
|
|
}
|
|
|
|
var user *rbac.User
|
|
|
|
//check user validation
|
|
ok, user, err := realm.Authenticate(req.Username, req.Password)
|
|
if err != nil {
|
|
h.WriteError(w, err.Error(), 500)
|
|
return
|
|
}
|
|
|
|
if !ok {
|
|
h.WriteError(w, "invalid username or password", 403)
|
|
return
|
|
}
|
|
|
|
if user == nil {
|
|
h.ErrorInternalServer(w, fmt.Sprintf("failed to authenticate user: %v", req.Username))
|
|
return
|
|
}
|
|
|
|
//check permissions
|
|
ok, err = realm.Authorize(user)
|
|
if err != nil || !ok {
|
|
h.ErrorInternalServer(w, fmt.Sprintf("failed to authorize user: %v", req.Username))
|
|
return
|
|
}
|
|
|
|
//fetch user profile
|
|
//TODO
|
|
if user.Nickname == "" {
|
|
user.Nickname = user.Username
|
|
}
|
|
|
|
//generate access token
|
|
token, err := rbac.GenerateAccessToken(user)
|
|
if err != nil {
|
|
h.ErrorInternalServer(w, fmt.Sprintf("failed to authorize user: %v", req.Username))
|
|
return
|
|
}
|
|
|
|
//api.SetSession(w, r, userInSession+req.Username, req.Username)
|
|
h.WriteOKJSON(w, token)
|
|
}
|