mirror of
https://github.com/khairul169/vaulterm.git
synced 2026-09-15 17:03:30 +07:00
feat: add gitlab oauth, cleanup code
This commit is contained in:
@@ -16,21 +16,22 @@ import (
|
||||
"rul.sh/vaulterm/server/utils"
|
||||
)
|
||||
|
||||
var config *oauth2.Config
|
||||
var githubCfg *oauth2.Config
|
||||
|
||||
func getGithubConfig() *oauth2.Config {
|
||||
if config != nil {
|
||||
return config
|
||||
if githubCfg != nil {
|
||||
return githubCfg
|
||||
}
|
||||
|
||||
config = &oauth2.Config{
|
||||
githubCfg = &oauth2.Config{
|
||||
ClientID: os.Getenv("GITHUB_CLIENT_ID"),
|
||||
ClientSecret: os.Getenv("GITHUB_CLIENT_SECRET"),
|
||||
Endpoint: github.Endpoint,
|
||||
RedirectURL: "http://localhost:3000/auth/oauth/github/callback",
|
||||
Scopes: []string{"read:user"},
|
||||
// RedirectURL: "http://localhost:3000/auth/oauth/github/callback",
|
||||
RedirectURL: "http://localhost:8081",
|
||||
Scopes: []string{"read:user"},
|
||||
}
|
||||
return config
|
||||
return githubCfg
|
||||
}
|
||||
|
||||
func githubRedir(c *fiber.Ctx) error {
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/gitlab"
|
||||
"gorm.io/gorm"
|
||||
"rul.sh/vaulterm/server/models"
|
||||
"rul.sh/vaulterm/server/utils"
|
||||
)
|
||||
|
||||
type GitlabCfg struct {
|
||||
oauth2.Config
|
||||
verifier string
|
||||
challenge string
|
||||
}
|
||||
|
||||
var gitlabCfg *GitlabCfg
|
||||
|
||||
func getGitlabConfig() *GitlabCfg {
|
||||
if gitlabCfg != nil {
|
||||
return gitlabCfg
|
||||
}
|
||||
|
||||
oauthCfg := oauth2.Config{
|
||||
ClientID: os.Getenv("GITLAB_CLIENT_ID"),
|
||||
ClientSecret: os.Getenv("GITLAB_CLIENT_SECRET"),
|
||||
Endpoint: gitlab.Endpoint,
|
||||
// RedirectURL: "http://localhost:3000/auth/oauth/gitlab/callback",
|
||||
RedirectURL: "http://localhost:8081",
|
||||
Scopes: []string{"read_user"},
|
||||
}
|
||||
verifier := oauth2.GenerateVerifier()
|
||||
challenge := oauth2.S256ChallengeFromVerifier(verifier)
|
||||
|
||||
gitlabCfg = &GitlabCfg{
|
||||
Config: oauthCfg,
|
||||
verifier: verifier,
|
||||
challenge: challenge,
|
||||
}
|
||||
return gitlabCfg
|
||||
}
|
||||
|
||||
func gitlabRedir(c *fiber.Ctx) error {
|
||||
// Redirect to Gitlab login page
|
||||
url := getGitlabConfig().
|
||||
AuthCodeURL("login", oauth2.S256ChallengeOption(getGitlabConfig().verifier))
|
||||
return c.Redirect(url)
|
||||
}
|
||||
|
||||
func gitlabCallback(c *fiber.Ctx) error {
|
||||
cfg := getGitlabConfig()
|
||||
code := c.Query("code")
|
||||
verifier := c.Query("verifier")
|
||||
|
||||
if code == "" {
|
||||
return c.Status(fiber.StatusBadRequest).SendString("Missing code")
|
||||
}
|
||||
if verifier == "" {
|
||||
verifier = cfg.verifier
|
||||
}
|
||||
|
||||
// Exchange code for a token
|
||||
token, err := cfg.Exchange(c.Context(), code, oauth2.VerifierOption(verifier))
|
||||
if err != nil {
|
||||
log.Println(token, err)
|
||||
return c.Status(fiber.StatusInternalServerError).SendString("Failed to exchange token")
|
||||
}
|
||||
|
||||
// Retrieve user info
|
||||
client := cfg.Client(c.Context(), token)
|
||||
resp, err := client.Get("https://gitlab.com/api/v4/user")
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).SendString("Failed to get user info")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode != 200 {
|
||||
return c.Status(fiber.StatusInternalServerError).
|
||||
SendString(fmt.Sprintf("Gitlab API error: %s", string(body)))
|
||||
}
|
||||
|
||||
// Parse user info
|
||||
var user struct {
|
||||
Username string `json:"username"`
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &user); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).SendString("Failed to parse user info")
|
||||
}
|
||||
|
||||
repo := NewRepository()
|
||||
accountId := strconv.Itoa(user.ID)
|
||||
userAccount, err := repo.FindUserAccount("gitlab", accountId)
|
||||
|
||||
// Register the user if the account not yet registered
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
acc := models.UserAccount{
|
||||
Type: "gitlab",
|
||||
AccountID: accountId,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
}
|
||||
user := models.User{
|
||||
Name: user.Name,
|
||||
Role: models.UserRoleUser,
|
||||
Image: user.AvatarURL,
|
||||
Accounts: []*models.UserAccount{&acc},
|
||||
}
|
||||
|
||||
sessionId, err := repo.CreateUser(&user)
|
||||
if err != nil {
|
||||
return utils.ResponseError(c, err, 500)
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"user": user,
|
||||
"sessionId": sessionId,
|
||||
})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return utils.ResponseError(c, err, 500)
|
||||
}
|
||||
sessionId, err := repo.CreateUserSession(&userAccount.User)
|
||||
if err != nil {
|
||||
return utils.ResponseError(c, err, 500)
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"user": userAccount.User,
|
||||
"sessionId": sessionId,
|
||||
})
|
||||
}
|
||||
@@ -3,8 +3,8 @@ package auth
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"rul.sh/vaulterm/server/db"
|
||||
"rul.sh/vaulterm/server/lib"
|
||||
"rul.sh/vaulterm/server/models"
|
||||
"rul.sh/vaulterm/server/utils"
|
||||
)
|
||||
|
||||
type Auth struct{ db *gorm.DB }
|
||||
@@ -30,7 +30,7 @@ func (r *Auth) FindUserAccount(accountType string, accountId string) (*models.Us
|
||||
}
|
||||
|
||||
func (r *Auth) CreateUserSession(user *models.User) (string, error) {
|
||||
sessionId, err := lib.GenerateSessionID(20)
|
||||
sessionId, err := utils.GenerateSessionID(20)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ func Router(app *fiber.App) {
|
||||
oauth := router.Group("/oauth")
|
||||
oauth.Get("/github", githubRedir)
|
||||
oauth.Get("/github/callback", githubCallback)
|
||||
oauth.Get("/gitlab", gitlabRedir)
|
||||
oauth.Get("/gitlab/callback", gitlabCallback)
|
||||
}
|
||||
|
||||
func login(c *fiber.Ctx) error {
|
||||
@@ -40,7 +42,7 @@ func login(c *fiber.Ctx) error {
|
||||
}
|
||||
}
|
||||
|
||||
if valid := lib.VerifyPassword(body.Password, user.Password); !valid {
|
||||
if valid := utils.VerifyPassword(body.Password, user.Password); !valid {
|
||||
return &fiber.Error{
|
||||
Code: fiber.StatusUnauthorized,
|
||||
Message: "Username or password is invalid",
|
||||
@@ -59,7 +61,7 @@ func login(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
func getUser(c *fiber.Ctx) error {
|
||||
user := utils.GetUser(c)
|
||||
user := lib.GetUser(c)
|
||||
teams := []TeamWithRole{}
|
||||
|
||||
for _, item := range user.Teams {
|
||||
@@ -96,15 +98,15 @@ func register(c *fiber.Ctx) error {
|
||||
}
|
||||
}
|
||||
|
||||
password, err := lib.HashPassword(body.Password)
|
||||
password, err := utils.HashPassword(body.Password)
|
||||
if err != nil {
|
||||
return utils.ResponseError(c, err, 500)
|
||||
}
|
||||
|
||||
user := &models.User{
|
||||
Name: body.Name,
|
||||
Username: body.Username,
|
||||
Email: body.Email,
|
||||
Username: &body.Username,
|
||||
Email: &body.Email,
|
||||
Password: password,
|
||||
Role: models.UserRoleUser,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user