Files
LoganandClaude 76ec9387f0 feat(rdp): 新增 RDP 远程桌面/SMB/账单同步能力 + 清理编译产物
主要变更:
- RDP 远程桌面:新增 backend/pkg/rdp(RDP 引擎 + credssp/display/rle/trace)、
  backend/controller/rdp*(连接/凭证/文件/会话/实时)、frontend RDP 组件与 API
- Windows SMB 文件传输:backend/pkg/winsmb
- 云账单同步:backend/pkg/billingsync + billing_sync/aliyun_billing,前端账单详情
- Agent CLI Kubernetes 工具:kubernetes_action/get、pod_execute/logs
- 服务器导入助手:server_import_helpers、ImportCredentialSettings
- 国际化与组件重构(cloud/deploy/monitor/server/system 等多模块)
- 清理编译产物二进制:移除 backend/server、backend/agent/bin/aiops-agent-*
- .gitignore:新增 backend/agent/ 与 .cache/(避免 334MB go-build 缓存误入库)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-04 01:50:36 +08:00

100 lines
3.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package controller
import (
"encoding/json"
"net/http"
"strconv"
"ezops/model"
"github.com/gin-gonic/gin"
)
// AssignCredential 将凭据分配给服务器(解密凭据并写入 password/ssh_key) // Logan.Li
func (h *CredentialHandler) AssignCredential(c *gin.Context) {
serverID, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "无效的服务器ID"})
return
}
var req struct {
CredentialID uint `json:"credential_id"`
}
if err := c.ShouldBindJSON(&req); err != nil || req.CredentialID == 0 {
c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "请选择凭据"})
return
}
var cred model.Credential
if err := h.db.First(&cred, req.CredentialID).Error; err != nil {
c.JSON(http.StatusNotFound, model.Response{Code: 404, Message: "凭据不存在"})
return
}
plain, err := h.crypt.Decrypt(cred.Content)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "凭据解密失败"})
return
}
var server model.Server
if err := h.db.First(&server, serverID).Error; err != nil {
c.JSON(http.StatusNotFound, model.Response{Code: 404, Message: "服务器不存在"})
return
}
applyCredential(cred, plain, &server)
if err := h.db.Save(&server).Error; err != nil {
c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "分配失败: " + err.Error()})
return
}
c.JSON(http.StatusOK, model.Response{Code: 200, Message: "凭据已关联"})
}
// applyCredential 将解密后的明文 plain 填充到 server 认证字段(统一入口,避免 plain JSON 误用) // Logan.Li
// ssh 凭证 plain 是 JSON {"private_key":...,"ssh_user":...,"ssh_port":...},须解析出 private_key(旧实现直接把
// 整个 JSON 当私钥,导致 ssh.ParsePrivateKey 失败 → ssh-key 登录不通);其余类型 plain 即密码。
// 供 AssignCredential / 单台服务器 CRUD / 批量导入 三处复用。
func applyCredential(cred model.Credential, plain string, server *model.Server) {
if cred.SecretType == "ssh" {
privateKey := plain
var sshc model.SSHSecretContent
if json.Unmarshal([]byte(plain), &sshc) == nil && sshc.PrivateKey != "" {
privateKey = sshc.PrivateKey
if sshc.SSHUser != "" {
server.Username = sshc.SSHUser
}
if sshc.SSHPort > 0 {
server.Port = sshc.SSHPort
}
}
server.SSHKey = privateKey
server.AuthType = "key"
server.Password = ""
server.Protocol = "ssh"
if server.OSType == "" {
server.OSType = "linux"
}
} else if cred.SecretType == "rdp" {
var rdpc model.RDPSecretContent
if json.Unmarshal([]byte(plain), &rdpc) == nil && rdpc.Username != "" {
server.Username = rdpc.Username
}
server.Password = plain
server.AuthType = "password"
server.SSHKey = ""
server.Protocol = "rdp"
server.OSType = "windows"
if server.RDPPort == 0 {
server.RDPPort = 3389
}
} else {
server.Password = plain
server.AuthType = "password"
server.SSHKey = ""
}
}