diff --git a/middleware/cors.go b/middleware/cors.go index 6aaa15d..8f68be1 100644 --- a/middleware/cors.go +++ b/middleware/cors.go @@ -8,7 +8,10 @@ import ( func CORS() gin.HandlerFunc { config := cors.DefaultConfig() - config.AllowAllOrigins = true + config.AllowAllOrigins = false + config.AllowOriginFunc = func(origin string) bool { + return true + } config.AllowCredentials = true config.AllowMethods = []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"} config.AllowHeaders = []string{"*"} diff --git a/router/api-router.go b/router/api-router.go index 7b08f5c..f3606d9 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -59,6 +59,7 @@ func SetApiRouter(router *gin.Engine) { apiRouter.POST("/verify", middleware.UserAuth(), middleware.CriticalRateLimit(), controller.UniversalVerify) userRoute := apiRouter.Group("/user") + userRoute.Use(middleware.CORS()) { userRoute.POST("/register", middleware.CriticalRateLimit(), middleware.TurnstileCheck(), controller.Register) userRoute.POST("/login", middleware.CriticalRateLimit(), middleware.TurnstileCheck(), controller.Login) diff --git a/web/dist/static/login-widget.js b/web/dist/static/login-widget.js index b84cc1d..43069f6 100644 --- a/web/dist/static/login-widget.js +++ b/web/dist/static/login-widget.js @@ -37,4 +37,4 @@ Error generating stack: `+u.message+` * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */var Nd=vt,Pd=Symbol.for("react.element"),zd=Symbol.for("react.fragment"),Td=Object.prototype.hasOwnProperty,Ld=Nd.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,Rd={key:!0,ref:!0,__self:!0,__source:!0};function tc(e,t,n){var r,l={},u=null,o=null;n!==void 0&&(u=""+n),t.key!==void 0&&(u=""+t.key),t.ref!==void 0&&(o=t.ref);for(r in t)Td.call(t,r)&&!Rd.hasOwnProperty(r)&&(l[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps,t)l[r]===void 0&&(l[r]=t[r]);return{$$typeof:Pd,type:e,key:u,ref:o,props:l,_owner:Ld.current}}pl.Fragment=zd,pl.jsx=tc,pl.jsxs=tc,ec.exports=pl;var Xe=ec.exports;function Od({apiUrl:e,onSuccess:t,onError:n}){const[r,l]=vt.useState(""),[u,o]=vt.useState(""),[i,s]=vt.useState(!1),[c,v]=vt.useState(""),m=async p=>{var g;if(p.preventDefault(),v(""),!r.trim()||!u.trim()){const w="请输入用户名和密码";v(w),n==null||n({message:w});return}s(!0);try{const S=await(await fetch(`${e}/api/user/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:r.trim(),password:u}),credentials:"include"})).json();if(S.success){if((g=S.data)!=null&&g.require_2fa){const O="此账户启用了两步验证,暂不支持通过 Widget 登录";v(O),n==null||n({message:O});return}t==null||t(S.data)}else{const O=S.message||"登录失败";v(O),n==null||n({message:O})}}catch{const S="网络错误,请检查网络连接";v(S),n==null||n({message:S})}finally{s(!1)}};return Xe.jsxs("form",{className:"naw-form",onSubmit:m,children:[Xe.jsxs("div",{className:"naw-field",children:[Xe.jsx("label",{className:"naw-label",children:"用户名或邮箱"}),Xe.jsx("input",{className:"naw-input",type:"text",placeholder:"请输入用户名或邮箱地址",value:r,onChange:p=>l(p.target.value),autoComplete:"username",disabled:i})]}),Xe.jsxs("div",{className:"naw-field",children:[Xe.jsx("label",{className:"naw-label",children:"密码"}),Xe.jsx("input",{className:"naw-input",type:"password",placeholder:"请输入密码",value:u,onChange:p=>o(p.target.value),autoComplete:"current-password",disabled:i})]}),Xe.jsx("p",{className:"naw-error-msg",children:c}),Xe.jsx("button",{className:"naw-button",type:"submit",disabled:i,children:i?"登录中...":"登录"})]})}const Md='@import"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap";:host{--naw-primary: #4f46e5;--naw-primary-hover: #4338ca;--naw-bg: #ffffff;--naw-text: #1f2937;--naw-text-secondary: #6b7280;--naw-border: #d1d5db;--naw-input-bg: #f9fafb;--naw-error: #ef4444;--naw-radius: 8px;--naw-font: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;display:block;font-family:var(--naw-font)}:host([theme="dark"]){--naw-primary: #818cf8;--naw-primary-hover: #6366f1;--naw-bg: #1f2937;--naw-text: #f9fafb;--naw-text-secondary: #9ca3af;--naw-border: #374151;--naw-input-bg: #374151;--naw-error: #f87171}.naw-container{max-width:400px;margin:0 auto;padding:32px 24px;background:var(--naw-bg);border-radius:16px}.naw-title{text-align:center;font-size:24px;font-weight:600;color:var(--naw-text);margin:0 0 32px}.naw-form{display:flex;flex-direction:column;gap:16px}.naw-field{display:flex;flex-direction:column;gap:6px}.naw-label{font-size:14px;font-weight:500;color:var(--naw-text)}.naw-input{width:100%;box-sizing:border-box;padding:10px 14px;font-size:15px;border:1px solid var(--naw-border);border-radius:var(--naw-radius);background:var(--naw-input-bg);color:var(--naw-text);outline:none;transition:border-color .2s;font-family:var(--naw-font)}.naw-input:focus{border-color:var(--naw-primary)}.naw-input::placeholder{color:var(--naw-text-secondary)}.naw-button{width:100%;padding:12px;font-size:15px;font-weight:600;color:#fff;background:var(--naw-primary);border:none;border-radius:var(--naw-radius);cursor:pointer;transition:background .2s;font-family:var(--naw-font)}.naw-button:hover{background:var(--naw-primary-hover)}.naw-button:disabled{opacity:.6;cursor:not-allowed}.naw-error-msg{color:var(--naw-error);font-size:13px;text-align:center;margin:0;min-height:20px}';function Dd(e,t){const n=document.createElement("div");n.setAttribute("data-new-api-widget","login"),e.appendChild(n);const r=n.attachShadow({mode:"open"}),l=document.createElement("style");l.textContent=Md,r.appendChild(l),t.theme==="dark"&&n.setAttribute("theme","dark");const u=document.createElement("div");r.appendChild(u);const o=qa(u);return o.render(El.createElement("div",{className:"naw-container"},El.createElement("h1",{className:"naw-title"},"登 录"),El.createElement(Od,{apiUrl:t.apiUrl,onSuccess:t.onSuccess,onError:t.onError}))),{host:n,root:o}}function nc(e){const t=typeof e.container=="string"?document.querySelector(e.container):e.container;if(!t)throw new Error("NewApiLoginWidget: container not found");if(!e.apiUrl)throw new Error("NewApiLoginWidget: apiUrl is required");const{host:n,root:r}=Dd(t,{apiUrl:e.apiUrl.replace(/\/+$/,""),onSuccess:e.onSuccess,onError:e.onError,theme:e.theme||"light"});return{destroy(){r.unmount(),n.remove()}}}return window.NewApiLoginWidget={init:nc},hl.init=nc,Object.defineProperty(hl,Symbol.toStringTag,{value:"Module"}),hl}({}); + */var Nd=vt,Pd=Symbol.for("react.element"),zd=Symbol.for("react.fragment"),Td=Object.prototype.hasOwnProperty,Ld=Nd.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,Rd={key:!0,ref:!0,__self:!0,__source:!0};function tc(e,t,n){var r,l={},u=null,o=null;n!==void 0&&(u=""+n),t.key!==void 0&&(u=""+t.key),t.ref!==void 0&&(o=t.ref);for(r in t)Td.call(t,r)&&!Rd.hasOwnProperty(r)&&(l[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps,t)l[r]===void 0&&(l[r]=t[r]);return{$$typeof:Pd,type:e,key:u,ref:o,props:l,_owner:Ld.current}}pl.Fragment=zd,pl.jsx=tc,pl.jsxs=tc,ec.exports=pl;var Xe=ec.exports;function Od({apiUrl:e,onSuccess:t,onError:n}){const[r,l]=vt.useState(""),[u,o]=vt.useState(""),[i,s]=vt.useState(!1),[c,v]=vt.useState(""),m=async p=>{var g;if(p.preventDefault(),v(""),!r.trim()||!u.trim()){const w="请输入用户名和密码";v(w),n==null||n({message:w});return}s(!0);try{const S=await(await fetch(`${e}/api/user/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:r.trim(),password:u})})).json();if(S.success){if((g=S.data)!=null&&g.require_2fa){const O="此账户启用了两步验证,暂不支持通过 Widget 登录";v(O),n==null||n({message:O});return}t==null||t(S.data)}else{const O=S.message||"登录失败";v(O),n==null||n({message:O})}}catch{const S="网络错误,请检查网络连接";v(S),n==null||n({message:S})}finally{s(!1)}};return Xe.jsxs("form",{className:"naw-form",onSubmit:m,children:[Xe.jsxs("div",{className:"naw-field",children:[Xe.jsx("label",{className:"naw-label",children:"用户名或邮箱"}),Xe.jsx("input",{className:"naw-input",type:"text",placeholder:"请输入用户名或邮箱地址",value:r,onChange:p=>l(p.target.value),autoComplete:"username",disabled:i})]}),Xe.jsxs("div",{className:"naw-field",children:[Xe.jsx("label",{className:"naw-label",children:"密码"}),Xe.jsx("input",{className:"naw-input",type:"password",placeholder:"请输入密码",value:u,onChange:p=>o(p.target.value),autoComplete:"current-password",disabled:i})]}),Xe.jsx("p",{className:"naw-error-msg",children:c}),Xe.jsx("button",{className:"naw-button",type:"submit",disabled:i,children:i?"登录中...":"登录"})]})}const Md='@import"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap";:host{--naw-primary: #4f46e5;--naw-primary-hover: #4338ca;--naw-bg: #ffffff;--naw-text: #1f2937;--naw-text-secondary: #6b7280;--naw-border: #d1d5db;--naw-input-bg: #f9fafb;--naw-error: #ef4444;--naw-radius: 8px;--naw-font: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;display:block;font-family:var(--naw-font)}:host([theme="dark"]){--naw-primary: #818cf8;--naw-primary-hover: #6366f1;--naw-bg: #1f2937;--naw-text: #f9fafb;--naw-text-secondary: #9ca3af;--naw-border: #374151;--naw-input-bg: #374151;--naw-error: #f87171}.naw-container{max-width:400px;margin:0 auto;padding:32px 24px;background:var(--naw-bg);border-radius:16px}.naw-title{text-align:center;font-size:24px;font-weight:600;color:var(--naw-text);margin:0 0 32px}.naw-form{display:flex;flex-direction:column;gap:16px}.naw-field{display:flex;flex-direction:column;gap:6px}.naw-label{font-size:14px;font-weight:500;color:var(--naw-text)}.naw-input{width:100%;box-sizing:border-box;padding:10px 14px;font-size:15px;border:1px solid var(--naw-border);border-radius:var(--naw-radius);background:var(--naw-input-bg);color:var(--naw-text);outline:none;transition:border-color .2s;font-family:var(--naw-font)}.naw-input:focus{border-color:var(--naw-primary)}.naw-input::placeholder{color:var(--naw-text-secondary)}.naw-button{width:100%;padding:12px;font-size:15px;font-weight:600;color:#fff;background:var(--naw-primary);border:none;border-radius:var(--naw-radius);cursor:pointer;transition:background .2s;font-family:var(--naw-font)}.naw-button:hover{background:var(--naw-primary-hover)}.naw-button:disabled{opacity:.6;cursor:not-allowed}.naw-error-msg{color:var(--naw-error);font-size:13px;text-align:center;margin:0;min-height:20px}';function Dd(e,t){const n=document.createElement("div");n.setAttribute("data-new-api-widget","login"),e.appendChild(n);const r=n.attachShadow({mode:"open"}),l=document.createElement("style");l.textContent=Md,r.appendChild(l),t.theme==="dark"&&n.setAttribute("theme","dark");const u=document.createElement("div");r.appendChild(u);const o=qa(u);return o.render(El.createElement("div",{className:"naw-container"},El.createElement("h1",{className:"naw-title"},"登 录"),El.createElement(Od,{apiUrl:t.apiUrl,onSuccess:t.onSuccess,onError:t.onError}))),{host:n,root:o}}function nc(e){const t=typeof e.container=="string"?document.querySelector(e.container):e.container;if(!t)throw new Error("NewApiLoginWidget: container not found");if(!e.apiUrl)throw new Error("NewApiLoginWidget: apiUrl is required");const{host:n,root:r}=Dd(t,{apiUrl:e.apiUrl.replace(/\/+$/,""),onSuccess:e.onSuccess,onError:e.onError,theme:e.theme||"light"});return{destroy(){r.unmount(),n.remove()}}}return window.NewApiLoginWidget={init:nc},hl.init=nc,Object.defineProperty(hl,Symbol.toStringTag,{value:"Module"}),hl}({}); diff --git a/web/widget/LoginForm.jsx b/web/widget/LoginForm.jsx index f91522d..335bd8c 100644 --- a/web/widget/LoginForm.jsx +++ b/web/widget/LoginForm.jsx @@ -23,7 +23,6 @@ export default function LoginForm({ apiUrl, onSuccess, onError }) { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: username.trim(), password }), - credentials: 'include', }); const data = await res.json();