chore: update implementation

This commit is contained in:
JustSong 2023-07-30 12:43:21 +08:00
parent c401842906
commit 2ea40b63c8
6 changed files with 92 additions and 68 deletions

View File

@ -94,7 +94,7 @@ _✨ 通过标准的 OpenAI API 格式访问所有的大模型,开箱即用
19. 支持通过系统访问令牌访问管理 API。 19. 支持通过系统访问令牌访问管理 API。
20. 支持 Cloudflare Turnstile 用户校验。 20. 支持 Cloudflare Turnstile 用户校验。
21. 支持用户管理,支持**多种用户登录注册方式** 21. 支持用户管理,支持**多种用户登录注册方式**
+ 邮箱登录注册以及通过邮箱进行密码重置。 + 邮箱登录注册(支持注册邮箱白名单)以及通过邮箱进行密码重置。
+ [GitHub 开放授权](https://github.com/settings/applications/new)。 + [GitHub 开放授权](https://github.com/settings/applications/new)。
+ 微信公众号授权(需要额外部署 [WeChat Server](https://github.com/songquanpeng/wechat-server))。 + 微信公众号授权(需要额外部署 [WeChat Server](https://github.com/songquanpeng/wechat-server))。

View File

@ -43,14 +43,16 @@ var TurnstileCheckEnabled = false
var RegisterEnabled = true var RegisterEnabled = true
var EmailDomainRestrictionEnabled = false var EmailDomainRestrictionEnabled = false
var RestrictedEmailDomains = []string{ var EmailDomainWhitelist = []string{
"gmail.com", "gmail.com",
"163.com", "163.com",
"126.com",
"qq.com", "qq.com",
"outlook.com", "outlook.com",
"hotmail.com", "hotmail.com",
"icloud.com", "icloud.com",
"yahoo.com", "yahoo.com",
"foxmail.com",
} }
var LogConsumeEnabled = true var LogConsumeEnabled = true

View File

@ -81,15 +81,17 @@ func SendEmailVerification(c *gin.Context) {
return return
} }
if common.EmailDomainRestrictionEnabled { if common.EmailDomainRestrictionEnabled {
allowedEmailDomains := common.RestrictedEmailDomains allowed := false
for _, domain := range common.EmailDomainWhitelist {
// Check if email suffix is allowed if strings.HasSuffix(email, "@"+domain) {
allowed := strings.Contains(strings.Join(allowedEmailDomains, ","), strings.Split(email, "@")[1]) allowed = true
break
}
}
if !allowed { if !allowed {
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"success": false, "success": false,
"message": "该邮箱地址不允许注册", "message": "管理员启用了邮箱域名白名单,您的邮箱地址的域名不在白名单中",
}) })
return return
} }

View File

