From 7b6891fdbba9fba5275a81ac88ca41e18bbe698c Mon Sep 17 00:00:00 2001 From: smail Date: Mon, 28 Sep 2026 21:31:37 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=85=AC=E4=BC=97=E5=8F=B7?= =?UTF-8?q?=E5=8F=98=E6=9B=B4=E5=90=8E=E7=9A=84=E4=B8=AA=E4=BA=BA=E9=87=8D?= =?UTF-8?q?=E7=BB=91=E7=8A=B6=E6=80=81=E5=92=8C=E5=8F=91=E9=80=81=E9=99=90?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 公众号身份不匹配时阻止重新启用、测试发送与邮件通知,保留停用及解绑;新增身份匹配回归源码。全量编译和相关包静态检查通过,未执行回归和实机验收。作为修复全量静态检查发现的既有用例签名错误前检查点。 --- backend/controllers/plugin_wechat.go | 5 ++-- backend/hooks/base.go | 2 +- backend/services/plugin/config_test.go | 22 ++++++++++++++ backend/services/plugin/wechat_settings.go | 34 +++++++++++++++++++--- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/backend/controllers/plugin_wechat.go b/backend/controllers/plugin_wechat.go index dc2951f..76ffde6 100644 --- a/backend/controllers/plugin_wechat.go +++ b/backend/controllers/plugin_wechat.go @@ -57,7 +57,8 @@ func weChatRequestService(ctx *appcontext.Context, w http.ResponseWriter, recent func weChatPublicSettings(status pluginservice.WeChatUserSettingsStatus) map[string]any { return map[string]any{"version": status.Version, "bound": status.Settings.OpenID != "", "enabled": status.Settings.Enabled, - "showContent": status.Settings.ShowContent, "displayName": status.Settings.DisplayName} + "showContent": status.Settings.ShowContent, "displayName": status.Settings.DisplayName, + "needsRebind": status.NeedsRebind} } func writeWeChatSettings(w http.ResponseWriter, userID int, status pluginservice.WeChatUserSettingsStatus) { @@ -175,7 +176,7 @@ func TestWeChatMessage(ctx *appcontext.Context, w http.ResponseWriter, req *http return } status, err := service.GetOwnWeChatSettings(ctx.UserID) - if err != nil || status.Settings.OpenID == "" { + if err != nil || status.Settings.OpenID == "" || status.NeedsRebind { writeWeChatError(w, pluginservice.WeChatNotice("请先绑定本人的微信")) return } diff --git a/backend/hooks/base.go b/backend/hooks/base.go index a792b34..f971944 100644 --- a/backend/hooks/base.go +++ b/backend/hooks/base.go @@ -129,7 +129,7 @@ func (h *HookSender) ReceiveSaveAfter(ctx *context.Context, email *parsemail.Ema } // 发信前重新读取,停用、解绑或禁用账户后不能继续使用插件缓存中的旧接收人。 status, err := pluginConfigService.GetOwnWeChatSettings(recipient.UserID) - if err != nil || !status.Settings.Enabled || status.Settings.OpenID == "" { + if err != nil || !status.Settings.Enabled || status.Settings.OpenID == "" || status.NeedsRebind { continue } payload, err := json.Marshal(status.Settings) diff --git a/backend/services/plugin/config_test.go b/backend/services/plugin/config_test.go index 5aaa01f..79d45e3 100644 --- a/backend/services/plugin/config_test.go +++ b/backend/services/plugin/config_test.go @@ -127,6 +127,28 @@ func TestEveryRoleKeepsIndependentOwnWeChatSettings(t *testing.T) { } } +func TestWeChatBindingIdentityMustMatchCurrentApplication(t *testing.T) { + for _, test := range []struct { + name string + settings WeChatUserSettings + appID string + want bool + }{ + {name: "unbound"}, + {name: "same-app", settings: WeChatUserSettings{AppID: "wx-original-app", OpenID: "openid-test-user", Enabled: true}, appID: "wx-original-app"}, + {name: "changed-app", settings: WeChatUserSettings{AppID: "wx-original-app", OpenID: "openid-test-user", Enabled: true}, appID: "wx-replacement-app", want: true}, + {name: "missing-app", settings: WeChatUserSettings{AppID: "wx-original-app", OpenID: "openid-test-user"}, want: true}, + {name: "invalid-app", settings: WeChatUserSettings{AppID: "wx-original-app", OpenID: "openid-test-user"}, appID: "invalid", want: true}, + {name: "disabled-same-app", settings: WeChatUserSettings{AppID: "wx-original-app", OpenID: "openid-test-user"}, appID: "wx-original-app"}, + } { + t.Run(test.name, func(t *testing.T) { + if got := weChatBindingNeedsRebind(test.settings, test.appID); got != test.want { + t.Fatal(got, test.want) + } + }) + } +} + func TestWeChatBindingStatusRejectsOtherSessionsAndRevokedAccounts(t *testing.T) { service, engine := newPluginConfigService(t) user := insertPluginTestUser(t, engine, "wechat-binding", access.RoleSuperAdmin) diff --git a/backend/services/plugin/wechat_settings.go b/backend/services/plugin/wechat_settings.go index 6a44629..68aa1df 100644 --- a/backend/services/plugin/wechat_settings.go +++ b/backend/services/plugin/wechat_settings.go @@ -5,6 +5,7 @@ import ( "errors" "strings" + "git.pcux.cn/xuans/Smail/config" "git.pcux.cn/xuans/Smail/models" "git.pcux.cn/xuans/Smail/services/access" "git.pcux.cn/xuans/Smail/utils/credential" @@ -29,8 +30,9 @@ type WeChatUserSettings struct { } type WeChatUserSettingsStatus struct { - Settings WeChatUserSettings - Version uint64 + Settings WeChatUserSettings + Version uint64 + NeedsRebind bool } type WeChatUserSettingsEntry struct { @@ -61,7 +63,27 @@ func (s *ConfigService) GetOwnWeChatSettings(userID int) (WeChatUserSettingsStat return WeChatUserSettingsStatus{}, err } settings, err := s.decodeWeChatSettings(record) - return WeChatUserSettingsStatus{Settings: settings, Version: record.Version}, err + return WeChatUserSettingsStatus{Settings: settings, Version: record.Version, + NeedsRebind: weChatBindingNeedsRebind(settings, currentWeChatAppID())}, err +} + +func currentWeChatAppID() string { + manager := config.CurrentManager() + if manager == nil { + return "" + } + instance, found := manager.Snapshot().Plugins.Plugins[weChatPluginID] + var settings struct { + AppID string `json:"appId"` + } + if !found || json.Unmarshal(instance.Settings, &settings) != nil { + return "" + } + return settings.AppID +} + +func weChatBindingNeedsRebind(settings WeChatUserSettings, appID string) bool { + return settings.OpenID != "" && (!validWeChatIdentity(appID) || settings.AppID != appID) } func (s *ConfigService) decodeWeChatSettings(record models.PluginUserSetting) (WeChatUserSettings, error) { @@ -147,7 +169,8 @@ func (s *ConfigService) saveWeChatSettings(userID int, settings WeChatUserSettin return WeChatUserSettingsStatus{}, ErrPluginSettingConflict } } - return WeChatUserSettingsStatus{Settings: settings, Version: record.Version}, nil + return WeChatUserSettingsStatus{Settings: settings, Version: record.Version, + NeedsRebind: weChatBindingNeedsRebind(settings, currentWeChatAppID())}, nil } func (s *ConfigService) UpdateOwnWeChatPreferences(userID int, enabled, showContent, unbind bool, expectedVersion uint64) (WeChatUserSettingsStatus, error) { @@ -156,6 +179,9 @@ func (s *ConfigService) UpdateOwnWeChatPreferences(userID int, enabled, showCont return current, err } settings := current.Settings + if !unbind && enabled && current.NeedsRebind { + return current, ErrWeChatBinding + } if unbind { settings = WeChatUserSettings{} } else {