diff --git a/.gitignore b/.gitignore
index 556feda..49e1259 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,8 @@
+/config.json
+/database.db
+/recharge.db
+logs
+模板
.DS_Store
networkDev
-node.txt
-/config.json
-database.db
-logs
-模板
\ No newline at end of file
+node.txt
\ No newline at end of file
diff --git a/controllers/admin/api.go b/controllers/admin/api.go
new file mode 100644
index 0000000..65dbf71
--- /dev/null
+++ b/controllers/admin/api.go
@@ -0,0 +1,418 @@
+package admin
+
+import (
+ "encoding/json"
+ "net/http"
+ "networkDev/database"
+ "networkDev/models"
+ "networkDev/utils"
+ "networkDev/utils/encrypt"
+ "strconv"
+ "strings"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/hex"
+ "encoding/pem"
+
+ "github.com/sirupsen/logrus"
+)
+
+// APIFragmentHandler 接口列表页面片段处理器
+func APIFragmentHandler(w http.ResponseWriter, r *http.Request) {
+ utils.RenderTemplate(w, "apis.html", map[string]interface{}{
+ "Title": "接口管理",
+ })
+}
+
+// APIListHandler 接口列表API处理器
+func APIListHandler(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodGet {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ // 获取分页参数
+ page, _ := strconv.Atoi(r.URL.Query().Get("page"))
+ if page <= 0 {
+ page = 1
+ }
+ limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
+ if limit <= 0 {
+ limit = 10
+ }
+
+ // 获取应用UUID参数(用于按应用筛选接口)
+ appUUID := strings.TrimSpace(r.URL.Query().Get("app_uuid"))
+
+ // 获取搜索参数
+ search := strings.TrimSpace(r.URL.Query().Get("search"))
+
+ // 构建查询
+ db, err := database.GetDB()
+ if err != nil {
+ logrus.WithError(err).Error("Failed to get database connection")
+ http.Error(w, "Internal server error", http.StatusInternalServerError)
+ return
+ }
+
+ // 构建基础查询
+ query := db.Model(&models.API{})
+
+ // 如果指定了应用UUID,则按应用筛选
+ if appUUID != "" {
+ query = query.Where("app_uuid = ?", appUUID)
+ }
+
+ // 如果有搜索条件,添加搜索
+ if search != "" {
+ query = query.Where("api_key LIKE ? OR app_uuid LIKE ?", "%"+search+"%", "%"+search+"%")
+ }
+
+ // 获取总数
+ var total int64
+ if err := query.Count(&total).Error; err != nil {
+ logrus.WithError(err).Error("Failed to count APIs")
+ http.Error(w, "Internal server error", http.StatusInternalServerError)
+ return
+ }
+
+ // 获取分页数据
+ var apis []models.API
+ offset := (page - 1) * limit
+ if err := query.Offset(offset).Limit(limit).Order("created_at DESC").Find(&apis).Error; err != nil {
+ logrus.WithError(err).Error("Failed to fetch APIs")
+ http.Error(w, "Internal server error", http.StatusInternalServerError)
+ return
+ }
+
+ // 获取关联的应用信息
+ var appUUIDs []string
+ for _, api := range apis {
+ appUUIDs = append(appUUIDs, api.AppUUID)
+ }
+
+ var apps []models.App
+ if len(appUUIDs) > 0 {
+ if err := db.Where("uuid IN ?", appUUIDs).Find(&apps).Error; err != nil {
+ logrus.WithError(err).Error("Failed to fetch related apps")
+ }
+ }
+
+ // 创建应用UUID到应用名称的映射
+ appMap := make(map[string]string)
+ for _, app := range apps {
+ appMap[app.UUID] = app.Name
+ }
+
+ // 构建响应数据
+ type APIResponse struct {
+ models.API
+ AppName string `json:"app_name"`
+ APITypeName string `json:"api_type_name"`
+ StatusName string `json:"status_name"`
+ AlgorithmNames struct {
+ Submit string `json:"submit"`
+ Return string `json:"return"`
+ } `json:"algorithm_names"`
+ }
+
+ var responseAPIs []APIResponse
+ for _, api := range apis {
+ responseAPI := APIResponse{
+ API: api,
+ AppName: appMap[api.AppUUID],
+ APITypeName: models.GetAPITypeName(api.APIType),
+ StatusName: getAPIStatusName(api.Status),
+ }
+ responseAPI.AlgorithmNames.Submit = models.GetAlgorithmName(api.SubmitAlgorithm)
+ responseAPI.AlgorithmNames.Return = models.GetAlgorithmName(api.ReturnAlgorithm)
+ responseAPIs = append(responseAPIs, responseAPI)
+ }
+
+ // 计算分页信息
+ totalPages := (total + int64(limit) - 1) / int64(limit)
+
+ response := map[string]interface{}{
+ "success": true,
+ "data": map[string]interface{}{
+ "apis": responseAPIs,
+ "total": total,
+ "page": page,
+ "limit": limit,
+ "total_pages": totalPages,
+ },
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+}
+
+// getAPIStatusName 获取API状态名称
+func getAPIStatusName(status int) string {
+ switch status {
+ case 1:
+ return "启用"
+ case 0:
+ return "禁用"
+ default:
+ return "未知"
+ }
+}
+
+// APIUpdateHandler 更新接口处理器
+func APIUpdateHandler(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ var req struct {
+ ID uint `json:"id"`
+ Status int `json:"status"`
+ SubmitAlgorithm int `json:"submit_algorithm"`
+ ReturnAlgorithm int `json:"return_algorithm"`
+ SubmitPublicKey string `json:"submit_public_key"`
+ SubmitPrivateKey string `json:"submit_private_key"`
+ ReturnPublicKey string `json:"return_public_key"`
+ ReturnPrivateKey string `json:"return_private_key"`
+ }
+
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ http.Error(w, "Invalid JSON", http.StatusBadRequest)
+ return
+ }
+
+ // 验证必填字段
+ if req.ID == 0 {
+ http.Error(w, "接口ID不能为空", http.StatusBadRequest)
+ return
+ }
+
+ if req.Status != 0 && req.Status != 1 {
+ http.Error(w, "无效的状态值", http.StatusBadRequest)
+ return
+ }
+
+ if !models.IsValidAlgorithm(req.SubmitAlgorithm) || !models.IsValidAlgorithm(req.ReturnAlgorithm) {
+ http.Error(w, "无效的算法类型", http.StatusBadRequest)
+ return
+ }
+
+ // 获取数据库连接
+ db, err := database.GetDB()
+ if err != nil {
+ logrus.WithError(err).Error("Failed to get database connection")
+ http.Error(w, "Internal server error", http.StatusInternalServerError)
+ return
+ }
+
+ // 查找并更新API记录
+ var api models.API
+ if err := db.First(&api, req.ID).Error; err != nil {
+ http.Error(w, "接口不存在", http.StatusNotFound)
+ return
+ }
+
+ // 更新字段(不允许修改 APIType)
+ api.Status = req.Status
+ api.SubmitAlgorithm = req.SubmitAlgorithm
+ api.ReturnAlgorithm = req.ReturnAlgorithm
+
+ // 可选更新密钥/证书(当提供时)
+ if req.SubmitPublicKey != "" || req.SubmitPrivateKey != "" {
+ api.SubmitPublicKey = req.SubmitPublicKey
+ api.SubmitPrivateKey = req.SubmitPrivateKey
+ }
+ if req.ReturnPublicKey != "" || req.ReturnPrivateKey != "" {
+ api.ReturnPublicKey = req.ReturnPublicKey
+ api.ReturnPrivateKey = req.ReturnPrivateKey
+ }
+
+ if err := db.Save(&api).Error; err != nil {
+ logrus.WithError(err).Error("Failed to update API")
+ http.Error(w, "更新接口失败", http.StatusInternalServerError)
+ return
+ }
+
+ response := map[string]interface{}{
+ "success": true,
+ "message": "接口更新成功",
+ "data": api,
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+}
+
+// APIGetAppsHandler 获取应用列表(用于接口页面的应用选择器)
+func APIGetAppsHandler(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodGet {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ // 获取数据库连接
+ db, err := database.GetDB()
+ if err != nil {
+ logrus.WithError(err).Error("Failed to get database connection")
+ http.Error(w, "Internal server error", http.StatusInternalServerError)
+ return
+ }
+
+ // 获取所有应用
+ var apps []models.App
+ if err := db.Select("uuid, name").Order("created_at ASC").Find(&apps).Error; err != nil {
+ logrus.WithError(err).Error("Failed to fetch apps")
+ http.Error(w, "Internal server error", http.StatusInternalServerError)
+ return
+ }
+
+ response := map[string]interface{}{
+ "success": true,
+ "data": apps,
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+}
+
+func APIGenerateKeysHandler(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ var req struct {
+ Side string `json:"side"` // submit | return
+ Algorithm int `json:"algorithm"` // 与 models.Algorithm* 对应
+ }
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ http.Error(w, "Invalid JSON", http.StatusBadRequest)
+ return
+ }
+ if req.Side != "submit" && req.Side != "return" {
+ http.Error(w, "side参数必须为submit或return", http.StatusBadRequest)
+ return
+ }
+ if !models.IsValidAlgorithm(req.Algorithm) {
+ http.Error(w, "无效的算法类型", http.StatusBadRequest)
+ return
+ }
+
+ // 根据算法生成密钥/证书
+ result := map[string]interface{}{}
+
+ switch req.Algorithm {
+ case models.AlgorithmNone:
+ // 不加密不生成任何密钥
+ result["public_key"] = ""
+ result["private_key"] = ""
+ case models.AlgorithmRC4:
+ // 生成16字节随机密钥并返回16位十六进制(大写)
+ bytes := make([]byte, 8)
+ if _, err := rand.Read(bytes); err != nil {
+ logrus.WithError(err).Error("Failed to generate RC4 key")
+ http.Error(w, "生成RC4密钥失败", http.StatusInternalServerError)
+ return
+ }
+ result["public_key"] = ""
+ result["private_key"] = strings.ToUpper(hex.EncodeToString(bytes))
+ case models.AlgorithmRSA, models.AlgorithmRSADynamic:
+ // 生成RSA 2048密钥对,返回PEM明文字符串
+ key, err := rsa.GenerateKey(rand.Reader, 2048)
+ if err != nil {
+ logrus.WithError(err).Error("Failed to generate RSA key pair")
+ http.Error(w, "生成RSA密钥失败", http.StatusInternalServerError)
+ return
+ }
+ privBytes := x509.MarshalPKCS1PrivateKey(key)
+ pubBytes := x509.MarshalPKCS1PublicKey(&key.PublicKey)
+ privPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: privBytes})
+ pubPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PUBLIC KEY", Bytes: pubBytes})
+ result["private_key"] = string(privPEM)
+ result["public_key"] = string(pubPEM)
+ case models.AlgorithmEasy:
+ // 生成易加密密钥对,返回逗号分隔的整数数组字符串
+ encryptKey, _, err := encrypt.GenerateEasyKey()
+ if err != nil {
+ logrus.WithError(err).Error("Failed to generate Easy encryption key")
+ http.Error(w, "生成易加密密钥失败", http.StatusInternalServerError)
+ return
+ }
+ result["public_key"] = ""
+ result["private_key"] = encrypt.FormatKeyAsString(encryptKey)
+ default:
+ http.Error(w, "不支持的算法类型", http.StatusBadRequest)
+ return
+ }
+
+ response := map[string]interface{}{
+ "success": true,
+ "message": "生成成功",
+ "data": result,
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+}
+
+func APIResetKeyHandler(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ var req struct {
+ ID uint `json:"id"`
+ }
+
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ http.Error(w, "Invalid JSON", http.StatusBadRequest)
+ return
+ }
+
+ if req.ID == 0 {
+ http.Error(w, "接口ID不能为空", http.StatusBadRequest)
+ return
+ }
+
+ db, err := database.GetDB()
+ if err != nil {
+ logrus.WithError(err).Error("Failed to get database connection")
+ http.Error(w, "Internal server error", http.StatusInternalServerError)
+ return
+ }
+
+ var api models.API
+ if err := db.First(&api, req.ID).Error; err != nil {
+ http.Error(w, "接口不存在", http.StatusNotFound)
+ return
+ }
+
+ // 生成新的16位大写十六进制密钥
+ bytes := make([]byte, 8)
+ if _, err := rand.Read(bytes); err != nil {
+ logrus.WithError(err).Error("Failed to generate random API key")
+ http.Error(w, "生成密钥失败", http.StatusInternalServerError)
+ return
+ }
+ newKey := strings.ToUpper(hex.EncodeToString(bytes))
+
+ if err := db.Model(&api).Update("api_key", newKey).Error; err != nil {
+ logrus.WithError(err).Error("Failed to update API key")
+ http.Error(w, "更新密钥失败", http.StatusInternalServerError)
+ return
+ }
+
+ response := map[string]interface{}{
+ "success": true,
+ "message": "接口密钥重置成功",
+ "data": map[string]interface{}{
+ "id": api.ID,
+ "api_key": newKey,
+ },
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+}
diff --git a/controllers/admin/app.go b/controllers/admin/app.go
index 19f3459..a8546f8 100644
--- a/controllers/admin/app.go
+++ b/controllers/admin/app.go
@@ -88,6 +88,76 @@ func AppsListHandler(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(response)
}
+// AppGetAppDataHandler 获取应用数据处理器
+func AppGetAppDataHandler(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodGet {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ // 获取UUID参数
+ uuid := r.URL.Query().Get("uuid")
+ if uuid == "" {
+ response := map[string]interface{}{
+ "code": 1,
+ "msg": "应用UUID不能为空",
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+ return
+ }
+
+ // 获取数据库连接
+ db, err := database.GetDB()
+ if err != nil {
+ logrus.WithError(err).Error("Failed to get database connection")
+ response := map[string]interface{}{
+ "code": 1,
+ "msg": "数据库连接失败",
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+ return
+ }
+
+ // 查找应用
+ var app models.App
+ if err := db.Where("uuid = ?", uuid).First(&app).Error; err != nil {
+ logrus.WithError(err).Error("Failed to find app")
+ response := map[string]interface{}{
+ "code": 1,
+ "msg": "应用不存在",
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+ return
+ }
+
+ // 解码base64应用数据内容
+ var appData string
+ if app.AppData != "" {
+ decodedBytes, err := base64.StdEncoding.DecodeString(app.AppData)
+ if err != nil {
+ logrus.WithError(err).Error("Failed to decode app data")
+ // 如果解码失败,返回空字符串
+ appData = ""
+ } else {
+ appData = string(decodedBytes)
+ }
+ }
+
+ response := map[string]interface{}{
+ "code": 0,
+ "msg": "获取成功",
+ "data": map[string]interface{}{
+ "app_data": appData,
+ },
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+}
+
// AppGetAnnouncementHandler 获取应用程序公告处理器
func AppGetAnnouncementHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
@@ -294,12 +364,73 @@ func AppCreateHandler(w http.ResponseWriter, r *http.Request) {
return
}
- if err := db.Create(&app).Error; err != nil {
+ // 开始事务
+ tx := db.Begin()
+ defer func() {
+ if r := recover(); r != nil {
+ tx.Rollback()
+ }
+ }()
+
+ // 创建应用
+ if err := tx.Create(&app).Error; err != nil {
+ tx.Rollback()
logrus.WithError(err).Error("Failed to create app")
http.Error(w, "创建应用失败", http.StatusInternalServerError)
return
}
+ // 为应用创建所有默认接口
+ defaultAPITypes := []int{
+ models.APITypeGetBulletin, // 获取程序公告
+ models.APITypeGetUpdateUrl, // 获取更新地址
+ models.APITypeCheckAppVersion, // 检测最新版本
+ models.APITypeGetCardInfo, // 获取卡密信息
+ models.APITypeSingleLogin, // 卡密登录
+ models.APITypeUserLogin, // 用户登录
+ models.APITypeUserRegin, // 用户注册
+ models.APITypeUserRecharge, // 用户充值
+ models.APITypeCardRegin, // 卡密注册
+ models.APITypeLogOut, // 退出登录
+ models.APITypeGetExpired, // 获取到期时间
+ models.APITypeCheckUserStatus, // 检测账号状态
+ models.APITypeGetAppData, // 获取程序数据
+ models.APITypeGetVariable, // 获取变量数据
+ models.APITypeUpdatePwd, // 修改账号密码
+ models.APITypeMacChangeBind, // 机器码转绑
+ models.APITypeIPChangeBind, // IP转绑
+ models.APITypeDisableUser, // 封停用户
+ models.APITypeBlackUser, // 添加黑名单
+ models.APITypeUserDeductedTime, // 扣除时间
+ }
+
+ // 批量创建默认接口
+ for _, apiType := range defaultAPITypes {
+ api := models.API{
+ APIType: apiType,
+ AppUUID: app.UUID,
+ Status: 1, // 默认启用
+ SubmitAlgorithm: models.AlgorithmNone, // 默认不加密
+ ReturnAlgorithm: models.AlgorithmNone, // 默认不加密
+ }
+
+ if err := tx.Create(&api).Error; err != nil {
+ tx.Rollback()
+ logrus.WithError(err).WithField("api_type", apiType).Error("Failed to create default API")
+ http.Error(w, "创建默认接口失败", http.StatusInternalServerError)
+ return
+ }
+ }
+
+ // 提交事务
+ if err := tx.Commit().Error; err != nil {
+ logrus.WithError(err).Error("Failed to commit transaction")
+ http.Error(w, "提交事务失败", http.StatusInternalServerError)
+ return
+ }
+
+ logrus.WithField("app_uuid", app.UUID).Info("Successfully created app with default APIs")
+
response := map[string]interface{}{
"code": 0,
"msg": "创建成功",
@@ -408,13 +539,51 @@ func AppDeleteHandler(w http.ResponseWriter, r *http.Request) {
return
}
+ // 开始事务
+ tx := db.Begin()
+ defer func() {
+ if r := recover(); r != nil {
+ tx.Rollback()
+ }
+ }()
+
+ // 首先获取应用信息以获取UUID
+ var app models.App
+ if err := tx.First(&app, req.ID).Error; err != nil {
+ tx.Rollback()
+ logrus.WithError(err).Error("Failed to find app")
+ http.Error(w, "应用不存在", http.StatusNotFound)
+ return
+ }
+
+ // 删除该应用的所有相关接口
+ if err := tx.Where("app_uuid = ?", app.UUID).Delete(&models.API{}).Error; err != nil {
+ tx.Rollback()
+ logrus.WithError(err).Error("Failed to delete related APIs")
+ http.Error(w, "删除相关接口失败", http.StatusInternalServerError)
+ return
+ }
+
// 删除应用
- if err := db.Delete(&models.App{}, req.ID).Error; err != nil {
+ if err := tx.Delete(&models.App{}, req.ID).Error; err != nil {
+ tx.Rollback()
logrus.WithError(err).Error("Failed to delete app")
http.Error(w, "删除应用失败", http.StatusInternalServerError)
return
}
+ // 提交事务
+ if err := tx.Commit().Error; err != nil {
+ logrus.WithError(err).Error("Failed to commit transaction")
+ http.Error(w, "提交事务失败", http.StatusInternalServerError)
+ return
+ }
+
+ logrus.WithFields(logrus.Fields{
+ "app_id": req.ID,
+ "app_uuid": app.UUID,
+ }).Info("Successfully deleted app and related APIs")
+
response := map[string]interface{}{
"code": 0,
"msg": "删除成功",
@@ -452,13 +621,59 @@ func AppsBatchDeleteHandler(w http.ResponseWriter, r *http.Request) {
return
}
- // 批量删除
- if err := db.Delete(&models.App{}, req.IDs).Error; err != nil {
+ // 开始事务
+ tx := db.Begin()
+ defer func() {
+ if r := recover(); r != nil {
+ tx.Rollback()
+ }
+ }()
+
+ // 首先获取要删除的应用的UUID列表
+ var apps []models.App
+ if err := tx.Where("id IN ?", req.IDs).Find(&apps).Error; err != nil {
+ tx.Rollback()
+ logrus.WithError(err).Error("Failed to find apps")
+ http.Error(w, "查找应用失败", http.StatusInternalServerError)
+ return
+ }
+
+ // 提取UUID列表
+ var appUUIDs []string
+ for _, app := range apps {
+ appUUIDs = append(appUUIDs, app.UUID)
+ }
+
+ // 删除这些应用的所有相关接口
+ if len(appUUIDs) > 0 {
+ if err := tx.Where("app_uuid IN ?", appUUIDs).Delete(&models.API{}).Error; err != nil {
+ tx.Rollback()
+ logrus.WithError(err).Error("Failed to delete related APIs")
+ http.Error(w, "删除相关接口失败", http.StatusInternalServerError)
+ return
+ }
+ }
+
+ // 批量删除应用
+ if err := tx.Delete(&models.App{}, req.IDs).Error; err != nil {
+ tx.Rollback()
logrus.WithError(err).Error("Failed to batch delete apps")
http.Error(w, "批量删除失败", http.StatusInternalServerError)
return
}
+ // 提交事务
+ if err := tx.Commit().Error; err != nil {
+ logrus.WithError(err).Error("Failed to commit transaction")
+ http.Error(w, "提交事务失败", http.StatusInternalServerError)
+ return
+ }
+
+ logrus.WithFields(logrus.Fields{
+ "app_ids": req.IDs,
+ "app_uuids": appUUIDs,
+ }).Info("Successfully batch deleted apps and related APIs")
+
response := map[string]interface{}{
"code": 0,
"msg": "批量删除成功",
@@ -523,6 +738,108 @@ func AppsBatchUpdateStatusHandler(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(response)
}
+// AppUpdateAppDataHandler 更新应用数据处理器
+func AppUpdateAppDataHandler(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ // 解析请求体
+ var req struct {
+ UUID string `json:"uuid"`
+ AppData string `json:"app_data"`
+ }
+
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ logrus.WithError(err).Error("Failed to decode request body")
+ response := map[string]interface{}{
+ "code": 1,
+ "msg": "请求参数格式错误",
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+ return
+ }
+
+ // 验证UUID
+ if req.UUID == "" {
+ response := map[string]interface{}{
+ "code": 1,
+ "msg": "应用UUID不能为空",
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+ return
+ }
+
+ // 验证UUID格式
+ if _, err := uuid.Parse(req.UUID); err != nil {
+ logrus.WithError(err).Error("Invalid UUID format")
+ response := map[string]interface{}{
+ "code": 1,
+ "msg": "无效的UUID格式",
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+ return
+ }
+
+ // 获取数据库连接
+ db, err := database.GetDB()
+ if err != nil {
+ logrus.WithError(err).Error("Failed to get database connection")
+ response := map[string]interface{}{
+ "code": 1,
+ "msg": "数据库连接失败",
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+ return
+ }
+
+ // 查找应用
+ var app models.App
+ if err := db.Where("uuid = ?", req.UUID).First(&app).Error; err != nil {
+ logrus.WithError(err).Error("Failed to find app")
+ response := map[string]interface{}{
+ "code": 1,
+ "msg": "应用不存在",
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+ return
+ }
+
+ // 对应用数据内容进行base64编码
+ encodedAppData := base64.StdEncoding.EncodeToString([]byte(req.AppData))
+
+ // 更新应用的数据内容
+ if err := db.Model(&app).Update("app_data", encodedAppData).Error; err != nil {
+ logrus.WithError(err).Error("Failed to update app data")
+ response := map[string]interface{}{
+ "code": 1,
+ "msg": "更新应用数据失败",
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+ return
+ }
+
+ logrus.WithFields(logrus.Fields{
+ "app_uuid": req.UUID,
+ "app_name": app.Name,
+ }).Info("App data updated successfully")
+
+ response := map[string]interface{}{
+ "code": 0,
+ "msg": "应用数据更新成功",
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+}
+
// AppUpdateAnnouncementHandler 更新应用程序公告处理器
func AppUpdateAnnouncementHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
diff --git a/models/api.go b/models/api.go
index 319c18c..2fbbc0b 100644
--- a/models/api.go
+++ b/models/api.go
@@ -1,10 +1,11 @@
package models
import (
+ "crypto/rand"
+ "encoding/hex"
"strings"
"time"
- "github.com/google/uuid"
"gorm.io/gorm"
)
@@ -30,24 +31,24 @@ type API struct {
Status int `gorm:"default:1;not null;comment:接口状态,1=启用,0=禁用" json:"status"`
// 接口提交算法
- // 支持的算法:0=不加密,1=RC4,2=RSA,3=RSA(动态)
- SubmitAlgorithm int `gorm:"default:0;not null;comment:提交算法,0=不加密,1=RC4,2=RSA,3=RSA动态" json:"submit_algorithm"`
+ // 支持的算法:0=不加密,1=RC4,2=RSA,3=RSA(动态),4=易加密
+ SubmitAlgorithm int `gorm:"default:0;not null;comment:提交算法,0=不加密,1=RC4,2=RSA,3=RSA动态,4=易加密" json:"submit_algorithm"`
// 接口返回算法
- // 支持的算法:0=不加密,1=RC4,2=RSA,3=RSA(动态)
- ReturnAlgorithm int `gorm:"default:0;not null;comment:返回算法,0=不加密,1=RC4,2=RSA,3=RSA动态" json:"return_algorithm"`
+ // 支持的算法:0=不加密,1=RC4,2=RSA,3=RSA(动态),4=易加密
+ ReturnAlgorithm int `gorm:"default:0;not null;comment:返回算法,0=不加密,1=RC4,2=RSA,3=RSA动态,4=易加密" json:"return_algorithm"`
- // 提交算法公钥(base64编码存储)
- SubmitPublicKey string `gorm:"type:text;comment:提交算法公钥,base64编码" json:"submit_public_key"`
+ // 提交算法公钥(明文PEM存储)
+ SubmitPublicKey string `gorm:"type:text;comment:提交算法公钥,明文PEM" json:"submit_public_key"`
- // 提交算法私钥(base64编码存储)
- SubmitPrivateKey string `gorm:"type:text;comment:提交算法私钥,base64编码" json:"submit_private_key"`
+ // 提交算法私钥(明文PEM存储)
+ SubmitPrivateKey string `gorm:"type:text;comment:提交算法私钥,明文PEM" json:"submit_private_key"`
- // 返回算法公钥(base64编码存储)
- ReturnPublicKey string `gorm:"type:text;comment:返回算法公钥,base64编码" json:"return_public_key"`
+ // 返回算法公钥(明文PEM存储)
+ ReturnPublicKey string `gorm:"type:text;comment:返回算法公钥,明文PEM" json:"return_public_key"`
- // 返回算法私钥(base64编码存储)
- ReturnPrivateKey string `gorm:"type:text;comment:返回算法私钥,base64编码" json:"return_private_key"`
+ // 返回算法私钥(明文PEM存储)
+ ReturnPrivateKey string `gorm:"type:text;comment:返回算法私钥,明文PEM" json:"return_private_key"`
// 时间字段
CreatedAt time.Time `gorm:"comment:创建时间" json:"created_at"`
@@ -57,8 +58,10 @@ type API struct {
// BeforeCreate 在创建记录前自动生成API密钥
func (api *API) BeforeCreate(tx *gorm.DB) error {
if api.APIKey == "" {
- // 生成唯一的API密钥
- api.APIKey = "api_" + strings.ToUpper(uuid.New().String())
+ // 生成16位大写十六进制API密钥
+ bytes := make([]byte, 8) // 8字节 = 16位十六进制字符
+ rand.Read(bytes)
+ api.APIKey = strings.ToUpper(hex.EncodeToString(bytes))
}
return nil
}
@@ -68,12 +71,50 @@ func (API) TableName() string {
return "apis"
}
+// API类型常量定义
+const (
+ // 基础信息获取类API
+ APITypeGetBulletin = 1 // 获取程序公告
+ APITypeGetUpdateUrl = 2 // 获取更新地址
+ APITypeCheckAppVersion = 3 // 检测最新版本
+ APITypeGetCardInfo = 4 // 获取卡密信息
+
+ // 登录相关API
+ APITypeSingleLogin = 10 // 卡密登录
+
+ // 用户账号管理API
+ APITypeUserLogin = 20 // 用户登录
+ APITypeUserRegin = 21 // 用户注册
+ APITypeUserRecharge = 22 // 用户充值
+ APITypeCardRegin = 23 // 卡密注册
+
+ // 登出API
+ APITypeLogOut = 30 // 退出登录
+
+ // 用户状态查询API
+ APITypeGetExpired = 40 // 获取到期时间
+ APITypeCheckUserStatus = 41 // 检测账号状态
+ APITypeGetAppData = 42 // 获取程序数据
+ APITypeGetVariable = 43 // 获取变量数据
+
+ // 用户操作API
+ APITypeUpdatePwd = 50 // 修改账号密码
+ APITypeMacChangeBind = 51 // 机器码转绑
+ APITypeIPChangeBind = 52 // IP转绑
+
+ // 管理员操作API
+ APITypeDisableUser = 60 // 封停用户
+ APITypeBlackUser = 61 // 添加黑名单
+ APITypeUserDeductedTime = 62 // 扣除时间
+)
+
// 算法类型常量
const (
AlgorithmNone = 0 // 不加密
AlgorithmRC4 = 1 // RC4
AlgorithmRSA = 2 // RSA
AlgorithmRSADynamic = 3 // RSA(动态)
+ AlgorithmEasy = 4 // 易加密
)
// GetAlgorithmName 获取算法名称
@@ -87,6 +128,8 @@ func GetAlgorithmName(algorithm int) string {
return "RSA"
case AlgorithmRSADynamic:
return "RSA(动态)"
+ case AlgorithmEasy:
+ return "易加密"
default:
return "未知算法"
}
@@ -94,5 +137,100 @@ func GetAlgorithmName(algorithm int) string {
// IsValidAlgorithm 验证算法类型是否有效
func IsValidAlgorithm(algorithm int) bool {
- return algorithm >= AlgorithmNone && algorithm <= AlgorithmRSADynamic
+ return algorithm >= AlgorithmNone && algorithm <= AlgorithmEasy
+}
+
+// GetAPITypeName 获取API类型名称
+func GetAPITypeName(apiType int) string {
+ switch apiType {
+ // 基础信息获取类API
+ case APITypeGetBulletin:
+ return "获取程序公告"
+ case APITypeGetUpdateUrl:
+ return "获取更新地址"
+ case APITypeCheckAppVersion:
+ return "检测最新版本"
+ case APITypeGetCardInfo:
+ return "获取卡密信息"
+
+ // 登录相关API
+ case APITypeSingleLogin:
+ return "卡密登录"
+
+ // 用户账号管理API
+ case APITypeUserLogin:
+ return "用户登录"
+ case APITypeUserRegin:
+ return "用户注册"
+ case APITypeUserRecharge:
+ return "用户充值"
+ case APITypeCardRegin:
+ return "卡密注册"
+
+ // 登出API
+ case APITypeLogOut:
+ return "退出登录"
+
+ // 用户状态查询API
+ case APITypeGetExpired:
+ return "获取到期时间"
+ case APITypeCheckUserStatus:
+ return "检测账号状态"
+ case APITypeGetAppData:
+ return "获取程序数据"
+ case APITypeGetVariable:
+ return "获取变量数据"
+
+ // 用户操作API
+ case APITypeUpdatePwd:
+ return "修改账号密码"
+ case APITypeMacChangeBind:
+ return "机器码转绑"
+ case APITypeIPChangeBind:
+ return "IP转绑"
+
+ // 管理员操作API
+ case APITypeDisableUser:
+ return "封停用户"
+ case APITypeBlackUser:
+ return "添加黑名单"
+ case APITypeUserDeductedTime:
+ return "扣除时间"
+
+ default:
+ return "未知API类型"
+ }
+}
+
+// IsValidAPIType 验证API类型是否有效
+func IsValidAPIType(apiType int) bool {
+ validTypes := []int{
+ APITypeGetBulletin, APITypeGetUpdateUrl, APITypeCheckAppVersion, APITypeGetCardInfo,
+ APITypeSingleLogin,
+ APITypeUserLogin, APITypeUserRegin, APITypeUserRecharge, APITypeCardRegin,
+ APITypeLogOut,
+ APITypeGetExpired, APITypeCheckUserStatus, APITypeGetAppData, APITypeGetVariable,
+ APITypeUpdatePwd, APITypeMacChangeBind, APITypeIPChangeBind,
+ APITypeDisableUser, APITypeBlackUser, APITypeUserDeductedTime,
+ }
+
+ for _, validType := range validTypes {
+ if apiType == validType {
+ return true
+ }
+ }
+ return false
+}
+
+// GetAPITypesByCategory 根据分类获取API类型列表
+func GetAPITypesByCategory() map[string][]int {
+ return map[string][]int{
+ "基础信息获取": {APITypeGetBulletin, APITypeGetUpdateUrl, APITypeCheckAppVersion, APITypeGetCardInfo},
+ "登录相关": {APITypeSingleLogin},
+ "用户账号管理": {APITypeUserLogin, APITypeUserRegin, APITypeUserRecharge, APITypeCardRegin},
+ "登出": {APITypeLogOut},
+ "用户状态查询": {APITypeGetExpired, APITypeCheckUserStatus, APITypeGetAppData, APITypeGetVariable},
+ "用户操作": {APITypeUpdatePwd, APITypeMacChangeBind, APITypeIPChangeBind},
+ "管理员操作": {APITypeDisableUser, APITypeBlackUser, APITypeUserDeductedTime},
+ }
}
diff --git a/models/app.go b/models/app.go
index be99d71..a2537fe 100644
--- a/models/app.go
+++ b/models/app.go
@@ -39,6 +39,9 @@ type App struct {
// DownloadURL:下载地址
DownloadURL string `gorm:"size:500;comment:下载地址" json:"download_url"`
+ // AppData:应用数据(base64编码存储)
+ AppData string `gorm:"type:text;comment:应用数据,base64编码存储" json:"app_data"`
+
// Announcement:程序公告内容(base64编码存储)
Announcement string `gorm:"type:text;comment:程序公告内容,base64编码存储" json:"announcement"`
diff --git a/server/admin.go b/server/admin.go
index f050ce8..87538da 100644
--- a/server/admin.go
+++ b/server/admin.go
@@ -43,7 +43,7 @@ func RegisterAdminRoutes(mux *http.ServeMux) {
mux.HandleFunc("/admin/user", adminctl.AdminAuthRequired(adminctl.UserFragmentHandler))
mux.HandleFunc("/admin/settings", adminctl.AdminAuthRequired(adminctl.SettingsFragmentHandler))
mux.HandleFunc("/admin/apps", adminctl.AdminAuthRequired(adminctl.AppsFragmentHandler))
-
+ mux.HandleFunc("/admin/apis", adminctl.AdminAuthRequired(adminctl.APIFragmentHandler))
// 个人资料API
mux.HandleFunc("/admin/api/user/profile", adminctl.AdminAuthRequired(adminctl.UserProfileQueryHandler))
@@ -61,6 +61,8 @@ func RegisterAdminRoutes(mux *http.ServeMux) {
mux.HandleFunc("/admin/api/apps/batch_delete", adminctl.AdminAuthRequired(adminctl.AppsBatchDeleteHandler))
mux.HandleFunc("/admin/api/apps/batch_update_status", adminctl.AdminAuthRequired(adminctl.AppsBatchUpdateStatusHandler))
mux.HandleFunc("/admin/api/apps/reset_secret", adminctl.AdminAuthRequired(adminctl.AppResetSecretHandler))
+ mux.HandleFunc("/admin/api/apps/get_app_data", adminctl.AdminAuthRequired(adminctl.AppGetAppDataHandler))
+ mux.HandleFunc("/admin/api/apps/update_app_data", adminctl.AdminAuthRequired(adminctl.AppUpdateAppDataHandler))
mux.HandleFunc("/admin/api/apps/get_announcement", adminctl.AdminAuthRequired(adminctl.AppGetAnnouncementHandler))
mux.HandleFunc("/admin/api/apps/update_announcement", adminctl.AdminAuthRequired(adminctl.AppUpdateAnnouncementHandler))
mux.HandleFunc("/admin/api/apps/get_multi_config", adminctl.AdminAuthRequired(adminctl.AppGetMultiConfigHandler))
@@ -70,6 +72,12 @@ func RegisterAdminRoutes(mux *http.ServeMux) {
mux.HandleFunc("/admin/api/apps/get_register_config", adminctl.AdminAuthRequired(adminctl.AppGetRegisterConfigHandler))
mux.HandleFunc("/admin/api/apps/update_register_config", adminctl.AdminAuthRequired(adminctl.AppUpdateRegisterConfigHandler))
+ // API接口管理API
+ mux.HandleFunc("/admin/api/apis/list", adminctl.AdminAuthRequired(adminctl.APIListHandler))
+ mux.HandleFunc("/admin/api/apis/update", adminctl.AdminAuthRequired(adminctl.APIUpdateHandler))
+ mux.HandleFunc("/admin/api/apis/apps", adminctl.AdminAuthRequired(adminctl.APIGetAppsHandler))
+ mux.HandleFunc("/admin/api/apis/reset_key", adminctl.AdminAuthRequired(adminctl.APIResetKeyHandler))
+ mux.HandleFunc("/admin/api/apis/generate_keys", adminctl.AdminAuthRequired(adminctl.APIGenerateKeysHandler))
// 系统信息API(用于仪表盘定时刷新)
mux.HandleFunc("/admin/api/system/info", adminctl.AdminAuthRequired(adminctl.SystemInfoHandler))
diff --git a/utils/encrypt/easy.go b/utils/encrypt/easy.go
new file mode 100644
index 0000000..c8b3675
--- /dev/null
+++ b/utils/encrypt/easy.go
@@ -0,0 +1,241 @@
+package encrypt
+
+import (
+ "crypto/rand"
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// EasyEncrypt 易加密算法结构体
+type EasyEncrypt struct {
+ encryptKey []int // 加密密钥
+ decryptKey []int // 解密密钥
+}
+
+// NewEasyEncrypt 创建新的易加密实例
+func NewEasyEncrypt(encryptKey, decryptKey []int) *EasyEncrypt {
+ return &EasyEncrypt{
+ encryptKey: encryptKey,
+ decryptKey: decryptKey,
+ }
+}
+
+// GenerateEasyKey 生成易加密密钥对
+func GenerateEasyKey() ([]int, []int, error) {
+ // 使用crypto/rand生成随机长度(15-30位)
+ var lengthByte [1]byte
+
+ // 生成加密密钥长度
+ if _, err := rand.Read(lengthByte[:]); err != nil {
+ return nil, nil, err
+ }
+ encryptKeyLen := 15 + int(lengthByte[0])%16 // 15-30位随机长度
+
+ encryptKey := make([]int, encryptKeyLen)
+ encryptBytes := make([]byte, encryptKeyLen)
+ if _, err := rand.Read(encryptBytes); err != nil {
+ return nil, nil, err
+ }
+ for i, b := range encryptBytes {
+ encryptKey[i] = int(b) // 0-255范围
+ }
+
+ // 生成解密密钥长度
+ if _, err := rand.Read(lengthByte[:]); err != nil {
+ return nil, nil, err
+ }
+ decryptKeyLen := 15 + int(lengthByte[0])%16 // 15-30位随机长度
+
+ decryptKey := make([]int, decryptKeyLen)
+ decryptBytes := make([]byte, decryptKeyLen)
+ if _, err := rand.Read(decryptBytes); err != nil {
+ return nil, nil, err
+ }
+ for i, b := range decryptBytes {
+ decryptKey[i] = int(b) // 0-255范围
+ }
+
+ return encryptKey, decryptKey, nil
+}
+
+// Encrypt 加密函数 - 对应 UserLogin_encrypt_Up_42510
+func (e *EasyEncrypt) Encrypt(input string) string {
+ if input == "" {
+ return ""
+ }
+
+ mKeyLen := len(e.encryptKey)
+ inputLen := len(input)
+ var result strings.Builder
+
+ for i := 0; i < inputLen; i++ {
+ mCode := int(input[i])
+ mCode = (mCode - 207) ^ e.encryptKey[i%mKeyLen]
+
+ if mCode < 0 {
+ mCode = -mCode
+ result.WriteString("-")
+ }
+
+ // 转换为16进制字符串
+ hexStr := strconv.FormatInt(int64(mCode), 16)
+ result.WriteString(hexStr)
+ result.WriteString(",")
+ }
+
+ // Base64编码
+ resultStr := result.String()
+ return base64.StdEncoding.EncodeToString([]byte(resultStr))
+}
+
+// Decrypt 解密函数 - 对应 UserLogin_decrypt_Down_42510
+func (e *EasyEncrypt) Decrypt(input string) string {
+ if input == "" {
+ return ""
+ }
+
+ // Base64解码
+ decoded, err := base64.StdEncoding.DecodeString(input)
+ if err != nil {
+ return ""
+ }
+
+ decodedStr := string(decoded)
+ mKeyLen := len(e.encryptKey)
+
+ // 按逗号分割
+ parts := strings.Split(decodedStr, ",")
+ var result strings.Builder
+
+ for i, part := range parts {
+ if part == "" {
+ continue
+ }
+
+ var d int
+ if strings.HasPrefix(part, "-") {
+ // 处理负数
+ hexStr := part[1:]
+ val, err := strconv.ParseInt(hexStr, 16, 32)
+ if err != nil {
+ continue
+ }
+ d = -int(val)
+ } else {
+ // 处理正数
+ val, err := strconv.ParseInt(part, 16, 32)
+ if err != nil {
+ continue
+ }
+ d = int(val)
+ }
+
+ // 解密计算
+ decryptedChar := (d ^ e.encryptKey[i%mKeyLen]) + 207
+ result.WriteByte(byte(decryptedChar))
+ }
+
+ return result.String()
+}
+
+// EncryptWithKey 使用指定密钥加密
+func EncryptWithKey(input string, key []int) string {
+ if input == "" || len(key) == 0 {
+ return ""
+ }
+
+ keyLen := len(key)
+ inputLen := len(input)
+ var result strings.Builder
+
+ for i := 0; i < inputLen; i++ {
+ mCode := int(input[i])
+ mCode = (mCode - 207) ^ key[i%keyLen]
+
+ if mCode < 0 {
+ mCode = -mCode
+ result.WriteString("-")
+ }
+
+ hexStr := strconv.FormatInt(int64(mCode), 16)
+ result.WriteString(hexStr)
+ result.WriteString(",")
+ }
+
+ resultStr := result.String()
+ return base64.StdEncoding.EncodeToString([]byte(resultStr))
+}
+
+// DecryptWithKey 使用指定密钥解密
+func DecryptWithKey(input string, key []int) string {
+ if input == "" || len(key) == 0 {
+ return ""
+ }
+
+ decoded, err := base64.StdEncoding.DecodeString(input)
+ if err != nil {
+ return ""
+ }
+
+ decodedStr := string(decoded)
+ keyLen := len(key)
+
+ parts := strings.Split(decodedStr, ",")
+ var result strings.Builder
+
+ for i, part := range parts {
+ if part == "" {
+ continue
+ }
+
+ var d int
+ if strings.HasPrefix(part, "-") {
+ hexStr := part[1:]
+ val, err := strconv.ParseInt(hexStr, 16, 32)
+ if err != nil {
+ continue
+ }
+ d = -int(val)
+ } else {
+ val, err := strconv.ParseInt(part, 16, 32)
+ if err != nil {
+ continue
+ }
+ d = int(val)
+ }
+
+ decryptedChar := (d ^ key[i%keyLen]) + 40
+ result.WriteByte(byte(decryptedChar))
+ }
+
+ return result.String()
+}
+
+// FormatKeyAsString 将密钥数组格式化为字符串(用于存储)
+func FormatKeyAsString(key []int) string {
+ var parts []string
+ for _, k := range key {
+ parts = append(parts, fmt.Sprintf("%d", k))
+ }
+ return strings.Join(parts, ",")
+}
+
+// ParseKeyFromString 从字符串解析密钥数组
+func ParseKeyFromString(keyStr string) []int {
+ if keyStr == "" {
+ return nil
+ }
+
+ parts := strings.Split(keyStr, ",")
+ var key []int
+
+ for _, part := range parts {
+ if val, err := strconv.Atoi(strings.TrimSpace(part)); err == nil {
+ key = append(key, val)
+ }
+ }
+
+ return key
+}
diff --git a/web/static/js/admin.js b/web/static/js/admin.js
index 151f252..cc94518 100755
--- a/web/static/js/admin.js
+++ b/web/static/js/admin.js
@@ -291,7 +291,13 @@ loadScript(layuijs, function () {
'user-username': '用户名:用于登录的用户名,可以修改但需要保证唯一性',
'user-old-password': '旧密码:修改密码时需要输入当前密码进行验证,不修改密码时可留空',
'user-new-password': '新密码:要设置的新密码,长度至少6位,不修改密码时可留空',
- 'user-confirm-password': '确认密码:再次输入新密码进行确认,必须与新密码一致'
+ 'user-confirm-password': '确认密码:再次输入新密码进行确认,必须与新密码一致',
+ // API接口管理相关 (apis.html)
+ 'submit-algorithm': '提交算法:客户端向服务器提交数据时使用的加密算法
• 不加密:数据明文传输,适用于内网环境
• RC4:对称加密,速度快,适用于一般场景
• RSA:非对称加密,安全性高,适用于敏感数据
• RSA(动态):动态生成密钥的RSA加密,安全性最高
• 易加密:自定义对称加密算法,使用15-30位整数密钥数组',
+ 'submit-keys': '提交密钥:用于加密客户端提交数据的密钥
• RC4:16位十六进制密钥,用于对称加密
• RSA:公钥用于客户端加密,私钥用于服务器解密
• 易加密:15-30位整数数组,逗号分隔
• 密钥由系统自动生成,确保安全性',
+ 'return-algorithm': '返回算法:服务器向客户端返回数据时使用的加密算法
• 不加密:数据明文传输,适用于内网环境
• RC4:对称加密,速度快,适用于一般场景
• RSA:非对称加密,安全性高,适用于敏感数据
• RSA(动态):动态生成密钥的RSA加密,安全性最高
• 易加密:自定义对称加密算法,使用15-30位整数密钥数组',
+ 'return-keys': '返回密钥:用于加密服务器返回数据的密钥
• RC4:16位十六进制密钥,用于对称加密
• RSA:公钥用于服务器加密,私钥用于客户端解密
• 易加密:15-30位整数数组,逗号分隔
• 密钥由系统自动生成,确保安全性',
+ 'api-status': '接口状态:控制当前API接口是否可用
• 启用:接口正常工作,客户端可以调用
• 禁用:接口暂停服务,客户端调用将返回错误'
};
return tips[type] || '暂无说明';
}
diff --git a/web/template/admin/apis.html b/web/template/admin/apis.html
new file mode 100644
index 0000000..7349141
--- /dev/null
+++ b/web/template/admin/apis.html
@@ -0,0 +1,526 @@
+{{ define "apis.html" }}
+接口管理
+
+
+
+
+
+