@ -51,7 +51,7 @@ func UpdateOption(c *gin.Context) {
return return
} }
case "EmailDomainRestrictionEnabled": case "EmailDomainRestrictionEnabled":
if option.Value == "true" && len(common.RestrictedEmailDomains) == 0 { if option.Value == "true" && len(common.EmailDomainWhitelist) == 0 {
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"success": false, "success": false,
"message": "无法启用邮箱域名限制,请先填入限制的邮箱域名!", "message": "无法启用邮箱域名限制,请先填入限制的邮箱域名!",

View File

@ -40,7 +40,7 @@ func InitOptionMap() {
common.OptionMap["DisplayTokenStatEnabled"] = strconv.FormatBool(common.DisplayTokenStatEnabled) common.OptionMap["DisplayTokenStatEnabled"] = strconv.FormatBool(common.DisplayTokenStatEnabled)
common.OptionMap["ChannelDisableThreshold"] = strconv.FormatFloat(common.ChannelDisableThreshold, 'f', -1, 64) common.OptionMap["ChannelDisableThreshold"] = strconv.FormatFloat(common.ChannelDisableThreshold, 'f', -1, 64)
common.OptionMap["EmailDomainRestrictionEnabled"] = strconv.FormatBool(common.EmailDomainRestrictionEnabled) common.OptionMap["EmailDomainRestrictionEnabled"] = strconv.FormatBool(common.EmailDomainRestrictionEnabled)
common.OptionMap["RestrictedEmailDomains"] = strings.Join(common.RestrictedEmailDomains, ",") common.OptionMap["EmailDomainWhitelist"] = strings.Join(common.EmailDomainWhitelist, ",")
common.OptionMap["SMTPServer"] = "" common.OptionMap["SMTPServer"] = ""
common.OptionMap["SMTPFrom"] = "" common.OptionMap["SMTPFrom"] = ""
common.OptionMap["SMTPPort"] = strconv.Itoa(common.SMTPPort) common.OptionMap["SMTPPort"] = strconv.Itoa(common.SMTPPort)
@ -158,8 +158,8 @@ func updateOptionMap(key string, value string) (err error) {
} }
} }
switch key { switch key {
case "RestrictedEmailDomains": case "EmailDomainWhitelist":
common.RestrictedEmailDomains = strings.Split(value, ",") common.EmailDomainWhitelist = strings.Split(value, ",")
case "SMTPServer": case "SMTPServer":
common.SMTPServer = value common.SMTPServer = value
case "SMTPPort": case "SMTPPort":

View File

@ -27,11 +27,11 @@ const SystemSetting = () => {
TurnstileSecretKey: '', TurnstileSecretKey: '',
RegisterEnabled: '', RegisterEnabled: '',
EmailDomainRestrictionEnabled: '', EmailDomainRestrictionEnabled: '',
RestrictedEmailDomains: '' EmailDomainWhitelist: ''
}); });
const [originInputs, setOriginInputs] = useState({}); const [originInputs, setOriginInputs] = useState({});
let [loading, setLoading] = useState(false); let [loading, setLoading] = useState(false);
const [restrictedEmailDomains, setRestrictedEmailDomains] = useState([]); const [EmailDomainWhitelist, setEmailDomainWhitelist] = useState([]);
const [restrictedDomainInput, setRestrictedDomainInput] = useState(''); const [restrictedDomainInput, setRestrictedDomainInput] = useState('');
const getOptions = async () => { const getOptions = async () => {
@ -44,11 +44,11 @@ const SystemSetting = () => {
}); });
setInputs({ setInputs({
...newInputs, ...newInputs,
RestrictedEmailDomains: newInputs.RestrictedEmailDomains.split(',') EmailDomainWhitelist: newInputs.EmailDomainWhitelist.split(',')
}); });
setOriginInputs(newInputs); setOriginInputs(newInputs);
setRestrictedEmailDomains(newInputs.RestrictedEmailDomains.split(',').map((item) => { setEmailDomainWhitelist(newInputs.EmailDomainWhitelist.split(',').map((item) => {
return { key: item, text: item, value: item }; return { key: item, text: item, value: item };
})); }));
} else { } else {
@ -82,7 +82,7 @@ const SystemSetting = () => {
}); });
const { success, message } = res.data; const { success, message } = res.data;
if (success) { if (success) {
if (key === 'RestrictedEmailDomains') { if (key === 'EmailDomainWhitelist') {
value = value.split(','); value = value.split(',');
} }
setInputs((inputs) => ({ setInputs((inputs) => ({
@ -106,7 +106,7 @@ const SystemSetting = () => {
name === 'WeChatAccountQRCodeImageURL' || name === 'WeChatAccountQRCodeImageURL' ||
name === 'TurnstileSiteKey' || name === 'TurnstileSiteKey' ||
name === 'TurnstileSecretKey' || name === 'TurnstileSecretKey' ||
name === 'RestrictedEmailDomains' name === 'EmailDomainWhitelist'
) { ) {
setInputs((inputs) => ({ ...inputs, [name]: value })); setInputs((inputs) => ({ ...inputs, [name]: value }));
} else { } else {
@ -141,11 +141,15 @@ const SystemSetting = () => {
) { ) {
await updateOption('SMTPToken', inputs.SMTPToken); await updateOption('SMTPToken', inputs.SMTPToken);
} }
};
const submitEmailDomainWhitelist = async () => {
if ( if (
originInputs['RestrictedEmailDomains'] !== inputs.RestrictedEmailDomains.join(',') && originInputs['EmailDomainWhitelist'] !== inputs.EmailDomainWhitelist.join(',') &&
inputs.SMTPToken !== '' inputs.SMTPToken !== ''
) { ) {
await updateOption('RestrictedEmailDomains', inputs.RestrictedEmailDomains.join(',')); await updateOption('EmailDomainWhitelist', inputs.EmailDomainWhitelist.join(','));
} }
}; };
@ -197,6 +201,22 @@ const SystemSetting = () => {
} }
}; };
const submitNewRestrictedDomain = () => {
const localDomainList = inputs.EmailDomainWhitelist;
if (restrictedDomainInput !== '' && !localDomainList.includes(restrictedDomainInput)) {
setRestrictedDomainInput('');
setInputs({
...inputs,
EmailDomainWhitelist: [...localDomainList, restrictedDomainInput],
});
setEmailDomainWhitelist([...EmailDomainWhitelist, {
key: restrictedDomainInput,
text: restrictedDomainInput,
value: restrictedDomainInput,
}]);
}
}
return ( return (
<Grid columns={1}> <Grid columns={1}>
<Grid.Column> <Grid.Column>
@ -263,6 +283,54 @@ const SystemSetting = () => {
/> />
</Form.Group> </Form.Group>
<Divider /> <Divider />
<Header as='h3'>
配置邮箱域名白名单
<Header.Subheader>用以防止恶意用户利用临时邮箱批量注册</Header.Subheader>
</Header>
<Form.Group widths={3}>
<Form.Checkbox
label='启用邮箱域名白名单'
name='EmailDomainRestrictionEnabled'
onChange={handleInputChange}
checked={inputs.EmailDomainRestrictionEnabled === 'true'}
/>
</Form.Group>
<Form.Group widths={2}>
<Form.Dropdown
label='允许的邮箱域名'
placeholder='允许的邮箱域名'
name='EmailDomainWhitelist'
required
fluid
multiple
selection
onChange={handleInputChange}
value={inputs.EmailDomainWhitelist}
autoComplete='new-password'
options={EmailDomainWhitelist}
/>
<Form.Input
label='添加新的允许的邮箱域名'
action={
<Button type='button' onClick={() => {
submitNewRestrictedDomain();
}}>填入</Button>
}
onKeyDown={(e) => {
if (e.key === 'Enter') {
submitNewRestrictedDomain();
}
}}
autoComplete='new-password'
placeholder='输入新的允许的邮箱域名'
value={restrictedDomainInput}
onChange={(e, { value }) => {
setRestrictedDomainInput(value);
}}
/>
</Form.Group>
<Form.Button onClick={submitEmailDomainWhitelist}>保存邮箱域名白名单设置</Form.Button>
<Divider />
<Header as='h3'> <Header as='h3'>
配置 SMTP 配置 SMTP
<Header.Subheader>用以支持系统的邮件发送</Header.Subheader> <Header.Subheader>用以支持系统的邮件发送</Header.Subheader>
@ -312,54 +380,6 @@ const SystemSetting = () => {
placeholder='敏感信息不会发送到前端显示' placeholder='敏感信息不会发送到前端显示'
/> />
</Form.Group> </Form.Group>
<Form.Group widths={3}>
<Form.Checkbox
label='电子邮件域名限制'
name='EmailDomainRestrictionEnabled'
onChange={handleInputChange}
checked={inputs.EmailDomainRestrictionEnabled === 'true'}
/>
</Form.Group>
<Form.Group widths={3}>
<Form.Dropdown
label='受限电子邮件域名'
placeholder='受限电子邮件域名'
name='RestrictedEmailDomains'
required
fluid
multiple
selection
onChange={handleInputChange}
value={inputs.RestrictedEmailDomains}
autoComplete='new-password'
options={restrictedEmailDomains}
/>
<Form.Input
label='添加受限电子邮件域名'
action={
<Button type='button' onClick={() => {
const localDomainList = inputs.RestrictedEmailDomains;
if (restrictedDomainInput !== '' && !localDomainList.includes(restrictedDomainInput)) {
setRestrictedDomainInput('');
setInputs({
...inputs,
RestrictedEmailDomains: [...localDomainList, restrictedDomainInput],
});
setRestrictedEmailDomains([...restrictedEmailDomains, {
key: restrictedDomainInput,
text: restrictedDomainInput,
value: restrictedDomainInput,
}]);
}
}}>填入</Button>
}
placeholder='输入受限电子邮件域名'
value={restrictedDomainInput}
onChange={(e, { value }) => {
setRestrictedDomainInput(value);
}}
/>
</Form.Group>
<Form.Button onClick={submitSMTP}>保存 SMTP 设置</Form.Button> <Form.Button onClick={submitSMTP}>保存 SMTP 设置</Form.Button>
<Divider /> <Divider />
<Header as='h3'> <Header as='h3'>