Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
12de1fac
authored
Nov 10, 2024
by
seefs001
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: integrate Linux DO OAuth authentication
parent
f66198b9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
451 additions
and
16 deletions
+451
-16
common/constants.go
+4
-0
controller/linuxdo.go
+265
-0
controller/misc.go
+2
-0
controller/option.go
+8
-0
i18n/en.json
+0
-0
model/option.go
+7
-0
model/user.go
+15
-0
router/api-router.go
+1
-0
web/src/components/LoginForm.js
+26
-7
web/src/components/PersonalSetting.js
+31
-3
web/src/components/SystemSetting.js
+78
-6
web/src/components/utils.js
+8
-0
web/src/pages/Home/index.js
+6
-0
No files found.
common/constants.go
View file @
12de1fac
...
...
@@ -41,6 +41,7 @@ var PasswordLoginEnabled = true
var
PasswordRegisterEnabled
=
true
var
EmailVerificationEnabled
=
false
var
GitHubOAuthEnabled
=
false
var
LinuxDOOAuthEnabled
=
false
var
WeChatAuthEnabled
=
false
var
TelegramOAuthEnabled
=
false
var
TurnstileCheckEnabled
=
false
...
...
@@ -75,6 +76,9 @@ var SMTPToken = ""
var
GitHubClientId
=
""
var
GitHubClientSecret
=
""
var
LinuxDOClientId
=
""
var
LinuxDOClientSecret
=
""
var
WeChatServerAddress
=
""
var
WeChatServerToken
=
""
var
WeChatAccountQRCodeImageURL
=
""
...
...
controller/linuxdo.go
0 → 100644
View file @
12de1fac
package
controller
import
(
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"one-api/common"
"one-api/model"
"strconv"
"strings"
"time"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
)
type
LinuxdoUser
struct
{
Id
int
`json:"id"`
Username
string
`json:"username"`
Name
string
`json:"name"`
Active
bool
`json:"active"`
TrustLevel
int
`json:"trust_level"`
Silenced
bool
`json:"silenced"`
}
func
LinuxDoBind
(
c
*
gin
.
Context
)
{
if
!
common
.
LinuxDOOAuthEnabled
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
"管理员未开启通过 Linux DO 登录以及注册"
,
})
return
}
code
:=
c
.
Query
(
"code"
)
linuxdoUser
,
err
:=
getLinuxdoUserInfoByCode
(
code
,
c
)
if
err
!=
nil
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
err
.
Error
(),
})
return
}
user
:=
model
.
User
{
LinuxDOId
:
strconv
.
Itoa
(
linuxdoUser
.
Id
),
}
if
model
.
IsLinuxDOIdAlreadyTaken
(
user
.
LinuxDOId
)
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
"该 Linux DO 账户已被绑定"
,
})
return
}
session
:=
sessions
.
Default
(
c
)
id
:=
session
.
Get
(
"id"
)
user
.
Id
=
id
.
(
int
)
err
=
user
.
FillUserById
()
if
err
!=
nil
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
err
.
Error
(),
})
return
}
user
.
LinuxDOId
=
strconv
.
Itoa
(
linuxdoUser
.
Id
)
err
=
user
.
Update
(
false
)
if
err
!=
nil
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
err
.
Error
(),
})
return
}
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
true
,
"message"
:
"bind"
,
})
}
func
getLinuxdoUserInfoByCode
(
code
string
,
c
*
gin
.
Context
)
(
*
LinuxdoUser
,
error
)
{
if
code
==
""
{
return
nil
,
errors
.
New
(
"invalid code"
)
}
// Get access token using Basic auth
tokenEndpoint
:=
"https://connect.linux.do/oauth2/token"
credentials
:=
common
.
LinuxDOClientId
+
":"
+
common
.
LinuxDOClientSecret
basicAuth
:=
"Basic "
+
base64
.
StdEncoding
.
EncodeToString
([]
byte
(
credentials
))
// Get redirect URI from request
scheme
:=
"http"
if
c
.
Request
.
TLS
!=
nil
{
scheme
=
"https"
}
redirectURI
:=
fmt
.
Sprintf
(
"%s://%s/api/oauth/linuxdo"
,
scheme
,
c
.
Request
.
Host
)
data
:=
url
.
Values
{}
data
.
Set
(
"grant_type"
,
"authorization_code"
)
data
.
Set
(
"code"
,
code
)
data
.
Set
(
"redirect_uri"
,
redirectURI
)
req
,
err
:=
http
.
NewRequest
(
"POST"
,
tokenEndpoint
,
strings
.
NewReader
(
data
.
Encode
()))
if
err
!=
nil
{
return
nil
,
err
}
req
.
Header
.
Set
(
"Authorization"
,
basicAuth
)
req
.
Header
.
Set
(
"Content-Type"
,
"application/x-www-form-urlencoded"
)
req
.
Header
.
Set
(
"Accept"
,
"application/json"
)
client
:=
http
.
Client
{
Timeout
:
5
*
time
.
Second
}
res
,
err
:=
client
.
Do
(
req
)
if
err
!=
nil
{
return
nil
,
errors
.
New
(
"failed to connect to Linux DO server"
)
}
defer
res
.
Body
.
Close
()
var
tokenRes
struct
{
AccessToken
string
`json:"access_token"`
Message
string
`json:"message"`
}
if
err
:=
json
.
NewDecoder
(
res
.
Body
)
.
Decode
(
&
tokenRes
);
err
!=
nil
{
return
nil
,
err
}
if
tokenRes
.
AccessToken
==
""
{
return
nil
,
fmt
.
Errorf
(
"failed to get access token: %s"
,
tokenRes
.
Message
)
}
// Get user info
userEndpoint
:=
"https://connect.linux.do/api/user"
req
,
err
=
http
.
NewRequest
(
"GET"
,
userEndpoint
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
req
.
Header
.
Set
(
"Authorization"
,
"Bearer "
+
tokenRes
.
AccessToken
)
req
.
Header
.
Set
(
"Accept"
,
"application/json"
)
res2
,
err
:=
client
.
Do
(
req
)
if
err
!=
nil
{
return
nil
,
errors
.
New
(
"failed to get user info from Linux DO"
)
}
defer
res2
.
Body
.
Close
()
var
linuxdoUser
LinuxdoUser
if
err
:=
json
.
NewDecoder
(
res2
.
Body
)
.
Decode
(
&
linuxdoUser
);
err
!=
nil
{
return
nil
,
err
}
if
linuxdoUser
.
Id
==
0
{
return
nil
,
errors
.
New
(
"invalid user info returned"
)
}
return
&
linuxdoUser
,
nil
}
func
LinuxdoOAuth
(
c
*
gin
.
Context
)
{
session
:=
sessions
.
Default
(
c
)
errorCode
:=
c
.
Query
(
"error"
)
if
errorCode
!=
""
{
errorDescription
:=
c
.
Query
(
"error_description"
)
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
errorDescription
,
})
return
}
state
:=
c
.
Query
(
"state"
)
if
state
==
""
||
session
.
Get
(
"oauth_state"
)
==
nil
||
state
!=
session
.
Get
(
"oauth_state"
)
.
(
string
)
{
c
.
JSON
(
http
.
StatusForbidden
,
gin
.
H
{
"success"
:
false
,
"message"
:
"state is empty or not same"
,
})
return
}
username
:=
session
.
Get
(
"username"
)
if
username
!=
nil
{
LinuxDoBind
(
c
)
return
}
if
!
common
.
LinuxDOOAuthEnabled
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
"管理员未开启通过 Linux DO 登录以及注册"
,
})
return
}
code
:=
c
.
Query
(
"code"
)
linuxdoUser
,
err
:=
getLinuxdoUserInfoByCode
(
code
,
c
)
if
err
!=
nil
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
err
.
Error
(),
})
return
}
user
:=
model
.
User
{
LinuxDOId
:
strconv
.
Itoa
(
linuxdoUser
.
Id
),
}
// Check if user exists
if
model
.
IsLinuxDOIdAlreadyTaken
(
user
.
LinuxDOId
)
{
err
:=
user
.
FillUserByLinuxDOId
()
if
err
!=
nil
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
err
.
Error
(),
})
return
}
if
user
.
Id
==
0
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
"用户已注销"
,
})
return
}
}
else
{
if
common
.
RegisterEnabled
{
user
.
Username
=
"linuxdo_"
+
strconv
.
Itoa
(
model
.
GetMaxUserId
()
+
1
)
user
.
DisplayName
=
linuxdoUser
.
Name
user
.
Role
=
common
.
RoleCommonUser
user
.
Status
=
common
.
UserStatusEnabled
if
err
:=
user
.
Insert
(
0
);
err
!=
nil
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
err
.
Error
(),
})
return
}
}
else
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
"管理员关闭了新用户注册"
,
})
return
}
}
if
user
.
Status
!=
common
.
UserStatusEnabled
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"message"
:
"用户已被封禁"
,
"success"
:
false
,
})
return
}
setupLogin
(
&
user
,
c
)
}
controller/misc.go
View file @
12de1fac
...
...
@@ -38,6 +38,8 @@ func GetStatus(c *gin.Context) {
"email_verification"
:
common
.
EmailVerificationEnabled
,
"github_oauth"
:
common
.
GitHubOAuthEnabled
,
"github_client_id"
:
common
.
GitHubClientId
,
"linuxdo_oauth"
:
common
.
LinuxDOOAuthEnabled
,
"linuxdo_client_id"
:
common
.
LinuxDOClientId
,
"telegram_oauth"
:
common
.
TelegramOAuthEnabled
,
"telegram_bot_name"
:
common
.
TelegramBotName
,
"system_name"
:
common
.
SystemName
,
...
...
controller/option.go
View file @
12de1fac
...
...
@@ -50,6 +50,14 @@ func UpdateOption(c *gin.Context) {
})
return
}
case
"LinuxDOOAuthEnabled"
:
if
option
.
Value
==
"true"
&&
common
.
LinuxDOClientId
==
""
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
"无法启用 LinuxDO OAuth,请先填入 LinuxDO Client Id 以及 LinuxDO Client Secret!"
,
})
return
}
case
"EmailDomainRestrictionEnabled"
:
if
option
.
Value
==
"true"
&&
len
(
common
.
EmailDomainWhitelist
)
==
0
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
...
...
i18n/en.json
View file @
12de1fac
This diff is collapsed.
Click to expand it.
model/option.go
View file @
12de1fac
...
...
@@ -31,6 +31,7 @@ func InitOptionMap() {
common
.
OptionMap
[
"PasswordRegisterEnabled"
]
=
strconv
.
FormatBool
(
common
.
PasswordRegisterEnabled
)
common
.
OptionMap
[
"EmailVerificationEnabled"
]
=
strconv
.
FormatBool
(
common
.
EmailVerificationEnabled
)
common
.
OptionMap
[
"GitHubOAuthEnabled"
]
=
strconv
.
FormatBool
(
common
.
GitHubOAuthEnabled
)
common
.
OptionMap
[
"LinuxDOOAuthEnabled"
]
=
strconv
.
FormatBool
(
common
.
LinuxDOOAuthEnabled
)
common
.
OptionMap
[
"TelegramOAuthEnabled"
]
=
strconv
.
FormatBool
(
common
.
TelegramOAuthEnabled
)
common
.
OptionMap
[
"WeChatAuthEnabled"
]
=
strconv
.
FormatBool
(
common
.
WeChatAuthEnabled
)
common
.
OptionMap
[
"TurnstileCheckEnabled"
]
=
strconv
.
FormatBool
(
common
.
TurnstileCheckEnabled
)
...
...
@@ -175,6 +176,8 @@ func updateOptionMap(key string, value string) (err error) {
common
.
EmailVerificationEnabled
=
boolValue
case
"GitHubOAuthEnabled"
:
common
.
GitHubOAuthEnabled
=
boolValue
case
"LinuxDOOAuthEnabled"
:
common
.
LinuxDOOAuthEnabled
=
boolValue
case
"WeChatAuthEnabled"
:
common
.
WeChatAuthEnabled
=
boolValue
case
"TelegramOAuthEnabled"
:
...
...
@@ -267,6 +270,10 @@ func updateOptionMap(key string, value string) (err error) {
common
.
GitHubClientId
=
value
case
"GitHubClientSecret"
:
common
.
GitHubClientSecret
=
value
case
"LinuxDOClientId"
:
common
.
LinuxDOClientId
=
value
case
"LinuxDOClientSecret"
:
common
.
LinuxDOClientSecret
=
value
case
"Footer"
:
common
.
Footer
=
value
case
"SystemName"
:
...
...
model/user.go
View file @
12de1fac
...
...
@@ -36,6 +36,7 @@ type User struct {
AffHistoryQuota
int
`json:"aff_history_quota" gorm:"type:int;default:0;column:aff_history"`
// 邀请历史额度
InviterId
int
`json:"inviter_id" gorm:"type:int;column:inviter_id;index"`
DeletedAt
gorm
.
DeletedAt
`gorm:"index"`
LinuxDOId
string
`json:"linux_do_id" gorm:"column:linux_do_id;index"`
}
func
(
user
*
User
)
GetAccessToken
()
string
{
...
...
@@ -537,3 +538,17 @@ func GetUsernameById(id int) (username string, err error) {
err
=
DB
.
Model
(
&
User
{})
.
Where
(
"id = ?"
,
id
)
.
Select
(
"username"
)
.
Find
(
&
username
)
.
Error
return
username
,
err
}
func
IsLinuxDOIdAlreadyTaken
(
linuxDOId
string
)
bool
{
var
user
User
err
:=
DB
.
Unscoped
()
.
Where
(
"linux_do_id = ?"
,
linuxDOId
)
.
First
(
&
user
)
.
Error
return
!
errors
.
Is
(
err
,
gorm
.
ErrRecordNotFound
)
}
func
(
u
*
User
)
FillUserByLinuxDOId
()
error
{
if
u
.
LinuxDOId
==
""
{
return
errors
.
New
(
"linux do id is empty"
)
}
err
:=
DB
.
Where
(
"linux_do_id = ?"
,
u
.
LinuxDOId
)
.
First
(
u
)
.
Error
return
err
}
router/api-router.go
View file @
12de1fac
...
...
@@ -25,6 +25,7 @@ func SetApiRouter(router *gin.Engine) {
apiRouter
.
GET
(
"/reset_password"
,
middleware
.
CriticalRateLimit
(),
middleware
.
TurnstileCheck
(),
controller
.
SendPasswordResetEmail
)
apiRouter
.
POST
(
"/user/reset"
,
middleware
.
CriticalRateLimit
(),
controller
.
ResetPassword
)
apiRouter
.
GET
(
"/oauth/github"
,
middleware
.
CriticalRateLimit
(),
controller
.
GitHubOAuth
)
apiRouter
.
GET
(
"/oauth/linuxdo"
,
middleware
.
CriticalRateLimit
(),
controller
.
LinuxdoOAuth
)
apiRouter
.
GET
(
"/oauth/state"
,
middleware
.
CriticalRateLimit
(),
controller
.
GenerateOAuthCode
)
apiRouter
.
GET
(
"/oauth/wechat"
,
middleware
.
CriticalRateLimit
(),
controller
.
WeChatAuth
)
apiRouter
.
GET
(
"/oauth/wechat/bind"
,
middleware
.
CriticalRateLimit
(),
middleware
.
UserAuth
(),
controller
.
WeChatBind
)
...
...
web/src/components/LoginForm.js
View file @
12de1fac
import
React
,
{
useContext
,
useEffect
,
useState
}
from
'react'
;
import
{
Link
,
useNavigate
,
useSearchParams
}
from
'react-router-dom'
;
import
{
UserContext
}
from
'../context/User'
;
import
{
API
,
getLogo
,
showError
,
showInfo
,
showSuccess
,
updateAPI
}
from
'../helpers'
;
import
{
onGitHubOAuthClicked
}
from
'./utils'
;
import
{
API
,
getLogo
,
showError
,
showInfo
,
showSuccess
,
updateAPI
,
}
from
'../helpers'
;
import
{
onGitHubOAuthClicked
,
onLinuxDOOAuthClicked
}
from
'./utils'
;
import
Turnstile
from
'react-turnstile'
;
import
{
Button
,
...
...
@@ -17,7 +24,7 @@ import Title from '@douyinfe/semi-ui/lib/es/typography/title';
import
Text
from
'@douyinfe/semi-ui/lib/es/typography/text'
;
import
TelegramLoginButton
from
'react-telegram-login'
;
import
{
IconGithubLogo
}
from
'@douyinfe/semi-icons'
;
import
{
IconGithubLogo
,
IconAlarm
}
from
'@douyinfe/semi-icons'
;
import
WeChatIcon
from
'./WeChatIcon'
;
import
{
setUserData
}
from
'../helpers/data.js'
;
...
...
@@ -72,7 +79,7 @@ const LoginForm = () => {
userDispatch
({
type
:
'login'
,
payload
:
data
});
localStorage
.
setItem
(
'user'
,
JSON
.
stringify
(
data
));
setUserData
(
data
);
updateAPI
()
updateAPI
()
;
navigate
(
'/'
);
showSuccess
(
'登录成功!'
);
setShowWeChatLoginModal
(
false
);
...
...
@@ -103,7 +110,7 @@ const LoginForm = () => {
if
(
success
)
{
userDispatch
({
type
:
'login'
,
payload
:
data
});
setUserData
(
data
);
updateAPI
()
updateAPI
()
;
showSuccess
(
'登录成功!'
);
if
(
username
===
'root'
&&
password
===
'123456'
)
{
Modal
.
error
({
...
...
@@ -146,7 +153,7 @@ const LoginForm = () => {
localStorage
.
setItem
(
'user'
,
JSON
.
stringify
(
data
));
showSuccess
(
'登录成功!'
);
setUserData
(
data
);
updateAPI
()
updateAPI
()
;
navigate
(
'/'
);
}
else
{
showError
(
message
);
...
...
@@ -214,7 +221,8 @@ const LoginForm = () => {
<
/div
>
{
status
.
github_oauth
||
status
.
wechat_login
||
status
.
telegram_oauth
?
(
status
.
telegram_oauth
||
status
.
linuxdo_oauth
?
(
<>
<
Divider
margin
=
'12px'
align
=
'center'
>
第三方登录
...
...
@@ -237,6 +245,17 @@ const LoginForm = () => {
)
:
(
<><
/
>
)}
{
status
.
linuxdo_oauth
?
(
<
Button
type
=
'primary'
icon
=
{
<
IconAlarm
/>
}
onClick
=
{()
=>
onLinuxDOOAuthClicked
(
status
.
linuxdo_client_id
)
}
/
>
)
:
(
<><
/
>
)}
{
status
.
wechat_login
?
(
<
Button
type
=
'primary'
...
...
web/src/components/PersonalSetting.js
View file @
12de1fac
...
...
@@ -10,7 +10,7 @@ import {
}
from
'../helpers'
;
import
Turnstile
from
'react-turnstile'
;
import
{
UserContext
}
from
'../context/User'
;
import
{
onGitHubOAuthClicked
}
from
'./utils'
;
import
{
onGitHubOAuthClicked
,
onLinuxDOOAuthClicked
}
from
'./utils'
;
import
{
Avatar
,
Banner
,
...
...
@@ -519,7 +519,6 @@ const PersonalSetting = () => {
</div>
</div>
</div>
<div style={{ marginTop: 10 }}>
<Typography.Text strong>Telegram</Typography.Text>
<div
...
...
@@ -551,7 +550,36 @@ const PersonalSetting = () => {
</div>
</div>
</div>
<div style={{ marginTop: 10 }}>
<Typography.Text strong>LinuxDO</Typography.Text>
<div
style={{ display: 'flex', justifyContent: 'space-between' }}
>
<div>
<Input
value={
userState.user && userState.user.linux_do_id !== ''
? userState.user.linux_do_id
: '未绑定'
}
readonly={true}
></Input>
</div>
<div>
<Button
onClick={() => {
onLinuxDOOAuthClicked(status.linuxdo_client_id);
}}
disabled={
(userState.user && userState.user.linux_do_id !== '') ||
!status.linuxdo_oauth
}
>
{status.linuxdo_oauth ? '绑定' : '未启用'}
</Button>
</div>
</div>
</div>
<div style={{ marginTop: 10 }}>
<Space>
<Button onClick={generateAccessToken}>
...
...
web/src/components/SystemSetting.js
View file @
12de1fac
...
...
@@ -53,6 +53,9 @@ const SystemSetting = () => {
TelegramOAuthEnabled
:
''
,
TelegramBotToken
:
''
,
TelegramBotName
:
''
,
LinuxDOOAuthEnabled
:
''
,
LinuxDOClientId
:
''
,
LinuxDOClientSecret
:
''
,
});
const
[
originInputs
,
setOriginInputs
]
=
useState
({});
let
[
loading
,
setLoading
]
=
useState
(
false
);
...
...
@@ -103,6 +106,7 @@ const SystemSetting = () => {
case
'PasswordRegisterEnabled'
:
case
'EmailVerificationEnabled'
:
case
'GitHubOAuthEnabled'
:
case
'LinuxDOOAuthEnabled'
:
case
'WeChatAuthEnabled'
:
case
'TelegramOAuthEnabled'
:
case
'TurnstileCheckEnabled'
:
...
...
@@ -163,7 +167,9 @@ const SystemSetting = () => {
name
===
'EmailDomainWhitelist'
||
name
===
'TopupGroupRatio'
||
name
===
'TelegramBotToken'
||
name
===
'TelegramBotName'
name
===
'TelegramBotName'
||
name
===
'LinuxDOClientId'
||
name
===
'LinuxDOClientSecret'
)
{
setInputs
((
inputs
)
=>
({
...
inputs
,
[
name
]:
value
}));
}
else
{
...
...
@@ -182,7 +188,7 @@ const SystemSetting = () => {
if
(
inputs
.
WorkerValidKey
!==
''
)
{
await
updateOption
(
'WorkerValidKey'
,
inputs
.
WorkerValidKey
);
}
}
}
;
const
submitPayAddress
=
async
()
=>
{
if
(
inputs
.
ServerAddress
===
''
)
{
...
...
@@ -320,6 +326,18 @@ const SystemSetting = () => {
}
};
const
submitLinuxDOOAuth
=
async
()
=>
{
if
(
originInputs
[
'LinuxDOClientId'
]
!==
inputs
.
LinuxDOClientId
)
{
await
updateOption
(
'LinuxDOClientId'
,
inputs
.
LinuxDOClientId
);
}
if
(
originInputs
[
'LinuxDOClientSecret'
]
!==
inputs
.
LinuxDOClientSecret
&&
inputs
.
LinuxDOClientSecret
!==
''
)
{
await
updateOption
(
'LinuxDOClientSecret'
,
inputs
.
LinuxDOClientSecret
);
}
};
return
(
<
Grid
columns
=
{
1
}
>
<
Grid
.
Column
>
...
...
@@ -340,7 +358,15 @@ const SystemSetting = () => {
更新服务器地址
<
/Form.Button
>
<
Header
as
=
'h3'
inverted
=
{
isDark
}
>
代理设置(支持
<
a
href
=
'https://github.com/Calcium-Ion/new-api-worker'
target
=
'_blank'
rel
=
'noreferrer'
>
new
-
api
-
worker
<
/a>
)
代理设置(支持
{
' '
}
<
a
href
=
'https://github.com/Calcium-Ion/new-api-worker'
target
=
'_blank'
rel
=
'noreferrer'
>
new
-
api
-
worker
<
/a
>
)
<
/Header
>
<
Form
.
Group
widths
=
'equal'
>
<
Form
.
Input
...
...
@@ -358,9 +384,7 @@ const SystemSetting = () => {
onChange
=
{
handleInputChange
}
/
>
<
/Form.Group
>
<
Form
.
Button
onClick
=
{
submitWorker
}
>
更新
Worker
设置
<
/Form.Button
>
<
Form
.
Button
onClick
=
{
submitWorker
}
>
更新
Worker
设置
<
/Form.Button
>
<
Divider
/>
<
Header
as
=
'h3'
inverted
=
{
isDark
}
>
支付设置(当前仅支持易支付接口,默认使用上方服务器地址作为回调地址!)
...
...
@@ -484,6 +508,12 @@ const SystemSetting = () => {
onChange
=
{
handleInputChange
}
/
>
<
Form
.
Checkbox
checked
=
{
inputs
.
LinuxDOOAuthEnabled
===
'true'
}
label
=
'允许通过 LinuxDO 账户登录 & 注册'
name
=
'LinuxDOOAuthEnabled'
onChange
=
{
handleInputChange
}
/
>
<
Form
.
Checkbox
checked
=
{
inputs
.
WeChatAuthEnabled
===
'true'
}
label
=
'允许通过微信登录 & 注册'
name
=
'WeChatAuthEnabled'
...
...
@@ -781,6 +811,48 @@ const SystemSetting = () => {
<
Form
.
Button
onClick
=
{
submitTurnstile
}
>
保存
Turnstile
设置
<
/Form.Button
>
<
Divider
/>
<
Header
as
=
'h3'
inverted
=
{
isDark
}
>
配置
LinuxDO
OAuth
App
<
Header
.
Subheader
>
用以支持通过
LinuxDO
进行登录注册,
<
a
href
=
'https://connect.linux.do/'
target
=
'_blank'
rel
=
'noreferrer'
>
点击此处
<
/a
>
管理你的
LinuxDO
OAuth
App
<
/Header.Subheader
>
<
/Header
>
<
Message
>
Homepage
URL
填
<
code
>
{
inputs
.
ServerAddress
}
<
/code
>
,
Authorization
callback
URL
填
{
' '
}
<
code
>
{
`
${
inputs
.
ServerAddress
}
/oauth/linuxdo`
}
<
/code
>
<
/Message
>
<
Form
.
Group
widths
=
{
3
}
>
<
Form
.
Input
label
=
'LinuxDO Client ID'
name
=
'LinuxDOClientId'
onChange
=
{
handleInputChange
}
autoComplete
=
'new-password'
value
=
{
inputs
.
LinuxDOClientId
}
placeholder
=
'输入你注册的 LinuxDO OAuth APP 的 ID'
/>
<
Form
.
Input
label
=
'LinuxDO Client Secret'
name
=
'LinuxDOClientSecret'
onChange
=
{
handleInputChange
}
type
=
'password'
autoComplete
=
'new-password'
value
=
{
inputs
.
LinuxDOClientSecret
}
placeholder
=
'敏感信息不会发送到前端显示'
/>
<
/Form.Group
>
<
Form
.
Button
onClick
=
{
submitLinuxDOOAuth
}
>
保存
LinuxDO
OAuth
设置
<
/Form.Button
>
<
/Form
>
<
/Grid.Column
>
<
/Grid
>
...
...
web/src/components/utils.js
View file @
12de1fac
...
...
@@ -19,6 +19,14 @@ export async function onGitHubOAuthClicked(github_client_id) {
);
}
export
async
function
onLinuxDOOAuthClicked
(
linuxdo_client_id
)
{
const
state
=
await
getOAuthState
();
if
(
!
state
)
return
;
window
.
open
(
`https://connect.linux.do/oauth2/authorize?response_type=code&client_id=
${
linuxdo_client_id
}
&state=
${
state
}
`
,
);
}
let
channelModels
=
undefined
;
export
async
function
loadChannelModels
()
{
const
res
=
await
API
.
get
(
'/api/models'
);
...
...
web/src/pages/Home/index.js
View file @
12de1fac
...
...
@@ -150,6 +150,12 @@ const Home = () => {
?
'已启用'
:
'未启用'
}
<
/p
>
<
p
>
Linux
DO
身份验证:
{
statusState
?.
status
?.
linuxdo_oauth
===
true
?
'已启用'
:
'未启用'
}
<
/p
>
<
/Card
>
<
/Col
>
<
/Row
>
...
...
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