mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-17 07:37:15 +00:00
fix(sub): prevent default profile page URL disclosure (#6538)
* fix(sub): prevent default profile page URL disclosure Add explicit none, builtin, and custom profile page modes. Preserve existing custom URLs and warn before exposing the built-in page. Cover mode selection, legacy settings, and subscription response headers. * fix(subscription): add profile page link options and upgrade notes
This commit is contained in:
@@ -44,6 +44,13 @@ const (
|
||||
maxRegexLength = 2048
|
||||
)
|
||||
|
||||
// Built-in profile links expose the subscription URL and require an explicit opt-in.
|
||||
const (
|
||||
SubProfileModeNone = "none"
|
||||
SubProfileModeBuiltin = "builtin"
|
||||
SubProfileModeCustom = "custom"
|
||||
)
|
||||
|
||||
var defaultValueMap = map[string]string{
|
||||
"xrayTemplateConfig": xrayTemplateConfig,
|
||||
"webListen": "",
|
||||
@@ -101,6 +108,7 @@ var defaultValueMap = map[string]string{
|
||||
"subClashUserAgentRegex": "",
|
||||
"subTitle": "",
|
||||
"subSupportUrl": "",
|
||||
"subProfileMode": SubProfileModeNone,
|
||||
"subProfileUrl": "",
|
||||
"subAnnounce": "",
|
||||
"subEnableRouting": "false",
|
||||
@@ -298,6 +306,11 @@ func (s *SettingService) GetAllSetting() (*entity.AllSetting, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// A missing mode must still preserve URLs configured before modes existed.
|
||||
if !keyMap["subProfileMode"] {
|
||||
allSetting.SubProfileMode = ""
|
||||
}
|
||||
allSetting.SubProfileMode = effectiveSubProfileMode(allSetting.SubProfileMode, allSetting.SubProfileUrl)
|
||||
return allSetting, nil
|
||||
}
|
||||
|
||||
@@ -850,6 +863,34 @@ func (s *SettingService) GetSubProfileUrl() (string, error) {
|
||||
return common.EnsureURLScheme(value), err
|
||||
}
|
||||
|
||||
func (s *SettingService) GetSubProfileMode() (string, error) {
|
||||
setting, err := s.getSetting("subProfileMode")
|
||||
if err != nil && !database.IsNotFound(err) {
|
||||
return SubProfileModeNone, err
|
||||
}
|
||||
if err == nil && setting.Value != "" {
|
||||
return effectiveSubProfileMode(setting.Value, ""), nil
|
||||
}
|
||||
profileURL, err := s.getString("subProfileUrl")
|
||||
if err != nil {
|
||||
return SubProfileModeNone, err
|
||||
}
|
||||
return effectiveSubProfileMode("", profileURL), nil
|
||||
}
|
||||
|
||||
func effectiveSubProfileMode(mode, profileURL string) string {
|
||||
switch mode {
|
||||
case SubProfileModeNone, SubProfileModeBuiltin, SubProfileModeCustom:
|
||||
return mode
|
||||
case "":
|
||||
// Older settings have no mode; only an existing custom URL opts them in.
|
||||
if strings.TrimSpace(profileURL) != "" {
|
||||
return SubProfileModeCustom
|
||||
}
|
||||
}
|
||||
return SubProfileModeNone
|
||||
}
|
||||
|
||||
func (s *SettingService) GetSubAnnounce() (string, error) {
|
||||
return s.getString("subAnnounce")
|
||||
}
|
||||
@@ -1448,6 +1489,12 @@ type SecretClears struct {
|
||||
}
|
||||
|
||||
func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting, clears SecretClears) error {
|
||||
switch allSetting.SubProfileMode {
|
||||
case "", SubProfileModeNone, SubProfileModeBuiltin, SubProfileModeCustom:
|
||||
allSetting.SubProfileMode = effectiveSubProfileMode(allSetting.SubProfileMode, allSetting.SubProfileUrl)
|
||||
default:
|
||||
return errors.New("subscription profile mode must be none, builtin, or custom")
|
||||
}
|
||||
if err := s.preserveRedactedSecrets(allSetting, clears); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user