Compare commits

..

4 Commits

Author SHA1 Message Date
DacongDA
2cc5e82d91 feat: support login button loading state (#3694) 2025-04-01 00:57:24 +08:00
DacongDA
e55cd94298 feat: fix issue that user email is still unverified after signup (#3685) 2025-03-29 21:24:01 +08:00
WindSpiritSR
08f7a05e61 feat: fix MFA + LDAP bug in /check-user-password API (#3681) 2025-03-26 22:11:58 +08:00
Yang Luo
4bee21f4a3 feat: use StaticBaseUrl in frontend 2025-03-26 21:32:31 +08:00
11 changed files with 38 additions and 14 deletions

View File

@@ -139,6 +139,8 @@ func (c *ApiController) Signup() {
invitationName = invitation.Name
}
userEmailVerified := false
if application.IsSignupItemVisible("Email") && application.GetSignupItemRule("Email") != "No verification" && authForm.Email != "" {
var checkResult *object.VerifyResult
checkResult, err = object.CheckVerificationCode(authForm.Email, authForm.EmailCode, c.GetAcceptLanguage())
@@ -150,6 +152,8 @@ func (c *ApiController) Signup() {
c.ResponseError(checkResult.Msg)
return
}
userEmailVerified = true
}
var checkPhone string
@@ -228,6 +232,7 @@ func (c *ApiController) Signup() {
Karma: 0,
Invitation: invitationName,
InvitationCode: authForm.InvitationCode,
EmailVerified: userEmailVerified,
}
if len(organization.Tags) > 0 {

View File

@@ -483,6 +483,14 @@ func (c *ApiController) Login() {
verificationType = "sms"
} else {
verificationType = "email"
if !user.EmailVerified {
user.EmailVerified = true
_, err = object.UpdateUser(user.GetId(), user, []string{"email_verified"}, false)
if err != nil {
c.ResponseError(err.Error(), nil)
return
}
}
}
} else {
var application *object.Application

View File

@@ -457,10 +457,10 @@ func (c *ApiController) SetPassword() {
newPassword := c.Ctx.Request.Form.Get("newPassword")
code := c.Ctx.Request.Form.Get("code")
//if userOwner == "built-in" && userName == "admin" {
// if userOwner == "built-in" && userName == "admin" {
// c.ResponseError(c.T("auth:Unauthorized operation"))
// return
//}
// }
if strings.Contains(newPassword, " ") {
c.ResponseError(c.T("user:New password cannot contain blank space."))
@@ -602,7 +602,11 @@ func (c *ApiController) CheckUserPassword() {
return
}
_, err = object.CheckUserPassword(user.Owner, user.Name, user.Password, c.GetAcceptLanguage())
/*
* Verified password with user as subject, if field ldap not empty,
* then `isPasswordWithLdapEnabled` is true
*/
_, err = object.CheckUserPassword(user.Owner, user.Name, user.Password, c.GetAcceptLanguage(), false, false, user.Ldap != "")
if err != nil {
c.ResponseError(err.Error())
} else {

View File

@@ -436,7 +436,8 @@ func (c *ApiController) ResetEmailOrPhone() {
switch destType {
case object.VerifyTypeEmail:
user.Email = dest
_, err = object.SetUserField(user, "email", user.Email)
user.EmailVerified = true
_, err = object.UpdateUser(user.GetId(), user, []string{"email", "email_verified"}, false)
case object.VerifyTypePhone:
user.Phone = dest
_, err = object.SetUserField(user, "phone", user.Phone)

View File

@@ -60,7 +60,8 @@ func (mfa *SmsMfa) Enable(user *User) error {
columns = append(columns, "mfa_phone_enabled", "phone", "country_code")
} else if mfa.MfaType == EmailType {
user.MfaEmailEnabled = true
columns = append(columns, "mfa_email_enabled", "email")
user.EmailVerified = true
columns = append(columns, "mfa_email_enabled", "email", "email_verified")
}
_, err := UpdateUser(user.GetId(), user, columns, false)

View File

@@ -86,11 +86,11 @@ const sideTemplate = `<style>
}
</style>
<div class="left-model">
<span class="side-logo"> <img src="https://cdn.casbin.org/img/casdoor-logo_1185x256.png" alt="Casdoor" style="width: 120px">
<span class="side-logo"> <img src="${Setting.StaticBaseUrl}/img/casdoor-logo_1185x256.png" alt="Casdoor" style="width: 120px">
<span>SSO</span>
</span>
<div class="img">
<img src="https://cdn.casbin.org/img/casbin.svg" alt="Casdoor"/>
<img src="${Setting.StaticBaseUrl}/img/casbin.svg" alt="Casdoor"/>
</div>
</div>
`;

View File

@@ -1532,7 +1532,7 @@ export function getUserCommonFields() {
}
export function getDefaultFooterContent() {
return "Powered by <a target=\"_blank\" href=\"https://casdoor.org\" rel=\"noreferrer\"><img style=\"padding-bottom: 3px\" height=\"20\" alt=\"Casdoor\" src=\"https://cdn.casbin.org/img/casdoor-logo_1185x256.png\"/></a>";
return `Powered by <a target="_blank" href="https://casdoor.org" rel="noreferrer"><img style="padding-bottom: 3px" height="20" alt="Casdoor" src="${StaticBaseUrl}/img/casdoor-logo_1185x256.png"/></a>`;
}
export function getEmptyFooterContent() {
@@ -1564,7 +1564,7 @@ export function getDefaultHtmlEmailContent() {
<div class="email-container">
<div class="header">
<h3>Casbin Organization</h3>
<img src="https://cdn.casbin.org/img/casdoor-logo_1185x256.png" alt="Casdoor Logo" width="300">
<img src="${StaticBaseUrl}/img/casdoor-logo_1185x256.png" alt="Casdoor Logo" width="300">
</div>
<p><strong>%{user.friendlyName}</strong>, here is your verification code</p>
<p>Use this code for your transaction. It's valid for 5 minutes</p>

View File

@@ -1,4 +1,5 @@
import React from "react";
import * as Setting from "./Setting";
export const TourObj = {
home: [
@@ -8,7 +9,7 @@ export const TourObj = {
cover: (
<img
alt="casdoor.png"
src="https://cdn.casbin.org/img/casdoor-logo_1185x256.png"
src={`${Setting.StaticBaseUrl}/img/casdoor-logo_1185x256.png`}
/>
),
},

View File

@@ -63,6 +63,7 @@ class LoginPage extends React.Component {
termsOfUseContent: "",
orgChoiceMode: new URLSearchParams(props.location?.search).get("orgChoiceMode") ?? null,
userLang: null,
loginLoading: false,
};
if (this.state.type === "cas" && props.match?.params.casApplicationName !== undefined) {
@@ -423,6 +424,7 @@ class LoginPage extends React.Component {
}
login(values) {
this.setState({loginLoading: true});
// here we are supposed to determine whether Casdoor is working as an OAuth server or CAS server
values["language"] = this.state.userLang ?? "";
if (this.state.type === "cas") {
@@ -452,6 +454,7 @@ class LoginPage extends React.Component {
} else {
Setting.showMessage("error", `${i18next.t("application:Failed to sign in")}: ${res.msg}`);
}
this.setState({loginLoading: false});
});
} else {
// OAuth
@@ -507,6 +510,7 @@ class LoginPage extends React.Component {
} else {
Setting.showMessage("error", `${i18next.t("application:Failed to sign in")}: ${res.msg}`);
}
this.setState({loginLoading: false});
});
}
}
@@ -694,6 +698,7 @@ class LoginPage extends React.Component {
<Form.Item key={resultItemKey} className="login-button-box">
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.customCss?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
<Button
loading={this.state.loginLoading}
type="primary"
htmlType="submit"
className="login-button"

View File

@@ -37,7 +37,6 @@ const FaceRecognitionModal = (props) => {
const loadModels = async() => {
// const MODEL_URL = process.env.PUBLIC_URL + "/models";
// const MODEL_URL = "https://justadudewhohacks.github.io/face-api.js/models";
// const MODEL_URL = "https://cdn.casbin.org/site/casdoor/models";
const MODEL_URL = "https://cdn.casdoor.com/casdoor/models";
Promise.all([

View File

@@ -137,10 +137,10 @@ class MfaAccountTable extends React.Component {
render: (text, record, index) => (
<Tooltip>
{text ? (
<Image width={36} height={36} preview={false} src={`https://cdn.casbin.org/img/social_${text.toLowerCase()}.png`}
fallback="https://cdn.casbin.org/img/social_default.png" alt={text} />
<Image width={36} height={36} preview={false} src={`${Setting.StaticBaseUrl}/img/social_${text.toLowerCase()}.png`}
fallback={`${Setting.StaticBaseUrl}/img/social_default.png`} alt={text} />
) : (
<Image width={36} height={36} preview={false} src={"https://cdn.casbin.org/img/social_default.png"} alt="default" />
<Image width={36} height={36} preview={false} src={`${Setting.StaticBaseUrl}/img/social_default.png`} alt="default" />
)}
</Tooltip>
),