250 lines
7.3 KiB
Go
250 lines
7.3 KiB
Go
package auth
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/go-playground/validator/v10"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
"github.com/gorilla/mux"
|
|
"github.com/markbates/goth"
|
|
"github.com/markbates/goth/gothic"
|
|
"sismedika.com/sas/westone/configs"
|
|
"sismedika.com/sas/westone/types"
|
|
"sismedika.com/sas/westone/utils"
|
|
)
|
|
|
|
type Handler struct {
|
|
store types.OauthStore
|
|
errorz types.ErrorLogStore
|
|
usrStore types.UserStore
|
|
}
|
|
|
|
func NewHandler(store types.OauthStore, errorz types.ErrorLogStore, usrStore types.UserStore) *Handler {
|
|
return &Handler{
|
|
store: store,
|
|
errorz: errorz,
|
|
usrStore: usrStore,
|
|
}
|
|
}
|
|
|
|
func (h *Handler) RegisterRoutes(router *mux.Router) {
|
|
authroute := router.PathPrefix("/auth").Subrouter()
|
|
|
|
authroute.HandleFunc("/generateauthcode", h.handlerGenerateAuthCode).Methods(http.MethodPost)
|
|
|
|
// auth
|
|
authroute.HandleFunc("/login", h.handleLogin).Methods(http.MethodPost)
|
|
// oauth
|
|
authroute.HandleFunc("/{provider}/login", h.handleAuthLogin).Methods(http.MethodGet)
|
|
authroute.HandleFunc("/{provider}/logout", h.handleAuthLogout).Methods(http.MethodGet)
|
|
authroute.HandleFunc("/{provider}/callback", h.handleAuthCallback).Methods(http.MethodGet)
|
|
authroute.HandleFunc("/{provider}/linking", h.handleAuthLinkAccount).Methods(http.MethodPost)
|
|
authroute.HandleFunc("/{provider}/authcode", h.handlerRedirectCode).Methods(http.MethodGet)
|
|
|
|
protec := authroute.PathPrefix("/redirect").Subrouter()
|
|
protec.Use(AuthMiddleware)
|
|
protec.HandleFunc("/dashboard", h.handleRedirectDash).Methods(http.MethodGet)
|
|
}
|
|
|
|
func (h *Handler) handleAuthLogin(w http.ResponseWriter, r *http.Request) {
|
|
if gothUser, err := gothic.CompleteUserAuth(w, r); err == nil {
|
|
// log.Println(gothUser)
|
|
log.Printf("[INFO] account found: %v", gothUser.Email)
|
|
} else {
|
|
gothic.BeginAuthHandler(w, r)
|
|
}
|
|
}
|
|
|
|
func (h *Handler) handleAuthCallback(w http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
provider := vars["provider"]
|
|
|
|
akungoogle, err := gothic.CompleteUserAuth(w, r)
|
|
if err != nil {
|
|
utils.WriteError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
// add user to cookie session
|
|
err = addUsertoSession(w, r, akungoogle)
|
|
if err != nil {
|
|
utils.WriteError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
// check google is linked to server
|
|
userID, err := h.store.CheckGoogleAccountLinked(types.UserGoogle{M_UserGoogleEmail: akungoogle.Email, M_UserGoogleIdentifier: akungoogle.UserID})
|
|
if err != nil {
|
|
utils.WriteError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
if userID > 0 {
|
|
// generate jwt token
|
|
user, err := h.usrStore.GetUserByID(userID)
|
|
if err != nil {
|
|
utils.WriteError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
user.Type_Akun = provider
|
|
timenow := time.Now()
|
|
token, err := CreateJWT(types.DataJWT{
|
|
User: *user,
|
|
Ip: r.RemoteAddr,
|
|
Agent: r.UserAgent(),
|
|
Version: "v1",
|
|
LastLogin: timenow.Format("2006-01-02 15:04:05"),
|
|
})
|
|
if err != nil {
|
|
utils.WriteError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
// data := "Bearer " + token
|
|
// w.Header().Set("Authorization", data)
|
|
// http.Redirect(w, r, "/api/v1/auth/redirect/dashboard", http.StatusFound)
|
|
utils.WriteJSONLogin(w, http.StatusOK, user, token, provider)
|
|
} else {
|
|
log.Println("[INFO] redirect to auth-code")
|
|
// http.Redirect(w, r, "/api/v1/auth/"+provider+"/authcode", http.StatusFound)
|
|
http.Redirect(w, r, configs.Envs.PublicHost+"/auth-code", http.StatusFound)
|
|
}
|
|
}
|
|
|
|
func (h *Handler) handleRedirectDash(w http.ResponseWriter, r *http.Request) {
|
|
claims, ok := r.Context().Value(UserContextKey).(jwt.MapClaims)
|
|
if !ok {
|
|
utils.WriteError(w, http.StatusInternalServerError, fmt.Errorf("token not found in context"))
|
|
return
|
|
}
|
|
|
|
username := claims["Username"].(string)
|
|
temp := "WELCOME TO DASHBOARD, " + username
|
|
utils.WriteJSON(w, http.StatusOK, temp)
|
|
}
|
|
|
|
func (h *Handler) handlerRedirectCode(w http.ResponseWriter, r *http.Request) {
|
|
user_session, _ := store.Get(r, usersession)
|
|
user := user_session.Values["user"].(goth.User)
|
|
if user.IDToken == "" {
|
|
log.Println("[ERROR] token not found in context")
|
|
utils.WriteJSON(w, http.StatusInternalServerError, "not found")
|
|
return
|
|
}
|
|
|
|
temp := "INSERT AUTH CODE, " + user.Email
|
|
utils.WriteJSON(w, http.StatusOK, temp)
|
|
}
|
|
|
|
func (h *Handler) handleAuthLogout(w http.ResponseWriter, r *http.Request) {
|
|
err := gothic.Logout(w, r)
|
|
if err != nil {
|
|
utils.WriteError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
err = removeUsertoSession(w, r)
|
|
if err != nil {
|
|
utils.WriteError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
utils.WriteJSON(w, http.StatusOK, "success logout")
|
|
}
|
|
|
|
func (h *Handler) handlerGenerateAuthCode(w http.ResponseWriter, r *http.Request) {
|
|
var payload types.GenerateAuthCode
|
|
if err := utils.ParseJSON(r, &payload); err != nil {
|
|
utils.WriteError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
if err := utils.Validate.Struct(payload); err != nil {
|
|
errorss := err.(validator.ValidationErrors)
|
|
utils.WriteError(w, http.StatusBadRequest, fmt.Errorf("invalid payload: %v", errorss))
|
|
return
|
|
}
|
|
|
|
err := h.store.GenerateAuthCode(payload.Email, payload.Types, payload.UserID)
|
|
if err != nil {
|
|
log.Println("[ERROR] failed generate auth code")
|
|
utils.WriteJSON(w, http.StatusInternalServerError, "failed generate auth code")
|
|
return
|
|
}
|
|
|
|
msg := "Auth Code Generated for " + payload.Email
|
|
utils.WriteJSON(w, http.StatusOK, msg)
|
|
}
|
|
|
|
func (h *Handler) handleAuthLinkAccount(w http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
provider := vars["provider"]
|
|
|
|
// var payload types.AuthCode
|
|
var payload types.AuthCodePayload
|
|
if err := utils.ParseJSON(r, &payload); err != nil {
|
|
utils.WriteError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
if err := utils.Validate.Struct(payload); err != nil {
|
|
errors := err.(validator.ValidationErrors)
|
|
utils.WriteError(w, http.StatusBadRequest, fmt.Errorf("invalid payload: %v", errors))
|
|
return
|
|
}
|
|
|
|
user_session, _ := store.Get(r, usersession)
|
|
akunGoogle := user_session.Values["user"].(goth.User)
|
|
if akunGoogle.IDToken == "" {
|
|
log.Println("[ERROR] google token not found in context")
|
|
utils.WriteError(w, http.StatusInternalServerError, fmt.Errorf("token not found"))
|
|
return
|
|
}
|
|
|
|
userID, err := h.store.CompareAuthCode(payload.Code, akunGoogle, provider)
|
|
if err != nil {
|
|
log.Println("[ERROR] compare auth code")
|
|
utils.WriteError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
user, err := h.usrStore.GetUserByID(userID)
|
|
if err != nil {
|
|
log.Println("[ERROR] cant get m_user data")
|
|
utils.WriteError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
user.Type_Akun = provider
|
|
timenow := time.Now()
|
|
token, err := CreateJWT(types.DataJWT{
|
|
User: *user,
|
|
Ip: r.RemoteAddr,
|
|
Agent: r.UserAgent(),
|
|
Version: "v1",
|
|
LastLogin: timenow.Format("2006-01-02 15:04:05"),
|
|
})
|
|
if err != nil {
|
|
utils.WriteError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
err = h.store.AddGoolgeAccount(types.UserGoogle{
|
|
M_UserGoogleM_UserID: user.M_UserID,
|
|
M_UserGoogleEmail: akunGoogle.Email,
|
|
M_UserGoogleIdentifier: akunGoogle.UserID,
|
|
M_UserGoogleCode: payload.Code,
|
|
M_UserGoogleToken: token,
|
|
})
|
|
if err != nil {
|
|
log.Printf("[ERROR] failed insert google account to db, %v", err)
|
|
utils.WriteError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
utils.WriteJSONLogin(w, http.StatusOK, user, token, provider)
|
|
}
|