diff --git a/controller/github.go b/controller/github.go index e1c64130..ee995379 100644 --- a/controller/github.go +++ b/controller/github.go @@ -79,6 +79,14 @@ func getGitHubUserInfoByCode(code string) (*GitHubUser, error) { func GitHubOAuth(c *gin.Context) { session := sessions.Default(c) + 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 { GitHubBind(c) @@ -205,3 +213,22 @@ func GitHubBind(c *gin.Context) { }) return } + +func GenerateOAuthCode(c *gin.Context) { + session := sessions.Default(c) + state := common.GetRandomString(12) + session.Set("oauth_state", state) + err := session.Save() + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "", + "data": state, + }) +} diff --git a/router/api-router.go b/router/api-router.go index dad417b1..7e64a3bf 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -22,6 +22,7 @@ func SetApiRouter(router *gin.Engine) { apiRouter.POST("/user/reset", middleware.CriticalRateLimit(), controller.ResetPassword) apiRouter.GET("/oauth/github", middleware.CriticalRateLimit(), controller.GitHubOAuth) apiRouter.GET("/oauth/discord", middleware.CriticalRateLimit(), controller.DiscordOAuth) + apiRouter.GET("/oauth/state", middleware.CriticalRateLimit(), controller.GenerateOAuthCode) apiRouter.GET("/oauth/wechat", middleware.CriticalRateLimit(), controller.WeChatAuth) apiRouter.GET("/oauth/google", middleware.CriticalRateLimit(), controller.GoogleOAuth) apiRouter.GET("/oauth/wechat/bind", middleware.CriticalRateLimit(), middleware.UserAuth(), controller.WeChatBind) diff --git a/web/src/components/GitHubOAuth.js b/web/src/components/GitHubOAuth.js index 147d4d30..c43ed2a1 100644 --- a/web/src/components/GitHubOAuth.js +++ b/web/src/components/GitHubOAuth.js @@ -13,8 +13,8 @@ const GitHubOAuth = () => { let navigate = useNavigate(); - const sendCode = async (code, count) => { - const res = await API.get(`/api/oauth/github?code=${code}`); + const sendCode = async (code, state, count) => { + const res = await API.get(`/api/oauth/github?code=${code}&state=${state}`); const { success, message, data } = res.data; if (success) { if (message === 'bind') { @@ -36,13 +36,14 @@ const GitHubOAuth = () => { count++; setPrompt(`出现错误,第 ${count} 次重试中...`); await new Promise((resolve) => setTimeout(resolve, count * 2000)); - await sendCode(code, count); + await sendCode(code, state, count); } }; useEffect(() => { let code = searchParams.get('code'); - sendCode(code, 0).then(); + let state = searchParams.get('state'); + sendCode(code, state, 0).then(); }, []); return ( diff --git a/web/src/components/LoginForm.js b/web/src/components/LoginForm.js index 46664323..50dd5fec 100644 --- a/web/src/components/LoginForm.js +++ b/web/src/components/LoginForm.js @@ -4,6 +4,7 @@ import { Link, useNavigate, useSearchParams } from 'react-router-dom'; import { UserContext } from '../context/User'; import { API, getLogo, showError, showInfo, showSuccess } from '../helpers'; import Turnstile from 'react-turnstile'; +import { getOAuthState, onGitHubOAuthClicked } from './utils';stream/main const LoginForm = () => { const [inputs, setInputs] = useState({ @@ -175,7 +176,7 @@ const LoginForm = () => { circular color='black' icon='github' - onClick={onGitHubOAuthClicked} + onClick={()=>onGitHubOAuthClicked(status.github_client_id)} /> )} {status.wechat_login && ( diff --git a/web/src/components/PersonalSetting.js b/web/src/components/PersonalSetting.js index deb5a38b..1f637e83 100644 --- a/web/src/components/PersonalSetting.js +++ b/web/src/components/PersonalSetting.js @@ -4,6 +4,7 @@ import { Link, useNavigate } from 'react-router-dom'; import { API, copy, showError, showInfo, showNotice, showSuccess } from '../helpers'; import Turnstile from 'react-turnstile'; import { UserContext } from '../context/User'; +import { onGitHubOAuthClicked } from './utils'; const PersonalSetting = () => { const [userState, userDispatch] = useContext(UserContext); @@ -265,7 +266,7 @@ const PersonalSetting = () => { { status.github_oauth && ( - + ) } { diff --git a/web/src/components/utils.js b/web/src/components/utils.js new file mode 100644 index 00000000..5363ba5e --- /dev/null +++ b/web/src/components/utils.js @@ -0,0 +1,20 @@ +import { API, showError } from '../helpers'; + +export async function getOAuthState() { + const res = await API.get('/api/oauth/state'); + const { success, message, data } = res.data; + if (success) { + return data; + } else { + showError(message); + return ''; + } +} + +export async function onGitHubOAuthClicked(github_client_id) { + const state = await getOAuthState(); + if (!state) return; + window.open( + `https://github.com/login/oauth/authorize?client_id=${github_client_id}&state=${state}&scope=user:email` + ); +} \ No newline at end of file