Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
ee3f158f
Commit
ee3f158f
authored
Apr 21, 2026
by
IanShaw027
Browse files
fix(settings): restore wechat and payment config persistence
parent
d08757ce
Changes
19
Expand all
Show whitespace changes
Inline
Side-by-side
backend/internal/handler/admin/setting_handler.go
View file @
ee3f158f
...
@@ -122,6 +122,13 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
...
@@ -122,6 +122,13 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
LinuxDoConnectClientID
:
settings
.
LinuxDoConnectClientID
,
LinuxDoConnectClientID
:
settings
.
LinuxDoConnectClientID
,
LinuxDoConnectClientSecretConfigured
:
settings
.
LinuxDoConnectClientSecretConfigured
,
LinuxDoConnectClientSecretConfigured
:
settings
.
LinuxDoConnectClientSecretConfigured
,
LinuxDoConnectRedirectURL
:
settings
.
LinuxDoConnectRedirectURL
,
LinuxDoConnectRedirectURL
:
settings
.
LinuxDoConnectRedirectURL
,
WeChatConnectEnabled
:
settings
.
WeChatConnectEnabled
,
WeChatConnectAppID
:
settings
.
WeChatConnectAppID
,
WeChatConnectAppSecretConfigured
:
settings
.
WeChatConnectAppSecretConfigured
,
WeChatConnectMode
:
settings
.
WeChatConnectMode
,
WeChatConnectScopes
:
settings
.
WeChatConnectScopes
,
WeChatConnectRedirectURL
:
settings
.
WeChatConnectRedirectURL
,
WeChatConnectFrontendRedirectURL
:
settings
.
WeChatConnectFrontendRedirectURL
,
OIDCConnectEnabled
:
settings
.
OIDCConnectEnabled
,
OIDCConnectEnabled
:
settings
.
OIDCConnectEnabled
,
OIDCConnectProviderName
:
settings
.
OIDCConnectProviderName
,
OIDCConnectProviderName
:
settings
.
OIDCConnectProviderName
,
OIDCConnectClientID
:
settings
.
OIDCConnectClientID
,
OIDCConnectClientID
:
settings
.
OIDCConnectClientID
,
...
@@ -246,6 +253,15 @@ type UpdateSettingsRequest struct {
...
@@ -246,6 +253,15 @@ type UpdateSettingsRequest struct {
LinuxDoConnectClientSecret
string
`json:"linuxdo_connect_client_secret"`
LinuxDoConnectClientSecret
string
`json:"linuxdo_connect_client_secret"`
LinuxDoConnectRedirectURL
string
`json:"linuxdo_connect_redirect_url"`
LinuxDoConnectRedirectURL
string
`json:"linuxdo_connect_redirect_url"`
// WeChat Connect OAuth 登录
WeChatConnectEnabled
bool
`json:"wechat_connect_enabled"`
WeChatConnectAppID
string
`json:"wechat_connect_app_id"`
WeChatConnectAppSecret
string
`json:"wechat_connect_app_secret"`
WeChatConnectMode
string
`json:"wechat_connect_mode"`
WeChatConnectScopes
string
`json:"wechat_connect_scopes"`
WeChatConnectRedirectURL
string
`json:"wechat_connect_redirect_url"`
WeChatConnectFrontendRedirectURL
string
`json:"wechat_connect_frontend_redirect_url"`
// Generic OIDC OAuth 登录
// Generic OIDC OAuth 登录
OIDCConnectEnabled
bool
`json:"oidc_connect_enabled"`
OIDCConnectEnabled
bool
`json:"oidc_connect_enabled"`
OIDCConnectProviderName
string
`json:"oidc_connect_provider_name"`
OIDCConnectProviderName
string
`json:"oidc_connect_provider_name"`
...
@@ -509,6 +525,54 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
...
@@ -509,6 +525,54 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
}
}
}
}
if
req
.
WeChatConnectEnabled
{
req
.
WeChatConnectAppID
=
strings
.
TrimSpace
(
req
.
WeChatConnectAppID
)
req
.
WeChatConnectAppSecret
=
strings
.
TrimSpace
(
req
.
WeChatConnectAppSecret
)
req
.
WeChatConnectMode
=
strings
.
ToLower
(
strings
.
TrimSpace
(
req
.
WeChatConnectMode
))
req
.
WeChatConnectScopes
=
strings
.
TrimSpace
(
req
.
WeChatConnectScopes
)
req
.
WeChatConnectRedirectURL
=
strings
.
TrimSpace
(
req
.
WeChatConnectRedirectURL
)
req
.
WeChatConnectFrontendRedirectURL
=
strings
.
TrimSpace
(
req
.
WeChatConnectFrontendRedirectURL
)
if
req
.
WeChatConnectAppID
==
""
{
response
.
BadRequest
(
c
,
"WeChat App ID is required when enabled"
)
return
}
if
req
.
WeChatConnectAppSecret
==
""
{
if
previousSettings
.
WeChatConnectAppSecret
==
""
{
response
.
BadRequest
(
c
,
"WeChat App Secret is required when enabled"
)
return
}
req
.
WeChatConnectAppSecret
=
previousSettings
.
WeChatConnectAppSecret
}
if
req
.
WeChatConnectMode
==
""
{
req
.
WeChatConnectMode
=
"open"
}
switch
req
.
WeChatConnectMode
{
case
"open"
,
"mp"
:
default
:
response
.
BadRequest
(
c
,
"WeChat mode must be open or mp"
)
return
}
if
req
.
WeChatConnectScopes
==
""
{
req
.
WeChatConnectScopes
=
service
.
DefaultWeChatConnectScopesForMode
(
req
.
WeChatConnectMode
)
}
if
req
.
WeChatConnectRedirectURL
==
""
{
response
.
BadRequest
(
c
,
"WeChat Redirect URL is required when enabled"
)
return
}
if
err
:=
config
.
ValidateAbsoluteHTTPURL
(
req
.
WeChatConnectRedirectURL
);
err
!=
nil
{
response
.
BadRequest
(
c
,
"WeChat Redirect URL must be an absolute http(s) URL"
)
return
}
if
req
.
WeChatConnectFrontendRedirectURL
==
""
{
req
.
WeChatConnectFrontendRedirectURL
=
"/auth/wechat/callback"
}
if
err
:=
config
.
ValidateFrontendRedirectURL
(
req
.
WeChatConnectFrontendRedirectURL
);
err
!=
nil
{
response
.
BadRequest
(
c
,
"WeChat Frontend Redirect URL is invalid"
)
return
}
}
// Generic OIDC 参数验证
// Generic OIDC 参数验证
if
req
.
OIDCConnectEnabled
{
if
req
.
OIDCConnectEnabled
{
req
.
OIDCConnectProviderName
=
strings
.
TrimSpace
(
req
.
OIDCConnectProviderName
)
req
.
OIDCConnectProviderName
=
strings
.
TrimSpace
(
req
.
OIDCConnectProviderName
)
...
@@ -857,6 +921,13 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
...
@@ -857,6 +921,13 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
LinuxDoConnectClientID
:
req
.
LinuxDoConnectClientID
,
LinuxDoConnectClientID
:
req
.
LinuxDoConnectClientID
,
LinuxDoConnectClientSecret
:
req
.
LinuxDoConnectClientSecret
,
LinuxDoConnectClientSecret
:
req
.
LinuxDoConnectClientSecret
,
LinuxDoConnectRedirectURL
:
req
.
LinuxDoConnectRedirectURL
,
LinuxDoConnectRedirectURL
:
req
.
LinuxDoConnectRedirectURL
,
WeChatConnectEnabled
:
req
.
WeChatConnectEnabled
,
WeChatConnectAppID
:
req
.
WeChatConnectAppID
,
WeChatConnectAppSecret
:
req
.
WeChatConnectAppSecret
,
WeChatConnectMode
:
req
.
WeChatConnectMode
,
WeChatConnectScopes
:
req
.
WeChatConnectScopes
,
WeChatConnectRedirectURL
:
req
.
WeChatConnectRedirectURL
,
WeChatConnectFrontendRedirectURL
:
req
.
WeChatConnectFrontendRedirectURL
,
OIDCConnectEnabled
:
req
.
OIDCConnectEnabled
,
OIDCConnectEnabled
:
req
.
OIDCConnectEnabled
,
OIDCConnectProviderName
:
req
.
OIDCConnectProviderName
,
OIDCConnectProviderName
:
req
.
OIDCConnectProviderName
,
OIDCConnectClientID
:
req
.
OIDCConnectClientID
,
OIDCConnectClientID
:
req
.
OIDCConnectClientID
,
...
@@ -1136,6 +1207,13 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
...
@@ -1136,6 +1207,13 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
LinuxDoConnectClientID
:
updatedSettings
.
LinuxDoConnectClientID
,
LinuxDoConnectClientID
:
updatedSettings
.
LinuxDoConnectClientID
,
LinuxDoConnectClientSecretConfigured
:
updatedSettings
.
LinuxDoConnectClientSecretConfigured
,
LinuxDoConnectClientSecretConfigured
:
updatedSettings
.
LinuxDoConnectClientSecretConfigured
,
LinuxDoConnectRedirectURL
:
updatedSettings
.
LinuxDoConnectRedirectURL
,
LinuxDoConnectRedirectURL
:
updatedSettings
.
LinuxDoConnectRedirectURL
,
WeChatConnectEnabled
:
updatedSettings
.
WeChatConnectEnabled
,
WeChatConnectAppID
:
updatedSettings
.
WeChatConnectAppID
,
WeChatConnectAppSecretConfigured
:
updatedSettings
.
WeChatConnectAppSecretConfigured
,
WeChatConnectMode
:
updatedSettings
.
WeChatConnectMode
,
WeChatConnectScopes
:
updatedSettings
.
WeChatConnectScopes
,
WeChatConnectRedirectURL
:
updatedSettings
.
WeChatConnectRedirectURL
,
WeChatConnectFrontendRedirectURL
:
updatedSettings
.
WeChatConnectFrontendRedirectURL
,
OIDCConnectEnabled
:
updatedSettings
.
OIDCConnectEnabled
,
OIDCConnectEnabled
:
updatedSettings
.
OIDCConnectEnabled
,
OIDCConnectProviderName
:
updatedSettings
.
OIDCConnectProviderName
,
OIDCConnectProviderName
:
updatedSettings
.
OIDCConnectProviderName
,
OIDCConnectClientID
:
updatedSettings
.
OIDCConnectClientID
,
OIDCConnectClientID
:
updatedSettings
.
OIDCConnectClientID
,
...
@@ -1329,6 +1407,27 @@ func diffSettings(before *service.SystemSettings, after *service.SystemSettings,
...
@@ -1329,6 +1407,27 @@ func diffSettings(before *service.SystemSettings, after *service.SystemSettings,
if
before
.
LinuxDoConnectRedirectURL
!=
after
.
LinuxDoConnectRedirectURL
{
if
before
.
LinuxDoConnectRedirectURL
!=
after
.
LinuxDoConnectRedirectURL
{
changed
=
append
(
changed
,
"linuxdo_connect_redirect_url"
)
changed
=
append
(
changed
,
"linuxdo_connect_redirect_url"
)
}
}
if
before
.
WeChatConnectEnabled
!=
after
.
WeChatConnectEnabled
{
changed
=
append
(
changed
,
"wechat_connect_enabled"
)
}
if
before
.
WeChatConnectAppID
!=
after
.
WeChatConnectAppID
{
changed
=
append
(
changed
,
"wechat_connect_app_id"
)
}
if
req
.
WeChatConnectAppSecret
!=
""
{
changed
=
append
(
changed
,
"wechat_connect_app_secret"
)
}
if
before
.
WeChatConnectMode
!=
after
.
WeChatConnectMode
{
changed
=
append
(
changed
,
"wechat_connect_mode"
)
}
if
before
.
WeChatConnectScopes
!=
after
.
WeChatConnectScopes
{
changed
=
append
(
changed
,
"wechat_connect_scopes"
)
}
if
before
.
WeChatConnectRedirectURL
!=
after
.
WeChatConnectRedirectURL
{
changed
=
append
(
changed
,
"wechat_connect_redirect_url"
)
}
if
before
.
WeChatConnectFrontendRedirectURL
!=
after
.
WeChatConnectFrontendRedirectURL
{
changed
=
append
(
changed
,
"wechat_connect_frontend_redirect_url"
)
}
if
before
.
OIDCConnectEnabled
!=
after
.
OIDCConnectEnabled
{
if
before
.
OIDCConnectEnabled
!=
after
.
OIDCConnectEnabled
{
changed
=
append
(
changed
,
"oidc_connect_enabled"
)
changed
=
append
(
changed
,
"oidc_connect_enabled"
)
}
}
...
...
backend/internal/handler/auth_wechat_oauth.go
View file @
ee3f158f
...
@@ -8,7 +8,6 @@ import (
...
@@ -8,7 +8,6 @@ import (
"io"
"io"
"net/http"
"net/http"
"net/url"
"net/url"
"os"
"strconv"
"strconv"
"strings"
"strings"
"time"
"time"
...
@@ -149,7 +148,7 @@ func (h *AuthHandler) WeChatOAuthStart(c *gin.Context) {
...
@@ -149,7 +148,7 @@ func (h *AuthHandler) WeChatOAuthStart(c *gin.Context) {
// WeChatOAuthCallback exchanges the code with WeChat, resolves openid/unionid,
// WeChatOAuthCallback exchanges the code with WeChat, resolves openid/unionid,
// and stores the result in the unified pending-auth flow.
// and stores the result in the unified pending-auth flow.
func
(
h
*
AuthHandler
)
WeChatOAuthCallback
(
c
*
gin
.
Context
)
{
func
(
h
*
AuthHandler
)
WeChatOAuthCallback
(
c
*
gin
.
Context
)
{
frontendCallback
:=
wechatOAuthFrontendCallback
()
frontendCallback
:=
h
.
wechatOAuthFrontendCallback
(
c
.
Request
.
Context
()
)
if
providerErr
:=
strings
.
TrimSpace
(
c
.
Query
(
"error"
));
providerErr
!=
""
{
if
providerErr
:=
strings
.
TrimSpace
(
c
.
Query
(
"error"
));
providerErr
!=
""
{
redirectOAuthError
(
c
,
frontendCallback
,
"provider_error"
,
providerErr
,
c
.
Query
(
"error_description"
))
redirectOAuthError
(
c
,
frontendCallback
,
"provider_error"
,
providerErr
,
c
.
Query
(
"error_description"
))
...
@@ -859,6 +858,10 @@ func (h *AuthHandler) getWeChatOAuthConfig(ctx context.Context, rawMode string,
...
@@ -859,6 +858,10 @@ func (h *AuthHandler) getWeChatOAuthConfig(ctx context.Context, rawMode string,
return
wechatOAuthConfig
{},
err
return
wechatOAuthConfig
{},
err
}
}
if
h
==
nil
||
h
.
settingSvc
==
nil
{
return
wechatOAuthConfig
{},
infraerrors
.
ServiceUnavailable
(
"CONFIG_NOT_READY"
,
"wechat oauth settings service not ready"
)
}
apiBaseURL
:=
""
apiBaseURL
:=
""
if
h
!=
nil
&&
h
.
settingSvc
!=
nil
{
if
h
!=
nil
&&
h
.
settingSvc
!=
nil
{
settings
,
err
:=
h
.
settingSvc
.
GetAllSettings
(
ctx
)
settings
,
err
:=
h
.
settingSvc
.
GetAllSettings
(
ctx
)
...
@@ -867,27 +870,28 @@ func (h *AuthHandler) getWeChatOAuthConfig(ctx context.Context, rawMode string,
...
@@ -867,27 +870,28 @@ func (h *AuthHandler) getWeChatOAuthConfig(ctx context.Context, rawMode string,
}
}
}
}
effective
,
err
:=
h
.
settingSvc
.
GetWeChatConnectOAuthConfig
(
ctx
)
if
err
!=
nil
{
return
wechatOAuthConfig
{},
err
}
if
effective
.
Mode
!=
mode
{
return
wechatOAuthConfig
{},
infraerrors
.
NotFound
(
"OAUTH_DISABLED"
,
"wechat oauth is disabled"
)
}
cfg
:=
wechatOAuthConfig
{
cfg
:=
wechatOAuthConfig
{
mode
:
mode
,
mode
:
mode
,
redirectURI
:
resolveWeChatOAuthAbsoluteURL
(
apiBaseURL
,
c
,
"/api/v1/auth/oauth/wechat/callback"
),
appID
:
strings
.
TrimSpace
(
effective
.
AppID
),
frontendCallback
:
wechatOAuthFrontendCallback
(),
appSecret
:
strings
.
TrimSpace
(
effective
.
AppSecret
),
redirectURI
:
firstNonEmpty
(
strings
.
TrimSpace
(
effective
.
RedirectURL
),
resolveWeChatOAuthAbsoluteURL
(
apiBaseURL
,
c
,
"/api/v1/auth/oauth/wechat/callback"
)),
frontendCallback
:
firstNonEmpty
(
strings
.
TrimSpace
(
effective
.
FrontendRedirectURL
),
wechatOAuthDefaultFrontendCB
),
scope
:
firstNonEmpty
(
strings
.
TrimSpace
(
effective
.
Scopes
),
service
.
DefaultWeChatConnectScopesForMode
(
mode
)),
}
}
switch
mode
{
switch
mode
{
case
"mp"
:
case
"mp"
:
cfg
.
appID
=
strings
.
TrimSpace
(
os
.
Getenv
(
"WECHAT_OAUTH_MP_APP_ID"
))
cfg
.
appSecret
=
strings
.
TrimSpace
(
os
.
Getenv
(
"WECHAT_OAUTH_MP_APP_SECRET"
))
cfg
.
authorizeURL
=
"https://open.weixin.qq.com/connect/oauth2/authorize"
cfg
.
authorizeURL
=
"https://open.weixin.qq.com/connect/oauth2/authorize"
cfg
.
scope
=
"snsapi_userinfo"
default
:
default
:
cfg
.
appID
=
strings
.
TrimSpace
(
os
.
Getenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
))
cfg
.
appSecret
=
strings
.
TrimSpace
(
os
.
Getenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
))
cfg
.
authorizeURL
=
"https://open.weixin.qq.com/connect/qrconnect"
cfg
.
authorizeURL
=
"https://open.weixin.qq.com/connect/qrconnect"
cfg
.
scope
=
"snsapi_login"
}
if
cfg
.
appID
==
""
||
cfg
.
appSecret
==
""
{
return
wechatOAuthConfig
{},
infraerrors
.
NotFound
(
"OAUTH_DISABLED"
,
"wechat oauth is disabled"
)
}
}
if
strings
.
TrimSpace
(
cfg
.
redirectURI
)
==
""
{
if
strings
.
TrimSpace
(
cfg
.
redirectURI
)
==
""
{
return
wechatOAuthConfig
{},
infraerrors
.
InternalServer
(
"OAUTH_CONFIG_INVALID"
,
"wechat oauth redirect url not configured"
)
return
wechatOAuthConfig
{},
infraerrors
.
InternalServer
(
"OAUTH_CONFIG_INVALID"
,
"wechat oauth redirect url not configured"
)
...
@@ -896,8 +900,14 @@ func (h *AuthHandler) getWeChatOAuthConfig(ctx context.Context, rawMode string,
...
@@ -896,8 +900,14 @@ func (h *AuthHandler) getWeChatOAuthConfig(ctx context.Context, rawMode string,
return
cfg
,
nil
return
cfg
,
nil
}
}
func
wechatOAuthFrontendCallback
()
string
{
func
(
h
*
AuthHandler
)
wechatOAuthFrontendCallback
(
ctx
context
.
Context
)
string
{
return
firstNonEmpty
(
strings
.
TrimSpace
(
os
.
Getenv
(
"WECHAT_OAUTH_FRONTEND_REDIRECT_URL"
)),
wechatOAuthDefaultFrontendCB
)
if
h
!=
nil
&&
h
.
settingSvc
!=
nil
{
cfg
,
err
:=
h
.
settingSvc
.
GetWeChatConnectOAuthConfig
(
ctx
)
if
err
==
nil
&&
strings
.
TrimSpace
(
cfg
.
FrontendRedirectURL
)
!=
""
{
return
strings
.
TrimSpace
(
cfg
.
FrontendRedirectURL
)
}
}
return
wechatOAuthDefaultFrontendCB
}
}
func
resolveWeChatOAuthMode
(
rawMode
string
,
c
*
gin
.
Context
)
(
string
,
error
)
{
func
resolveWeChatOAuthMode
(
rawMode
string
,
c
*
gin
.
Context
)
(
string
,
error
)
{
...
...
backend/internal/handler/auth_wechat_oauth_test.go
View file @
ee3f158f
...
@@ -33,16 +33,22 @@ import (
...
@@ -33,16 +33,22 @@ import (
)
)
func
TestWeChatOAuthStartRedirectsAndSetsPendingCookies
(
t
*
testing
.
T
)
{
func
TestWeChatOAuthStartRedirectsAndSetsPendingCookies
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
,
"wx-open-app"
)
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
,
"wx-open-secret"
)
gin
.
SetMode
(
gin
.
TestMode
)
gin
.
SetMode
(
gin
.
TestMode
)
handler
,
client
:=
newWeChatOAuthTestHandlerWithSettings
(
t
,
false
,
map
[
string
]
string
{
service
.
SettingKeyWeChatConnectEnabled
:
"true"
,
service
.
SettingKeyWeChatConnectAppID
:
"wx-open-app"
,
service
.
SettingKeyWeChatConnectAppSecret
:
"wx-open-secret"
,
service
.
SettingKeyWeChatConnectMode
:
"open"
,
service
.
SettingKeyWeChatConnectScopes
:
"snsapi_login"
,
service
.
SettingKeyWeChatConnectRedirectURL
:
"https://api.example.com/api/v1/auth/oauth/wechat/callback"
,
service
.
SettingKeyWeChatConnectFrontendRedirectURL
:
"/auth/wechat/callback"
,
})
defer
client
.
Close
()
recorder
:=
httptest
.
NewRecorder
()
recorder
:=
httptest
.
NewRecorder
()
c
,
_
:=
gin
.
CreateTestContext
(
recorder
)
c
,
_
:=
gin
.
CreateTestContext
(
recorder
)
c
.
Request
=
httptest
.
NewRequest
(
http
.
MethodGet
,
"/api/v1/auth/oauth/wechat/start?mode=open&redirect=/billing"
,
nil
)
c
.
Request
=
httptest
.
NewRequest
(
http
.
MethodGet
,
"/api/v1/auth/oauth/wechat/start?mode=open&redirect=/billing"
,
nil
)
c
.
Request
.
Host
=
"api.example.com"
c
.
Request
.
Host
=
"api.example.com"
handler
:=
&
AuthHandler
{}
handler
.
WeChatOAuthStart
(
c
)
handler
.
WeChatOAuthStart
(
c
)
require
.
Equal
(
t
,
http
.
StatusFound
,
recorder
.
Code
)
require
.
Equal
(
t
,
http
.
StatusFound
,
recorder
.
Code
)
...
@@ -60,10 +66,6 @@ func TestWeChatOAuthStartRedirectsAndSetsPendingCookies(t *testing.T) {
...
@@ -60,10 +66,6 @@ func TestWeChatOAuthStartRedirectsAndSetsPendingCookies(t *testing.T) {
}
}
func
TestWeChatOAuthCallbackCreatesPendingSessionForUnifiedFlow
(
t
*
testing
.
T
)
{
func
TestWeChatOAuthCallbackCreatesPendingSessionForUnifiedFlow
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
,
"wx-open-app"
)
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
,
"wx-open-secret"
)
t
.
Setenv
(
"WECHAT_OAUTH_FRONTEND_REDIRECT_URL"
,
"/auth/wechat/callback"
)
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
t
.
Cleanup
(
func
()
{
t
.
Cleanup
(
func
()
{
...
@@ -124,10 +126,6 @@ func TestWeChatOAuthCallbackCreatesPendingSessionForUnifiedFlow(t *testing.T) {
...
@@ -124,10 +126,6 @@ func TestWeChatOAuthCallbackCreatesPendingSessionForUnifiedFlow(t *testing.T) {
}
}
func
TestWeChatOAuthCallbackRejectsMissingUnionID
(
t
*
testing
.
T
)
{
func
TestWeChatOAuthCallbackRejectsMissingUnionID
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
,
"wx-open-app"
)
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
,
"wx-open-secret"
)
t
.
Setenv
(
"WECHAT_OAUTH_FRONTEND_REDIRECT_URL"
,
"https://app.example.com/auth/wechat/callback"
)
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
t
.
Cleanup
(
func
()
{
t
.
Cleanup
(
func
()
{
...
@@ -151,7 +149,7 @@ func TestWeChatOAuthCallbackRejectsMissingUnionID(t *testing.T) {
...
@@ -151,7 +149,7 @@ func TestWeChatOAuthCallbackRejectsMissingUnionID(t *testing.T) {
wechatOAuthAccessTokenURL
=
upstream
.
URL
+
"/sns/oauth2/access_token"
wechatOAuthAccessTokenURL
=
upstream
.
URL
+
"/sns/oauth2/access_token"
wechatOAuthUserInfoURL
=
upstream
.
URL
+
"/sns/userinfo"
wechatOAuthUserInfoURL
=
upstream
.
URL
+
"/sns/userinfo"
handler
,
client
:=
newWeChatOAuthTestHandler
(
t
,
false
)
handler
,
client
:=
newWeChatOAuthTestHandler
WithSettings
(
t
,
false
,
wechatOAuthTestSettings
(
"open"
,
"wx-open-app"
,
"wx-open-secret"
,
"https://app.example.com/auth/wechat/callback"
)
)
defer
client
.
Close
()
defer
client
.
Close
()
recorder
:=
httptest
.
NewRecorder
()
recorder
:=
httptest
.
NewRecorder
()
...
@@ -177,9 +175,6 @@ func TestWeChatOAuthCallbackRejectsMissingUnionID(t *testing.T) {
...
@@ -177,9 +175,6 @@ func TestWeChatOAuthCallbackRejectsMissingUnionID(t *testing.T) {
}
}
func
TestWeChatPaymentOAuthCallbackRedirectsWithOpaqueResumeToken
(
t
*
testing
.
T
)
{
func
TestWeChatPaymentOAuthCallbackRedirectsWithOpaqueResumeToken
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_ID"
,
"wx-mp-app"
)
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_SECRET"
,
"wx-mp-secret"
)
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
t
.
Cleanup
(
func
()
{
t
.
Cleanup
(
func
()
{
wechatOAuthAccessTokenURL
=
originalAccessTokenURL
wechatOAuthAccessTokenURL
=
originalAccessTokenURL
...
@@ -196,7 +191,7 @@ func TestWeChatPaymentOAuthCallbackRedirectsWithOpaqueResumeToken(t *testing.T)
...
@@ -196,7 +191,7 @@ func TestWeChatPaymentOAuthCallbackRedirectsWithOpaqueResumeToken(t *testing.T)
defer
upstream
.
Close
()
defer
upstream
.
Close
()
wechatOAuthAccessTokenURL
=
upstream
.
URL
+
"/sns/oauth2/access_token"
wechatOAuthAccessTokenURL
=
upstream
.
URL
+
"/sns/oauth2/access_token"
handler
,
client
:=
newWeChatOAuthTestHandler
(
t
,
false
)
handler
,
client
:=
newWeChatOAuthTestHandler
WithSettings
(
t
,
false
,
wechatOAuthTestSettings
(
"mp"
,
"wx-mp-app"
,
"wx-mp-secret"
,
"/auth/wechat/callback"
)
)
defer
client
.
Close
()
defer
client
.
Close
()
handler
.
cfg
.
Totp
.
EncryptionKey
=
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
handler
.
cfg
.
Totp
.
EncryptionKey
=
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
...
@@ -240,7 +235,6 @@ func TestWeChatOAuthCallbackBindUsesUnionCanonicalIdentityAcrossChannels(t *test
...
@@ -240,7 +235,6 @@ func TestWeChatOAuthCallbackBindUsesUnionCanonicalIdentityAcrossChannels(t *test
testCases
:=
[]
struct
{
testCases
:=
[]
struct
{
name
string
name
string
mode
string
mode
string
appIDEnv
string
appID
string
appID
string
appSecret
string
appSecret
string
openID
string
openID
string
...
@@ -248,7 +242,6 @@ func TestWeChatOAuthCallbackBindUsesUnionCanonicalIdentityAcrossChannels(t *test
...
@@ -248,7 +242,6 @@ func TestWeChatOAuthCallbackBindUsesUnionCanonicalIdentityAcrossChannels(t *test
{
{
name
:
"open"
,
name
:
"open"
,
mode
:
"open"
,
mode
:
"open"
,
appIDEnv
:
"WECHAT_OAUTH_OPEN_APP_ID"
,
appID
:
"wx-open-app"
,
appID
:
"wx-open-app"
,
appSecret
:
"wx-open-secret"
,
appSecret
:
"wx-open-secret"
,
openID
:
"openid-open-123"
,
openID
:
"openid-open-123"
,
...
@@ -256,7 +249,6 @@ func TestWeChatOAuthCallbackBindUsesUnionCanonicalIdentityAcrossChannels(t *test
...
@@ -256,7 +249,6 @@ func TestWeChatOAuthCallbackBindUsesUnionCanonicalIdentityAcrossChannels(t *test
{
{
name
:
"mp"
,
name
:
"mp"
,
mode
:
"mp"
,
mode
:
"mp"
,
appIDEnv
:
"WECHAT_OAUTH_MP_APP_ID"
,
appID
:
"wx-mp-app"
,
appID
:
"wx-mp-app"
,
appSecret
:
"wx-mp-secret"
,
appSecret
:
"wx-mp-secret"
,
openID
:
"openid-mp-123"
,
openID
:
"openid-mp-123"
,
...
@@ -265,15 +257,6 @@ func TestWeChatOAuthCallbackBindUsesUnionCanonicalIdentityAcrossChannels(t *test
...
@@ -265,15 +257,6 @@ func TestWeChatOAuthCallbackBindUsesUnionCanonicalIdentityAcrossChannels(t *test
for
_
,
tc
:=
range
testCases
{
for
_
,
tc
:=
range
testCases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
t
.
Setenv
(
tc
.
appIDEnv
,
tc
.
appID
)
switch
tc
.
mode
{
case
"open"
:
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
,
tc
.
appSecret
)
case
"mp"
:
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_SECRET"
,
tc
.
appSecret
)
}
t
.
Setenv
(
"WECHAT_OAUTH_FRONTEND_REDIRECT_URL"
,
"/auth/wechat/callback"
)
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
t
.
Cleanup
(
func
()
{
t
.
Cleanup
(
func
()
{
...
@@ -297,7 +280,7 @@ func TestWeChatOAuthCallbackBindUsesUnionCanonicalIdentityAcrossChannels(t *test
...
@@ -297,7 +280,7 @@ func TestWeChatOAuthCallbackBindUsesUnionCanonicalIdentityAcrossChannels(t *test
wechatOAuthAccessTokenURL
=
upstream
.
URL
+
"/sns/oauth2/access_token"
wechatOAuthAccessTokenURL
=
upstream
.
URL
+
"/sns/oauth2/access_token"
wechatOAuthUserInfoURL
=
upstream
.
URL
+
"/sns/userinfo"
wechatOAuthUserInfoURL
=
upstream
.
URL
+
"/sns/userinfo"
handler
,
client
:=
newWeChatOAuthTestHandler
(
t
,
false
)
handler
,
client
:=
newWeChatOAuthTestHandler
WithSettings
(
t
,
false
,
wechatOAuthTestSettings
(
tc
.
mode
,
tc
.
appID
,
tc
.
appSecret
,
"/auth/wechat/callback"
)
)
defer
client
.
Close
()
defer
client
.
Close
()
currentUser
,
err
:=
client
.
User
.
Create
()
.
currentUser
,
err
:=
client
.
User
.
Create
()
.
...
@@ -354,10 +337,6 @@ func TestWeChatOAuthCallbackBindUsesUnionCanonicalIdentityAcrossChannels(t *test
...
@@ -354,10 +337,6 @@ func TestWeChatOAuthCallbackBindUsesUnionCanonicalIdentityAcrossChannels(t *test
}
}
func
TestWeChatOAuthCallbackBindRejectsCanonicalOwnershipConflict
(
t
*
testing
.
T
)
{
func
TestWeChatOAuthCallbackBindRejectsCanonicalOwnershipConflict
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
,
"wx-open-app"
)
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
,
"wx-open-secret"
)
t
.
Setenv
(
"WECHAT_OAUTH_FRONTEND_REDIRECT_URL"
,
"/auth/wechat/callback"
)
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
t
.
Cleanup
(
func
()
{
t
.
Cleanup
(
func
()
{
...
@@ -436,10 +415,6 @@ func TestWeChatOAuthCallbackBindRejectsCanonicalOwnershipConflict(t *testing.T)
...
@@ -436,10 +415,6 @@ func TestWeChatOAuthCallbackBindRejectsCanonicalOwnershipConflict(t *testing.T)
}
}
func
TestWeChatOAuthCallbackBindRejectsChannelOwnershipConflict
(
t
*
testing
.
T
)
{
func
TestWeChatOAuthCallbackBindRejectsChannelOwnershipConflict
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
,
"wx-open-app"
)
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
,
"wx-open-secret"
)
t
.
Setenv
(
"WECHAT_OAUTH_FRONTEND_REDIRECT_URL"
,
"/auth/wechat/callback"
)
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
t
.
Cleanup
(
func
()
{
t
.
Cleanup
(
func
()
{
...
@@ -529,10 +504,6 @@ func TestWeChatOAuthCallbackBindRejectsChannelOwnershipConflict(t *testing.T) {
...
@@ -529,10 +504,6 @@ func TestWeChatOAuthCallbackBindRejectsChannelOwnershipConflict(t *testing.T) {
}
}
func
TestWeChatOAuthCallbackBindRejectsLegacyProviderKeyOwnershipConflict
(
t
*
testing
.
T
)
{
func
TestWeChatOAuthCallbackBindRejectsLegacyProviderKeyOwnershipConflict
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
,
"wx-open-app"
)
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
,
"wx-open-secret"
)
t
.
Setenv
(
"WECHAT_OAUTH_FRONTEND_REDIRECT_URL"
,
"/auth/wechat/callback"
)
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
t
.
Cleanup
(
func
()
{
t
.
Cleanup
(
func
()
{
...
@@ -611,10 +582,6 @@ func TestWeChatOAuthCallbackBindRejectsLegacyProviderKeyOwnershipConflict(t *tes
...
@@ -611,10 +582,6 @@ func TestWeChatOAuthCallbackBindRejectsLegacyProviderKeyOwnershipConflict(t *tes
}
}
func
TestCompleteWeChatOAuthRegistrationAfterInvitationPendingSession
(
t
*
testing
.
T
)
{
func
TestCompleteWeChatOAuthRegistrationAfterInvitationPendingSession
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
,
"wx-open-app"
)
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
,
"wx-open-secret"
)
t
.
Setenv
(
"WECHAT_OAUTH_FRONTEND_REDIRECT_URL"
,
"/auth/wechat/callback"
)
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
t
.
Cleanup
(
func
()
{
t
.
Cleanup
(
func
()
{
...
@@ -737,10 +704,6 @@ func TestCompleteWeChatOAuthRegistrationAfterInvitationPendingSession(t *testing
...
@@ -737,10 +704,6 @@ func TestCompleteWeChatOAuthRegistrationAfterInvitationPendingSession(t *testing
}
}
func
TestWeChatOAuthCallbackRepairsLegacyOpenIDOnlyIdentity
(
t
*
testing
.
T
)
{
func
TestWeChatOAuthCallbackRepairsLegacyOpenIDOnlyIdentity
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
,
"wx-open-app"
)
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
,
"wx-open-secret"
)
t
.
Setenv
(
"WECHAT_OAUTH_FRONTEND_REDIRECT_URL"
,
"/auth/wechat/callback"
)
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
t
.
Cleanup
(
func
()
{
t
.
Cleanup
(
func
()
{
...
@@ -900,10 +863,6 @@ func TestCompleteWeChatOAuthRegistrationRejectsAdoptExistingUserSession(t *testi
...
@@ -900,10 +863,6 @@ func TestCompleteWeChatOAuthRegistrationRejectsAdoptExistingUserSession(t *testi
}
}
func
TestWeChatOAuthCallbackRepairsLegacyProviderKeyCanonicalIdentity
(
t
*
testing
.
T
)
{
func
TestWeChatOAuthCallbackRepairsLegacyProviderKeyCanonicalIdentity
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
,
"wx-open-app"
)
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
,
"wx-open-secret"
)
t
.
Setenv
(
"WECHAT_OAUTH_FRONTEND_REDIRECT_URL"
,
"/auth/wechat/callback"
)
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalAccessTokenURL
:=
wechatOAuthAccessTokenURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
originalUserInfoURL
:=
wechatOAuthUserInfoURL
t
.
Cleanup
(
func
()
{
t
.
Cleanup
(
func
()
{
...
@@ -1010,6 +969,22 @@ func TestWeChatOAuthCallbackRepairsLegacyProviderKeyCanonicalIdentity(t *testing
...
@@ -1010,6 +969,22 @@ func TestWeChatOAuthCallbackRepairsLegacyProviderKeyCanonicalIdentity(t *testing
}
}
func
newWeChatOAuthTestHandler
(
t
*
testing
.
T
,
invitationEnabled
bool
)
(
*
AuthHandler
,
*
dbent
.
Client
)
{
func
newWeChatOAuthTestHandler
(
t
*
testing
.
T
,
invitationEnabled
bool
)
(
*
AuthHandler
,
*
dbent
.
Client
)
{
return
newWeChatOAuthTestHandlerWithSettings
(
t
,
invitationEnabled
,
nil
)
}
func
wechatOAuthTestSettings
(
mode
,
appID
,
secret
,
frontendRedirect
string
)
map
[
string
]
string
{
return
map
[
string
]
string
{
service
.
SettingKeyWeChatConnectEnabled
:
"true"
,
service
.
SettingKeyWeChatConnectAppID
:
appID
,
service
.
SettingKeyWeChatConnectAppSecret
:
secret
,
service
.
SettingKeyWeChatConnectMode
:
mode
,
service
.
SettingKeyWeChatConnectScopes
:
service
.
DefaultWeChatConnectScopesForMode
(
mode
),
service
.
SettingKeyWeChatConnectRedirectURL
:
"https://api.example.com/api/v1/auth/oauth/wechat/callback"
,
service
.
SettingKeyWeChatConnectFrontendRedirectURL
:
frontendRedirect
,
}
}
func
newWeChatOAuthTestHandlerWithSettings
(
t
*
testing
.
T
,
invitationEnabled
bool
,
extraSettings
map
[
string
]
string
)
(
*
AuthHandler
,
*
dbent
.
Client
)
{
t
.
Helper
()
t
.
Helper
()
db
,
err
:=
sql
.
Open
(
"sqlite"
,
"file:auth_wechat_oauth?mode=memory&cache=shared"
)
db
,
err
:=
sql
.
Open
(
"sqlite"
,
"file:auth_wechat_oauth?mode=memory&cache=shared"
)
...
@@ -1036,12 +1011,17 @@ func newWeChatOAuthTestHandler(t *testing.T, invitationEnabled bool) (*AuthHandl
...
@@ -1036,12 +1011,17 @@ func newWeChatOAuthTestHandler(t *testing.T, invitationEnabled bool) (*AuthHandl
UserConcurrency
:
1
,
UserConcurrency
:
1
,
},
},
}
}
settingSvc
:=
service
.
NewSettingService
(
&
wechatOAuthSettingRepoStub
{
values
:=
map
[
string
]
string
{
values
:
map
[
string
]
string
{
service
.
SettingKeyRegistrationEnabled
:
"true"
,
service
.
SettingKeyRegistrationEnabled
:
"true"
,
service
.
SettingKeyInvitationCodeEnabled
:
boolSettingValue
(
invitationEnabled
),
service
.
SettingKeyInvitationCodeEnabled
:
boolSettingValue
(
invitationEnabled
),
},
}
},
cfg
)
for
key
,
value
:=
range
wechatOAuthTestSettings
(
"open"
,
"wx-open-app"
,
"wx-open-secret"
,
"/auth/wechat/callback"
)
{
values
[
key
]
=
value
}
for
key
,
value
:=
range
extraSettings
{
values
[
key
]
=
value
}
settingSvc
:=
service
.
NewSettingService
(
&
wechatOAuthSettingRepoStub
{
values
:
values
},
cfg
)
authSvc
:=
service
.
NewAuthService
(
authSvc
:=
service
.
NewAuthService
(
client
,
client
,
...
...
backend/internal/handler/dto/settings.go
View file @
ee3f158f
...
@@ -51,6 +51,14 @@ type SystemSettings struct {
...
@@ -51,6 +51,14 @@ type SystemSettings struct {
LinuxDoConnectClientSecretConfigured
bool
`json:"linuxdo_connect_client_secret_configured"`
LinuxDoConnectClientSecretConfigured
bool
`json:"linuxdo_connect_client_secret_configured"`
LinuxDoConnectRedirectURL
string
`json:"linuxdo_connect_redirect_url"`
LinuxDoConnectRedirectURL
string
`json:"linuxdo_connect_redirect_url"`
WeChatConnectEnabled
bool
`json:"wechat_connect_enabled"`
WeChatConnectAppID
string
`json:"wechat_connect_app_id"`
WeChatConnectAppSecretConfigured
bool
`json:"wechat_connect_app_secret_configured"`
WeChatConnectMode
string
`json:"wechat_connect_mode"`
WeChatConnectScopes
string
`json:"wechat_connect_scopes"`
WeChatConnectRedirectURL
string
`json:"wechat_connect_redirect_url"`
WeChatConnectFrontendRedirectURL
string
`json:"wechat_connect_frontend_redirect_url"`
OIDCConnectEnabled
bool
`json:"oidc_connect_enabled"`
OIDCConnectEnabled
bool
`json:"oidc_connect_enabled"`
OIDCConnectProviderName
string
`json:"oidc_connect_provider_name"`
OIDCConnectProviderName
string
`json:"oidc_connect_provider_name"`
OIDCConnectClientID
string
`json:"oidc_connect_client_id"`
OIDCConnectClientID
string
`json:"oidc_connect_client_id"`
...
...
backend/internal/handler/setting_handler_public_test.go
View file @
ee3f158f
...
@@ -84,12 +84,17 @@ func TestSettingHandler_GetPublicSettings_ExposesForceEmailOnThirdPartySignup(t
...
@@ -84,12 +84,17 @@ func TestSettingHandler_GetPublicSettings_ExposesForceEmailOnThirdPartySignup(t
func
TestSettingHandler_GetPublicSettings_ExposesWeChatOAuthModeCapabilities
(
t
*
testing
.
T
)
{
func
TestSettingHandler_GetPublicSettings_ExposesWeChatOAuthModeCapabilities
(
t
*
testing
.
T
)
{
gin
.
SetMode
(
gin
.
TestMode
)
gin
.
SetMode
(
gin
.
TestMode
)
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
,
"wx-open-app"
)
h
:=
NewSettingHandler
(
service
.
NewSettingService
(
&
settingHandlerPublicRepoStub
{
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
,
"wx-open-secret"
)
values
:
map
[
string
]
string
{
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_ID"
,
""
)
service
.
SettingKeyWeChatConnectEnabled
:
"true"
,
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_SECRET"
,
""
)
service
.
SettingKeyWeChatConnectAppID
:
"wx-mp-app"
,
service
.
SettingKeyWeChatConnectAppSecret
:
"wx-mp-secret"
,
h
:=
NewSettingHandler
(
service
.
NewSettingService
(
&
settingHandlerPublicRepoStub
{},
&
config
.
Config
{}),
"test-version"
)
service
.
SettingKeyWeChatConnectMode
:
"mp"
,
service
.
SettingKeyWeChatConnectScopes
:
"snsapi_base"
,
service
.
SettingKeyWeChatConnectRedirectURL
:
"https://api.example.com/api/v1/auth/oauth/wechat/callback"
,
service
.
SettingKeyWeChatConnectFrontendRedirectURL
:
"/auth/wechat/callback"
,
},
},
&
config
.
Config
{}),
"test-version"
)
recorder
:=
httptest
.
NewRecorder
()
recorder
:=
httptest
.
NewRecorder
()
c
,
_
:=
gin
.
CreateTestContext
(
recorder
)
c
,
_
:=
gin
.
CreateTestContext
(
recorder
)
...
@@ -110,6 +115,6 @@ func TestSettingHandler_GetPublicSettings_ExposesWeChatOAuthModeCapabilities(t *
...
@@ -110,6 +115,6 @@ func TestSettingHandler_GetPublicSettings_ExposesWeChatOAuthModeCapabilities(t *
require
.
NoError
(
t
,
json
.
Unmarshal
(
recorder
.
Body
.
Bytes
(),
&
resp
))
require
.
NoError
(
t
,
json
.
Unmarshal
(
recorder
.
Body
.
Bytes
(),
&
resp
))
require
.
Equal
(
t
,
0
,
resp
.
Code
)
require
.
Equal
(
t
,
0
,
resp
.
Code
)
require
.
True
(
t
,
resp
.
Data
.
WeChatOAuthEnabled
)
require
.
True
(
t
,
resp
.
Data
.
WeChatOAuthEnabled
)
require
.
Tru
e
(
t
,
resp
.
Data
.
WeChatOAuthOpenEnabled
)
require
.
Fals
e
(
t
,
resp
.
Data
.
WeChatOAuthOpenEnabled
)
require
.
Fals
e
(
t
,
resp
.
Data
.
WeChatOAuthMPEnabled
)
require
.
Tru
e
(
t
,
resp
.
Data
.
WeChatOAuthMPEnabled
)
}
}
backend/internal/service/domain_constants.go
View file @
ee3f158f
...
@@ -111,6 +111,15 @@ const (
...
@@ -111,6 +111,15 @@ const (
SettingKeyLinuxDoConnectClientSecret
=
"linuxdo_connect_client_secret"
SettingKeyLinuxDoConnectClientSecret
=
"linuxdo_connect_client_secret"
SettingKeyLinuxDoConnectRedirectURL
=
"linuxdo_connect_redirect_url"
SettingKeyLinuxDoConnectRedirectURL
=
"linuxdo_connect_redirect_url"
// WeChat Connect OAuth 登录设置
SettingKeyWeChatConnectEnabled
=
"wechat_connect_enabled"
SettingKeyWeChatConnectAppID
=
"wechat_connect_app_id"
SettingKeyWeChatConnectAppSecret
=
"wechat_connect_app_secret"
SettingKeyWeChatConnectMode
=
"wechat_connect_mode"
SettingKeyWeChatConnectScopes
=
"wechat_connect_scopes"
SettingKeyWeChatConnectRedirectURL
=
"wechat_connect_redirect_url"
SettingKeyWeChatConnectFrontendRedirectURL
=
"wechat_connect_frontend_redirect_url"
// Generic OIDC OAuth 登录设置
// Generic OIDC OAuth 登录设置
SettingKeyOIDCConnectEnabled
=
"oidc_connect_enabled"
SettingKeyOIDCConnectEnabled
=
"oidc_connect_enabled"
SettingKeyOIDCConnectProviderName
=
"oidc_connect_provider_name"
SettingKeyOIDCConnectProviderName
=
"oidc_connect_provider_name"
...
...
backend/internal/service/payment_config_service.go
View file @
ee3f158f
...
@@ -93,6 +93,11 @@ type UpdatePaymentConfigRequest struct {
...
@@ -93,6 +93,11 @@ type UpdatePaymentConfigRequest struct {
CancelRateLimitWindow
*
int
`json:"cancel_rate_limit_window"`
CancelRateLimitWindow
*
int
`json:"cancel_rate_limit_window"`
CancelRateLimitUnit
*
string
`json:"cancel_rate_limit_unit"`
CancelRateLimitUnit
*
string
`json:"cancel_rate_limit_unit"`
CancelRateLimitMode
*
string
`json:"cancel_rate_limit_window_mode"`
CancelRateLimitMode
*
string
`json:"cancel_rate_limit_window_mode"`
VisibleMethodAlipaySource
*
string
`json:"payment_visible_method_alipay_source"`
VisibleMethodWxpaySource
*
string
`json:"payment_visible_method_wxpay_source"`
VisibleMethodAlipayEnabled
*
bool
`json:"payment_visible_method_alipay_enabled"`
VisibleMethodWxpayEnabled
*
bool
`json:"payment_visible_method_wxpay_enabled"`
}
}
// MethodLimits holds per-payment-type limits.
// MethodLimits holds per-payment-type limits.
...
@@ -319,6 +324,10 @@ func (s *PaymentConfigService) UpdatePaymentConfig(ctx context.Context, req Upda
...
@@ -319,6 +324,10 @@ func (s *PaymentConfigService) UpdatePaymentConfig(ctx context.Context, req Upda
SettingCancelWindowSize
:
formatPositiveInt
(
req
.
CancelRateLimitWindow
),
SettingCancelWindowSize
:
formatPositiveInt
(
req
.
CancelRateLimitWindow
),
SettingCancelWindowUnit
:
derefStr
(
req
.
CancelRateLimitUnit
),
SettingCancelWindowUnit
:
derefStr
(
req
.
CancelRateLimitUnit
),
SettingCancelWindowMode
:
derefStr
(
req
.
CancelRateLimitMode
),
SettingCancelWindowMode
:
derefStr
(
req
.
CancelRateLimitMode
),
SettingPaymentVisibleMethodAlipaySource
:
derefStr
(
req
.
VisibleMethodAlipaySource
),
SettingPaymentVisibleMethodWxpaySource
:
derefStr
(
req
.
VisibleMethodWxpaySource
),
SettingPaymentVisibleMethodAlipayEnabled
:
formatBoolOrEmpty
(
req
.
VisibleMethodAlipayEnabled
),
SettingPaymentVisibleMethodWxpayEnabled
:
formatBoolOrEmpty
(
req
.
VisibleMethodWxpayEnabled
),
}
}
if
req
.
EnabledTypes
!=
nil
{
if
req
.
EnabledTypes
!=
nil
{
m
[
SettingEnabledPaymentTypes
]
=
strings
.
Join
(
req
.
EnabledTypes
,
","
)
m
[
SettingEnabledPaymentTypes
]
=
strings
.
Join
(
req
.
EnabledTypes
,
","
)
...
...
backend/internal/service/payment_config_service_test.go
View file @
ee3f158f
...
@@ -367,6 +367,7 @@ func newPaymentConfigServiceTestClient(t *testing.T) *dbent.Client {
...
@@ -367,6 +367,7 @@ func newPaymentConfigServiceTestClient(t *testing.T) *dbent.Client {
type
paymentConfigSettingRepoStub
struct
{
type
paymentConfigSettingRepoStub
struct
{
values
map
[
string
]
string
values
map
[
string
]
string
updates
map
[
string
]
string
}
}
func
(
s
*
paymentConfigSettingRepoStub
)
Get
(
context
.
Context
,
string
)
(
*
Setting
,
error
)
{
func
(
s
*
paymentConfigSettingRepoStub
)
Get
(
context
.
Context
,
string
)
(
*
Setting
,
error
)
{
...
@@ -383,10 +384,52 @@ func (s *paymentConfigSettingRepoStub) GetMultiple(_ context.Context, keys []str
...
@@ -383,10 +384,52 @@ func (s *paymentConfigSettingRepoStub) GetMultiple(_ context.Context, keys []str
}
}
return
out
,
nil
return
out
,
nil
}
}
func
(
s
*
paymentConfigSettingRepoStub
)
SetMultiple
(
context
.
Context
,
map
[
string
]
string
)
error
{
func
(
s
*
paymentConfigSettingRepoStub
)
SetMultiple
(
_
context
.
Context
,
values
map
[
string
]
string
)
error
{
s
.
updates
=
make
(
map
[
string
]
string
,
len
(
values
))
for
key
,
value
:=
range
values
{
s
.
updates
[
key
]
=
value
if
s
.
values
==
nil
{
s
.
values
=
map
[
string
]
string
{}
}
s
.
values
[
key
]
=
value
}
return
nil
return
nil
}
}
func
(
s
*
paymentConfigSettingRepoStub
)
GetAll
(
context
.
Context
)
(
map
[
string
]
string
,
error
)
{
func
(
s
*
paymentConfigSettingRepoStub
)
GetAll
(
context
.
Context
)
(
map
[
string
]
string
,
error
)
{
return
s
.
values
,
nil
return
s
.
values
,
nil
}
}
func
(
s
*
paymentConfigSettingRepoStub
)
Delete
(
context
.
Context
,
string
)
error
{
return
nil
}
func
(
s
*
paymentConfigSettingRepoStub
)
Delete
(
context
.
Context
,
string
)
error
{
return
nil
}
func
TestUpdatePaymentConfig_PersistsVisibleMethodRouting
(
t
*
testing
.
T
)
{
repo
:=
&
paymentConfigSettingRepoStub
{
values
:
map
[
string
]
string
{}}
svc
:=
&
PaymentConfigService
{
settingRepo
:
repo
}
alipayEnabled
:=
true
wxpayEnabled
:=
false
err
:=
svc
.
UpdatePaymentConfig
(
context
.
Background
(),
UpdatePaymentConfigRequest
{
VisibleMethodAlipayEnabled
:
&
alipayEnabled
,
VisibleMethodAlipaySource
:
paymentConfigStrPtr
(
VisibleMethodSourceEasyPayAlipay
),
VisibleMethodWxpayEnabled
:
&
wxpayEnabled
,
VisibleMethodWxpaySource
:
paymentConfigStrPtr
(
VisibleMethodSourceOfficialWechat
),
})
if
err
!=
nil
{
t
.
Fatalf
(
"UpdatePaymentConfig returned error: %v"
,
err
)
}
if
repo
.
values
[
SettingPaymentVisibleMethodAlipayEnabled
]
!=
"true"
{
t
.
Fatalf
(
"alipay enabled = %q, want true"
,
repo
.
values
[
SettingPaymentVisibleMethodAlipayEnabled
])
}
if
repo
.
values
[
SettingPaymentVisibleMethodAlipaySource
]
!=
VisibleMethodSourceEasyPayAlipay
{
t
.
Fatalf
(
"alipay source = %q, want %q"
,
repo
.
values
[
SettingPaymentVisibleMethodAlipaySource
],
VisibleMethodSourceEasyPayAlipay
)
}
if
repo
.
values
[
SettingPaymentVisibleMethodWxpayEnabled
]
!=
"false"
{
t
.
Fatalf
(
"wxpay enabled = %q, want false"
,
repo
.
values
[
SettingPaymentVisibleMethodWxpayEnabled
])
}
if
repo
.
values
[
SettingPaymentVisibleMethodWxpaySource
]
!=
VisibleMethodSourceOfficialWechat
{
t
.
Fatalf
(
"wxpay source = %q, want %q"
,
repo
.
values
[
SettingPaymentVisibleMethodWxpaySource
],
VisibleMethodSourceOfficialWechat
)
}
}
func
paymentConfigStrPtr
(
value
string
)
*
string
{
return
&
value
}
backend/internal/service/payment_order.go
View file @
ee3f158f
...
@@ -6,7 +6,6 @@ import (
...
@@ -6,7 +6,6 @@ import (
"log/slog"
"log/slog"
"math"
"math"
"net/url"
"net/url"
"os"
"strconv"
"strconv"
"strings"
"strings"
"time"
"time"
...
@@ -512,16 +511,21 @@ func requiresWeChatJSAPICompatibleSelection(req CreateOrderRequest, sel *payment
...
@@ -512,16 +511,21 @@ func requiresWeChatJSAPICompatibleSelection(req CreateOrderRequest, sel *payment
return
req
.
IsWeChatBrowser
||
strings
.
TrimSpace
(
req
.
OpenID
)
!=
""
return
req
.
IsWeChatBrowser
||
strings
.
TrimSpace
(
req
.
OpenID
)
!=
""
}
}
func
(
s
*
PaymentService
)
getWeChatPaymentOAuthCredential
(
context
.
Context
)
(
string
,
string
,
error
)
{
func
(
s
*
PaymentService
)
getWeChatPaymentOAuthCredential
(
ctx
context
.
Context
)
(
string
,
string
,
error
)
{
appID
:=
strings
.
TrimSpace
(
os
.
Getenv
(
"WECHAT_OAUTH_MP_APP_ID"
))
if
s
==
nil
||
s
.
configService
==
nil
||
s
.
configService
.
settingRepo
==
nil
{
appSecret
:=
strings
.
TrimSpace
(
os
.
Getenv
(
"WECHAT_OAUTH_MP_APP_SECRET"
))
return
""
,
""
,
infraerrors
.
ServiceUnavailable
(
if
appID
==
""
||
appSecret
==
""
{
"WECHAT_PAYMENT_MP_NOT_CONFIGURED"
,
"wechat in-app payment requires a complete WeChat MP OAuth credential"
,
)
}
cfg
,
err
:=
(
&
SettingService
{
settingRepo
:
s
.
configService
.
settingRepo
})
.
GetWeChatConnectOAuthConfig
(
ctx
)
if
err
!=
nil
||
cfg
.
Mode
!=
"mp"
||
strings
.
TrimSpace
(
cfg
.
AppID
)
==
""
||
strings
.
TrimSpace
(
cfg
.
AppSecret
)
==
""
{
return
""
,
""
,
infraerrors
.
ServiceUnavailable
(
return
""
,
""
,
infraerrors
.
ServiceUnavailable
(
"WECHAT_PAYMENT_MP_NOT_CONFIGURED"
,
"WECHAT_PAYMENT_MP_NOT_CONFIGURED"
,
"wechat in-app payment requires a complete WeChat MP OAuth credential"
,
"wechat in-app payment requires a complete WeChat MP OAuth credential"
,
)
)
}
}
return
a
ppID
,
a
ppSecret
,
nil
return
strings
.
TrimSpace
(
cfg
.
A
ppID
)
,
strings
.
TrimSpace
(
cfg
.
A
ppSecret
)
,
nil
}
}
func
classifyCreatePaymentError
(
req
CreateOrderRequest
,
providerKey
string
,
err
error
)
error
{
func
classifyCreatePaymentError
(
req
CreateOrderRequest
,
providerKey
string
,
err
error
)
error
{
...
...
backend/internal/service/payment_order_jsapi_test.go
View file @
ee3f158f
...
@@ -64,6 +64,13 @@ func TestSelectCreateOrderInstancePrefersJSAPICompatibleWxpayInstance(t *testing
...
@@ -64,6 +64,13 @@ func TestSelectCreateOrderInstancePrefersJSAPICompatibleWxpayInstance(t *testing
settingRepo
:
&
paymentConfigSettingRepoStub
{
values
:
map
[
string
]
string
{
settingRepo
:
&
paymentConfigSettingRepoStub
{
values
:
map
[
string
]
string
{
SettingPaymentVisibleMethodWxpayEnabled
:
"true"
,
SettingPaymentVisibleMethodWxpayEnabled
:
"true"
,
SettingPaymentVisibleMethodWxpaySource
:
VisibleMethodSourceOfficialWechat
,
SettingPaymentVisibleMethodWxpaySource
:
VisibleMethodSourceOfficialWechat
,
SettingKeyWeChatConnectEnabled
:
"true"
,
SettingKeyWeChatConnectAppID
:
"wx-mp-app"
,
SettingKeyWeChatConnectAppSecret
:
"wechat-secret"
,
SettingKeyWeChatConnectMode
:
"mp"
,
SettingKeyWeChatConnectScopes
:
"snsapi_base"
,
SettingKeyWeChatConnectRedirectURL
:
"https://api.example.com/api/v1/auth/oauth/wechat/callback"
,
SettingKeyWeChatConnectFrontendRedirectURL
:
"/auth/wechat/callback"
,
}},
}},
encryptionKey
:
[]
byte
(
jsapiTestEncryptionKey
),
encryptionKey
:
[]
byte
(
jsapiTestEncryptionKey
),
}
}
...
@@ -77,9 +84,6 @@ func TestSelectCreateOrderInstancePrefersJSAPICompatibleWxpayInstance(t *testing
...
@@ -77,9 +84,6 @@ func TestSelectCreateOrderInstancePrefersJSAPICompatibleWxpayInstance(t *testing
configService
:
configService
,
configService
:
configService
,
}
}
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_ID"
,
"wx-mp-app"
)
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_SECRET"
,
"wechat-secret"
)
sel
,
err
:=
svc
.
selectCreateOrderInstance
(
ctx
,
CreateOrderRequest
{
sel
,
err
:=
svc
.
selectCreateOrderInstance
(
ctx
,
CreateOrderRequest
{
PaymentType
:
payment
.
TypeWxpay
,
PaymentType
:
payment
.
TypeWxpay
,
OpenID
:
"openid-123"
,
OpenID
:
"openid-123"
,
...
...
backend/internal/service/payment_order_result_test.go
View file @
ee3f158f
...
@@ -91,10 +91,15 @@ func TestBuildCreateOrderResponseCopiesJSAPIPayload(t *testing.T) {
...
@@ -91,10 +91,15 @@ func TestBuildCreateOrderResponseCopiesJSAPIPayload(t *testing.T) {
}
}
func
TestMaybeBuildWeChatOAuthRequiredResponse
(
t
*
testing
.
T
)
{
func
TestMaybeBuildWeChatOAuthRequiredResponse
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_ID"
,
"wx123456"
)
svc
:=
newWeChatPaymentOAuthTestService
(
map
[
string
]
string
{
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_SECRET"
,
"wechat-secret"
)
SettingKeyWeChatConnectEnabled
:
"true"
,
SettingKeyWeChatConnectAppID
:
"wx123456"
,
svc
:=
&
PaymentService
{}
SettingKeyWeChatConnectAppSecret
:
"wechat-secret"
,
SettingKeyWeChatConnectMode
:
"mp"
,
SettingKeyWeChatConnectScopes
:
"snsapi_base"
,
SettingKeyWeChatConnectRedirectURL
:
"https://api.example.com/api/v1/auth/oauth/wechat/callback"
,
SettingKeyWeChatConnectFrontendRedirectURL
:
"/auth/wechat/callback"
,
})
resp
,
err
:=
svc
.
maybeBuildWeChatOAuthRequiredResponse
(
context
.
Background
(),
CreateOrderRequest
{
resp
,
err
:=
svc
.
maybeBuildWeChatOAuthRequiredResponse
(
context
.
Background
(),
CreateOrderRequest
{
Amount
:
12.5
,
Amount
:
12.5
,
...
@@ -132,7 +137,7 @@ func TestMaybeBuildWeChatOAuthRequiredResponse(t *testing.T) {
...
@@ -132,7 +137,7 @@ func TestMaybeBuildWeChatOAuthRequiredResponse(t *testing.T) {
func
TestMaybeBuildWeChatOAuthRequiredResponseRequiresMPConfigInWeChat
(
t
*
testing
.
T
)
{
func
TestMaybeBuildWeChatOAuthRequiredResponseRequiresMPConfigInWeChat
(
t
*
testing
.
T
)
{
t
.
Parallel
()
t
.
Parallel
()
svc
:=
&
Paymen
tService
{}
svc
:=
newWeChatPaymentOAuthTes
tService
(
nil
)
resp
,
err
:=
svc
.
maybeBuildWeChatOAuthRequiredResponse
(
context
.
Background
(),
CreateOrderRequest
{
resp
,
err
:=
svc
.
maybeBuildWeChatOAuthRequiredResponse
(
context
.
Background
(),
CreateOrderRequest
{
Amount
:
12.5
,
Amount
:
12.5
,
...
@@ -155,10 +160,15 @@ func TestMaybeBuildWeChatOAuthRequiredResponseRequiresMPConfigInWeChat(t *testin
...
@@ -155,10 +160,15 @@ func TestMaybeBuildWeChatOAuthRequiredResponseRequiresMPConfigInWeChat(t *testin
}
}
func
TestMaybeBuildWeChatOAuthRequiredResponseForSelectionSkipsEasyPayProvider
(
t
*
testing
.
T
)
{
func
TestMaybeBuildWeChatOAuthRequiredResponseForSelectionSkipsEasyPayProvider
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_ID"
,
"wx123456"
)
svc
:=
newWeChatPaymentOAuthTestService
(
map
[
string
]
string
{
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_SECRET"
,
"wechat-secret"
)
SettingKeyWeChatConnectEnabled
:
"true"
,
SettingKeyWeChatConnectAppID
:
"wx123456"
,
svc
:=
&
PaymentService
{}
SettingKeyWeChatConnectAppSecret
:
"wechat-secret"
,
SettingKeyWeChatConnectMode
:
"mp"
,
SettingKeyWeChatConnectScopes
:
"snsapi_base"
,
SettingKeyWeChatConnectRedirectURL
:
"https://api.example.com/api/v1/auth/oauth/wechat/callback"
,
SettingKeyWeChatConnectFrontendRedirectURL
:
"/auth/wechat/callback"
,
})
resp
,
err
:=
svc
.
maybeBuildWeChatOAuthRequiredResponseForSelection
(
context
.
Background
(),
CreateOrderRequest
{
resp
,
err
:=
svc
.
maybeBuildWeChatOAuthRequiredResponseForSelection
(
context
.
Background
(),
CreateOrderRequest
{
Amount
:
12.5
,
Amount
:
12.5
,
...
@@ -175,3 +185,11 @@ func TestMaybeBuildWeChatOAuthRequiredResponseForSelectionSkipsEasyPayProvider(t
...
@@ -175,3 +185,11 @@ func TestMaybeBuildWeChatOAuthRequiredResponseForSelectionSkipsEasyPayProvider(t
t
.
Fatalf
(
"expected nil response, got %+v"
,
resp
)
t
.
Fatalf
(
"expected nil response, got %+v"
,
resp
)
}
}
}
}
func
newWeChatPaymentOAuthTestService
(
values
map
[
string
]
string
)
*
PaymentService
{
return
&
PaymentService
{
configService
:
&
PaymentConfigService
{
settingRepo
:
&
paymentConfigSettingRepoStub
{
values
:
values
},
},
}
}
backend/internal/service/setting_service.go
View file @
ee3f158f
...
@@ -9,7 +9,6 @@ import (
...
@@ -9,7 +9,6 @@ import (
"fmt"
"fmt"
"log/slog"
"log/slog"
"net/url"
"net/url"
"os"
"sort"
"sort"
"strconv"
"strconv"
"strings"
"strings"
...
@@ -173,8 +172,43 @@ var (
...
@@ -173,8 +172,43 @@ var (
const
(
const
(
defaultAuthSourceBalance
=
0
defaultAuthSourceBalance
=
0
defaultAuthSourceConcurrency
=
5
defaultAuthSourceConcurrency
=
5
defaultWeChatConnectMode
=
"open"
defaultWeChatConnectScopes
=
"snsapi_login"
defaultWeChatConnectFrontend
=
"/auth/wechat/callback"
)
)
func
normalizeWeChatConnectModeSetting
(
raw
string
)
string
{
switch
strings
.
ToLower
(
strings
.
TrimSpace
(
raw
))
{
case
"mp"
:
return
"mp"
default
:
return
"open"
}
}
func
defaultWeChatConnectScopeForMode
(
mode
string
)
string
{
if
normalizeWeChatConnectModeSetting
(
mode
)
==
"mp"
{
return
"snsapi_userinfo"
}
return
defaultWeChatConnectScopes
}
func
normalizeWeChatConnectScopeSetting
(
raw
,
mode
string
)
string
{
switch
normalizeWeChatConnectModeSetting
(
mode
)
{
case
"mp"
:
switch
strings
.
TrimSpace
(
raw
)
{
case
"snsapi_base"
:
return
"snsapi_base"
case
"snsapi_userinfo"
:
return
"snsapi_userinfo"
default
:
return
defaultWeChatConnectScopeForMode
(
mode
)
}
default
:
return
defaultWeChatConnectScopes
}
}
// NewSettingService 创建系统设置服务实例
// NewSettingService 创建系统设置服务实例
func
NewSettingService
(
settingRepo
SettingRepository
,
cfg
*
config
.
Config
)
*
SettingService
{
func
NewSettingService
(
settingRepo
SettingRepository
,
cfg
*
config
.
Config
)
*
SettingService
{
return
&
SettingService
{
return
&
SettingService
{
...
@@ -240,6 +274,13 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
...
@@ -240,6 +274,13 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
SettingKeyCustomMenuItems
,
SettingKeyCustomMenuItems
,
SettingKeyCustomEndpoints
,
SettingKeyCustomEndpoints
,
SettingKeyLinuxDoConnectEnabled
,
SettingKeyLinuxDoConnectEnabled
,
SettingKeyWeChatConnectEnabled
,
SettingKeyWeChatConnectAppID
,
SettingKeyWeChatConnectAppSecret
,
SettingKeyWeChatConnectMode
,
SettingKeyWeChatConnectScopes
,
SettingKeyWeChatConnectRedirectURL
,
SettingKeyWeChatConnectFrontendRedirectURL
,
SettingKeyBackendModeEnabled
,
SettingKeyBackendModeEnabled
,
SettingPaymentEnabled
,
SettingPaymentEnabled
,
SettingKeyOIDCConnectEnabled
,
SettingKeyOIDCConnectEnabled
,
...
@@ -274,9 +315,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
...
@@ -274,9 +315,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
if
oidcProviderName
==
""
{
if
oidcProviderName
==
""
{
oidcProviderName
=
"OIDC"
oidcProviderName
=
"OIDC"
}
}
weChatOpenEnabled
:=
isWeChatOAuthOpenConfigured
()
weChatEnabled
,
weChatOpenEnabled
,
weChatMPEnabled
:=
s
.
weChatOAuthCapabilitiesFromSettings
(
settings
)
weChatMPEnabled
:=
isWeChatOAuthMPConfigured
()
weChatEnabled
:=
weChatOpenEnabled
||
weChatMPEnabled
// Password reset requires email verification to be enabled
// Password reset requires email verification to be enabled
emailVerifyEnabled
:=
settings
[
SettingKeyEmailVerifyEnabled
]
==
"true"
emailVerifyEnabled
:=
settings
[
SettingKeyEmailVerifyEnabled
]
==
"true"
...
@@ -431,6 +470,56 @@ func (s *SettingService) GetPublicSettingsForInjection(ctx context.Context) (any
...
@@ -431,6 +470,56 @@ func (s *SettingService) GetPublicSettingsForInjection(ctx context.Context) (any
},
nil
},
nil
}
}
func
DefaultWeChatConnectScopesForMode
(
mode
string
)
string
{
return
defaultWeChatConnectScopeForMode
(
mode
)
}
func
(
s
*
SettingService
)
parseWeChatConnectOAuthConfig
(
settings
map
[
string
]
string
)
(
WeChatConnectOAuthConfig
,
error
)
{
cfg
:=
WeChatConnectOAuthConfig
{
Enabled
:
settings
[
SettingKeyWeChatConnectEnabled
]
==
"true"
,
AppID
:
strings
.
TrimSpace
(
settings
[
SettingKeyWeChatConnectAppID
]),
AppSecret
:
strings
.
TrimSpace
(
settings
[
SettingKeyWeChatConnectAppSecret
]),
Mode
:
normalizeWeChatConnectModeSetting
(
settings
[
SettingKeyWeChatConnectMode
]),
Scopes
:
normalizeWeChatConnectScopeSetting
(
settings
[
SettingKeyWeChatConnectScopes
],
settings
[
SettingKeyWeChatConnectMode
]),
RedirectURL
:
strings
.
TrimSpace
(
settings
[
SettingKeyWeChatConnectRedirectURL
]),
FrontendRedirectURL
:
strings
.
TrimSpace
(
settings
[
SettingKeyWeChatConnectFrontendRedirectURL
]),
}
if
cfg
.
FrontendRedirectURL
==
""
{
cfg
.
FrontendRedirectURL
=
defaultWeChatConnectFrontend
}
if
!
cfg
.
Enabled
{
return
WeChatConnectOAuthConfig
{},
infraerrors
.
NotFound
(
"OAUTH_DISABLED"
,
"wechat oauth is disabled"
)
}
if
cfg
.
AppID
==
""
{
return
WeChatConnectOAuthConfig
{},
infraerrors
.
InternalServer
(
"OAUTH_CONFIG_INVALID"
,
"wechat oauth app id not configured"
)
}
if
cfg
.
AppSecret
==
""
{
return
WeChatConnectOAuthConfig
{},
infraerrors
.
InternalServer
(
"OAUTH_CONFIG_INVALID"
,
"wechat oauth app secret not configured"
)
}
if
cfg
.
RedirectURL
==
""
{
return
WeChatConnectOAuthConfig
{},
infraerrors
.
InternalServer
(
"OAUTH_CONFIG_INVALID"
,
"wechat oauth redirect url not configured"
)
}
if
cfg
.
FrontendRedirectURL
==
""
{
return
WeChatConnectOAuthConfig
{},
infraerrors
.
InternalServer
(
"OAUTH_CONFIG_INVALID"
,
"wechat oauth frontend redirect url not configured"
)
}
if
err
:=
config
.
ValidateAbsoluteHTTPURL
(
cfg
.
RedirectURL
);
err
!=
nil
{
return
WeChatConnectOAuthConfig
{},
infraerrors
.
InternalServer
(
"OAUTH_CONFIG_INVALID"
,
"wechat oauth redirect url invalid"
)
}
if
err
:=
config
.
ValidateFrontendRedirectURL
(
cfg
.
FrontendRedirectURL
);
err
!=
nil
{
return
WeChatConnectOAuthConfig
{},
infraerrors
.
InternalServer
(
"OAUTH_CONFIG_INVALID"
,
"wechat oauth frontend redirect url invalid"
)
}
return
cfg
,
nil
}
func
(
s
*
SettingService
)
weChatOAuthCapabilitiesFromSettings
(
settings
map
[
string
]
string
)
(
bool
,
bool
,
bool
)
{
cfg
,
err
:=
s
.
parseWeChatConnectOAuthConfig
(
settings
)
if
err
!=
nil
{
return
false
,
false
,
false
}
return
true
,
cfg
.
Mode
==
"open"
,
cfg
.
Mode
==
"mp"
}
// filterUserVisibleMenuItems filters out admin-only menu items from a raw JSON
// filterUserVisibleMenuItems filters out admin-only menu items from a raw JSON
// array string, returning only items with visibility != "admin".
// array string, returning only items with visibility != "admin".
func
filterUserVisibleMenuItems
(
raw
string
)
json
.
RawMessage
{
func
filterUserVisibleMenuItems
(
raw
string
)
json
.
RawMessage
{
...
@@ -467,20 +556,6 @@ func filterUserVisibleMenuItems(raw string) json.RawMessage {
...
@@ -467,20 +556,6 @@ func filterUserVisibleMenuItems(raw string) json.RawMessage {
return
result
return
result
}
}
func
isWeChatOAuthConfigured
()
bool
{
return
isWeChatOAuthOpenConfigured
()
||
isWeChatOAuthMPConfigured
()
}
func
isWeChatOAuthOpenConfigured
()
bool
{
return
strings
.
TrimSpace
(
os
.
Getenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
))
!=
""
&&
strings
.
TrimSpace
(
os
.
Getenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
))
!=
""
}
func
isWeChatOAuthMPConfigured
()
bool
{
return
strings
.
TrimSpace
(
os
.
Getenv
(
"WECHAT_OAUTH_MP_APP_ID"
))
!=
""
&&
strings
.
TrimSpace
(
os
.
Getenv
(
"WECHAT_OAUTH_MP_APP_SECRET"
))
!=
""
}
// safeRawJSONArray returns raw as json.RawMessage if it's valid JSON, otherwise "[]".
// safeRawJSONArray returns raw as json.RawMessage if it's valid JSON, otherwise "[]".
func
safeRawJSONArray
(
raw
string
)
json
.
RawMessage
{
func
safeRawJSONArray
(
raw
string
)
json
.
RawMessage
{
raw
=
strings
.
TrimSpace
(
raw
)
raw
=
strings
.
TrimSpace
(
raw
)
...
@@ -625,6 +700,15 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
...
@@ -625,6 +700,15 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
}
}
settings
.
PaymentVisibleMethodAlipaySource
=
alipaySource
settings
.
PaymentVisibleMethodAlipaySource
=
alipaySource
settings
.
PaymentVisibleMethodWxpaySource
=
wxpaySource
settings
.
PaymentVisibleMethodWxpaySource
=
wxpaySource
settings
.
WeChatConnectAppID
=
strings
.
TrimSpace
(
settings
.
WeChatConnectAppID
)
settings
.
WeChatConnectAppSecret
=
strings
.
TrimSpace
(
settings
.
WeChatConnectAppSecret
)
settings
.
WeChatConnectMode
=
normalizeWeChatConnectModeSetting
(
settings
.
WeChatConnectMode
)
settings
.
WeChatConnectScopes
=
normalizeWeChatConnectScopeSetting
(
settings
.
WeChatConnectScopes
,
settings
.
WeChatConnectMode
)
settings
.
WeChatConnectRedirectURL
=
strings
.
TrimSpace
(
settings
.
WeChatConnectRedirectURL
)
settings
.
WeChatConnectFrontendRedirectURL
=
strings
.
TrimSpace
(
settings
.
WeChatConnectFrontendRedirectURL
)
if
settings
.
WeChatConnectFrontendRedirectURL
==
""
{
settings
.
WeChatConnectFrontendRedirectURL
=
defaultWeChatConnectFrontend
}
updates
:=
make
(
map
[
string
]
string
)
updates
:=
make
(
map
[
string
]
string
)
...
@@ -694,6 +778,17 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
...
@@ -694,6 +778,17 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
updates
[
SettingKeyOIDCConnectClientSecret
]
=
settings
.
OIDCConnectClientSecret
updates
[
SettingKeyOIDCConnectClientSecret
]
=
settings
.
OIDCConnectClientSecret
}
}
// WeChat Connect OAuth 登录
updates
[
SettingKeyWeChatConnectEnabled
]
=
strconv
.
FormatBool
(
settings
.
WeChatConnectEnabled
)
updates
[
SettingKeyWeChatConnectAppID
]
=
settings
.
WeChatConnectAppID
updates
[
SettingKeyWeChatConnectMode
]
=
settings
.
WeChatConnectMode
updates
[
SettingKeyWeChatConnectScopes
]
=
settings
.
WeChatConnectScopes
updates
[
SettingKeyWeChatConnectRedirectURL
]
=
settings
.
WeChatConnectRedirectURL
updates
[
SettingKeyWeChatConnectFrontendRedirectURL
]
=
settings
.
WeChatConnectFrontendRedirectURL
if
settings
.
WeChatConnectAppSecret
!=
""
{
updates
[
SettingKeyWeChatConnectAppSecret
]
=
settings
.
WeChatConnectAppSecret
}
// OEM设置
// OEM设置
updates
[
SettingKeySiteName
]
=
settings
.
SiteName
updates
[
SettingKeySiteName
]
=
settings
.
SiteName
updates
[
SettingKeySiteLogo
]
=
settings
.
SiteLogo
updates
[
SettingKeySiteLogo
]
=
settings
.
SiteLogo
...
@@ -1200,6 +1295,10 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
...
@@ -1200,6 +1295,10 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
SettingKeyTablePageSizeOptions
:
"[10,20,50,100]"
,
SettingKeyTablePageSizeOptions
:
"[10,20,50,100]"
,
SettingKeyCustomMenuItems
:
"[]"
,
SettingKeyCustomMenuItems
:
"[]"
,
SettingKeyCustomEndpoints
:
"[]"
,
SettingKeyCustomEndpoints
:
"[]"
,
SettingKeyWeChatConnectEnabled
:
"false"
,
SettingKeyWeChatConnectMode
:
"open"
,
SettingKeyWeChatConnectScopes
:
"snsapi_login"
,
SettingKeyWeChatConnectFrontendRedirectURL
:
defaultWeChatConnectFrontend
,
SettingKeyOIDCConnectEnabled
:
"false"
,
SettingKeyOIDCConnectEnabled
:
"false"
,
SettingKeyOIDCConnectProviderName
:
"OIDC"
,
SettingKeyOIDCConnectProviderName
:
"OIDC"
,
SettingKeyDefaultConcurrency
:
strconv
.
Itoa
(
s
.
cfg
.
Default
.
UserConcurrency
),
SettingKeyDefaultConcurrency
:
strconv
.
Itoa
(
s
.
cfg
.
Default
.
UserConcurrency
),
...
@@ -1491,6 +1590,19 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin
...
@@ -1491,6 +1590,19 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin
}
}
result
.
OIDCConnectClientSecretConfigured
=
result
.
OIDCConnectClientSecret
!=
""
result
.
OIDCConnectClientSecretConfigured
=
result
.
OIDCConnectClientSecret
!=
""
// WeChat Connect 设置:完全以 DB 系统设置为准。
result
.
WeChatConnectEnabled
=
settings
[
SettingKeyWeChatConnectEnabled
]
==
"true"
result
.
WeChatConnectAppID
=
strings
.
TrimSpace
(
settings
[
SettingKeyWeChatConnectAppID
])
result
.
WeChatConnectAppSecret
=
strings
.
TrimSpace
(
settings
[
SettingKeyWeChatConnectAppSecret
])
result
.
WeChatConnectAppSecretConfigured
=
result
.
WeChatConnectAppSecret
!=
""
result
.
WeChatConnectMode
=
normalizeWeChatConnectModeSetting
(
settings
[
SettingKeyWeChatConnectMode
])
result
.
WeChatConnectScopes
=
normalizeWeChatConnectScopeSetting
(
settings
[
SettingKeyWeChatConnectScopes
],
settings
[
SettingKeyWeChatConnectMode
])
result
.
WeChatConnectRedirectURL
=
strings
.
TrimSpace
(
settings
[
SettingKeyWeChatConnectRedirectURL
])
result
.
WeChatConnectFrontendRedirectURL
=
strings
.
TrimSpace
(
settings
[
SettingKeyWeChatConnectFrontendRedirectURL
])
if
result
.
WeChatConnectFrontendRedirectURL
==
""
{
result
.
WeChatConnectFrontendRedirectURL
=
defaultWeChatConnectFrontend
}
// Model fallback settings
// Model fallback settings
result
.
EnableModelFallback
=
settings
[
SettingKeyEnableModelFallback
]
==
"true"
result
.
EnableModelFallback
=
settings
[
SettingKeyEnableModelFallback
]
==
"true"
result
.
FallbackModelAnthropic
=
s
.
getStringOrDefault
(
settings
,
SettingKeyFallbackModelAnthropic
,
"claude-3-5-sonnet-20241022"
)
result
.
FallbackModelAnthropic
=
s
.
getStringOrDefault
(
settings
,
SettingKeyFallbackModelAnthropic
,
"claude-3-5-sonnet-20241022"
)
...
@@ -1972,6 +2084,26 @@ func (s *SettingService) GetLinuxDoConnectOAuthConfig(ctx context.Context) (conf
...
@@ -1972,6 +2084,26 @@ func (s *SettingService) GetLinuxDoConnectOAuthConfig(ctx context.Context) (conf
return
effective
,
nil
return
effective
,
nil
}
}
// GetWeChatConnectOAuthConfig 返回用于登录的最终生效 WeChat Connect 配置。
//
// WeChat Connect 已回归 DB 系统设置模型,不再回退到 config/env。
func
(
s
*
SettingService
)
GetWeChatConnectOAuthConfig
(
ctx
context
.
Context
)
(
WeChatConnectOAuthConfig
,
error
)
{
keys
:=
[]
string
{
SettingKeyWeChatConnectEnabled
,
SettingKeyWeChatConnectAppID
,
SettingKeyWeChatConnectAppSecret
,
SettingKeyWeChatConnectMode
,
SettingKeyWeChatConnectScopes
,
SettingKeyWeChatConnectRedirectURL
,
SettingKeyWeChatConnectFrontendRedirectURL
,
}
settings
,
err
:=
s
.
settingRepo
.
GetMultiple
(
ctx
,
keys
)
if
err
!=
nil
{
return
WeChatConnectOAuthConfig
{},
fmt
.
Errorf
(
"get wechat connect settings: %w"
,
err
)
}
return
s
.
parseWeChatConnectOAuthConfig
(
settings
)
}
// GetOverloadCooldownSettings 获取529过载冷却配置
// GetOverloadCooldownSettings 获取529过载冷却配置
func
(
s
*
SettingService
)
GetOverloadCooldownSettings
(
ctx
context
.
Context
)
(
*
OverloadCooldownSettings
,
error
)
{
func
(
s
*
SettingService
)
GetOverloadCooldownSettings
(
ctx
context
.
Context
)
(
*
OverloadCooldownSettings
,
error
)
{
value
,
err
:=
s
.
settingRepo
.
GetValue
(
ctx
,
SettingKeyOverloadCooldownSettings
)
value
,
err
:=
s
.
settingRepo
.
GetValue
(
ctx
,
SettingKeyOverloadCooldownSettings
)
...
...
backend/internal/service/setting_service_public_test.go
View file @
ee3f158f
...
@@ -92,16 +92,21 @@ func TestSettingService_GetPublicSettings_ExposesForceEmailOnThirdPartySignup(t
...
@@ -92,16 +92,21 @@ func TestSettingService_GetPublicSettings_ExposesForceEmailOnThirdPartySignup(t
}
}
func
TestSettingService_GetPublicSettings_ExposesWeChatOAuthModeCapabilities
(
t
*
testing
.
T
)
{
func
TestSettingService_GetPublicSettings_ExposesWeChatOAuthModeCapabilities
(
t
*
testing
.
T
)
{
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_ID"
,
"wx-open-app"
)
svc
:=
NewSettingService
(
&
settingPublicRepoStub
{
t
.
Setenv
(
"WECHAT_OAUTH_OPEN_APP_SECRET"
,
"wx-open-secret"
)
values
:
map
[
string
]
string
{
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_ID"
,
""
)
SettingKeyWeChatConnectEnabled
:
"true"
,
t
.
Setenv
(
"WECHAT_OAUTH_MP_APP_SECRET"
,
""
)
SettingKeyWeChatConnectAppID
:
"wx-mp-app"
,
SettingKeyWeChatConnectAppSecret
:
"wx-mp-secret"
,
svc
:=
NewSettingService
(
&
settingPublicRepoStub
{},
&
config
.
Config
{})
SettingKeyWeChatConnectMode
:
"mp"
,
SettingKeyWeChatConnectScopes
:
"snsapi_base"
,
SettingKeyWeChatConnectRedirectURL
:
"https://api.example.com/api/v1/auth/oauth/wechat/callback"
,
SettingKeyWeChatConnectFrontendRedirectURL
:
"/auth/wechat/callback"
,
},
},
&
config
.
Config
{})
settings
,
err
:=
svc
.
GetPublicSettings
(
context
.
Background
())
settings
,
err
:=
svc
.
GetPublicSettings
(
context
.
Background
())
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
require
.
True
(
t
,
settings
.
WeChatOAuthEnabled
)
require
.
True
(
t
,
settings
.
WeChatOAuthEnabled
)
require
.
Tru
e
(
t
,
settings
.
WeChatOAuthOpenEnabled
)
require
.
Fals
e
(
t
,
settings
.
WeChatOAuthOpenEnabled
)
require
.
Fals
e
(
t
,
settings
.
WeChatOAuthMPEnabled
)
require
.
Tru
e
(
t
,
settings
.
WeChatOAuthMPEnabled
)
}
}
backend/internal/service/setting_service_wechat_config_test.go
0 → 100644
View file @
ee3f158f
//go:build unit
package
service
import
(
"context"
"testing"
"github.com/Wei-Shaw/sub2api/internal/config"
"github.com/stretchr/testify/require"
)
type
settingWeChatRepoStub
struct
{
values
map
[
string
]
string
}
func
(
s
*
settingWeChatRepoStub
)
Get
(
context
.
Context
,
string
)
(
*
Setting
,
error
)
{
panic
(
"unexpected Get call"
)
}
func
(
s
*
settingWeChatRepoStub
)
GetValue
(
_
context
.
Context
,
key
string
)
(
string
,
error
)
{
if
value
,
ok
:=
s
.
values
[
key
];
ok
{
return
value
,
nil
}
return
""
,
ErrSettingNotFound
}
func
(
s
*
settingWeChatRepoStub
)
Set
(
context
.
Context
,
string
,
string
)
error
{
panic
(
"unexpected Set call"
)
}
func
(
s
*
settingWeChatRepoStub
)
GetMultiple
(
_
context
.
Context
,
keys
[]
string
)
(
map
[
string
]
string
,
error
)
{
out
:=
make
(
map
[
string
]
string
,
len
(
keys
))
for
_
,
key
:=
range
keys
{
if
value
,
ok
:=
s
.
values
[
key
];
ok
{
out
[
key
]
=
value
}
}
return
out
,
nil
}
func
(
s
*
settingWeChatRepoStub
)
SetMultiple
(
context
.
Context
,
map
[
string
]
string
)
error
{
panic
(
"unexpected SetMultiple call"
)
}
func
(
s
*
settingWeChatRepoStub
)
GetAll
(
context
.
Context
)
(
map
[
string
]
string
,
error
)
{
panic
(
"unexpected GetAll call"
)
}
func
(
s
*
settingWeChatRepoStub
)
Delete
(
context
.
Context
,
string
)
error
{
panic
(
"unexpected Delete call"
)
}
func
TestSettingService_GetWeChatConnectOAuthConfig_UsesDatabaseOverrides
(
t
*
testing
.
T
)
{
repo
:=
&
settingWeChatRepoStub
{
values
:
map
[
string
]
string
{
SettingKeyWeChatConnectEnabled
:
"true"
,
SettingKeyWeChatConnectAppID
:
"wx-db-app"
,
SettingKeyWeChatConnectAppSecret
:
"wx-db-secret"
,
SettingKeyWeChatConnectMode
:
"mp"
,
SettingKeyWeChatConnectScopes
:
"snsapi_base"
,
SettingKeyWeChatConnectRedirectURL
:
"https://api.example.com/api/v1/auth/oauth/wechat/callback"
,
SettingKeyWeChatConnectFrontendRedirectURL
:
"/auth/wechat/callback"
,
},
}
svc
:=
NewSettingService
(
repo
,
&
config
.
Config
{})
got
,
err
:=
svc
.
GetWeChatConnectOAuthConfig
(
context
.
Background
())
require
.
NoError
(
t
,
err
)
require
.
True
(
t
,
got
.
Enabled
)
require
.
Equal
(
t
,
"wx-db-app"
,
got
.
AppID
)
require
.
Equal
(
t
,
"wx-db-secret"
,
got
.
AppSecret
)
require
.
Equal
(
t
,
"mp"
,
got
.
Mode
)
require
.
Equal
(
t
,
"snsapi_base"
,
got
.
Scopes
)
require
.
Equal
(
t
,
"https://api.example.com/api/v1/auth/oauth/wechat/callback"
,
got
.
RedirectURL
)
require
.
Equal
(
t
,
"/auth/wechat/callback"
,
got
.
FrontendRedirectURL
)
}
backend/internal/service/settings_view.go
View file @
ee3f158f
...
@@ -31,6 +31,16 @@ type SystemSettings struct {
...
@@ -31,6 +31,16 @@ type SystemSettings struct {
LinuxDoConnectClientSecretConfigured
bool
LinuxDoConnectClientSecretConfigured
bool
LinuxDoConnectRedirectURL
string
LinuxDoConnectRedirectURL
string
// WeChat Connect OAuth 登录
WeChatConnectEnabled
bool
WeChatConnectAppID
string
WeChatConnectAppSecret
string
WeChatConnectAppSecretConfigured
bool
WeChatConnectMode
string
WeChatConnectScopes
string
WeChatConnectRedirectURL
string
WeChatConnectFrontendRedirectURL
string
// Generic OIDC OAuth 登录
// Generic OIDC OAuth 登录
OIDCConnectEnabled
bool
OIDCConnectEnabled
bool
OIDCConnectProviderName
string
OIDCConnectProviderName
string
...
@@ -177,6 +187,16 @@ type PublicSettings struct {
...
@@ -177,6 +187,16 @@ type PublicSettings struct {
BalanceLowNotifyRechargeURL
string
BalanceLowNotifyRechargeURL
string
}
}
type
WeChatConnectOAuthConfig
struct
{
Enabled
bool
AppID
string
AppSecret
string
Mode
string
Scopes
string
RedirectURL
string
FrontendRedirectURL
string
}
// StreamTimeoutSettings 流超时处理配置(仅控制超时后的处理方式,超时判定由网关配置控制)
// StreamTimeoutSettings 流超时处理配置(仅控制超时后的处理方式,超时判定由网关配置控制)
type
StreamTimeoutSettings
struct
{
type
StreamTimeoutSettings
struct
{
// Enabled 是否启用流超时处理
// Enabled 是否启用流超时处理
...
...
frontend/src/api/__tests__/settings.wechatConnect.spec.ts
0 → 100644
View file @
ee3f158f
import
{
describe
,
expect
,
it
}
from
"
vitest
"
;
import
{
defaultWeChatConnectScopesForMode
,
normalizeWeChatConnectMode
,
}
from
"
@/api/admin/settings
"
;
describe
(
"
admin settings wechat connect helpers
"
,
()
=>
{
it
(
"
normalizes legacy or noisy mode values to the backend contract
"
,
()
=>
{
expect
(
normalizeWeChatConnectMode
(
"
OPEN
"
)).
toBe
(
"
open
"
);
expect
(
normalizeWeChatConnectMode
(
"
open_platform
"
)).
toBe
(
"
open
"
);
expect
(
normalizeWeChatConnectMode
(
"
mp
"
)).
toBe
(
"
mp
"
);
expect
(
normalizeWeChatConnectMode
(
"
official_account
"
)).
toBe
(
"
mp
"
);
expect
(
normalizeWeChatConnectMode
(
"
unknown
"
)).
toBe
(
"
open
"
);
});
it
(
"
maps each mode to the backend default scopes
"
,
()
=>
{
expect
(
defaultWeChatConnectScopesForMode
(
"
open
"
)).
toBe
(
"
snsapi_login
"
);
expect
(
defaultWeChatConnectScopesForMode
(
"
mp
"
)).
toBe
(
"
snsapi_userinfo
"
);
});
});
frontend/src/api/admin/settings.ts
View file @
ee3f158f
This diff is collapsed.
Click to expand it.
frontend/src/views/admin/SettingsView.vue
View file @
ee3f158f
This diff is collapsed.
Click to expand it.
frontend/src/views/admin/__tests__/SettingsView.spec.ts
View file @
ee3f158f
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment