Compare commits

..

8 Commits

Author SHA1 Message Date
Yang Luo
2077db9091 fix: fix bug in VerificationListPage 2024-04-07 15:39:25 +08:00
无别
800f0ed249 feat: add tzdata package in Dockerfile to fix timezone issue (#2857)
Add tzdata to resolve possible time zone errors
2024-04-07 14:27:45 +08:00
xyt
6161040c67 fix: Dismiss google one tap after logged in by setting disableCancelOnUnmount to false (#2854)
* fix: Google One Tap should be hidden after logged in

* Change the call location for google.accounts.id.cancel()

* fix: hide google one tap after login by set disableCancelOnUnmount to false
2024-04-05 23:39:33 +08:00
xyt
1d785e61c6 feat: Google One Tap should be hidden after logged in (#2853)
* fix: Google One Tap should be hidden after logged in

* Change the call location for google.accounts.id.cancel()
2024-04-05 20:10:13 +08:00
Yang Luo
0329d24867 feat: add isUsernameLowered to config 2024-04-02 21:54:16 +08:00
Yang Luo
fb6f3623ee feat: add requireProviderPermission() 2024-03-30 23:24:59 +08:00
DacongDA
eb448bd043 fix: fix permission problem in provider (#2848) 2024-03-30 23:18:03 +08:00
xyt
ea88839db9 feat: add back button in forget password page (#2847)
* feat: add back button in forget password page

* fix: can't step back when directly entering forgot password page

* feat: forget password page always return to login page

* feat: if has history then go back to history & change style

* Update ForgetPage.js

* fix: reset button position

* Update ForgetPage.js

* Update ForgetPage.js

---------

Co-authored-by: Eric Luo <hsluoyz@qq.com>
2024-03-30 23:17:47 +08:00
8 changed files with 95 additions and 34 deletions

View File

@@ -16,6 +16,7 @@ ARG USER=casdoor
RUN sed -i 's/https/http/' /etc/apk/repositories RUN sed -i 's/https/http/' /etc/apk/repositories
RUN apk add --update sudo RUN apk add --update sudo
RUN apk add tzdata
RUN apk add curl RUN apk add curl
RUN apk add ca-certificates && update-ca-certificates RUN apk add ca-certificates && update-ca-certificates

View File

@@ -15,6 +15,7 @@ socks5Proxy = "127.0.0.1:10808"
verificationCodeTimeout = 10 verificationCodeTimeout = 10
initScore = 0 initScore = 0
logPostOnly = true logPostOnly = true
isUsernameLowered = false
origin = origin =
originFrontend = originFrontend =
staticBaseUrl = "https://cdn.casbin.org" staticBaseUrl = "https://cdn.casbin.org"

View File

@@ -141,6 +141,20 @@ func (c *ApiController) GetProvider() {
c.ResponseOk(object.GetMaskedProvider(provider, isMaskEnabled)) c.ResponseOk(object.GetMaskedProvider(provider, isMaskEnabled))
} }
func (c *ApiController) requireProviderPermission(provider *object.Provider) bool {
isGlobalAdmin, user := c.isGlobalAdmin()
if isGlobalAdmin {
return true
}
if provider.Owner == "admin" || user.Owner != provider.Owner {
c.ResponseError(c.T("auth:Unauthorized operation"))
return false
}
return true
}
// UpdateProvider // UpdateProvider
// @Title UpdateProvider // @Title UpdateProvider
// @Tag Provider API // @Tag Provider API
@@ -159,6 +173,11 @@ func (c *ApiController) UpdateProvider() {
return return
} }
ok := c.requireProviderPermission(&provider)
if !ok {
return
}
c.Data["json"] = wrapActionResponse(object.UpdateProvider(id, &provider)) c.Data["json"] = wrapActionResponse(object.UpdateProvider(id, &provider))
c.ServeJSON() c.ServeJSON()
} }
@@ -184,11 +203,17 @@ func (c *ApiController) AddProvider() {
return return
} }
if err := checkQuotaForProvider(int(count)); err != nil { err = checkQuotaForProvider(int(count))
if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
ok := c.requireProviderPermission(&provider)
if !ok {
return
}
c.Data["json"] = wrapActionResponse(object.AddProvider(&provider)) c.Data["json"] = wrapActionResponse(object.AddProvider(&provider))
c.ServeJSON() c.ServeJSON()
} }
@@ -208,6 +233,11 @@ func (c *ApiController) DeleteProvider() {
return return
} }
ok := c.requireProviderPermission(&provider)
if !ok {
return
}
c.Data["json"] = wrapActionResponse(object.DeleteProvider(&provider)) c.Data["json"] = wrapActionResponse(object.DeleteProvider(&provider))
c.ServeJSON() c.ServeJSON()
} }

View File

@@ -833,6 +833,11 @@ func AddUser(user *User) (bool, error) {
} }
} }
isUsernameLowered := conf.GetConfigBool("isUsernameLowered")
if isUsernameLowered {
user.Name = strings.ToLower(user.Name)
}
affected, err := ormer.Engine.Insert(user) affected, err := ormer.Engine.Insert(user)
if err != nil { if err != nil {
return false, err return false, err
@@ -846,6 +851,8 @@ func AddUsers(users []*User) (bool, error) {
return false, fmt.Errorf("no users are provided") return false, fmt.Errorf("no users are provided")
} }
isUsernameLowered := conf.GetConfigBool("isUsernameLowered")
// organization := GetOrganizationByUser(users[0]) // organization := GetOrganizationByUser(users[0])
for _, user := range users { for _, user := range users {
// this function is only used for syncer or batch upload, so no need to encrypt the password // this function is only used for syncer or batch upload, so no need to encrypt the password
@@ -869,6 +876,10 @@ func AddUsers(users []*User) (bool, error) {
return false, err return false, err
} }
} }
if isUsernameLowered {
user.Name = strings.ToLower(user.Name)
}
} }
affected, err := ormer.Engine.Insert(users) affected, err := ormer.Engine.Insert(users)

View File

@@ -374,6 +374,7 @@ class App extends Component {
}); });
}} }}
onLoginSuccess={(redirectUrl) => { onLoginSuccess={(redirectUrl) => {
window.google?.accounts?.id?.cancel();
if (redirectUrl) { if (redirectUrl) {
localStorage.setItem("mfaRedirectUrl", redirectUrl); localStorage.setItem("mfaRedirectUrl", redirectUrl);
} }

View File

@@ -35,26 +35,48 @@ class VerificationListPage extends BaseListPage {
renderTable(verifications) { renderTable(verifications) {
const columns = [ const columns = [
{ {
title: i18next.t("general:Name"), title: i18next.t("general:Organization"),
dataIndex: "name", dataIndex: "owner",
key: "name", key: "owner",
width: "150px", width: "120px",
fixed: "left",
sorter: true, sorter: true,
...this.getColumnSearchProps("name"), ...this.getColumnSearchProps("owner"),
render: (text, record, index) => { render: (text, record, index) => {
if (text === "admin") {
return `(${i18next.t("general:empty")})`;
}
return ( return (
<Link to={`/syncers/${text}`}> <Link to={`/organizations/${text}`}>
{text} {text}
</Link> </Link>
); );
}, },
}, },
{
title: i18next.t("general:Name"),
dataIndex: "name",
key: "name",
width: "260px",
fixed: "left",
sorter: true,
...this.getColumnSearchProps("name"),
},
{
title: i18next.t("general:Created time"),
dataIndex: "createdTime",
key: "createdTime",
width: "160px",
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
},
},
{ {
title: i18next.t("provider:Type"), title: i18next.t("provider:Type"),
dataIndex: "type", dataIndex: "type",
key: "type", key: "type",
width: "120px", width: "90px",
sorter: true, sorter: true,
...this.getColumnSearchProps("type"), ...this.getColumnSearchProps("type"),
}, },
@@ -67,7 +89,7 @@ class VerificationListPage extends BaseListPage {
...this.getColumnSearchProps("user"), ...this.getColumnSearchProps("user"),
render: (text, record, index) => { render: (text, record, index) => {
return ( return (
<Link to={`/users/${record.owner}/${text}`}> <Link to={`/users/${text}`}>
{text} {text}
</Link> </Link>
); );
@@ -100,30 +122,10 @@ class VerificationListPage extends BaseListPage {
title: i18next.t("login:Verification code"), title: i18next.t("login:Verification code"),
dataIndex: "code", dataIndex: "code",
key: "code", key: "code",
width: "120px", width: "150px",
sorter: true, sorter: true,
...this.getColumnSearchProps("code"), ...this.getColumnSearchProps("code"),
}, },
{
title: i18next.t("general:Timestamp"),
dataIndex: "time",
key: "time",
width: "160px",
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text * 1000);
},
},
{
title: i18next.t("general:Created time"),
dataIndex: "createdTime",
key: "createdTime",
width: "160px",
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
},
},
]; ];
const paginationProps = { const paginationProps = {
@@ -156,7 +158,7 @@ class VerificationListPage extends BaseListPage {
value = params.type; value = params.type;
} }
this.setState({loading: true}); this.setState({loading: true});
VerificationBackend.getVerifications("admin", Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) VerificationBackend.getVerifications("", Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
.then((res) => { .then((res) => {
this.setState({ this.setState({
loading: false, loading: false,

View File

@@ -21,7 +21,7 @@ import * as Setting from "../Setting";
import i18next from "i18next"; import i18next from "i18next";
import {SendCodeInput} from "../common/SendCodeInput"; import {SendCodeInput} from "../common/SendCodeInput";
import * as UserBackend from "../backend/UserBackend"; import * as UserBackend from "../backend/UserBackend";
import {CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons"; import {ArrowLeftOutlined, CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons";
import CustomGithubCorner from "../common/CustomGithubCorner"; import CustomGithubCorner from "../common/CustomGithubCorner";
import {withRouter} from "react-router-dom"; import {withRouter} from "react-router-dom";
import * as PasswordChecker from "../common/PasswordChecker"; import * as PasswordChecker from "../common/PasswordChecker";
@@ -443,6 +443,18 @@ class ForgetPage extends React.Component {
); );
} }
stepBack() {
if (this.state.current > 0) {
this.setState({
current: this.state.current - 1,
});
} else if (this.props.history.length > 1) {
this.props.history.goBack();
} else {
Setting.redirectToLoginPage(this.getApplicationObj(), this.props.history);
}
}
render() { render() {
const application = this.getApplicationObj(); const application = this.getApplicationObj();
if (application === undefined) { if (application === undefined) {
@@ -456,6 +468,9 @@ class ForgetPage extends React.Component {
<React.Fragment> <React.Fragment>
<CustomGithubCorner /> <CustomGithubCorner />
<div className="forget-content" style={{padding: Setting.isMobile() ? "0" : null, boxShadow: Setting.isMobile() ? "none" : null}}> <div className="forget-content" style={{padding: Setting.isMobile() ? "0" : null, boxShadow: Setting.isMobile() ? "none" : null}}>
<Button type="text" style={{position: "relative", left: Setting.isMobile() ? "10px" : "-90px", top: 0}} size={"large"} onClick={() => {this.stepBack();}}>
<ArrowLeftOutlined style={{fontSize: "24px"}} />
</Button>
<Row> <Row>
<Col span={24} style={{justifyContent: "center"}}> <Col span={24} style={{justifyContent: "center"}}>
<Row> <Row>

View File

@@ -52,7 +52,7 @@ export function GoogleOneTapLoginVirtualButton(prop) {
redirectUri = `${redirectUri}?state=${state}&code=${encodeURIComponent(code)}`; redirectUri = `${redirectUri}?state=${state}&code=${encodeURIComponent(code)}`;
Setting.goToLink(redirectUri); Setting.goToLink(redirectUri);
}, },
disableCancelOnUnmount: true, disableCancelOnUnmount: false,
}); });
} }