Compare commits

...

9 Commits

Author SHA1 Message Date
6b8c24e1f0 feat: fix password not encrypted issue in SetPassword() API (#2990)
* fix: fix password not encrypted in set password and password type not changed

* Update user.go

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-06-04 13:32:13 +08:00
8a79bb64dd feat: test SMTP connection with browser parameters (#2986) 2024-06-04 01:34:36 +08:00
e5f9aab28f feat: support resetting password on first login (#2980)
* feat: support reset password in first login

* feat: disable needUpdatePassword when user haven't email and phone and mfa
2024-06-02 01:00:55 +08:00
7d05b69aac feat: remove useless code 2024-05-28 20:33:55 +08:00
868e66e866 feat: fix QQ login error when using mobile browser (#2971) 2024-05-27 01:07:15 +08:00
40ad3c9234 feat: support MFA fields in syncer (#2966)
* feat:add fields of sync-database

* feat:add fields of sync-database
2024-05-27 01:06:59 +08:00
e2cd0604c2 feat: add back arm64 support in Docker image (#2969) 2024-05-26 01:22:49 +08:00
78c3065fbb feat: fix address field bug in user edit page 2024-05-24 17:19:27 +08:00
af2a9f0374 feat: get phone number and country from Google OAuth provider (#2965)
* feat: get phone number and country from Google OAuth provider

* feat: fix i18n
2024-05-23 00:42:36 +08:00
49 changed files with 331 additions and 70 deletions

View File

@ -194,7 +194,7 @@ jobs:
with:
context: .
target: STANDARD
platforms: linux/amd64
platforms: linux/amd64,linux/arm64
push: true
tags: casbin/casdoor:${{steps.get-current-tag.outputs.tag }},casbin/casdoor:latest
@ -204,7 +204,7 @@ jobs:
with:
context: .
target: ALLINONE
platforms: linux/amd64
platforms: linux/amd64,linux/arm64
push: true
tags: casbin/casdoor-all-in-one:${{steps.get-current-tag.outputs.tag }},casbin/casdoor-all-in-one:latest

View File

@ -1,10 +1,10 @@
FROM node:18.19.0 AS FRONT
FROM --platform=$BUILDPLATFORM node:18.19.0 AS FRONT
WORKDIR /web
COPY ./web .
RUN yarn install --frozen-lockfile --network-timeout 1000000 && yarn run build
FROM golang:1.20.12 AS BACK
FROM --platform=$BUILDPLATFORM golang:1.20.12 AS BACK
WORKDIR /go/src/casdoor
COPY . .
RUN ./build.sh
@ -13,6 +13,9 @@ RUN go test -v -run TestGetVersionInfo ./util/system_test.go ./util/system.go >
FROM alpine:latest AS STANDARD
LABEL MAINTAINER="https://casdoor.org/"
ARG USER=casdoor
ARG TARGETOS
ARG TARGETARCH
ENV BUILDX_ARCH="${TARGETOS:-linux}_${TARGETARCH:-amd64}"
RUN sed -i 's/https/http/' /etc/apk/repositories
RUN apk add --update sudo
@ -28,7 +31,7 @@ RUN adduser -D $USER -u 1000 \
USER 1000
WORKDIR /
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/server ./server
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/server_${BUILDX_ARCH} ./server
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/swagger ./swagger
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/conf/app.conf ./conf/app.conf
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/version_info.txt ./go/src/casdoor/version_info.txt
@ -47,12 +50,15 @@ RUN apt update \
FROM db AS ALLINONE
LABEL MAINTAINER="https://casdoor.org/"
ARG TARGETOS
ARG TARGETARCH
ENV BUILDX_ARCH="${TARGETOS:-linux}_${TARGETARCH:-amd64}"
RUN apt update
RUN apt install -y ca-certificates && update-ca-certificates
WORKDIR /
COPY --from=BACK /go/src/casdoor/server ./server
COPY --from=BACK /go/src/casdoor/server_${BUILDX_ARCH} ./server
COPY --from=BACK /go/src/casdoor/swagger ./swagger
COPY --from=BACK /go/src/casdoor/docker-entrypoint.sh /docker-entrypoint.sh
COPY --from=BACK /go/src/casdoor/conf/app.conf ./conf/app.conf

View File

@ -8,4 +8,6 @@ else
echo "Google is blocked, Go proxy is enabled: GOPROXY=https://goproxy.cn,direct"
export GOPROXY="https://goproxy.cn,direct"
fi
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server .
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server_linux_amd64 .
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="-w -s" -o server_linux_arm64 .

View File

@ -117,7 +117,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
if form.Type == ResponseTypeLogin {
c.SetSessionUsername(userId)
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
resp = &Response{Status: "ok", Msg: "", Data: userId}
resp = &Response{Status: "ok", Msg: "", Data: userId, Data2: user.NeedUpdatePassword}
} else if form.Type == ResponseTypeCode {
clientId := c.Input().Get("clientId")
responseType := c.Input().Get("responseType")
@ -139,7 +139,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
}
resp = codeToResponse(code)
resp.Data2 = user.NeedUpdatePassword
if application.EnableSigninSession || application.HasPromptPage() {
// The prompt page needs the user to be signed in
c.SetSessionUsername(userId)
@ -152,6 +152,8 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
nonce := c.Input().Get("nonce")
token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host)
resp = tokenToResponse(token)
resp.Data2 = user.NeedUpdatePassword
}
} else if form.Type == ResponseTypeSaml { // saml flow
res, redirectUrl, method, err := object.GetSamlResponse(application, user, form.SamlRequest, c.Ctx.Request.Host)
@ -159,7 +161,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
c.ResponseError(err.Error(), nil)
return
}
resp = &Response{Status: "ok", Msg: "", Data: res, Data2: map[string]string{"redirectUrl": redirectUrl, "method": method}}
resp = &Response{Status: "ok", Msg: "", Data: res, Data2: map[string]interface{}{"redirectUrl": redirectUrl, "method": method, "needUpdatePassword": user.NeedUpdatePassword}}
if application.EnableSigninSession || application.HasPromptPage() {
// The prompt page needs the user to be signed in

View File

@ -27,11 +27,12 @@ import (
)
type EmailForm struct {
Title string `json:"title"`
Content string `json:"content"`
Sender string `json:"sender"`
Receivers []string `json:"receivers"`
Provider string `json:"provider"`
Title string `json:"title"`
Content string `json:"content"`
Sender string `json:"sender"`
Receivers []string `json:"receivers"`
Provider string `json:"provider"`
ProviderObject object.Provider `json:"providerObject"`
}
type SmsForm struct {
@ -74,7 +75,6 @@ func (c *ApiController) SendEmail() {
c.ResponseError(err.Error())
return
}
} else {
// called by Casdoor SDK via Client ID & Client Secret, so the used Email provider will be the application' Email provider or the default Email provider
provider, err = c.GetProviderFromContext("Email")
@ -84,6 +84,13 @@ func (c *ApiController) SendEmail() {
}
}
if emailForm.ProviderObject.Name != "" {
if emailForm.ProviderObject.ClientSecret == "***" {
emailForm.ProviderObject.ClientSecret = provider.ClientSecret
}
provider = &emailForm.ProviderObject
}
// when receiver is the reserved keyword: "TestSmtpServer", it means to test the SMTP server instead of sending a real Email
if len(emailForm.Receivers) == 1 && emailForm.Receivers[0] == "TestSmtpServer" {
err = object.DailSmtpServer(provider)

View File

@ -509,8 +509,21 @@ func (c *ApiController) SetPassword() {
return
}
organization, err := object.GetOrganizationByUser(targetUser)
if err != nil {
c.ResponseError(err.Error())
return
}
if organization == nil {
c.ResponseError(fmt.Sprintf(c.T("the organization: %s is not found"), targetUser.Owner))
return
}
targetUser.Password = newPassword
_, err = object.SetUserField(targetUser, "password", targetUser.Password)
targetUser.UpdateUserPassword(organization)
targetUser.NeedUpdatePassword = false
_, err = object.UpdateUser(userId, targetUser, []string{"password", "need_update_password", "password_type"}, false)
if err != nil {
c.ResponseError(err.Error())
return

2
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/beego/beego v1.12.12
github.com/beevik/etree v1.1.0
github.com/casbin/casbin/v2 v2.77.2
github.com/casdoor/go-sms-sender v0.23.0
github.com/casdoor/go-sms-sender v0.24.0
github.com/casdoor/gomail/v2 v2.0.1
github.com/casdoor/notify v0.45.0
github.com/casdoor/oss v1.6.0

4
go.sum
View File

@ -1085,8 +1085,8 @@ github.com/casbin/casbin/v2 v2.77.2 h1:yQinn/w9x8AswiwqwtrXz93VU48R1aYTXdHEx4RI3
github.com/casbin/casbin/v2 v2.77.2/go.mod h1:mzGx0hYW9/ksOSpw3wNjk3NRAroq5VMFYUQ6G43iGPk=
github.com/casdoor/go-reddit/v2 v2.1.0 h1:kIbfdJ7AA7H0uTQ8s0q4GGZqSS5V9wVE74RrXyD9XPs=
github.com/casdoor/go-reddit/v2 v2.1.0/go.mod h1:eagkvwlZ4Hcsuc/uQsLHYEulz5jN65SVSwV/AIE7zsc=
github.com/casdoor/go-sms-sender v0.23.0 h1:N8+By4JNwyilEcx7cp0QGOepafefM88VwV+o3UEFZio=
github.com/casdoor/go-sms-sender v0.23.0/go.mod h1:bOm4H8/YfJmEHjBatEVQFOnAf0OOn1B0Wi5B7zDhws0=
github.com/casdoor/go-sms-sender v0.24.0 h1:LNLsce3EG/87I3JS6UiajF3LlQmdIiCgebEu0IE4wSM=
github.com/casdoor/go-sms-sender v0.24.0/go.mod h1:bOm4H8/YfJmEHjBatEVQFOnAf0OOn1B0Wi5B7zDhws0=
github.com/casdoor/gomail/v2 v2.0.1 h1:J+FG6x80s9e5lBHUn8Sv0Y56mud34KiWih5YdmudR/w=
github.com/casdoor/gomail/v2 v2.0.1/go.mod h1:VnGPslEAtpix5FjHisR/WKB1qvZDBaujbikxDe9d+2Q=
github.com/casdoor/notify v0.45.0 h1:OlaFvcQFjGOgA4mRx07M8AH1gvb5xNo21mcqrVGlLgk=

View File

@ -25,6 +25,7 @@ import (
"time"
"github.com/casdoor/casdoor/util"
"github.com/nyaruka/phonenumbers"
"golang.org/x/oauth2"
)
@ -130,6 +131,23 @@ type GoogleUserInfo struct {
Locale string `json:"locale"`
}
type GooglePeopleApiPhoneNumberMetaData struct {
Primary bool `json:"primary"`
}
type GooglePeopleApiPhoneNumber struct {
CanonicalForm string `json:"canonicalForm"`
MetaData GooglePeopleApiPhoneNumberMetaData `json:"metadata"`
Value string `json:"value"`
Type string `json:"type"`
}
type GooglePeopleApiResult struct {
PhoneNumbers []GooglePeopleApiPhoneNumber `json:"phoneNumbers"`
Etag string `json:"etag"`
ResourceName string `json:"resourceName"`
}
func (idp *GoogleIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
if strings.HasPrefix(token.AccessToken, GoogleIdTokenKey) {
googleIdToken, ok := token.Extra(GoogleIdTokenKey).(GoogleIdToken)
@ -167,12 +185,49 @@ func (idp *GoogleIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
return nil, errors.New("google email is empty")
}
url = fmt.Sprintf("https://people.googleapis.com/v1/people/me?personFields=phoneNumbers&access_token=%s", token.AccessToken)
resp, err = idp.Client.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err = io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var googlePeopleResult GooglePeopleApiResult
err = json.Unmarshal(body, &googlePeopleResult)
if err != nil {
return nil, err
}
var phoneNumber string
var countryCode string
if len(googlePeopleResult.PhoneNumbers) != 0 {
for _, phoneData := range googlePeopleResult.PhoneNumbers {
if phoneData.MetaData.Primary {
phoneNumber = phoneData.CanonicalForm
break
}
}
phoneNumberParsed, err := phonenumbers.Parse(phoneNumber, "")
if err != nil {
return nil, err
}
countryCode = phonenumbers.GetRegionCodeForNumber(phoneNumberParsed)
phoneNumber = fmt.Sprintf("%d", phoneNumberParsed.GetNationalNumber())
}
userInfo := UserInfo{
Id: googleUserInfo.Id,
Username: googleUserInfo.Email,
DisplayName: googleUserInfo.Name,
Email: googleUserInfo.Email,
AvatarUrl: googleUserInfo.Picture,
Phone: phoneNumber,
CountryCode: countryCode,
}
return &userInfo, nil
}

View File

@ -50,7 +50,7 @@ type Provider struct {
Host string `xorm:"varchar(100)" json:"host"`
Port int `json:"port"`
DisableSsl bool `json:"disableSsl"` // If the provider type is WeChat, DisableSsl means EnableQRCode
DisableSsl bool `json:"disableSsl"` // If the provider type is WeChat, DisableSsl means EnableQRCode, if type is Google, it means sync phone number
Title string `xorm:"varchar(100)" json:"title"`
Content string `xorm:"varchar(2000)" json:"content"` // If provider type is WeChat, Content means QRCode string by Base64 encoding
Receiver string `xorm:"varchar(100)" json:"receiver"`

View File

@ -48,7 +48,7 @@ func SendSms(provider *Provider, content string, phoneNumbers ...string) error {
if provider.AppId != "" {
phoneNumbers = append([]string{provider.AppId}, phoneNumbers...)
}
} else if provider.Type == sender.Aliyun || provider.Type == sender.SendCloud {
} else if provider.Type == sender.Aliyun {
for i, number := range phoneNumbers {
phoneNumbers[i] = strings.TrimPrefix(number, "+86")
}

View File

@ -169,6 +169,12 @@ func (syncer *Syncer) setUserByKeyValue(user *User, key string, value string) {
user.TotpSecret = value
case "SignupApplication":
user.SignupApplication = value
case "MfaPhoneEnabled":
user.MfaPhoneEnabled = util.ParseBool(value)
case "MfaEmailEnabled":
user.MfaEmailEnabled = util.ParseBool(value)
case "RecoveryCodes":
user.RecoveryCodes = strings.Split(value, ",")
}
}
@ -303,6 +309,9 @@ func (syncer *Syncer) getMapFromOriginalUser(user *OriginalUser) map[string]stri
m["PreferredMfaType"] = user.PreferredMfaType
m["TotpSecret"] = user.TotpSecret
m["SignupApplication"] = user.SignupApplication
m["MfaPhoneEnabled"] = util.BoolToString(user.MfaPhoneEnabled)
m["MfaEmailEnabled"] = util.BoolToString(user.MfaEmailEnabled)
m["RecoveryCodes"] = strings.Join(user.RecoveryCodes, ",")
m2 := map[string]string{}
for _, tableColumn := range syncer.TableColumns {

View File

@ -203,7 +203,8 @@ type User struct {
LastSigninWrongTime string `xorm:"varchar(100)" json:"lastSigninWrongTime"`
SigninWrongTimes int `json:"signinWrongTimes"`
ManagedAccounts []ManagedAccount `xorm:"managedAccounts blob" json:"managedAccounts"`
ManagedAccounts []ManagedAccount `xorm:"managedAccounts blob" json:"managedAccounts"`
NeedUpdatePassword bool `json:"needUpdatePassword"`
}
type Userinfo struct {
@ -682,7 +683,7 @@ func UpdateUser(id string, user *User, columns []string, isAdmin bool) (bool, er
"eveonline", "fitbit", "gitea", "heroku", "influxcloud", "instagram", "intercom", "kakao", "lastfm", "mailru", "meetup",
"microsoftonline", "naver", "nextcloud", "onedrive", "oura", "patreon", "paypal", "salesforce", "shopify", "soundcloud",
"spotify", "strava", "stripe", "type", "tiktok", "tumblr", "twitch", "twitter", "typetalk", "uber", "vk", "wepay", "xero", "yahoo",
"yammer", "yandex", "zoom", "custom",
"yammer", "yandex", "zoom", "custom", "need_update_password",
}
}
if isAdmin {

View File

@ -411,6 +411,10 @@ func CheckPermissionForUpdateUser(oldUser, newUser *User, isAdmin bool, lang str
item := GetAccountItemByName("Is deleted", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.NeedUpdatePassword != newUser.NeedUpdatePassword {
item := GetAccountItemByName("Need update password", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Score != newUser.Score {
item := GetAccountItemByName("Score", organization)

View File

@ -414,6 +414,7 @@ class App extends Component {
<Layout id="parent-area">
<ManagementPage
account={this.state.account}
application={this.state.application}
uri={this.state.uri}
themeData={this.state.themeData}
themeAlgorithm={this.state.themeAlgorithm}

View File

@ -108,8 +108,8 @@ class EntryPage extends React.Component {
<Route exact path="/signup/oauth/authorize" render={(props) => <SignupPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />} />
<Route exact path="/login/oauth/authorize" render={(props) => <LoginPage {...this.props} application={this.state.application} type={"code"} mode={"signin"} onUpdateApplication={onUpdateApplication} {...props} />} />
<Route exact path="/login/saml/authorize/:owner/:applicationName" render={(props) => <LoginPage {...this.props} application={this.state.application} type={"saml"} mode={"signin"} onUpdateApplication={onUpdateApplication} {...props} />} />
<Route exact path="/forget" render={(props) => this.renderHomeIfLoggedIn(<SelfForgetPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/forget/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ForgetPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/forget" render={(props) => <SelfForgetPage {...this.props} account={this.props.account} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />} />
<Route exact path="/forget/:applicationName" render={(props) => <ForgetPage {...this.props} account={this.props.account} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />} />
<Route exact path="/prompt" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/prompt/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/result" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />

View File

@ -328,6 +328,8 @@ function ManagementPage(props) {
return <Redirect to="/login" />;
} else if (props.account === undefined) {
return null;
} else if (props.account.needUpdatePassword) {
return <Redirect to={"/forget/" + props.application.name} />;
} else {
return component;
}

View File

@ -209,8 +209,6 @@ class ProviderEditPage extends React.Component {
return Setting.getLabel(i18next.t("provider:Public key"), i18next.t("provider:Public key - Tooltip"));
} else if (provider.type === "Msg91 SMS" || provider.type === "Infobip SMS" || provider.type === "OSON SMS") {
return Setting.getLabel(i18next.t("provider:Sender Id"), i18next.t("provider:Sender Id - Tooltip"));
} else if (provider.type === "SendCloud SMS") {
return "SMS_USER";
} else {
return Setting.getLabel(i18next.t("provider:Client ID"), i18next.t("provider:Client ID - Tooltip"));
}
@ -262,8 +260,6 @@ class ProviderEditPage extends React.Component {
return Setting.getLabel(i18next.t("provider:Auth Key"), i18next.t("provider:Auth Key - Tooltip"));
} else if (provider.type === "Infobip SMS") {
return Setting.getLabel(i18next.t("provider:Api Key"), i18next.t("provider:Api Key - Tooltip"));
} else if (provider.type === "SendCloud SMS") {
return "SMS_KEY";
} else {
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip"));
}
@ -832,6 +828,20 @@ class ProviderEditPage extends React.Component {
</React.Fragment>
)
}
{
this.state.provider.type !== "Google" ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Get phone number"), i18next.t("provider:Get phone number - Tooltip"))} :
</Col>
<Col span={1} >
<Switch disabled={!this.state.provider.clientId} checked={this.state.provider.disableSsl} onChange={checked => {
this.updateProviderField("disableSsl", checked);
}} />
</Col>
</Row>
)
}
{
this.state.provider.type !== "ADFS" && this.state.provider.type !== "AzureAD" && this.state.provider.type !== "AzureADB2C" && this.state.provider.type !== "Casdoor" && this.state.provider.type !== "Okta" ? null : (
<Row style={{marginTop: "20px"}} >
@ -1093,7 +1103,7 @@ class ProviderEditPage extends React.Component {
</React.Fragment>
) : this.state.provider.category === "SMS" ? (
<React.Fragment>
{["Custom HTTP SMS", "Twilio SMS", "Amazon SNS", "Azure ACS", "Msg91 SMS", "Infobip SMS", "SendCloud SMS"].includes(this.state.provider.type) ?
{["Custom HTTP SMS", "Twilio SMS", "Amazon SNS", "Azure ACS", "Msg91 SMS", "Infobip SMS"].includes(this.state.provider.type) ?
null :
(<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>

View File

@ -139,10 +139,6 @@ export const OtherProviderInfo = {
logo: `${StaticBaseUrl}/img/social_twilio.svg`,
url: "https://www.twilio.com/messaging",
},
"SendCloud SMS": {
logo: `${StaticBaseUrl}/img/sms_sendcloud.png`,
url: "https://www.sendcloud.net/",
},
"SmsBao SMS": {
logo: `${StaticBaseUrl}/img/social_smsbao.png`,
url: "https://www.smsbao.com/",
@ -1043,7 +1039,6 @@ export function getProviderTypeOptions(category) {
{id: "Huawei Cloud SMS", name: "Huawei Cloud SMS"},
{id: "UCloud SMS", name: "UCloud SMS"},
{id: "Twilio SMS", name: "Twilio SMS"},
{id: "SendCloud SMS", name: "SendCloud SMS"},
{id: "SmsBao SMS", name: "SmsBao SMS"},
{id: "SUBMAIL SMS", name: "SUBMAIL SMS"},
{id: "Msg91 SMS", name: "Msg91 SMS"},
@ -1468,7 +1463,7 @@ export function getUserCommonFields() {
return ["Owner", "Name", "CreatedTime", "UpdatedTime", "DeletedTime", "Id", "Type", "Password", "PasswordSalt", "DisplayName", "FirstName", "LastName", "Avatar", "PermanentAvatar",
"Email", "EmailVerified", "Phone", "Location", "Address", "Affiliation", "Title", "IdCardType", "IdCard", "Homepage", "Bio", "Tag", "Region",
"Language", "Gender", "Birthday", "Education", "Score", "Ranking", "IsDefaultAvatar", "IsOnline", "IsAdmin", "IsForbidden", "IsDeleted", "CreatedIp",
"PreferredMfaType", "TotpSecret", "SignupApplication"];
"PreferredMfaType", "TotpSecret", "SignupApplication", "RecoveryCodes", "MfaPhoneEnabled", "MfaEmailEnabled"];
}
export function getDefaultFooterContent() {

View File

@ -211,6 +211,9 @@ class UserEditPage extends React.Component {
const user = this.state.user;
if (key === "address") {
if (!user[key]) {
user[key] = ["", ""];
}
user[key][idx] = value;
} else {
user[key] = value;
@ -515,7 +518,7 @@ class UserEditPage extends React.Component {
<span>{i18next.t("user:Address line") + " 1"}</span> :
</Col>
<Col span={20} >
<Input value={this.state.user.address[0]} onChange={e => {
<Input value={!this.state.user.address ? "" : this.state.user.address[0]} onChange={e => {
this.updateUserField("address", e.target.value, 0);
}} />
</Col>
@ -527,7 +530,7 @@ class UserEditPage extends React.Component {
<span>{i18next.t("user:Address line") + " 2"}</span> :
</Col>
<Col span={20} >
<Input value={this.state.user.address[1]} onChange={e => {
<Input value={!this.state.user.address ? "" : this.state.user.address[1]} onChange={e => {
this.updateUserField("address", e.target.value, 1);
}} />
</Col>
@ -1023,6 +1026,19 @@ class UserEditPage extends React.Component {
</Col>
</Row>
);
} else if (accountItem.name === "Need update password") {
return (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("user:Need update password"), i18next.t("user:Need update password - Tooltip"))} :
</Col>
<Col span={(Setting.isMobile()) ? 22 : 2} >
<Switch disabled={(!this.state.user.phone) && (!this.state.user.email) && (!this.state.user.mfaProps)} checked={this.state.user.needUpdatePassword} onChange={checked => {
this.updateUserField("needUpdatePassword", checked);
}} />
</Col>
</Row>
);
}
}

View File

@ -153,21 +153,37 @@ class AuthCallback extends React.Component {
// OAuth
const oAuthParams = Util.getOAuthGetParameters(innerParams);
const concatChar = oAuthParams?.redirectUri?.includes("?") ? "&" : "?";
const signinUrl = localStorage.getItem("signinUrl");
AuthBackend.login(body, oAuthParams)
.then((res) => {
if (res.status === "ok") {
const responseType = this.getResponseType();
if (responseType === "login") {
if (res.data2) {
sessionStorage.setItem("signinUrl", signinUrl);
Setting.goToLinkSoft(this, `/forget/${applicationName}`);
return;
}
Setting.showMessage("success", "Logged in successfully");
// Setting.goToLinkSoft(this, "/");
const link = Setting.getFromLink();
Setting.goToLink(link);
} else if (responseType === "code") {
if (res.data2) {
sessionStorage.setItem("signinUrl", signinUrl);
Setting.goToLinkSoft(this, `/forget/${applicationName}`);
return;
}
const code = res.data;
Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}code=${code}&state=${oAuthParams.state}`);
// Setting.showMessage("success", `Authorization code: ${res.data}`);
} else if (responseType === "token" || responseType === "id_token") {
if (res.data2) {
sessionStorage.setItem("signinUrl", signinUrl);
Setting.goToLinkSoft(this, `/forget/${applicationName}`);
return;
}
const token = res.data;
Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}${responseType}=${token}&state=${oAuthParams.state}&token_type=bearer`);
} else if (responseType === "link") {
@ -181,6 +197,11 @@ class AuthCallback extends React.Component {
relayState: oAuthParams.relayState,
});
} else {
if (res.data2.needUpdatePassword) {
sessionStorage.setItem("signinUrl", signinUrl);
Setting.goToLinkSoft(this, `/forget/${applicationName}`);
return;
}
const SAMLResponse = res.data;
const redirectUri = res.data2.redirectUrl;
Setting.goToLink(`${redirectUri}?SAMLResponse=${encodeURIComponent(SAMLResponse)}&RelayState=${oAuthParams.relayState}`);

View File

@ -35,8 +35,8 @@ class ForgetPage extends React.Component {
classes: props,
applicationName: props.applicationName ?? props.match.params?.applicationName,
msg: null,
name: "",
username: "",
name: props.account ? props.account.name : "",
username: props.account ? props.account.name : "",
phone: "",
email: "",
dest: "",
@ -44,7 +44,6 @@ class ForgetPage extends React.Component {
verifyType: "", // "email", "phone"
current: 0,
};
this.form = React.createRef();
}
@ -205,6 +204,7 @@ class ForgetPage extends React.Component {
initialValues={{
application: application.name,
organization: application.organization,
username: this.state.name,
}}
style={{width: "300px"}}
size="large"
@ -488,7 +488,7 @@ class ForgetPage extends React.Component {
<Row>
<Col span={24}>
<div style={{textAlign: "center", fontSize: "28px"}}>
{i18next.t("forget:Retrieve password")}
{i18next.t("forget:Reset password")}
</div>
</Col>
</Row>

View File

@ -68,6 +68,8 @@ class LoginPage extends React.Component {
this.state.applicationName = props.match?.params?.casApplicationName;
}
localStorage.setItem("signinUrl", window.location.href);
this.form = React.createRef();
}
@ -300,6 +302,12 @@ class LoginPage extends React.Component {
return;
}
if (resp.data2) {
sessionStorage.setItem("signinUrl", window.location.href);
Setting.goToLinkSoft(ths, `/forget/${application.name}`);
return;
}
if (Setting.hasPromptPage(application)) {
AuthBackend.getAccount()
.then((res) => {
@ -442,15 +450,27 @@ class LoginPage extends React.Component {
const responseType = values["type"];
if (responseType === "login") {
if (res.data2) {
sessionStorage.setItem("signinUrl", window.location.href);
Setting.goToLink(this, `/forget/${this.state.applicationName}`);
}
Setting.showMessage("success", i18next.t("application:Logged in successfully"));
this.props.onLoginSuccess();
} else if (responseType === "code") {
this.postCodeLoginAction(res);
} else if (responseType === "token" || responseType === "id_token") {
if (res.data2) {
sessionStorage.setItem("signinUrl", window.location.href);
Setting.goToLink(this, `/forget/${this.state.applicationName}`);
}
const amendatoryResponseType = responseType === "token" ? "access_token" : responseType;
const accessToken = res.data;
Setting.goToLink(`${oAuthParams.redirectUri}#${amendatoryResponseType}=${accessToken}&state=${oAuthParams.state}&token_type=bearer`);
} else if (responseType === "saml") {
if (res.data2.needUpdatePassword) {
sessionStorage.setItem("signinUrl", window.location.href);
Setting.goToLink(this, `/forget/${this.state.applicationName}`);
}
if (res.data2.method === "POST") {
this.setState({
samlResponse: res.data,

View File

@ -384,8 +384,7 @@ export function getAuthUrl(application, provider, method, code) {
let endpoint = authInfo[provider.type].endpoint;
let redirectUri = `${window.location.origin}/callback`;
const scope = authInfo[provider.type].scope;
let scope = authInfo[provider.type].scope;
const isShortState = (provider.type === "WeChat" && navigator.userAgent.includes("MicroMessenger")) || (provider.type === "Twitter");
const state = Util.getStateFromQueryParams(application.name, provider.name, method, isShortState);
const codeChallenge = "P3S-a7dr8bgM4bF6vOyiKkKETDl16rcAzao9F8UIL1Y"; // SHA256(Base64-URL-encode("casdoor-verifier"))
@ -396,9 +395,11 @@ export function getAuthUrl(application, provider, method, code) {
}
} else if (provider.type === "Apple") {
redirectUri = `${window.location.origin}/api/callback`;
} else if (provider.type === "Google" && provider.disableSsl) {
scope += "+https://www.googleapis.com/auth/user.phonenumbers.read";
}
if (provider.type === "Google" || provider.type === "GitHub" || provider.type === "QQ" || provider.type === "Facebook"
if (provider.type === "Google" || provider.type === "GitHub" || provider.type === "Facebook"
|| provider.type === "Weibo" || provider.type === "Gitee" || provider.type === "LinkedIn" || provider.type === "GitLab" || provider.type === "AzureAD"
|| provider.type === "Slack" || provider.type === "Line" || provider.type === "Amazon" || provider.type === "Auth0" || provider.type === "BattleNet"
|| provider.type === "Bitbucket" || provider.type === "Box" || provider.type === "CloudFoundry" || provider.type === "Dailymotion"
@ -410,6 +411,8 @@ export function getAuthUrl(application, provider, method, code) {
|| provider.type === "Twitch" || provider.type === "Typetalk" || provider.type === "Uber" || provider.type === "VK" || provider.type === "Wepay"
|| provider.type === "Xero" || provider.type === "Yahoo" || provider.type === "Yammer" || provider.type === "Yandex" || provider.type === "Zoom") {
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&scope=${scope}&response_type=code&state=${state}`;
} else if (provider.type === "QQ") {
return `${endpoint}?response_type=code&client_id=${provider.clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&state=${encodeURIComponent(state)}&scope=${encodeURIComponent(scope)}`;
} else if (provider.type === "AzureADB2C") {
return `https://${provider.domain}.b2clogin.com/${provider.domain}.onmicrosoft.com/${provider.appId}/oauth2/v2.0/authorize?client_id=${provider.clientId}&nonce=defaultNonce&redirect_uri=${encodeURIComponent(redirectUri)}&scope=${scope}&response_type=code&state=${state}&prompt=login`;
} else if (provider.type === "DingTalk") {

View File

@ -50,6 +50,7 @@ function testEmailProvider(provider, email = "") {
sender: provider.displayName,
receivers: email === "" ? ["TestSmtpServer"] : [email],
provider: provider.name,
providerObject: provider,
};
return fetch(`${Setting.ServerUrl}/api/send-email`, {

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step",
"Please input your username!": "Please input your username!",
"Reset": "Reset",
"Retrieve password": "Retrieve password",
"Reset password": "Reset password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"",
"From name": "From name",
"From name - Tooltip": "Name of \"From\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name of host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Nächster Schritt",
"Please input your username!": "Bitte gib deinen Benutzernamen ein!",
"Reset": "Zurücksetzen",
"Retrieve password": "Passwort abrufen",
"Reset password": "Passwort abrufen",
"Unknown forget type": "Unbekannter Vergesslichkeitstyp",
"Verify": "überprüfen"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip",
"From name": "From name",
"From name - Tooltip": "From name - Tooltip",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name des Hosts",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Verwaltete Konten",
"Modify password...": "Passwort ändern...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "Neue E-Mail",
"New Password": "Neues Passwort",
"New User": "Neuer Benutzer",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step",
"Please input your username!": "Please input your username!",
"Reset": "Reset",
"Retrieve password": "Retrieve password",
"Reset password": "Reset password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"",
"From name": "From name",
"From name - Tooltip": "Name of \"From\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name of host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Siguiente paso",
"Please input your username!": "¡Por favor, ingrese su nombre de usuario!",
"Reset": "Restablecer",
"Retrieve password": "Recuperar contraseña",
"Reset password": "Reset password",
"Unknown forget type": "Tipo de olvido desconocido",
"Verify": "Verificar"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip",
"From name": "From name",
"From name - Tooltip": "From name - Tooltip",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Anfitrión",
"Host - Tooltip": "Nombre del anfitrión",
"IdP": "IdP = Proveedor de Identidad",
@ -1128,6 +1130,8 @@
"Managed accounts": "Cuentas gestionadas",
"Modify password...": "Modificar contraseña...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "Nuevo correo electrónico",
"New Password": "Nueva contraseña",
"New User": "Nuevo Usuario",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step",
"Please input your username!": "Please input your username!",
"Reset": "Reset",
"Retrieve password": "Retrieve password",
"Reset password": "Reset password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"",
"From name": "From name",
"From name - Tooltip": "Name of \"From\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name of host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step",
"Please input your username!": "Please input your username!",
"Reset": "Reset",
"Retrieve password": "Retrieve password",
"Reset password": "Reset password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"",
"From name": "From name",
"From name - Tooltip": "Name of \"From\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name of host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Étape suivante",
"Please input your username!": "Veuillez saisir votre identifiant !",
"Reset": "Réinitialiser",
"Retrieve password": "Récupérer le mot de passe",
"Reset password": "Récupérer le mot de passe",
"Unknown forget type": "Type d'oubli inconnu",
"Verify": "Vérifier"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "L'adresse e-mail affichée comme expéditeur dans les e-mails envoyés",
"From name": "Nom de l'expéditeur",
"From name - Tooltip": "Le nom affiché comme expéditeur dans les e-mails envoyés",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Hôte",
"Host - Tooltip": "Nom d'hôte",
"IdP": "IdP (Identité Fournisseur)",
@ -1128,6 +1130,8 @@
"Managed accounts": "Comptes gérés",
"Modify password...": "Modifier le mot de passe...",
"Multi-factor authentication": "Authentification multifacteur",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "Nouvelle adresse e-mail",
"New Password": "Nouveau mot de passe",
"New User": "Nouveau compte",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step",
"Please input your username!": "Please input your username!",
"Reset": "Reset",
"Retrieve password": "Retrieve password",
"Reset password": "Reset password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"",
"From name": "From name",
"From name - Tooltip": "Name of \"From\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name of host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Langkah selanjutnya",
"Please input your username!": "Silakan masukkan nama pengguna Anda!",
"Reset": "Menyetel-ulang",
"Retrieve password": "Mengambil password",
"Reset password": "Mengambil password",
"Unknown forget type": "Tipe yang tidak diketahui terlupakan",
"Verify": "Memverifikasi"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip",
"From name": "From name",
"From name - Tooltip": "From name - Tooltip",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Tuan rumah",
"Host - Tooltip": "Nama tuan rumah",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Akun yang dikelola",
"Modify password...": "Mengubah kata sandi...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "Email baru",
"New Password": "Kata Sandi Baru",
"New User": "Pengguna Baru",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step",
"Please input your username!": "Please input your username!",
"Reset": "Reset",
"Retrieve password": "Retrieve password",
"Reset password": "Reset password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"",
"From name": "From name",
"From name - Tooltip": "Name of \"From\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name of host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "次のステップ",
"Please input your username!": "ユーザー名を入力してください!",
"Reset": "リセット",
"Retrieve password": "パスワードの取得",
"Reset password": "パスワードの取得",
"Unknown forget type": "未知の忘却タイプ",
"Verify": "検証"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip",
"From name": "From name",
"From name - Tooltip": "From name - Tooltip",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "ホスト",
"Host - Tooltip": "ホストの名前",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "管理アカウント",
"Modify password...": "パスワードを変更する...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "新しいメール",
"New Password": "新しいパスワード",
"New User": "新しいユーザー",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step",
"Please input your username!": "Please input your username!",
"Reset": "Reset",
"Retrieve password": "Retrieve password",
"Reset password": "Reset password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"",
"From name": "From name",
"From name - Tooltip": "Name of \"From\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name of host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "다음 단계",
"Please input your username!": "사용자 이름을 입력하세요!",
"Reset": "리셋",
"Retrieve password": "비밀번호를 복구하세요",
"Reset password": "비밀번호를 복구하세요",
"Unknown forget type": "미지의 잊혀진 유형",
"Verify": "검증하다"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip",
"From name": "From name",
"From name - Tooltip": "From name - Tooltip",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "호스트",
"Host - Tooltip": "호스트의 이름",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "관리 계정",
"Modify password...": "비밀번호 수정하기...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "새 이메일",
"New Password": "새로운 비밀번호",
"New User": "새로운 사용자",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step",
"Please input your username!": "Please input your username!",
"Reset": "Reset",
"Retrieve password": "Retrieve password",
"Reset password": "Reset password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"",
"From name": "From name",
"From name - Tooltip": "Name of \"From\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name of host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step",
"Please input your username!": "Please input your username!",
"Reset": "Reset",
"Retrieve password": "Retrieve password",
"Reset password": "Reset password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"",
"From name": "From name",
"From name - Tooltip": "Name of \"From\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name of host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step",
"Please input your username!": "Please input your username!",
"Reset": "Reset",
"Retrieve password": "Retrieve password",
"Reset password": "Reset password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"",
"From name": "From name",
"From name - Tooltip": "Name of \"From\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name of host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Próxima Etapa",
"Please input your username!": "Por favor, insira seu nome de usuário!",
"Reset": "Redefinir",
"Retrieve password": "Recuperar senha",
"Reset password": "Recuperar senha",
"Unknown forget type": "Tipo de recuperação desconhecido",
"Verify": "Verificar"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Endereço de e-mail do remetente",
"From name": "Nome do remetente",
"From name - Tooltip": "Nome do remetente",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Nome do host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Contas gerenciadas",
"Modify password...": "Modificar senha...",
"Multi-factor authentication": "Autenticação de vários fatores",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "Novo E-mail",
"New Password": "Nova Senha",
"New User": "Novo Usuário",

View File

@ -166,7 +166,7 @@
"Next Step": "Следующий шаг",
"Please input your username!": "Пожалуйста, введите своё имя пользователя!",
"Reset": "Сбросить",
"Retrieve password": "Восстановить пароль",
"Reset password": "Восстановить пароль",
"Unknown forget type": "Неизвестный забытый тип",
"Verify": "Проверить"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip",
"From name": "From name",
"From name - Tooltip": "From name - Tooltip",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Хост",
"Host - Tooltip": "Имя хоста",
"IdP": "ИдП",
@ -1128,6 +1130,8 @@
"Managed accounts": "Управляемые аккаунты",
"Modify password...": "Изменить пароль...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "Новое электронное письмо",
"New Password": "Новый пароль",
"New User": "Новый пользователь",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step",
"Please input your username!": "Please input your username!",
"Reset": "Reset",
"Retrieve password": "Retrieve password",
"Reset password": "Reset password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"",
"From name": "From name",
"From name - Tooltip": "Name of \"From\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name of host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Sonraki adım",
"Please input your username!": "Lütfen kullanıcı adınızı girin",
"Reset": "Sıfırla",
"Retrieve password": "Şifre kurtar",
"Reset password": "Şifre kurtar",
"Unknown forget type": "Unknown forget type",
"Verify": "Doğrula"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"",
"From name": "From name",
"From name - Tooltip": "Name of \"From\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Host",
"Host - Tooltip": "Name of host",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Наступний крок",
"Please input your username!": "Будь ласка, введіть своє ім'я користувача!",
"Reset": "Скинути",
"Retrieve password": "Отримати пароль",
"Reset password": "Отримати пароль",
"Unknown forget type": "Невідомий забутий тип",
"Verify": "Підтвердити"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "Електронна адреса \"Від\"",
"From name": "Від імені",
"From name - Tooltip": "Назва \"Від\"",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Хост",
"Host - Tooltip": "Ім'я хоста",
"IdP": "IDP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Керовані облікові записи",
"Modify password...": "Змінити пароль...",
"Multi-factor authentication": "Багатофакторна аутентифікація",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "Нова електронна пошта",
"New Password": "Новий пароль",
"New User": "Новий користувач",

View File

@ -166,7 +166,7 @@
"Next Step": "Bước tiếp theo",
"Please input your username!": "Vui lòng nhập tên đăng nhập của bạn!",
"Reset": "Đặt lại",
"Retrieve password": "Truy xuất mật khẩu",
"Reset password": "Truy xuất mật khẩu",
"Unknown forget type": "Loại quên chưa biết",
"Verify": "Xác thực"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip",
"From name": "From name",
"From name - Tooltip": "From name - Tooltip",
"Get phone number": "Get phone number",
"Get phone number - Tooltip": "If sync phone number is enabled, you should enable google people api first and add scope https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "Chủ nhà",
"Host - Tooltip": "Tên của người chủ chỗ ở",
"IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Quản lý tài khoản",
"Modify password...": "Sửa đổi mật khẩu...",
"Multi-factor authentication": "Multi-factor authentication",
"Need update password": "Need update password",
"Need update password - Tooltip": "Force user update password after login",
"New Email": "Email mới",
"New Password": "Mật khẩu mới",
"New User": "Người dùng mới",

View File

@ -166,7 +166,7 @@
"Next Step": "下一步",
"Please input your username!": "请输入您的用户名!",
"Reset": "重置",
"Retrieve password": "找回密码",
"Reset password": "重置密码",
"Unknown forget type": "未知的忘记密码类型",
"Verify": "验证"
},
@ -778,6 +778,8 @@
"From address - Tooltip": "邮件里发件人的邮箱地址",
"From name": "发件人名称",
"From name - Tooltip": "邮件里发件人的显示名称",
"Get phone number": "获取手机号码",
"Get phone number - Tooltip": "如果启用获取手机号码你需要先启用peopleApi并添加范围https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "主机",
"Host - Tooltip": "主机名",
"IdP": "身份提供商",
@ -1128,6 +1130,8 @@
"Managed accounts": "托管账户",
"Modify password...": "编辑密码...",
"Multi-factor authentication": "多因素认证",
"Need update password": "需要更新密码",
"Need update password - Tooltip": "强制用户在登录后更新密码",
"New Email": "新邮箱",
"New Password": "新密码",
"New User": "添加用户",

View File

@ -102,6 +102,7 @@ class AccountTable extends React.Component {
{name: "Is admin", label: i18next.t("user:Is admin")},
{name: "Is forbidden", label: i18next.t("user:Is forbidden")},
{name: "Is deleted", label: i18next.t("user:Is deleted")},
{name: "Need update password", label: i18next.t("user:Need update password")},
{name: "Multi-factor authentication", label: i18next.t("user:Multi-factor authentication")},
{name: "WebAuthn credentials", label: i18next.t("user:WebAuthn credentials")},
{name: "Managed accounts", label: i18next.t("user:Managed accounts")},