Files

227 lines
6.5 KiB
Go

package themes_handler
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"net/url"
"strings"
"github.com/dchest/captcha"
"github.com/gin-gonic/gin"
)
func (h *Handler) GetUserRole(c *gin.Context) {
userID, _ := c.Get("user_id")
userName, _ := c.Get("user_name")
displayName, _ := c.Get("display_name")
isAdmin, _ := c.Get("is_admin")
userTag, _ := c.Get("user_tag")
isAdminBool := false
if isAdmin != nil {
isAdminBool = isAdmin.(bool)
}
displayNameStr := ""
if displayName != nil {
displayNameStr = displayName.(string)
}
userTagStr := ""
if userTag != nil {
userTagStr = userTag.(string)
}
c.JSON(http.StatusOK, gin.H{
"code": http.StatusOK,
"msg": "GET > user role",
"data": gin.H{
"user_id": userID,
"user_name": userName,
"display_name": displayNameStr,
"is_admin": isAdminBool,
"is_verified": isAdminBool || userTagStr == "verified",
},
})
}
// GET /api/user/downloads (stretch goal)
func (h *Handler) GetUserDownloads(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"code": http.StatusOK,
"msg": "GET > download history not yet implemented",
"data": []interface{}{},
})
}
// GET /api/marketplace/auth/captcha
func (h *Handler) GetCaptcha(c *gin.Context) {
id := captcha.NewLen(4)
var buf bytes.Buffer
if err := captcha.WriteImage(&buf, id, 150, 50); err != nil {
log.Printf("[E] CAPTCHA > failed to generate: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "msg": "captcha generation failed", "data": nil})
return
}
c.JSON(http.StatusOK, gin.H{
"code": http.StatusOK,
"msg": "GET > captcha",
"data": gin.H{
"captchaId": id,
"captchaImage": "data:image/png;base64," + base64.StdEncoding.EncodeToString(buf.Bytes()),
},
})
}
// GET /api/marketplace/auth/config
func (h *Handler) GetAuthConfig(c *gin.Context) {
cfg := h.Config
casdoorConfigured := cfg.Backend.Casdoor.Endpoint != "" && cfg.Backend.Casdoor.ClientID != ""
c.JSON(http.StatusOK, gin.H{
"code": http.StatusOK,
"msg": "GET > auth config",
"data": gin.H{
"casdoor_configured": casdoorConfigured,
"casdoor_endpoint": cfg.Backend.Casdoor.Endpoint,
"casdoor_client_id": cfg.Backend.Casdoor.ClientID,
"casdoor_organization": cfg.Backend.Casdoor.Organization,
"casdoor_application": cfg.Backend.Casdoor.Application,
},
})
}
// POST /api/marketplace/auth/login
func (h *Handler) LoginProxy(c *gin.Context) {
cfg := h.Config
var req struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": "PUT > invalid request body", "data": nil})
return
}
// Proxy to Casdoor OAuth token endpoint
tokenURL := cfg.Backend.Casdoor.Endpoint + "/api/login/oauth/access_token"
values := url.Values{
"grant_type": {"password"},
"client_id": {cfg.Backend.Casdoor.ClientID},
"client_secret": {cfg.Backend.Casdoor.ClientSecret},
"username": {req.Username},
"password": {req.Password},
"scope": {"read"},
}
reqHTTP, err := http.NewRequestWithContext(c.Request.Context(), http.MethodPost, tokenURL, strings.NewReader(values.Encode()))
if err != nil {
fail(c, http.StatusBadGateway, "Invalid authentication server configuration")
return
}
reqHTTP.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := h.HTTP.Do(reqHTTP)
if err != nil {
log.Printf("[E] AUTH > login proxy error: %v", err)
c.JSON(http.StatusBadGateway, gin.H{"code": http.StatusBadGateway, "msg": "auth server unreachable", "data": nil})
return
}
defer resp.Body.Close()
body, readErr := io.ReadAll(io.LimitReader(resp.Body, 2<<20))
if readErr != nil {
fail(c, http.StatusBadGateway, "Unable to read authentication response")
return
}
if resp.StatusCode != http.StatusOK {
c.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "invalid credentials", "data": nil})
return
}
c.Header("Content-Type", "application/json")
c.String(http.StatusOK, string(body))
}
// POST /api/marketplace/auth/signup
func (h *Handler) SignupProxy(c *gin.Context) {
cfg := h.Config
var req struct {
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
Name string `json:"name"`
CaptchaId string `json:"captchaId"`
CaptchaCode string `json:"captchaCode"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": "PUT > invalid request body", "data": nil})
return
}
if req.Username == "" || req.Password == "" {
c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": "用户名和密码为必填项", "data": nil})
return
}
// Validate captcha
if !captcha.VerifyString(req.CaptchaId, req.CaptchaCode) {
c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": "验证码错误或已过期", "data": nil})
return
}
// Proxy to Casdoor signup API
signupData := map[string]interface{}{
"organization": cfg.Backend.Casdoor.Organization,
"username": req.Username,
"password": req.Password,
"application": cfg.Backend.Casdoor.Application,
}
if req.Email != "" {
signupData["email"] = req.Email
}
if req.Name != "" {
signupData["name"] = req.Name
}
signupURL := cfg.Backend.Casdoor.Endpoint + "/api/signup"
signupBody, _ := json.Marshal(signupData)
reqHTTP, err := http.NewRequestWithContext(c.Request.Context(), http.MethodPost, signupURL, bytes.NewReader(signupBody))
if err != nil {
fail(c, http.StatusBadGateway, "Invalid authentication server configuration")
return
}
reqHTTP.Header.Set("Content-Type", "application/json")
resp, err := h.HTTP.Do(reqHTTP)
if err != nil {
log.Printf("[E] AUTH > signup proxy error: %v", err)
c.JSON(http.StatusBadGateway, gin.H{"code": http.StatusBadGateway, "msg": "auth server unreachable", "data": nil})
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result map[string]interface{}
json.Unmarshal(body, &result)
if status, ok := result["status"]; !ok || status != "ok" {
msg := "注册失败"
if m, ok := result["msg"]; ok {
msg = fmt.Sprintf("%v", m)
}
c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": msg, "data": nil})
return
}
log.Printf("[I] AUTH > signup successful for user: %s", req.Username)
c.Header("Content-Type", "application/json")
c.String(http.StatusOK, string(body))
}