aliyun sensor server

This commit is contained in:
tamakyi
2026-09-10 18:04:19 +08:00
parent e3e59e7c69
commit 8e2325eda5
38 changed files with 3147 additions and 344 deletions
+8 -23
View File
@@ -14,7 +14,7 @@ import (
"github.com/tamakyi/TamaBox/internal/form"
"github.com/tamakyi/TamaBox/internal/i18n"
"github.com/tamakyi/TamaBox/internal/mail"
"github.com/tamakyi/TamaBox/internal/security/censor"
"github.com/tamakyi/TamaBox/internal/security/moderation"
"github.com/tamakyi/TamaBox/internal/shared"
)
@@ -100,17 +100,10 @@ func PublishFollowUp(ctx context.Context, pageUser *db.User, question *db.Questi
return
}
// 内容安全检测
censorResponse, err := censor.Text(ctx.Request().Context(), f.Content)
if err != nil {
// 审核源全部不可用:fail-closed,拒绝发布而非免审放行。
logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to censor follow up text")
ctx.SetErrorFlash(i18n.T(ctx.Lang(), "censor.unavailable"))
ctx.Redirect(fmt.Sprintf("/_/%s/%d?t=%s", pageUser.Domain, question.ID, question.Token))
return
}
if !censorResponse.Pass {
ctx.SetErrorFlash(censorResponse.ErrorMessage())
// 内容安全检测:统一守卫,按箱主「审核严格度」裁决是否放行
// (提问 / 投票 / 私聊共用同一份判定,见 internal/security/moderation)。
if _, err := moderation.Check(ctx.Request().Context(), moderation.StrictnessFor(pageUser.ModerationStrictness), ctx.Lang(), f.Content); err != nil {
ctx.SetErrorFlash(err.Error())
ctx.Redirect(fmt.Sprintf("/_/%s/%d?t=%s", pageUser.Domain, question.ID, question.Token))
return
}
@@ -167,17 +160,9 @@ func AnswerFollowUp(ctx context.Context, pageUser *db.User, question *db.Questio
followUpID := uint(ctx.ParamInt("followUpID"))
// 内容安全检测
censorResponse, err := censor.Text(ctx.Request().Context(), f.Answer)
if err != nil {
// 审核源全部不可用:fail-closed,拒绝发布而非免审放行。
logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to censor follow up answer")
ctx.SetErrorFlash(i18n.T(ctx.Lang(), "censor.unavailable"))
ctx.Success("question/item")
return
}
if !censorResponse.Pass {
ctx.SetErrorFlash(censorResponse.ErrorMessage())
// 内容安全检测:统一守卫,箱主本人回复同样按自己的审核严格度裁决。
if _, err := moderation.Check(ctx.Request().Context(), moderation.StrictnessFor(pageUser.ModerationStrictness), ctx.Lang(), f.Answer); err != nil {
ctx.SetErrorFlash(err.Error())
ctx.Success("question/item")
return
}
+14 -23
View File
@@ -36,7 +36,7 @@ import (
"github.com/tamakyi/TamaBox/internal/i18n"
"github.com/tamakyi/TamaBox/internal/imagecheck"
"github.com/tamakyi/TamaBox/internal/mail"
"github.com/tamakyi/TamaBox/internal/security/censor"
"github.com/tamakyi/TamaBox/internal/security/moderation"
"github.com/tamakyi/TamaBox/internal/shared"
"github.com/tamakyi/TamaBox/internal/storage"
templatepkg "github.com/tamakyi/TamaBox/internal/template"
@@ -343,6 +343,11 @@ func New(ctx context.Context, f form.NewQuestion, pageUser *db.User, recaptcha r
return
}
// 内容审核严格度:提问 / 私聊 / 投票三条链路共用同一份档位(users.moderation_strictness),
// 取值解释与裁决逻辑见 internal/security/censor/policy.go。
// 在此解析一次,供下方私聊分支与普通提问分支复用,保证同一请求的判定口径一致。
strictness := moderation.StrictnessFor(pageUser.ModerationStrictness)
// ---------- 私聊处理 ----------
if f.StartChat == "true" && ctx.IsLogged {
@@ -431,17 +436,10 @@ func New(ctx context.Context, f form.NewQuestion, pageUser *db.User, recaptcha r
return
}
// 内容安全检测
censorResponse, err := censor.Text(ctx.Request().Context(), f.Content)
if err != nil {
// 审核源全部不可用:fail-closed,拒绝发布而非免审放行。
logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to censor text")
ctx.SetError(errors.New(i18n.T(ctx.Lang(), "censor.unavailable")), f)
ctx.Success("question/list")
return
}
if !censorResponse.Pass {
ctx.SetError(errors.New(censorResponse.ErrorMessage()), f)
// 内容安全检测:统一守卫,按箱主「审核严格度」裁决是否放行
// (审核源不可用时 moderation.Check 内部仍为 fail-closed)。
if _, err := moderation.Check(ctx.Request().Context(), strictness, ctx.Lang(), f.Content); err != nil {
ctx.SetError(err, f)
ctx.Success("question/list")
return
}
@@ -571,18 +569,11 @@ func New(ctx context.Context, f form.NewQuestion, pageUser *db.User, recaptcha r
return
}
censorResponse, err := censor.Text(ctx.Request().Context(), content)
// 内容安全检测:统一守卫,按箱主「审核严格度」裁决是否放行。
// 返回的 censorResponse 供下方落 content_censor_metadata(审计留痕)。
censorResponse, err := moderation.Check(ctx.Request().Context(), strictness, ctx.Lang(), content)
if err != nil {
// 审核源全部不可用:fail-closed,拒绝发布而非免审放行,
// 避免审核服务宕机期间提问内容免审直接公开。
logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to censor text")
ctx.SetError(errors.New(i18n.T(ctx.Lang(), "censor.unavailable")), f)
ctx.Success("question/list")
return
}
if !censorResponse.Pass {
errorMessage := censorResponse.ErrorMessage()
ctx.SetError(errors.New(errorMessage), f)
ctx.SetError(err, f)
ctx.Success("question/list")
return
}
+5 -11
View File
@@ -20,7 +20,7 @@ import (
"github.com/tamakyi/TamaBox/internal/i18n"
"github.com/tamakyi/TamaBox/internal/imagecheck"
"github.com/tamakyi/TamaBox/internal/mail"
"github.com/tamakyi/TamaBox/internal/security/censor"
"github.com/tamakyi/TamaBox/internal/security/moderation"
"github.com/tamakyi/TamaBox/internal/shared"
)
@@ -165,17 +165,11 @@ func PublishAnswer(ctx context.Context, pageUser *db.User, question *db.Question
answer := f.Answer
// 🚨 Content security check.
censorResponse, err := censor.Text(ctx.Request().Context(), answer)
// 统一守卫:按箱主「审核严格度」裁决是否放行(审核源不可用仍为 fail-closed,
// 拒绝发布而非免审放行)。返回的 censorResponse 用于下方落审计字段。
censorResponse, err := moderation.Check(ctx.Request().Context(), moderation.StrictnessFor(pageUser.ModerationStrictness), ctx.Lang(), answer)
if err != nil {
// 审核源全部不可用:fail-closed,拒绝发布而非免审放行。
logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to censor text")
ctx.SetError(errors.New(i18n.T(ctx.Lang(), "censor.unavailable")), f)
ctx.Success("question/item")
return
}
if !censorResponse.Pass {
errorMessage := censorResponse.ErrorMessage()
ctx.SetError(errors.New(errorMessage), f)
ctx.SetError(err, f)
ctx.Success("question/item")
return
}