Files
ris-backend-go/services/auth/oauth.routes.go
2024-12-09 09:51:19 +07:00

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)
}