diff --git a/backend/controllers/attachments.go b/backend/controllers/attachments.go index 8060e74..e33a7b5 100644 --- a/backend/controllers/attachments.go +++ b/backend/controllers/attachments.go @@ -60,10 +60,10 @@ func Download(ctx *context.Context, w http.ResponseWriter, req *http.Request) { func writeAttachmentError(ctx *context.Context, w http.ResponseWriter, err error) { log.WithContext(ctx).WithError(err).Error("load attachment failed") if errors.Is(err, attachments.ErrAttachmentUnavailable) { - response.NewErrorResponse(response.ParamsError, "\u9644\u4ef6\u4e0d\u53ef\u7528", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "附件不可用", "").FPrint(w) return } - response.NewErrorResponse(response.ServerError, "\u8bfb\u53d6\u9644\u4ef6\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "读取附件失败", "").FPrint(w) } func safeDownloadName(name string) string { diff --git a/backend/controllers/attachments_test.go b/backend/controllers/attachments_test.go index 4a303d1..f3315fd 100644 --- a/backend/controllers/attachments_test.go +++ b/backend/controllers/attachments_test.go @@ -24,7 +24,7 @@ func TestSafeDownloadNameLength(t *testing.T) { if got := safeDownloadName(input); len([]rune(got)) != 180 { t.Fatalf("unexpected filename length: %d", len([]rune(got))) } - if got := safeDownloadName("\u4e2d\u6587-report.txt"); got != "\u4e2d\u6587-report.txt" { + if got := safeDownloadName("中文-report.txt"); got != "中文-report.txt" { t.Fatalf("unicode filename changed: %q", got) } } diff --git a/backend/controllers/email/delete.go b/backend/controllers/email/delete.go index 8d5de68..4ea4911 100644 --- a/backend/controllers/email/delete.go +++ b/backend/controllers/email/delete.go @@ -17,7 +17,7 @@ func EmailDelete(ctx *context.Context, w http.ResponseWriter, req *http.Request) var reqData emailDeleteRequest if err := decodeEmailJSONRequest(w, req, &reqData, maxEmailJSONRequestBytes); err != nil { log.WithContext(ctx).WithError(err).Info("invalid email delete request") - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } @@ -29,7 +29,7 @@ func EmailDelete(ctx *context.Context, w http.ResponseWriter, req *http.Request) err := del_email.DelEmail(ctx, reqData.IDs, reqData.ForcedDel) if err != nil { log.WithContext(ctx).WithError(err).Error("delete email failed") - response.NewErrorResponse(response.ServerError, "\u5220\u9664\u90ae\u4ef6\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "删除邮件失败", "").FPrint(w) return } response.NewSuccessResponse("success").FPrint(w) diff --git a/backend/controllers/email/detail.go b/backend/controllers/email/detail.go index c704a60..8916a43 100644 --- a/backend/controllers/email/detail.go +++ b/backend/controllers/email/detail.go @@ -16,7 +16,7 @@ func EmailDetail(ctx *context.Context, w http.ResponseWriter, req *http.Request) var retData emailDetailRequest if err := decodeEmailJSONRequest(w, req, &retData, maxEmailJSONRequestBytes); err != nil { log.WithContext(ctx).WithError(err).Info("invalid email detail request") - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } @@ -28,7 +28,7 @@ func EmailDetail(ctx *context.Context, w http.ResponseWriter, req *http.Request) email, err := detail.GetEmailDetail(ctx, retData.ID, true) if err != nil { log.WithContext(ctx).WithError(err).Error("load email detail failed") - response.NewErrorResponse(response.ServerError, "\u8bfb\u53d6\u90ae\u4ef6\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "读取邮件失败", "").FPrint(w) return } diff --git a/backend/controllers/email/list.go b/backend/controllers/email/list.go index ef2da25..c4ae321 100644 --- a/backend/controllers/email/list.go +++ b/backend/controllers/email/list.go @@ -56,19 +56,19 @@ func EmailList(ctx *context.Context, w http.ResponseWriter, req *http.Request) { var retData emailRequest if err := decodeEmailJSONRequest(w, req, &retData, maxEmailJSONRequestBytes); err != nil { log.WithContext(ctx).Info("email list request validation failed") - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } offset, err := normalizeEmailListRequest(&retData) if err != nil { - response.NewErrorResponse(response.ParamsError, "\u5206\u9875\u53c2\u6570\u8d85\u51fa\u9650\u5236", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "分页参数超出限制", "").FPrint(w) return } tagInfo := dto.SearchTag{Type: -1, Status: -1, GroupId: -1} if strings.TrimSpace(retData.Tag) != "" { if err := json.Unmarshal([]byte(retData.Tag), &tagInfo); err != nil { - response.NewErrorResponse(response.ParamsError, "\u90ae\u4ef6\u7b5b\u9009\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "邮件筛选参数错误", "").FPrint(w) return } } @@ -76,7 +76,7 @@ func EmailList(ctx *context.Context, w http.ResponseWriter, req *http.Request) { emailList, total, err := list.GetEmailList(ctx, tagInfo, retData.Keyword, false, offset, retData.PageSize) if err != nil { log.WithContext(ctx).WithError(err).Error("query email list failed") - response.NewErrorResponse(response.ServerError, "\u8bfb\u53d6\u90ae\u4ef6\u5217\u8868\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "读取邮件列表失败", "").FPrint(w) return } items := make([]*emilItem, 0, len(emailList)) @@ -84,7 +84,7 @@ func EmailList(ctx *context.Context, w http.ResponseWriter, req *http.Request) { var sender User if err := decodeStoredJSON(email.Sender, &sender); err != nil { log.WithContext(ctx).WithField("email_id", email.Id).WithError(err).Error("decode stored sender failed") - response.NewErrorResponse(response.ServerError, "\u8bfb\u53d6\u90ae\u4ef6\u5217\u8868\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "读取邮件列表失败", "").FPrint(w) return } if sender.EmailAddress == "" { @@ -95,7 +95,7 @@ func EmailList(ctx *context.Context, w http.ResponseWriter, req *http.Request) { var recipients []User if err := decodeStoredJSON(email.To, &recipients); err != nil { log.WithContext(ctx).WithField("email_id", email.Id).WithError(err).Error("decode stored recipients failed") - response.NewErrorResponse(response.ServerError, "\u8bfb\u53d6\u90ae\u4ef6\u5217\u8868\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "读取邮件列表失败", "").FPrint(w) return } authentication := parsemail.NewEmailAuthentication(email.SPFCheck == 1, email.DKIMCheck == 1) diff --git a/backend/controllers/email/move.go b/backend/controllers/email/move.go index b7656a7..fb0cc5a 100644 --- a/backend/controllers/email/move.go +++ b/backend/controllers/email/move.go @@ -19,7 +19,7 @@ func Move(ctx *context.Context, w http.ResponseWriter, req *http.Request) { var reqData moveRequest if err := decodeEmailJSONRequest(w, req, &reqData, maxEmailJSONRequestBytes); err != nil { log.WithContext(ctx).WithError(err).Info("invalid email move request") - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } @@ -32,12 +32,12 @@ func Move(ctx *context.Context, w http.ResponseWriter, req *http.Request) { err := group.Move2DefaultBox(ctx, reqData.IDs, name) if err != nil { log.WithContext(ctx).WithError(err).Error("move email failed") - response.NewErrorResponse(response.ServerError, "\u79fb\u52a8\u90ae\u4ef6\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "移动邮件失败", "").FPrint(w) return } } else if err := group.MoveMailToGroup(ctx, reqData.IDs, reqData.GroupId); err != nil { log.WithContext(ctx).WithError(err).Error("move email to user mailbox failed") - response.NewErrorResponse(response.ServerError, "\u79fb\u52a8\u90ae\u4ef6\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "移动邮件失败", "").FPrint(w) return } response.NewSuccessResponse("success").FPrint(w) diff --git a/backend/controllers/email/read.go b/backend/controllers/email/read.go index b041844..ccced46 100644 --- a/backend/controllers/email/read.go +++ b/backend/controllers/email/read.go @@ -16,7 +16,7 @@ func MarkRead(ctx *context.Context, w http.ResponseWriter, req *http.Request) { var reqData markReadRequest if err := decodeEmailJSONRequest(w, req, &reqData, maxEmailJSONRequestBytes); err != nil { log.WithContext(ctx).WithError(err).Info("invalid email read request") - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } @@ -28,7 +28,7 @@ func MarkRead(ctx *context.Context, w http.ResponseWriter, req *http.Request) { for _, id := range reqData.IDs { if _, err := detail.GetEmailDetail(ctx, id, true); err != nil { log.WithContext(ctx).WithError(err).Error("mark email read failed") - response.NewErrorResponse(response.ServerError, "\u66f4\u65b0\u90ae\u4ef6\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "更新邮件失败", "").FPrint(w) return } } diff --git a/backend/controllers/email/send.go b/backend/controllers/email/send.go index 025395f..8bdd759 100644 --- a/backend/controllers/email/send.go +++ b/backend/controllers/email/send.go @@ -71,18 +71,18 @@ func Send(ctx *context.Context, w http.ResponseWriter, req *http.Request) { var reqData sendRequest if err := decodeEmailJSONRequest(w, req, &reqData, maxSendRequestBytes); err != nil { log.WithContext(ctx).Errorf("%+v", err) - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } log.WithContext(ctx).Infof("发送邮件") allowLocalAlias := ctx.EffectiveRole() == access.RoleSuperAdmin if reqData.From.Email != "" && !validation.IsAuthorizedSender(reqData.From.Email, ctx.UserAccount, allowLocalAlias, domains.Accepted) { - response.NewErrorResponse(response.ParamsError, "\u53d1\u4ef6\u4eba\u5730\u5740\u4e0d\u5141\u8bb8", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "发件人地址不允许", "").FPrint(w) return } if reqData.Sender.Email != "" && !validation.IsAuthorizedSender(reqData.Sender.Email, ctx.UserAccount, allowLocalAlias, domains.Accepted) { - response.NewErrorResponse(response.ParamsError, "\u53d1\u9001\u8005\u5730\u5740\u4e0d\u5141\u8bb8", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "发送者地址不允许", "").FPrint(w) return } @@ -197,7 +197,7 @@ func Send(ctx *context.Context, w http.ResponseWriter, req *http.Request) { log.WithContext(ctx).Debugf("插件执行--SendBefore End") if e.From == nil || e.Sender == nil || !validation.IsAuthorizedSender(e.From.EmailAddress, ctx.UserAccount, allowLocalAlias, domains.Accepted) || !validation.IsAuthorizedSender(e.Sender.EmailAddress, ctx.UserAccount, allowLocalAlias, domains.Accepted) { - response.NewErrorResponse(response.ParamsError, "\u63d2\u4ef6\u4fee\u6539\u4e86\u672a\u6388\u6743\u7684\u53d1\u4ef6\u4eba", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "插件修改了未授权的发件人", "").FPrint(w) return } if err := validation.ValidateEmail(e, validation.EmailLimits{ @@ -208,7 +208,7 @@ func Send(ctx *context.Context, w http.ResponseWriter, req *http.Request) { MaxBodyBytes: maxSendBodyBytes, MaxEstimatedBytes: maxSendRequestBytes, }); err != nil { - response.NewErrorResponse(response.ParamsError, "\u63d2\u4ef6\u4fee\u6539\u540e\u7684\u90ae\u4ef6\u8d85\u51fa\u5b89\u5168\u9650\u5236", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "插件修改后的邮件超出安全限制", "").FPrint(w) return } diff --git a/backend/controllers/email/send_test.go b/backend/controllers/email/send_test.go index ce1d459..04001b7 100644 --- a/backend/controllers/email/send_test.go +++ b/backend/controllers/email/send_test.go @@ -1,4 +1,4 @@ -package email +package email import ( "testing" diff --git a/backend/controllers/group.go b/backend/controllers/group.go index a87d18d..b1379f6 100644 --- a/backend/controllers/group.go +++ b/backend/controllers/group.go @@ -22,7 +22,7 @@ func GetUserGroupList(ctx *context.Context, w http.ResponseWriter, req *http.Req infos, err := group.GetGroupList(ctx) if err != nil { log.WithContext(ctx).WithError(err).Error("query group list failed") - response.NewErrorResponse(response.ServerError, "\u83b7\u53d6\u5206\u7ec4\u5217\u8868\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "获取分组列表失败", "").FPrint(w) return } @@ -57,7 +57,7 @@ func GetUserGroup(ctx *context.Context, w http.ResponseWriter, req *http.Request infos, err := group.GetGroupInfoList(ctx) if err != nil { log.WithContext(ctx).WithError(err).Error("query group tree failed") - response.NewErrorResponse(response.ServerError, "\u83b7\u53d6\u5206\u7ec4\u5217\u8868\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "获取分组列表失败", "").FPrint(w) return } retData = array.Merge(retData, infos) @@ -74,14 +74,14 @@ func AddGroup(ctx *context.Context, w http.ResponseWriter, req *http.Request) { var reqData addGroupRequest if err := decodeJSONRequest(w, req, &reqData); err != nil { log.WithContext(ctx).WithError(err).Info("invalid group create request") - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } newGroup, err := group.CreateGroup(ctx, reqData.Name, reqData.ParentId) if err != nil { log.WithContext(ctx).WithError(err).Error("create group failed") - response.NewErrorResponse(response.ServerError, "\u521b\u5efa\u5206\u7ec4\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "创建分组失败", "").FPrint(w) return } @@ -96,13 +96,13 @@ func DelGroup(ctx *context.Context, w http.ResponseWriter, req *http.Request) { var reqData delGroupRequest if err := decodeJSONRequest(w, req, &reqData); err != nil { log.WithContext(ctx).WithError(err).Info("invalid group delete request") - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } succ, err := group.DelGroup(ctx, reqData.Id) if err != nil { log.WithContext(ctx).WithError(err).Error("delete group failed") - response.NewErrorResponse(response.ServerError, "\u5220\u9664\u5206\u7ec4\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "删除分组失败", "").FPrint(w) return } response.NewSuccessResponse(succ).FPrint(w) diff --git a/backend/controllers/plugin.go b/backend/controllers/plugin.go index 64452e8..ecccb68 100644 --- a/backend/controllers/plugin.go +++ b/backend/controllers/plugin.go @@ -20,7 +20,7 @@ const ( func GetPluginList(ctx *context.Context, w http.ResponseWriter, req *http.Request) { if !authenticatedPluginUser(ctx) || authorizeCapability(ctx, access.CapabilityPluginReadGlobal, "", false) != nil { - response.NewErrorResponse(response.NoAccessPrivileges, "\u65e0\u6743\u8bbf\u95ee", "").FPrint(w) + response.NewErrorResponse(response.NoAccessPrivileges, "无权访问", "").FPrint(w) return } ret := []string{} @@ -33,7 +33,7 @@ func GetPluginList(ctx *context.Context, w http.ResponseWriter, req *http.Reques func SettingsHtml(ctx *context.Context, w http.ResponseWriter, req *http.Request) { if !authenticatedPluginUser(ctx) || authorizeCapability(ctx, access.CapabilityPluginReadGlobal, "", false) != nil { - response.NewErrorResponse(response.NoAccessPrivileges, "\u65e0\u6743\u8bbf\u95ee", "").FPrint(w) + response.NewErrorResponse(response.NoAccessPrivileges, "无权访问", "").FPrint(w) return } rawPath := strings.TrimPrefix(req.URL.Path, "/api/plugin/settings/") diff --git a/backend/controllers/plugin_test.go b/backend/controllers/plugin_test.go index 2839f7e..419cf61 100644 --- a/backend/controllers/plugin_test.go +++ b/backend/controllers/plugin_test.go @@ -93,7 +93,7 @@ func TestSettingsHtmlRejectsNonAdminSave(t *testing.T) { recorder := httptest.NewRecorder() SettingsHtml(&context.Context{}, recorder, httptest.NewRequest(http.MethodPost, "/api/plugin/settings/PluginTest/save", strings.NewReader(`{"url":"https://model.example.com"}`))) - if recorder.Code != http.StatusOK || !strings.Contains(recorder.Body.String(), "\u65e0\u6743\u8bbf\u95ee") { + if recorder.Code != http.StatusOK || !strings.Contains(recorder.Body.String(), "无权访问") { t.Fatalf("non-admin plugin save was not rejected: status=%d body=%s", recorder.Code, recorder.Body.String()) } if hook.resource != "" || hook.body != "" { @@ -109,7 +109,7 @@ func TestPluginConfigurationRejectsNonAdminAccess(t *testing.T) { listRecorder := httptest.NewRecorder() GetPluginList(&context.Context{}, listRecorder, httptest.NewRequest(http.MethodGet, "/api/plugin/list", nil)) - if !strings.Contains(listRecorder.Body.String(), "\u65e0\u6743\u8bbf\u95ee") { + if !strings.Contains(listRecorder.Body.String(), "无权访问") { t.Fatalf("unauthenticated plugin list was not rejected: body=%s", listRecorder.Body.String()) } @@ -121,7 +121,7 @@ func TestPluginConfigurationRejectsNonAdminAccess(t *testing.T) { pageRecorder := httptest.NewRecorder() SettingsHtml(&context.Context{UserID: 2, Role: access.RoleUser}, pageRecorder, httptest.NewRequest(http.MethodGet, "/api/plugin/settings/PluginTest/index.html", nil)) - if !strings.Contains(pageRecorder.Body.String(), "\u65e0\u6743\u8bbf\u95ee") { + if !strings.Contains(pageRecorder.Body.String(), "无权访问") { t.Fatalf("non-admin plugin page was not rejected: body=%s", pageRecorder.Body.String()) } if hook.resource != "" || hook.body != "" { diff --git a/backend/controllers/rule.go b/backend/controllers/rule.go index 22dac38..9e9f8c3 100644 --- a/backend/controllers/rule.go +++ b/backend/controllers/rule.go @@ -34,7 +34,7 @@ func GetRule(ctx *context.Context, w http.ResponseWriter, req *http.Request) { res, err := rule.GetAllRules(ctx, ctx.UserID) if err != nil { log.WithContext(ctx).WithError(err).Error("load rules failed") - response.NewErrorResponse(response.ServerError, "\u8bfb\u53d6\u89c4\u5219\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "读取规则失败", "").FPrint(w) return } response.NewSuccessResponse(res).FPrint(w) @@ -45,14 +45,14 @@ func UpsertRule(ctx *context.Context, w http.ResponseWriter, req *http.Request) var data dto.Rule if err := decodeRuleBody(w, req, &data); err != nil { log.WithContext(ctx).WithError(err).Info("invalid rule request") - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } data.Name = strings.TrimSpace(data.Name) data.Params = strings.TrimSpace(data.Params) if data.Id < 0 || data.UserId != 0 || data.Name == "" || len(data.Name) > maxRuleNameBytes || len(data.Params) > maxRuleParamsBytes || data.Sort < -maxRuleSort || data.Sort > maxRuleSort { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } @@ -63,23 +63,23 @@ func UpsertRule(ctx *context.Context, w http.ResponseWriter, req *http.Request) } if (data.Action == dto.READ || data.Action == dto.DELETE) && data.Params != "" { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } if len(data.Rules) == 0 || len(data.Rules) > maxRuleConditions || !array.InArray(data.Action, []dto.RuleType{dto.READ, dto.FORWARD, dto.DELETE, dto.MOVE}) { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } for _, r := range data.Rules { if r == nil || r.Rule == "" || len(r.Rule) > maxRuleValueBytes || !array.InArray(r.Field, []string{"From", "Subject", "To", "Cc", "Text", "Html", "Content"}) || !array.InArray(r.Type, []string{match.RuleTypeRegex, match.RuleTypeContains, match.RuleTypeEq}) { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } if r.Type == match.RuleTypeRegex { if err := match.ValidateRegex(r.Rule); err != nil { - response.NewErrorResponse(response.ParamsError, "\u6b63\u5219\u8868\u8fbe\u5f0f\u65e0\u6548", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "正则表达式无效", "").FPrint(w) return } } @@ -88,12 +88,12 @@ func UpsertRule(ctx *context.Context, w http.ResponseWriter, req *http.Request) encoded, err := data.Encode() if err != nil { log.WithContext(ctx).WithError(err).Error("encode rule failed") - response.NewErrorResponse(response.ServerError, "\u4fdd\u5b58\u89c4\u5219\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "保存规则失败", "").FPrint(w) return } if err := save(ctx, encoded); err != nil { log.WithContext(ctx).WithError(err).Error("save rule failed") - response.NewErrorResponse(response.ServerError, "\u4fdd\u5b58\u89c4\u5219\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "保存规则失败", "").FPrint(w) return } response.NewSuccessResponse("succ").FPrint(w) @@ -149,19 +149,19 @@ func DelRule(ctx *context.Context, w http.ResponseWriter, req *http.Request) { var data delRuleReq if err := decodeRuleBody(w, req, &data); err != nil { log.WithContext(ctx).WithError(err).Info("invalid delete rule request") - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } if data.Id <= 0 { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } _, err := db.Instance.Exec(db.WithContext(ctx, "delete from rule where id =? and user_id =?"), data.Id, ctx.UserID) if err != nil { log.WithContext(ctx).WithError(err).Error("delete rule failed") - response.NewErrorResponse(response.ServerError, "\u5220\u9664\u89c4\u5219\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "删除规则失败", "").FPrint(w) return } diff --git a/backend/controllers/security.go b/backend/controllers/security.go index cce3528..93af8da 100644 --- a/backend/controllers/security.go +++ b/backend/controllers/security.go @@ -501,7 +501,7 @@ func BeginPasswordRecovery(ctx *context.Context, w http.ResponseWriter, req *htt if emailRecoveryBeginIPAttempts.blocked(beginKey) { id, err := newOpaqueRecoveryChallengeID() if err != nil { - writeSecurityError(w, response.ParamsError, "\u8bf7\u6c42\u5df2\u53d7\u7406") + writeSecurityError(w, response.ParamsError, "请求已受理") return } response.NewSuccessResponse(map[string]any{"id": id}).FPrint(w) @@ -512,7 +512,7 @@ func BeginPasswordRecovery(ctx *context.Context, w http.ResponseWriter, req *htt } browserContext, ok := recoveryBrowserContext(req, w, true) if !ok { - writeSecurityError(w, response.ParamsError, "\u8bf7\u6c42\u5df2\u53d7\u7406") + writeSecurityError(w, response.ParamsError, "请求已受理") return } id, err := runtime.recovery.Begin(recovery.BeginRequest{Identifier: input.Account, Email: input.Email, BrowserContext: browserContext}, remoteIP(req)) @@ -532,7 +532,7 @@ func VerifyPasswordRecovery(ctx *context.Context, w http.ResponseWriter, req *ht } failureKey := emailRecoveryFailureIPAttempts.ipKey(req) if emailRecoveryFailureIPAttempts.blocked(failureKey) { - writeSecurityError(w, response.ParamsError, "\u9a8c\u8bc1\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "验证失败") return } var input verificationCheckRequest @@ -550,7 +550,7 @@ func VerifyPasswordRecovery(ctx *context.Context, w http.ResponseWriter, req *ht browserContext, ok := recoveryBrowserContext(req, w, methodOffline) if !ok { emailRecoveryFailureIPAttempts.recordFailure(failureKey) - writeSecurityError(w, response.ParamsError, "\u9a8c\u8bc1\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "验证失败") return } if methodOffline { @@ -573,7 +573,7 @@ func CompletePasswordRecovery(ctx *context.Context, w http.ResponseWriter, req * } failureKey := emailRecoveryFailureIPAttempts.ipKey(req) if emailRecoveryFailureIPAttempts.blocked(failureKey) { - writeSecurityError(w, response.ParamsError, "\u91cd\u7f6e\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "重置失败") return } var input recoveryCompleteRequest @@ -585,7 +585,7 @@ func CompletePasswordRecovery(ctx *context.Context, w http.ResponseWriter, req * browserContext, ok := recoveryBrowserContext(req, w, false) if !ok { emailRecoveryFailureIPAttempts.recordFailure(failureKey) - writeSecurityError(w, response.ParamsError, "\u9a8c\u8bc1\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "验证失败") return } if err := runtime.recovery.CompleteWithContext(input.Ticket, input.NewPassword, browserContext); err != nil { diff --git a/backend/controllers/settings.go b/backend/controllers/settings.go index 82d53c0..f425e82 100644 --- a/backend/controllers/settings.go +++ b/backend/controllers/settings.go @@ -30,7 +30,7 @@ func ModifyPassword(ctx *context.Context, w http.ResponseWriter, req *http.Reque return } if ctx.EffectiveRole() == access.RoleSuperAdmin { - response.NewErrorResponse(response.NoAccessPrivileges, "\u8d85\u7ea7\u7ba1\u7406\u5458\u5fc5\u987b\u901a\u8fc7\u90e8\u7f72\u7aef\u4e13\u7528\u901a\u9053\u91cd\u7f6e\u5bc6\u7801", "").FPrint(w) + response.NewErrorResponse(response.NoAccessPrivileges, "超级管理员必须通过部署端专用通道重置密码", "").FPrint(w) return } var retData modifyPasswordRequest @@ -76,7 +76,7 @@ func ModifyPassword(ctx *context.Context, w http.ResponseWriter, req *http.Reque } if err := auth.SetPassword(&user, retData.Password); err != nil { if errors.Is(err, password.ErrInvalidLength) { - response.NewErrorResponse(response.ParamsError, "\u5bc6\u7801\u957f\u5ea6\u5fc5\u987b\u4e3a 8-12 \u5b57\u8282", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "密码长度必须为 8-12 字节", "").FPrint(w) return } log.WithContext(ctx).WithError(err).Error("password hash failed") diff --git a/backend/controllers/setup.go b/backend/controllers/setup.go index 1ffb000..26b5c43 100644 --- a/backend/controllers/setup.go +++ b/backend/controllers/setup.go @@ -84,7 +84,7 @@ func writeSetupError(ctx *context.Context, w http.ResponseWriter, err error) { message = ssl.UserCertificateErrorMessage(err) } if message == "" { - message = "\u521d\u59cb\u5316\u64cd\u4f5c\u5931\u8d25" + message = "初始化操作失败" } response.NewErrorResponse(response.ServerError, message, "").FPrint(w) } @@ -94,7 +94,7 @@ func Setup(ctx *context.Context, w http.ResponseWriter, req *http.Request) { reqBytes, err := io.ReadAll(req.Body) if err != nil { log.WithContext(ctx).WithError(err).Info("setup request body rejected") - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } @@ -102,7 +102,7 @@ func Setup(ctx *context.Context, w http.ResponseWriter, req *http.Request) { err = json.Unmarshal(reqBytes, &reqData) if err != nil { log.WithContext(ctx).WithError(err).Info("setup request json rejected") - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } diff --git a/backend/controllers/user.go b/backend/controllers/user.go index 8fa34a3..1068524 100644 --- a/backend/controllers/user.go +++ b/backend/controllers/user.go @@ -65,29 +65,29 @@ func CreateUser(ctx *context.Context, w http.ResponseWriter, req *http.Request) return } if reqData.Username == "" || reqData.Password == "" || reqData.Account == "" { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } if reqData.Disabled != 0 && reqData.Disabled != 1 { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } account, err := validation.NormalizeAccount(reqData.Account) if err != nil { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } username, err := validation.NormalizeDisplayName(reqData.Username) if err != nil { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } user := models.User{Name: username, Account: account, Disabled: reqData.Disabled, SessionVersion: 1, SecurityVersion: 1} user.ApplyRole(targetRole) if err := auth.SetPassword(&user, reqData.Password); err != nil { if errors.Is(err, password.ErrInvalidLength) { - response.NewErrorResponse(response.ParamsError, "\u5bc6\u7801\u957f\u5ea6\u5fc5\u987b\u4e3a 8-12 \u5b57\u8282", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "密码长度必须为 8-12 字节", "").FPrint(w) return } log.WithContext(ctx).WithError(err).Error("password hash failed") @@ -96,7 +96,7 @@ func CreateUser(ctx *context.Context, w http.ResponseWriter, req *http.Request) } if _, err := db.Instance.Insert(&user); err != nil { log.WithContext(ctx).WithError(err).Error("create user failed") - response.NewErrorResponse(response.ServerError, "\u521b\u5efa\u7528\u6237\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "创建用户失败", "").FPrint(w) return } response.NewSuccessResponse(user).FPrint(w) @@ -153,12 +153,12 @@ func loadUserSecurityStatus(users []models.User) (map[int]bool, map[int]bool, er func UserList(ctx *context.Context, w http.ResponseWriter, req *http.Request) { if err := authorizeCapability(ctx, access.CapabilityUserRead, "", false); err != nil { - response.NewErrorResponse(response.NoAccessPrivileges, "\u65e0\u6743\u8bbf\u95ee", "").FPrint(w) + response.NewErrorResponse(response.NoAccessPrivileges, "无权访问", "").FPrint(w) return } var reqData userListRequest if err := decodeUserRequest(w, req, &reqData); err != nil { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } if reqData.PageSize <= 0 || reqData.PageSize > 100 { @@ -251,11 +251,11 @@ func EditUser(ctx *context.Context, w http.ResponseWriter, req *http.Request) { return } if reqData.Id == 0 && reqData.Account == "" { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } if reqData.Disabled != 0 && reqData.Disabled != 1 { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } @@ -267,18 +267,18 @@ func EditUser(ctx *context.Context, w http.ResponseWriter, req *http.Request) { } else { account, validationErr := validation.NormalizeAccount(reqData.Account) if validationErr != nil { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } found, err = db.Instance.Where("account=?", account).Get(&user) } if err != nil { log.WithContext(ctx).Errorf("SQL Error: %+v", err) - response.NewErrorResponse(response.ServerError, "\u67e5\u8be2\u7528\u6237\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "查询用户失败", "").FPrint(w) return } if !found || user.ID == 0 { - response.NewErrorResponse(response.ParamsError, "\u7528\u6237\u4e0d\u5b58\u5728", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "用户不存在", "").FPrint(w) return } targetRole := user.EffectiveRole() @@ -319,17 +319,17 @@ func EditUser(ctx *context.Context, w http.ResponseWriter, req *http.Request) { user.ApplyRole(newRole) } if user.IsAdmin == 1 && reqData.Disabled != 0 { - response.NewErrorResponse(response.ParamsError, "\u4e0d\u5141\u8bb8\u7981\u7528\u7ba1\u7406\u5458\u8d26\u6237", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "不允许禁用管理员账户", "").FPrint(w) return } if user.ID == ctx.UserID && reqData.Password != "" { - response.NewErrorResponse(response.ParamsError, "\u8bf7\u901a\u8fc7\u5b89\u5168\u8bbe\u7f6e\u4fee\u6539\u5f53\u524d\u8d26\u6237\u5bc6\u7801", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "请通过安全设置修改当前账户密码", "").FPrint(w) return } if reqData.Username != "" { username, validationErr := validation.NormalizeDisplayName(reqData.Username) if validationErr != nil { - response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "参数错误", "").FPrint(w) return } user.Name = username @@ -338,7 +338,7 @@ func EditUser(ctx *context.Context, w http.ResponseWriter, req *http.Request) { if reqData.Password != "" { if err := auth.SetPassword(&user, reqData.Password); err != nil { if errors.Is(err, password.ErrInvalidLength) { - response.NewErrorResponse(response.ParamsError, "\u5bc6\u7801\u957f\u5ea6\u5fc5\u987b\u4e3a 8-12 \u5b57\u8282", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "密码长度必须为 8-12 字节", "").FPrint(w) return } log.WithContext(ctx).WithError(err).Error("password hash failed") diff --git a/backend/controllers/webauthn.go b/backend/controllers/webauthn.go index b484eb5..5a93e20 100644 --- a/backend/controllers/webauthn.go +++ b/backend/controllers/webauthn.go @@ -180,19 +180,19 @@ func RevokeWebAuthnCredential(ctx *context.Context, w http.ResponseWriter, req * func BeginWebAuthnLogin(ctx *context.Context, w http.ResponseWriter, req *http.Request) { service := webAuthnRuntime() if service == nil { - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u767b\u5f55\u4e0d\u53ef\u7528") + writeSecurityError(w, response.ParamsError, "安全密钥登录不可用") return } beginKey := webAuthnLoginBeginIPAttempts.ipKey(req) failureKey := webAuthnLoginFailureIPAttempts.ipKey(req) if webAuthnLoginBeginIPAttempts.blocked(beginKey) || webAuthnLoginFailureIPAttempts.blocked(failureKey) || loginIPAttempts.blocked(loginIPAttempts.ipKey(req)) { - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u767b\u5f55\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "安全密钥登录失败") return } var input webAuthnLoginBeginRequest if err := decodeJSONRequest(w, req, &input); err != nil || strings.TrimSpace(input.ChallengeID) == "" || strings.TrimSpace(input.Account) == "" { webAuthnLoginFailureIPAttempts.recordFailure(failureKey) - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u767b\u5f55\u8bf7\u6c42\u65e0\u6548") + writeSecurityError(w, response.ParamsError, "安全密钥登录请求无效") return } item, ok := pendingLoginVerification(input.ChallengeID, input.Account) @@ -204,7 +204,7 @@ func BeginWebAuthnLogin(ctx *context.Context, w http.ResponseWriter, req *http.R options, sessionID, err := service.BeginLogin(item.UserID) if err != nil { webAuthnLoginFailureIPAttempts.recordFailure(failureKey) - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u767b\u5f55\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "安全密钥登录失败") return } response.NewSuccessResponse(map[string]any{ @@ -221,19 +221,19 @@ func FinishWebAuthnLogin(ctx *context.Context, w http.ResponseWriter, req *http. runtime := currentSecurityRuntime() service := runtime.webauthn if service == nil { - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u767b\u5f55\u4e0d\u53ef\u7528") + writeSecurityError(w, response.ParamsError, "安全密钥登录不可用") return } failureKey := webAuthnLoginFailureIPAttempts.ipKey(req) if webAuthnLoginFailureIPAttempts.blocked(failureKey) || loginIPAttempts.blocked(loginIPAttempts.ipKey(req)) { - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u767b\u5f55\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "安全密钥登录失败") return } var input webAuthnFinishRequest if err := decodeJSONRequest(w, req, &input); err != nil || strings.TrimSpace(input.ChallengeID) == "" || strings.TrimSpace(input.SessionID) == "" || len(input.Credential) == 0 || !json.Valid(input.Credential) { webAuthnLoginFailureIPAttempts.recordFailure(failureKey) loginIPAttempts.recordFailure(loginIPAttempts.ipKey(req)) - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u767b\u5f55\u8bf7\u6c42\u65e0\u6548") + writeSecurityError(w, response.ParamsError, "安全密钥登录请求无效") return } account := strings.TrimSpace(input.Account) @@ -251,7 +251,7 @@ func FinishWebAuthnLogin(ctx *context.Context, w http.ResponseWriter, req *http. if _, err := service.FinishLogin(item.UserID, input.SessionID, credentialRequest); err != nil { webAuthnLoginFailureIPAttempts.recordFailure(failureKey) loginIPAttempts.recordFailure(loginIPAttempts.ipKey(req)) - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u767b\u5f55\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "安全密钥登录失败") return } var user models.User @@ -273,28 +273,28 @@ func BeginWebAuthnRecovery(ctx *context.Context, w http.ResponseWriter, req *htt } service := currentSecurityRuntime().recovery if service == nil { - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u6062\u590d\u4e0d\u53ef\u7528") + writeSecurityError(w, response.ParamsError, "安全密钥恢复不可用") return } beginKey := webAuthnRecoveryBeginIPAttempts.ipKey(req) failureKey := webAuthnRecoveryFailureIPAttempts.ipKey(req) if webAuthnRecoveryBeginIPAttempts.blocked(beginKey) || webAuthnRecoveryFailureIPAttempts.blocked(failureKey) { - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u9a8c\u8bc1\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "安全密钥验证失败") return } var input webAuthnRecoveryBeginRequest if err := decodeJSONRequest(w, req, &input); err != nil || strings.TrimSpace(input.Identifier) == "" { webAuthnRecoveryFailureIPAttempts.recordFailure(failureKey) - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u6062\u590d\u8bf7\u6c42\u65e0\u6548") + writeSecurityError(w, response.ParamsError, "安全密钥恢复请求无效") return } if _, ok := recoveryBrowserContext(req, w, true); !ok { - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u6062\u590d\u8bf7\u6c42\u65e0\u6548") + writeSecurityError(w, response.ParamsError, "安全密钥恢复请求无效") return } options, sessionID, err := service.BeginWebAuthn(input.Identifier) if err != nil { - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u9a8c\u8bc1\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "安全密钥验证失败") return } webAuthnRecoveryBeginIPAttempts.recordFailure(beginKey) @@ -307,31 +307,31 @@ func VerifyWebAuthnRecovery(ctx *context.Context, w http.ResponseWriter, req *ht } service := currentSecurityRuntime().recovery if service == nil { - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u6062\u590d\u4e0d\u53ef\u7528") + writeSecurityError(w, response.ParamsError, "安全密钥恢复不可用") return } failureKey := webAuthnRecoveryFailureIPAttempts.ipKey(req) if webAuthnRecoveryFailureIPAttempts.blocked(failureKey) { - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u9a8c\u8bc1\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "安全密钥验证失败") return } var input webAuthnRecoveryVerifyRequest if err := decodeJSONRequest(w, req, &input); err != nil || strings.TrimSpace(input.Identifier) == "" || strings.TrimSpace(input.SessionID) == "" || len(input.Credential) == 0 || !json.Valid(input.Credential) { webAuthnRecoveryFailureIPAttempts.recordFailure(failureKey) - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u6062\u590d\u8bf7\u6c42\u65e0\u6548") + writeSecurityError(w, response.ParamsError, "安全密钥恢复请求无效") return } browserContext, ok := recoveryBrowserContext(req, w, false) if !ok { webAuthnRecoveryFailureIPAttempts.recordFailure(failureKey) - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u9a8c\u8bc1\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "安全密钥验证失败") return } credentialRequest := cloneWebAuthnRequest(req, input.Credential) ticket, err := service.VerifyWebAuthnWithContext(input.Identifier, input.SessionID, credentialRequest, browserContext) if err != nil { webAuthnRecoveryFailureIPAttempts.recordFailure(failureKey) - writeSecurityError(w, response.ParamsError, "\u5b89\u5168\u5bc6\u94a5\u9a8c\u8bc1\u5931\u8d25") + writeSecurityError(w, response.ParamsError, "安全密钥验证失败") return } response.NewSuccessResponse(map[string]any{"ticket": ticket}).FPrint(w) diff --git a/backend/db/init.go b/backend/db/init.go index 1f3106f..37d4d1d 100644 --- a/backend/db/init.go +++ b/backend/db/init.go @@ -78,7 +78,7 @@ func Init(version string) error { if err != nil { return errors.Wrap(err) } - log.Infof("\u5f53\u524d\u6570\u636e\u5e93\u7ed3\u6784\u7248\u672c: %d", report.CurrentVersion) + log.Infof("当前数据库结构版本: %d", report.CurrentVersion) // 更新历史数据 if err := fixHistoryData(); err != nil { return errors.Wrap(err) @@ -125,7 +125,7 @@ func legacySyncEnabled(version string) bool { return false } if version != "test" && !config.DevelopmentMode { - log.Warn("\u751f\u4ea7\u73af\u5883\u5df2\u62d2\u7edd\u542f\u7528\u65e7 Sync2 \u517c\u5bb9\u6a21\u5f0f") + log.Warn("生产环境已拒绝启用旧 Sync2 兼容模式") return false } return true diff --git a/backend/dto/response/response.go b/backend/dto/response/response.go index 1e4a81b..e76c987 100644 --- a/backend/dto/response/response.go +++ b/backend/dto/response/response.go @@ -25,7 +25,7 @@ func (p *Response) FPrint(w http.ResponseWriter) { bytesData, err := json.Marshal(p) if err != nil { log.WithError(err).Error("serialize HTTP response failed") - http.Error(w, "\u54cd\u5e94\u5e8f\u5217\u5316\u5931\u8d25", http.StatusInternalServerError) + http.Error(w, "响应序列化失败", http.StatusInternalServerError) return } if observer, ok := w.(interface{ ObserveResult(int) }); ok { diff --git a/backend/hooks/spam_block/export/export.go b/backend/hooks/spam_block/export/export.go index 0f5ba75..4a05da2 100644 --- a/backend/hooks/spam_block/export/export.go +++ b/backend/hooks/spam_block/export/export.go @@ -50,7 +50,7 @@ func main() { fmt.Println("文件第一列是分类,0表示正常邮件,1表示垃圾邮件,2表示诈骗邮件") if err := exportEmails(id); err != nil { - fmt.Fprintf(os.Stderr, "\u5bfc\u51fa\u5931\u8d25: %v\n", err) + fmt.Fprintf(os.Stderr, "导出失败: %v\n", err) os.Exit(1) } } diff --git a/backend/hooks/spam_block/spam_block_test.go b/backend/hooks/spam_block/spam_block_test.go index cc5f15f..79cc886 100644 --- a/backend/hooks/spam_block/spam_block_test.go +++ b/backend/hooks/spam_block/spam_block_test.go @@ -201,7 +201,7 @@ func TestSettingsHtmlEscapesConfiguredURL(t *testing.T) { func TestBuildSpamBlockModelTextLimitsInput(t *testing.T) { email := &parsemail.Email{ - Subject: strings.Repeat("\u754c", maxSpamBlockModelTextBytes), + Subject: strings.Repeat("界", maxSpamBlockModelTextBytes), HTML: []byte(strings.Repeat("
body
", maxSpamBlockSourceBytes)), } text := buildSpamBlockModelText(email) diff --git a/backend/hooks/wechat_push/wechat_push_test.go b/backend/hooks/wechat_push/wechat_push_test.go index c4f7477..78b47cf 100644 --- a/backend/hooks/wechat_push/wechat_push_test.go +++ b/backend/hooks/wechat_push/wechat_push_test.go @@ -115,7 +115,7 @@ func TestWeChatRuntimeConfigRejectsTrailingJSON(t *testing.T) { func TestBuildWeChatMessageLimitsContent(t *testing.T) { message := buildWeChatMessage(&parsemail.Email{ - Subject: strings.Repeat("\u754c", maxWeChatMessageBytes), + Subject: strings.Repeat("界", maxWeChatMessageBytes), Text: []byte(strings.Repeat("body", maxWeChatMessageBytes)), }) if len(message) > maxWeChatMessageBytes { diff --git a/backend/listen/http_server/https_server.go b/backend/listen/http_server/https_server.go index a6e21ec..b6826a2 100644 --- a/backend/listen/http_server/https_server.go +++ b/backend/listen/http_server/https_server.go @@ -115,7 +115,7 @@ func contextIterceptor(h controllers.HandlerFunc) http.HandlerFunc { r.Body = http.MaxBytesReader(w, r.Body, 64<<20) if normalizedAPIPath(r.URL.Path) == "/api/login" && !loginRequestAllowed(r) { - response.NewErrorResponse(response.ParamsError, "\u8bf7\u6c42\u6765\u6e90\u6821\u9a8c\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ParamsError, "请求来源校验失败", "").FPrint(w) return } @@ -146,7 +146,7 @@ func contextIterceptor(h controllers.HandlerFunc) http.HandlerFunc { found, err := db.Instance.ID(identity.ID).Get(¤tUser) if err != nil { log.WithContext(ctx).WithError(err).Error("validate session user failed") - response.NewErrorResponse(response.ServerError, "\u4f1a\u8bdd\u6821\u9a8c\u5931\u8d25", "").FPrint(w) + response.NewErrorResponse(response.ServerError, "会话校验失败", "").FPrint(w) return } if !found || currentUser.Disabled != 0 || currentUser.Account != identity.Account || currentUser.SessionVersion != identity.SessionVersion || (identity.SecurityVersion > 0 && currentUser.SecurityVersion != identity.SecurityVersion) { diff --git a/backend/listen/smtp_server/audit_persistence.go b/backend/listen/smtp_server/audit_persistence.go index 5ebe9e2..e75850b 100644 --- a/backend/listen/smtp_server/audit_persistence.go +++ b/backend/listen/smtp_server/audit_persistence.go @@ -175,7 +175,7 @@ func resolveIncomingUsers(ctx *context.Context, email *parsemail.Email, emailTyp } log.WithContext(ctx).Infof("收件人不存在但DKIM验证通过,转交管理员: recipient_count=%d", len(accounts)) - if err := db.Instance.Table(&models.User{}).Where("is_admin=1 AND disabled=0").Find(&users); err != nil { + if err := db.Instance.Table(&models.User{}).Where(models.SuperAdminPredicate + " AND disabled=0").Find(&users); err != nil { return nil, false, err } if len(users) == 0 { diff --git a/backend/models/user_scope.go b/backend/models/user_scope.go index dd103af..aeaf132 100644 --- a/backend/models/user_scope.go +++ b/backend/models/user_scope.go @@ -2,3 +2,6 @@ package models // OrdinaryUserPredicate 与 EffectiveRole 的兼容规则一致,旧管理员不能混入普通用户范围。 const OrdinaryUserPredicate = "(role = 'user' OR ((role IS NULL OR role NOT IN ('user', 'admin', 'super_admin')) AND is_admin <> 1))" + +// SuperAdminPredicate 与 EffectiveRole 的兼容规则一致,确保未知收件人等系统邮件严格仅流向超级管理员。 +const SuperAdminPredicate = "(role = 'super_admin' OR ((role IS NULL OR role NOT IN ('user', 'admin', 'super_admin')) AND is_admin = 1))" diff --git a/backend/services/adminreset/password_windows.go b/backend/services/adminreset/password_windows.go index 188942f..a92202c 100644 --- a/backend/services/adminreset/password_windows.go +++ b/backend/services/adminreset/password_windows.go @@ -46,7 +46,7 @@ func readWindowsPassword(prompt string) (string, error) { value[i] = 0 } if password.ValidateUserPassword(normalized) != nil { - return "", errors.New("\u5bc6\u7801\u957f\u5ea6\u5fc5\u987b\u4e3a 8 \u5230 12 \u4e2a\u5b57\u7b26") + return "", errors.New("密码长度必须为 8 到 12 个字符") } return normalized, nil } diff --git a/backend/services/adminreset/protocol_test.go b/backend/services/adminreset/protocol_test.go index 2c5a3f5..af9a2dc 100644 --- a/backend/services/adminreset/protocol_test.go +++ b/backend/services/adminreset/protocol_test.go @@ -82,7 +82,7 @@ func TestProtocolEnforcesUnifiedPasswordLength(t *testing.T) { valid := []string{ `{"version":1,"nonce":"n","new_password":"12345678"}`, `{"version":1,"nonce":"n","new_password":"123456789012"}`, - `{"version":1,"nonce":"n","new_password":"\u5bc6\u7801aa"}`, + `{"version":1,"nonce":"n","new_password":"密码aa"}`, } for _, input := range valid { if _, err := DecodeRequest(strings.NewReader(input)); err != nil { @@ -93,7 +93,7 @@ func TestProtocolEnforcesUnifiedPasswordLength(t *testing.T) { invalid := []string{ `{"version":1,"nonce":"n","new_password":"1234567"}`, `{"version":1,"nonce":"n","new_password":"1234567890123"}`, - `{"version":1,"nonce":"n","new_password":"\u5bc6\u7801\u5bc6\u7801a"}`, + `{"version":1,"nonce":"n","new_password":"密码密码a"}`, } for _, input := range invalid { if _, err := DecodeRequest(strings.NewReader(input)); !errors.Is(err, ErrInvalidRequest) { diff --git a/backend/services/setup/db.go b/backend/services/setup/db.go index 9734a84..8feeeec 100644 --- a/backend/services/setup/db.go +++ b/backend/services/setup/db.go @@ -144,7 +144,7 @@ func GetDatabaseSettingsDetail(ctx *context.Context) (map[string]string, error) func GetAdminPassword(ctx *context.Context) (string, error) { if db.Instance == nil { - return "", databaseError("\u6570\u636e\u5e93\u5c1a\u672a\u521d\u59cb\u5316\uff0c\u8bf7\u5148\u5b8c\u6210\u6570\u636e\u5e93\u8bbe\u7f6e", nil) + return "", databaseError("数据库尚未初始化,请先完成数据库设置", nil) } users := []*models.User{} if err := db.Instance.Find(&users); err != nil { @@ -162,7 +162,7 @@ func SetAdminPassword(ctx *context.Context, account, pwd string) error { adminSetupMutex.Lock() defer adminSetupMutex.Unlock() if db.Instance == nil { - return databaseError("\u6570\u636e\u5e93\u5c1a\u672a\u521d\u59cb\u5316\uff0c\u8bf7\u5148\u5b8c\u6210\u6570\u636e\u5e93\u8bbe\u7f6e", nil) + return databaseError("数据库尚未初始化,请先完成数据库设置", nil) } if err := validateAdminPassword(pwd); err != nil { diff --git a/backend/services/setup/dns.go b/backend/services/setup/dns.go index 9c3c1e7..f4f9c9a 100644 --- a/backend/services/setup/dns.go +++ b/backend/services/setup/dns.go @@ -58,7 +58,7 @@ func buildDNSItems(configData *config.Config, domain, dkimPublicKey, ipv4, ipv6, func buildDNSItemsWithWebIPv4(configData *config.Config, domain, dkimPublicKey, ipv4, ipv6, ipTips string, webIPv4 []string) []*DNSItem { address := normalizeDNSAddress(ipv4) if address == "" { - address = "[\u672a\u68c0\u6d4b\u5230\u516c\u7f51 IPv4]" + address = "[未检测到公网 IPv4]" } items := make([]*DNSItem, 0, 13)