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: with:
context: . context: .
target: STANDARD target: STANDARD
platforms: linux/amd64 platforms: linux/amd64,linux/arm64
push: true push: true
tags: casbin/casdoor:${{steps.get-current-tag.outputs.tag }},casbin/casdoor:latest tags: casbin/casdoor:${{steps.get-current-tag.outputs.tag }},casbin/casdoor:latest
@ -204,7 +204,7 @@ jobs:
with: with:
context: . context: .
target: ALLINONE target: ALLINONE
platforms: linux/amd64 platforms: linux/amd64,linux/arm64
push: true push: true
tags: casbin/casdoor-all-in-one:${{steps.get-current-tag.outputs.tag }},casbin/casdoor-all-in-one:latest 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 WORKDIR /web
COPY ./web . COPY ./web .
RUN yarn install --frozen-lockfile --network-timeout 1000000 && yarn run build 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 WORKDIR /go/src/casdoor
COPY . . COPY . .
RUN ./build.sh 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 FROM alpine:latest AS STANDARD
LABEL MAINTAINER="https://casdoor.org/" LABEL MAINTAINER="https://casdoor.org/"
ARG USER=casdoor ARG USER=casdoor
ARG TARGETOS
ARG TARGETARCH
ENV BUILDX_ARCH="${TARGETOS:-linux}_${TARGETARCH:-amd64}"
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
@ -28,7 +31,7 @@ RUN adduser -D $USER -u 1000 \
USER 1000 USER 1000
WORKDIR / 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/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/conf/app.conf ./conf/app.conf
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/version_info.txt ./go/src/casdoor/version_info.txt 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 FROM db AS ALLINONE
LABEL MAINTAINER="https://casdoor.org/" LABEL MAINTAINER="https://casdoor.org/"
ARG TARGETOS
ARG TARGETARCH
ENV BUILDX_ARCH="${TARGETOS:-linux}_${TARGETARCH:-amd64}"
RUN apt update RUN apt update
RUN apt install -y ca-certificates && update-ca-certificates RUN apt install -y ca-certificates && update-ca-certificates
WORKDIR / 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/swagger ./swagger
COPY --from=BACK /go/src/casdoor/docker-entrypoint.sh /docker-entrypoint.sh COPY --from=BACK /go/src/casdoor/docker-entrypoint.sh /docker-entrypoint.sh
COPY --from=BACK /go/src/casdoor/conf/app.conf ./conf/app.conf 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" echo "Google is blocked, Go proxy is enabled: GOPROXY=https://goproxy.cn,direct"
export GOPROXY="https://goproxy.cn,direct" export GOPROXY="https://goproxy.cn,direct"
fi 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 { if form.Type == ResponseTypeLogin {
c.SetSessionUsername(userId) c.SetSessionUsername(userId)
util.LogInfo(c.Ctx, "API: [%s] signed in", 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 { } else if form.Type == ResponseTypeCode {
clientId := c.Input().Get("clientId") clientId := c.Input().Get("clientId")
responseType := c.Input().Get("responseType") responseType := c.Input().Get("responseType")
@ -139,7 +139,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
} }
resp = codeToResponse(code) resp = codeToResponse(code)
resp.Data2 = user.NeedUpdatePassword
if application.EnableSigninSession || application.HasPromptPage() { if application.EnableSigninSession || application.HasPromptPage() {
// The prompt page needs the user to be signed in // The prompt page needs the user to be signed in
c.SetSessionUsername(userId) c.SetSessionUsername(userId)
@ -152,6 +152,8 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
nonce := c.Input().Get("nonce") nonce := c.Input().Get("nonce")
token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host) token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host)
resp = tokenToResponse(token) resp = tokenToResponse(token)
resp.Data2 = user.NeedUpdatePassword
} }
} else if form.Type == ResponseTypeSaml { // saml flow } else if form.Type == ResponseTypeSaml { // saml flow
res, redirectUrl, method, err := object.GetSamlResponse(application, user, form.SamlRequest, c.Ctx.Request.Host) 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) c.ResponseError(err.Error(), nil)
return 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() { if application.EnableSigninSession || application.HasPromptPage() {
// The prompt page needs the user to be signed in // The prompt page needs the user to be signed in

View File

@ -32,6 +32,7 @@ type EmailForm struct {
Sender string `json:"sender"` Sender string `json:"sender"`
Receivers []string `json:"receivers"` Receivers []string `json:"receivers"`
Provider string `json:"provider"` Provider string `json:"provider"`
ProviderObject object.Provider `json:"providerObject"`
} }
type SmsForm struct { type SmsForm struct {
@ -74,7 +75,6 @@ func (c *ApiController) SendEmail() {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
} else { } 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 // 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") 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 // 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" { if len(emailForm.Receivers) == 1 && emailForm.Receivers[0] == "TestSmtpServer" {
err = object.DailSmtpServer(provider) err = object.DailSmtpServer(provider)

View File

@ -509,8 +509,21 @@ func (c *ApiController) SetPassword() {
return 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 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 { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return

2
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/beego/beego v1.12.12 github.com/beego/beego v1.12.12
github.com/beevik/etree v1.1.0 github.com/beevik/etree v1.1.0
github.com/casbin/casbin/v2 v2.77.2 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/gomail/v2 v2.0.1
github.com/casdoor/notify v0.45.0 github.com/casdoor/notify v0.45.0
github.com/casdoor/oss v1.6.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/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 h1:kIbfdJ7AA7H0uTQ8s0q4GGZqSS5V9wVE74RrXyD9XPs=
github.com/casdoor/go-reddit/v2 v2.1.0/go.mod h1:eagkvwlZ4Hcsuc/uQsLHYEulz5jN65SVSwV/AIE7zsc= 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.24.0 h1:LNLsce3EG/87I3JS6UiajF3LlQmdIiCgebEu0IE4wSM=
github.com/casdoor/go-sms-sender v0.23.0/go.mod h1:bOm4H8/YfJmEHjBatEVQFOnAf0OOn1B0Wi5B7zDhws0= 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 h1:J+FG6x80s9e5lBHUn8Sv0Y56mud34KiWih5YdmudR/w=
github.com/casdoor/gomail/v2 v2.0.1/go.mod h1:VnGPslEAtpix5FjHisR/WKB1qvZDBaujbikxDe9d+2Q= github.com/casdoor/gomail/v2 v2.0.1/go.mod h1:VnGPslEAtpix5FjHisR/WKB1qvZDBaujbikxDe9d+2Q=
github.com/casdoor/notify v0.45.0 h1:OlaFvcQFjGOgA4mRx07M8AH1gvb5xNo21mcqrVGlLgk= github.com/casdoor/notify v0.45.0 h1:OlaFvcQFjGOgA4mRx07M8AH1gvb5xNo21mcqrVGlLgk=

View File

@ -25,6 +25,7 @@ import (
"time" "time"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/nyaruka/phonenumbers"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
@ -130,6 +131,23 @@ type GoogleUserInfo struct {
Locale string `json:"locale"` 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) { func (idp *GoogleIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
if strings.HasPrefix(token.AccessToken, GoogleIdTokenKey) { if strings.HasPrefix(token.AccessToken, GoogleIdTokenKey) {
googleIdToken, ok := token.Extra(GoogleIdTokenKey).(GoogleIdToken) 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") 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{ userInfo := UserInfo{
Id: googleUserInfo.Id, Id: googleUserInfo.Id,
Username: googleUserInfo.Email, Username: googleUserInfo.Email,
DisplayName: googleUserInfo.Name, DisplayName: googleUserInfo.Name,
Email: googleUserInfo.Email, Email: googleUserInfo.Email,
AvatarUrl: googleUserInfo.Picture, AvatarUrl: googleUserInfo.Picture,
Phone: phoneNumber,
CountryCode: countryCode,
} }
return &userInfo, nil return &userInfo, nil
} }

View File

@ -50,7 +50,7 @@ type Provider struct {
Host string `xorm:"varchar(100)" json:"host"` Host string `xorm:"varchar(100)" json:"host"`
Port int `json:"port"` 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"` 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 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"` 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 != "" { if provider.AppId != "" {
phoneNumbers = append([]string{provider.AppId}, phoneNumbers...) 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 { for i, number := range phoneNumbers {
phoneNumbers[i] = strings.TrimPrefix(number, "+86") 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 user.TotpSecret = value
case "SignupApplication": case "SignupApplication":
user.SignupApplication = value 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["PreferredMfaType"] = user.PreferredMfaType
m["TotpSecret"] = user.TotpSecret m["TotpSecret"] = user.TotpSecret
m["SignupApplication"] = user.SignupApplication 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{} m2 := map[string]string{}
for _, tableColumn := range syncer.TableColumns { for _, tableColumn := range syncer.TableColumns {

View File

@ -204,6 +204,7 @@ type User struct {
SigninWrongTimes int `json:"signinWrongTimes"` 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 { 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", "eveonline", "fitbit", "gitea", "heroku", "influxcloud", "instagram", "intercom", "kakao", "lastfm", "mailru", "meetup",
"microsoftonline", "naver", "nextcloud", "onedrive", "oura", "patreon", "paypal", "salesforce", "shopify", "soundcloud", "microsoftonline", "naver", "nextcloud", "onedrive", "oura", "patreon", "paypal", "salesforce", "shopify", "soundcloud",
"spotify", "strava", "stripe", "type", "tiktok", "tumblr", "twitch", "twitter", "typetalk", "uber", "vk", "wepay", "xero", "yahoo", "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 { if isAdmin {

View File

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

View File

@ -414,6 +414,7 @@ class App extends Component {
<Layout id="parent-area"> <Layout id="parent-area">
<ManagementPage <ManagementPage
account={this.state.account} account={this.state.account}
application={this.state.application}
uri={this.state.uri} uri={this.state.uri}
themeData={this.state.themeData} themeData={this.state.themeData}
themeAlgorithm={this.state.themeAlgorithm} 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="/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/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="/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" render={(props) => <SelfForgetPage {...this.props} account={this.props.account} 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/: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" 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="/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} />)} /> <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" />; return <Redirect to="/login" />;
} else if (props.account === undefined) { } else if (props.account === undefined) {
return null; return null;
} else if (props.account.needUpdatePassword) {
return <Redirect to={"/forget/" + props.application.name} />;
} else { } else {
return component; 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")); 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") { } 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")); return Setting.getLabel(i18next.t("provider:Sender Id"), i18next.t("provider:Sender Id - Tooltip"));
} else if (provider.type === "SendCloud SMS") {
return "SMS_USER";
} else { } else {
return Setting.getLabel(i18next.t("provider:Client ID"), i18next.t("provider:Client ID - Tooltip")); 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")); return Setting.getLabel(i18next.t("provider:Auth Key"), i18next.t("provider:Auth Key - Tooltip"));
} else if (provider.type === "Infobip SMS") { } else if (provider.type === "Infobip SMS") {
return Setting.getLabel(i18next.t("provider:Api Key"), i18next.t("provider:Api Key - Tooltip")); return Setting.getLabel(i18next.t("provider:Api Key"), i18next.t("provider:Api Key - Tooltip"));
} else if (provider.type === "SendCloud SMS") {
return "SMS_KEY";
} else { } else {
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip")); 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> </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 : ( 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"}} > <Row style={{marginTop: "20px"}} >
@ -1093,7 +1103,7 @@ class ProviderEditPage extends React.Component {
</React.Fragment> </React.Fragment>
) : this.state.provider.category === "SMS" ? ( ) : this.state.provider.category === "SMS" ? (
<React.Fragment> <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 : null :
(<Row style={{marginTop: "20px"}} > (<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>

View File

@ -139,10 +139,6 @@ export const OtherProviderInfo = {
logo: `${StaticBaseUrl}/img/social_twilio.svg`, logo: `${StaticBaseUrl}/img/social_twilio.svg`,
url: "https://www.twilio.com/messaging", url: "https://www.twilio.com/messaging",
}, },
"SendCloud SMS": {
logo: `${StaticBaseUrl}/img/sms_sendcloud.png`,
url: "https://www.sendcloud.net/",
},
"SmsBao SMS": { "SmsBao SMS": {
logo: `${StaticBaseUrl}/img/social_smsbao.png`, logo: `${StaticBaseUrl}/img/social_smsbao.png`,
url: "https://www.smsbao.com/", url: "https://www.smsbao.com/",
@ -1043,7 +1039,6 @@ export function getProviderTypeOptions(category) {
{id: "Huawei Cloud SMS", name: "Huawei Cloud SMS"}, {id: "Huawei Cloud SMS", name: "Huawei Cloud SMS"},
{id: "UCloud SMS", name: "UCloud SMS"}, {id: "UCloud SMS", name: "UCloud SMS"},
{id: "Twilio SMS", name: "Twilio SMS"}, {id: "Twilio SMS", name: "Twilio SMS"},
{id: "SendCloud SMS", name: "SendCloud SMS"},
{id: "SmsBao SMS", name: "SmsBao SMS"}, {id: "SmsBao SMS", name: "SmsBao SMS"},
{id: "SUBMAIL SMS", name: "SUBMAIL SMS"}, {id: "SUBMAIL SMS", name: "SUBMAIL SMS"},
{id: "Msg91 SMS", name: "Msg91 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", 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", "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", "Language", "Gender", "Birthday", "Education", "Score", "Ranking", "IsDefaultAvatar", "IsOnline", "IsAdmin", "IsForbidden", "IsDeleted", "CreatedIp",
"PreferredMfaType", "TotpSecret", "SignupApplication"]; "PreferredMfaType", "TotpSecret", "SignupApplication", "RecoveryCodes", "MfaPhoneEnabled", "MfaEmailEnabled"];
} }
export function getDefaultFooterContent() { export function getDefaultFooterContent() {

View File

@ -211,6 +211,9 @@ class UserEditPage extends React.Component {
const user = this.state.user; const user = this.state.user;
if (key === "address") { if (key === "address") {
if (!user[key]) {
user[key] = ["", ""];
}
user[key][idx] = value; user[key][idx] = value;
} else { } else {
user[key] = value; user[key] = value;
@ -515,7 +518,7 @@ class UserEditPage extends React.Component {
<span>{i18next.t("user:Address line") + " 1"}</span> : <span>{i18next.t("user:Address line") + " 1"}</span> :
</Col> </Col>
<Col span={20} > <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); this.updateUserField("address", e.target.value, 0);
}} /> }} />
</Col> </Col>
@ -527,7 +530,7 @@ class UserEditPage extends React.Component {
<span>{i18next.t("user:Address line") + " 2"}</span> : <span>{i18next.t("user:Address line") + " 2"}</span> :
</Col> </Col>
<Col span={20} > <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); this.updateUserField("address", e.target.value, 1);
}} /> }} />
</Col> </Col>
@ -1023,6 +1026,19 @@ class UserEditPage extends React.Component {
</Col> </Col>
</Row> </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 // OAuth
const oAuthParams = Util.getOAuthGetParameters(innerParams); const oAuthParams = Util.getOAuthGetParameters(innerParams);
const concatChar = oAuthParams?.redirectUri?.includes("?") ? "&" : "?"; const concatChar = oAuthParams?.redirectUri?.includes("?") ? "&" : "?";
const signinUrl = localStorage.getItem("signinUrl");
AuthBackend.login(body, oAuthParams) AuthBackend.login(body, oAuthParams)
.then((res) => { .then((res) => {
if (res.status === "ok") { if (res.status === "ok") {
const responseType = this.getResponseType(); const responseType = this.getResponseType();
if (responseType === "login") { if (responseType === "login") {
if (res.data2) {
sessionStorage.setItem("signinUrl", signinUrl);
Setting.goToLinkSoft(this, `/forget/${applicationName}`);
return;
}
Setting.showMessage("success", "Logged in successfully"); Setting.showMessage("success", "Logged in successfully");
// Setting.goToLinkSoft(this, "/"); // Setting.goToLinkSoft(this, "/");
const link = Setting.getFromLink(); const link = Setting.getFromLink();
Setting.goToLink(link); Setting.goToLink(link);
} else if (responseType === "code") { } else if (responseType === "code") {
if (res.data2) {
sessionStorage.setItem("signinUrl", signinUrl);
Setting.goToLinkSoft(this, `/forget/${applicationName}`);
return;
}
const code = res.data; const code = res.data;
Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}code=${code}&state=${oAuthParams.state}`); Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}code=${code}&state=${oAuthParams.state}`);
// Setting.showMessage("success", `Authorization code: ${res.data}`); // Setting.showMessage("success", `Authorization code: ${res.data}`);
} else if (responseType === "token" || responseType === "id_token") { } else if (responseType === "token" || responseType === "id_token") {
if (res.data2) {
sessionStorage.setItem("signinUrl", signinUrl);
Setting.goToLinkSoft(this, `/forget/${applicationName}`);
return;
}
const token = res.data; const token = res.data;
Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}${responseType}=${token}&state=${oAuthParams.state}&token_type=bearer`); Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}${responseType}=${token}&state=${oAuthParams.state}&token_type=bearer`);
} else if (responseType === "link") { } else if (responseType === "link") {
@ -181,6 +197,11 @@ class AuthCallback extends React.Component {
relayState: oAuthParams.relayState, relayState: oAuthParams.relayState,
}); });
} else { } else {
if (res.data2.needUpdatePassword) {
sessionStorage.setItem("signinUrl", signinUrl);
Setting.goToLinkSoft(this, `/forget/${applicationName}`);
return;
}
const SAMLResponse = res.data; const SAMLResponse = res.data;
const redirectUri = res.data2.redirectUrl; const redirectUri = res.data2.redirectUrl;
Setting.goToLink(`${redirectUri}?SAMLResponse=${encodeURIComponent(SAMLResponse)}&RelayState=${oAuthParams.relayState}`); Setting.goToLink(`${redirectUri}?SAMLResponse=${encodeURIComponent(SAMLResponse)}&RelayState=${oAuthParams.relayState}`);

View File

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

View File

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

View File

@ -384,8 +384,7 @@ export function getAuthUrl(application, provider, method, code) {
let endpoint = authInfo[provider.type].endpoint; let endpoint = authInfo[provider.type].endpoint;
let redirectUri = `${window.location.origin}/callback`; 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 isShortState = (provider.type === "WeChat" && navigator.userAgent.includes("MicroMessenger")) || (provider.type === "Twitter");
const state = Util.getStateFromQueryParams(application.name, provider.name, method, isShortState); const state = Util.getStateFromQueryParams(application.name, provider.name, method, isShortState);
const codeChallenge = "P3S-a7dr8bgM4bF6vOyiKkKETDl16rcAzao9F8UIL1Y"; // SHA256(Base64-URL-encode("casdoor-verifier")) 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") { } else if (provider.type === "Apple") {
redirectUri = `${window.location.origin}/api/callback`; 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 === "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 === "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" || 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 === "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") { || 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}`; 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") { } 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`; 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") { } else if (provider.type === "DingTalk") {

View File

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

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step", "Next Step": "Next Step",
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Reset password": "Reset password",
"Unknown forget type": "Unknown forget type", "Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"", "From address - Tooltip": "Email address of \"From\"",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "Name of \"From\"", "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": "Host",
"Host - Tooltip": "Name of host", "Host - Tooltip": "Name of host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts", "Managed accounts": "Managed accounts",
"Modify password...": "Modify password...", "Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "New Email",
"New Password": "New Password", "New Password": "New Password",
"New User": "New User", "New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Nächster Schritt", "Next Step": "Nächster Schritt",
"Please input your username!": "Bitte gib deinen Benutzernamen ein!", "Please input your username!": "Bitte gib deinen Benutzernamen ein!",
"Reset": "Zurücksetzen", "Reset": "Zurücksetzen",
"Retrieve password": "Passwort abrufen", "Reset password": "Passwort abrufen",
"Unknown forget type": "Unbekannter Vergesslichkeitstyp", "Unknown forget type": "Unbekannter Vergesslichkeitstyp",
"Verify": "überprüfen" "Verify": "überprüfen"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip", "From address - Tooltip": "From address - Tooltip",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "From name - Tooltip", "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": "Host",
"Host - Tooltip": "Name des Hosts", "Host - Tooltip": "Name des Hosts",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Verwaltete Konten", "Managed accounts": "Verwaltete Konten",
"Modify password...": "Passwort ändern...", "Modify password...": "Passwort ändern...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "Neue E-Mail",
"New Password": "Neues Passwort", "New Password": "Neues Passwort",
"New User": "Neuer Benutzer", "New User": "Neuer Benutzer",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step", "Next Step": "Next Step",
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Reset password": "Reset password",
"Unknown forget type": "Unknown forget type", "Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"", "From address - Tooltip": "Email address of \"From\"",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "Name of \"From\"", "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": "Host",
"Host - Tooltip": "Name of host", "Host - Tooltip": "Name of host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts", "Managed accounts": "Managed accounts",
"Modify password...": "Modify password...", "Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "New Email",
"New Password": "New Password", "New Password": "New Password",
"New User": "New User", "New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Siguiente paso", "Next Step": "Siguiente paso",
"Please input your username!": "¡Por favor, ingrese su nombre de usuario!", "Please input your username!": "¡Por favor, ingrese su nombre de usuario!",
"Reset": "Restablecer", "Reset": "Restablecer",
"Retrieve password": "Recuperar contraseña", "Reset password": "Reset password",
"Unknown forget type": "Tipo de olvido desconocido", "Unknown forget type": "Tipo de olvido desconocido",
"Verify": "Verificar" "Verify": "Verificar"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip", "From address - Tooltip": "From address - Tooltip",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "From name - Tooltip", "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": "Anfitrión",
"Host - Tooltip": "Nombre del anfitrión", "Host - Tooltip": "Nombre del anfitrión",
"IdP": "IdP = Proveedor de Identidad", "IdP": "IdP = Proveedor de Identidad",
@ -1128,6 +1130,8 @@
"Managed accounts": "Cuentas gestionadas", "Managed accounts": "Cuentas gestionadas",
"Modify password...": "Modificar contraseña...", "Modify password...": "Modificar contraseña...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "Nuevo correo electrónico",
"New Password": "Nueva contraseña", "New Password": "Nueva contraseña",
"New User": "Nuevo Usuario", "New User": "Nuevo Usuario",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step", "Next Step": "Next Step",
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Reset password": "Reset password",
"Unknown forget type": "Unknown forget type", "Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"", "From address - Tooltip": "Email address of \"From\"",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "Name of \"From\"", "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": "Host",
"Host - Tooltip": "Name of host", "Host - Tooltip": "Name of host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts", "Managed accounts": "Managed accounts",
"Modify password...": "Modify password...", "Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "New Email",
"New Password": "New Password", "New Password": "New Password",
"New User": "New User", "New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step", "Next Step": "Next Step",
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Reset password": "Reset password",
"Unknown forget type": "Unknown forget type", "Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"", "From address - Tooltip": "Email address of \"From\"",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "Name of \"From\"", "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": "Host",
"Host - Tooltip": "Name of host", "Host - Tooltip": "Name of host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts", "Managed accounts": "Managed accounts",
"Modify password...": "Modify password...", "Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "New Email",
"New Password": "New Password", "New Password": "New Password",
"New User": "New User", "New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Étape suivante", "Next Step": "Étape suivante",
"Please input your username!": "Veuillez saisir votre identifiant !", "Please input your username!": "Veuillez saisir votre identifiant !",
"Reset": "Réinitialiser", "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", "Unknown forget type": "Type d'oubli inconnu",
"Verify": "Vérifier" "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 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": "Nom de l'expéditeur",
"From name - Tooltip": "Le nom affiché comme expéditeur dans les e-mails envoyés", "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": "Hôte",
"Host - Tooltip": "Nom d'hôte", "Host - Tooltip": "Nom d'hôte",
"IdP": "IdP (Identité Fournisseur)", "IdP": "IdP (Identité Fournisseur)",
@ -1128,6 +1130,8 @@
"Managed accounts": "Comptes gérés", "Managed accounts": "Comptes gérés",
"Modify password...": "Modifier le mot de passe...", "Modify password...": "Modifier le mot de passe...",
"Multi-factor authentication": "Authentification multifacteur", "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 Email": "Nouvelle adresse e-mail",
"New Password": "Nouveau mot de passe", "New Password": "Nouveau mot de passe",
"New User": "Nouveau compte", "New User": "Nouveau compte",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step", "Next Step": "Next Step",
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Reset password": "Reset password",
"Unknown forget type": "Unknown forget type", "Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"", "From address - Tooltip": "Email address of \"From\"",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "Name of \"From\"", "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": "Host",
"Host - Tooltip": "Name of host", "Host - Tooltip": "Name of host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts", "Managed accounts": "Managed accounts",
"Modify password...": "Modify password...", "Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "New Email",
"New Password": "New Password", "New Password": "New Password",
"New User": "New User", "New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Langkah selanjutnya", "Next Step": "Langkah selanjutnya",
"Please input your username!": "Silakan masukkan nama pengguna Anda!", "Please input your username!": "Silakan masukkan nama pengguna Anda!",
"Reset": "Menyetel-ulang", "Reset": "Menyetel-ulang",
"Retrieve password": "Mengambil password", "Reset password": "Mengambil password",
"Unknown forget type": "Tipe yang tidak diketahui terlupakan", "Unknown forget type": "Tipe yang tidak diketahui terlupakan",
"Verify": "Memverifikasi" "Verify": "Memverifikasi"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip", "From address - Tooltip": "From address - Tooltip",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "From name - Tooltip", "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": "Tuan rumah",
"Host - Tooltip": "Nama tuan rumah", "Host - Tooltip": "Nama tuan rumah",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Akun yang dikelola", "Managed accounts": "Akun yang dikelola",
"Modify password...": "Mengubah kata sandi...", "Modify password...": "Mengubah kata sandi...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "Email baru",
"New Password": "Kata Sandi Baru", "New Password": "Kata Sandi Baru",
"New User": "Pengguna Baru", "New User": "Pengguna Baru",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step", "Next Step": "Next Step",
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Reset password": "Reset password",
"Unknown forget type": "Unknown forget type", "Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"", "From address - Tooltip": "Email address of \"From\"",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "Name of \"From\"", "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": "Host",
"Host - Tooltip": "Name of host", "Host - Tooltip": "Name of host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts", "Managed accounts": "Managed accounts",
"Modify password...": "Modify password...", "Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "New Email",
"New Password": "New Password", "New Password": "New Password",
"New User": "New User", "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": "パスワードの取得", "Reset password": "パスワードの取得",
"Unknown forget type": "未知の忘却タイプ", "Unknown forget type": "未知の忘却タイプ",
"Verify": "検証" "Verify": "検証"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip", "From address - Tooltip": "From address - Tooltip",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "From name - Tooltip", "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": "ホストの名前", "Host - Tooltip": "ホストの名前",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "管理アカウント", "Managed accounts": "管理アカウント",
"Modify password...": "パスワードを変更する...", "Modify password...": "パスワードを変更する...",
"Multi-factor authentication": "Multi-factor authentication", "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", "Next Step": "Next Step",
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Reset password": "Reset password",
"Unknown forget type": "Unknown forget type", "Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"", "From address - Tooltip": "Email address of \"From\"",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "Name of \"From\"", "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": "Host",
"Host - Tooltip": "Name of host", "Host - Tooltip": "Name of host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts", "Managed accounts": "Managed accounts",
"Modify password...": "Modify password...", "Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "New Email",
"New Password": "New Password", "New Password": "New Password",
"New User": "New User", "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": "비밀번호를 복구하세요", "Reset password": "비밀번호를 복구하세요",
"Unknown forget type": "미지의 잊혀진 유형", "Unknown forget type": "미지의 잊혀진 유형",
"Verify": "검증하다" "Verify": "검증하다"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip", "From address - Tooltip": "From address - Tooltip",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "From name - Tooltip", "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": "호스트의 이름", "Host - Tooltip": "호스트의 이름",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "관리 계정", "Managed accounts": "관리 계정",
"Modify password...": "비밀번호 수정하기...", "Modify password...": "비밀번호 수정하기...",
"Multi-factor authentication": "Multi-factor authentication", "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", "Next Step": "Next Step",
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Reset password": "Reset password",
"Unknown forget type": "Unknown forget type", "Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"", "From address - Tooltip": "Email address of \"From\"",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "Name of \"From\"", "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": "Host",
"Host - Tooltip": "Name of host", "Host - Tooltip": "Name of host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts", "Managed accounts": "Managed accounts",
"Modify password...": "Modify password...", "Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "New Email",
"New Password": "New Password", "New Password": "New Password",
"New User": "New User", "New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step", "Next Step": "Next Step",
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Reset password": "Reset password",
"Unknown forget type": "Unknown forget type", "Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"", "From address - Tooltip": "Email address of \"From\"",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "Name of \"From\"", "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": "Host",
"Host - Tooltip": "Name of host", "Host - Tooltip": "Name of host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts", "Managed accounts": "Managed accounts",
"Modify password...": "Modify password...", "Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "New Email",
"New Password": "New Password", "New Password": "New Password",
"New User": "New User", "New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Next Step", "Next Step": "Next Step",
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Reset password": "Reset password",
"Unknown forget type": "Unknown forget type", "Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"", "From address - Tooltip": "Email address of \"From\"",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "Name of \"From\"", "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": "Host",
"Host - Tooltip": "Name of host", "Host - Tooltip": "Name of host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts", "Managed accounts": "Managed accounts",
"Modify password...": "Modify password...", "Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "New Email",
"New Password": "New Password", "New Password": "New Password",
"New User": "New User", "New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Próxima Etapa", "Next Step": "Próxima Etapa",
"Please input your username!": "Por favor, insira seu nome de usuário!", "Please input your username!": "Por favor, insira seu nome de usuário!",
"Reset": "Redefinir", "Reset": "Redefinir",
"Retrieve password": "Recuperar senha", "Reset password": "Recuperar senha",
"Unknown forget type": "Tipo de recuperação desconhecido", "Unknown forget type": "Tipo de recuperação desconhecido",
"Verify": "Verificar" "Verify": "Verificar"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Endereço de e-mail do remetente", "From address - Tooltip": "Endereço de e-mail do remetente",
"From name": "Nome do remetente", "From name": "Nome do remetente",
"From name - Tooltip": "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": "Host",
"Host - Tooltip": "Nome do host", "Host - Tooltip": "Nome do host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Contas gerenciadas", "Managed accounts": "Contas gerenciadas",
"Modify password...": "Modificar senha...", "Modify password...": "Modificar senha...",
"Multi-factor authentication": "Autenticação de vários fatores", "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 Email": "Novo E-mail",
"New Password": "Nova Senha", "New Password": "Nova Senha",
"New User": "Novo Usuário", "New User": "Novo Usuário",

View File

@ -166,7 +166,7 @@
"Next Step": "Следующий шаг", "Next Step": "Следующий шаг",
"Please input your username!": "Пожалуйста, введите своё имя пользователя!", "Please input your username!": "Пожалуйста, введите своё имя пользователя!",
"Reset": "Сбросить", "Reset": "Сбросить",
"Retrieve password": "Восстановить пароль", "Reset password": "Восстановить пароль",
"Unknown forget type": "Неизвестный забытый тип", "Unknown forget type": "Неизвестный забытый тип",
"Verify": "Проверить" "Verify": "Проверить"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip", "From address - Tooltip": "From address - Tooltip",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "From name - Tooltip", "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": "Имя хоста", "Host - Tooltip": "Имя хоста",
"IdP": "ИдП", "IdP": "ИдП",
@ -1128,6 +1130,8 @@
"Managed accounts": "Управляемые аккаунты", "Managed accounts": "Управляемые аккаунты",
"Modify password...": "Изменить пароль...", "Modify password...": "Изменить пароль...",
"Multi-factor authentication": "Multi-factor authentication", "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", "Next Step": "Next Step",
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Reset password": "Reset password",
"Unknown forget type": "Unknown forget type", "Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"", "From address - Tooltip": "Email address of \"From\"",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "Name of \"From\"", "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": "Host",
"Host - Tooltip": "Name of host", "Host - Tooltip": "Name of host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts", "Managed accounts": "Managed accounts",
"Modify password...": "Modify password...", "Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "New Email",
"New Password": "New Password", "New Password": "New Password",
"New User": "New User", "New User": "New User",

View File

@ -166,7 +166,7 @@
"Next Step": "Sonraki adım", "Next Step": "Sonraki adım",
"Please input your username!": "Lütfen kullanıcı adınızı girin", "Please input your username!": "Lütfen kullanıcı adınızı girin",
"Reset": "Sıfırla", "Reset": "Sıfırla",
"Retrieve password": "Şifre kurtar", "Reset password": "Şifre kurtar",
"Unknown forget type": "Unknown forget type", "Unknown forget type": "Unknown forget type",
"Verify": "Doğrula" "Verify": "Doğrula"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "Email address of \"From\"", "From address - Tooltip": "Email address of \"From\"",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "Name of \"From\"", "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": "Host",
"Host - Tooltip": "Name of host", "Host - Tooltip": "Name of host",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Managed accounts", "Managed accounts": "Managed accounts",
"Modify password...": "Modify password...", "Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "New Email",
"New Password": "New Password", "New Password": "New Password",
"New User": "New User", "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": "Отримати пароль", "Reset password": "Отримати пароль",
"Unknown forget type": "Невідомий забутий тип", "Unknown forget type": "Невідомий забутий тип",
"Verify": "Підтвердити" "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": "Хост",
"Host - Tooltip": "Ім'я хоста", "Host - Tooltip": "Ім'я хоста",
"IdP": "IDP", "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": "Bước tiếp theo", "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!", "Please input your username!": "Vui lòng nhập tên đăng nhập của bạn!",
"Reset": "Đặt lại", "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", "Unknown forget type": "Loại quên chưa biết",
"Verify": "Xác thực" "Verify": "Xác thực"
}, },
@ -778,6 +778,8 @@
"From address - Tooltip": "From address - Tooltip", "From address - Tooltip": "From address - Tooltip",
"From name": "From name", "From name": "From name",
"From name - Tooltip": "From name - Tooltip", "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": "Chủ nhà",
"Host - Tooltip": "Tên của người chủ chỗ ở", "Host - Tooltip": "Tên của người chủ chỗ ở",
"IdP": "IdP", "IdP": "IdP",
@ -1128,6 +1130,8 @@
"Managed accounts": "Quản lý tài khoản", "Managed accounts": "Quản lý tài khoản",
"Modify password...": "Sửa đổi mật khẩu...", "Modify password...": "Sửa đổi mật khẩu...",
"Multi-factor authentication": "Multi-factor authentication", "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 Email": "Email mới",
"New Password": "Mật khẩu mới", "New Password": "Mật khẩu mới",
"New User": "Người dùng mới", "New User": "Người dùng mới",

View File

@ -166,7 +166,7 @@
"Next Step": "下一步", "Next Step": "下一步",
"Please input your username!": "请输入您的用户名!", "Please input your username!": "请输入您的用户名!",
"Reset": "重置", "Reset": "重置",
"Retrieve password": "找回密码", "Reset password": "重置密码",
"Unknown forget type": "未知的忘记密码类型", "Unknown forget type": "未知的忘记密码类型",
"Verify": "验证" "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 - Tooltip": "如果启用获取手机号码你需要先启用peopleApi并添加范围https://www.googleapis.com/auth/user.phonenumbers.read",
"Host": "主机", "Host": "主机",
"Host - Tooltip": "主机名", "Host - Tooltip": "主机名",
"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 - Tooltip": "强制用户在登录后更新密码",
"New Email": "新邮箱", "New Email": "新邮箱",
"New Password": "新密码", "New Password": "新密码",
"New User": "添加用户", "New User": "添加用户",

View File

@ -102,6 +102,7 @@ class AccountTable extends React.Component {
{name: "Is admin", label: i18next.t("user:Is admin")}, {name: "Is admin", label: i18next.t("user:Is admin")},
{name: "Is forbidden", label: i18next.t("user:Is forbidden")}, {name: "Is forbidden", label: i18next.t("user:Is forbidden")},
{name: "Is deleted", label: i18next.t("user:Is deleted")}, {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: "Multi-factor authentication", label: i18next.t("user:Multi-factor authentication")},
{name: "WebAuthn credentials", label: i18next.t("user:WebAuthn credentials")}, {name: "WebAuthn credentials", label: i18next.t("user:WebAuthn credentials")},
{name: "Managed accounts", label: i18next.t("user:Managed accounts")}, {name: "Managed accounts", label: i18next.t("user:Managed accounts")},