Compare commits

..

43 Commits

Author SHA1 Message Date
7cd8f030ee feat: support IP limitation for user entry pages (#3267)
* feat: support IP limitation for user entry pages

* fix: error message, ip whiteList, check_entry_ip

* fix: perform checks on the backend

* fix: change the implementation of checking IpWhitelist

* fix: add entryIpCheck in SetPassword and remove it from VerifyCode

* fix: remove additional error message pop-ups

* fix: add isRestricted and show ip error in EntryPage.js

* fix: error message

* Update auth.go

* Update check_ip.go

* Update check_ip.go

* fix: update return value of the check function from string to error

* fix: remoteAddress position

* fix: IP whitelist

* fix: clientIp

* fix:add util.GetClientIpFromRequest

* fix: remove duplicate IP and port separation codes and remove extra special characters after clientIp

* fix: gofumpt

* fix: getIpInfo and localhost

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-10-15 20:40:14 +08:00
a3f8ded10c feat: refactor util.GetClientIpFromRequest() 2024-10-15 12:22:38 +08:00
e3d135bc6e feat: improve MFA desc text (#3284)
* fix: fix i18n error for mfa

* fix: fix i18n error for mfa

* fix: promote translate
2024-10-14 18:31:48 +08:00
fc864b0de4 feat: support ".login-panel-dark" CSS for signup/login pages (#3269)
* feat: add custom dark mode CSS for login and registration forms.

* refactor: extract dark theme check to Setting.js
2024-10-13 22:31:54 +08:00
3211bcc777 feat: add getCaptchaRule() to fix bug (#3281)
* feat: update captcha rule when the login page component is mounted

* fix: remove enableCaptchaModel from the state of the login page to avoid inconsistency issues

* fix: use this.getApplicationObj() instead of this.props.application
2024-10-12 10:02:45 +08:00
9f4430ed04 feat: fix MFA's i18n error (#3273) 2024-10-08 21:58:06 +08:00
05830b9ff6 feat: update import lib: github.com/casdoor/ldapserver 2024-10-08 19:18:56 +08:00
347b25676f feat: dark mode now works for login/signup pages too (#3252)
* fix: trying to fix dark mode not applying on login/registration interface

* fix: trying to fix dark mode not applying on login/registration interface

* fix: trying to fix dark mode not applying on login/registration interface

* fix: Clean up unused code

* fix: loginBackgroundDark move to App.less

* fix: fix typo
2024-10-05 21:26:25 +08:00
2417ff84e6 feat: support initial group assignment for new invited users via invitation.SignupGroup field (#3266) 2024-10-04 20:15:51 +08:00
468631e654 feat: support "All" in organization's country codes (#3264) 2024-10-03 22:58:09 +08:00
e1dea9f697 feat: add organization's PasswordObfuscator to obfuscate login API's password (#3260)
* feat: add PasswordObfuscator to the login API

* fix: change key error message

* fix: remove unnecessary change

* fix: fix one

* fix: fix two

* fix: fix three

* fix: fix five

* fix: disable organization update when key is invalid

* fix: fix six

* fix: use Form.Item to control key

* fix: update obfuscator.js

* Update obfuscator.go

* Update obfuscator.go

* Update auth.go

* fix: remove real-time key monitoring

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-10-03 10:38:37 +08:00
c0f22bae43 feat: better handling of organization.AccountItems on init_data import (#3263)
* Better handling of accountitems on init_data import.

* Removed commented code.

* Update init_data.go

* Update init_data.go

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-10-03 08:49:09 +08:00
c9635d9e2b feat: improve i18n (#3259) 2024-10-01 00:10:49 +08:00
3bd52172ea feat: add Hide-Password option for signin method rule field (#3258) 2024-09-30 23:31:41 +08:00
bf730050d5 feat: increase Organization.Favicon to 200 chars 2024-09-29 11:45:56 +08:00
5b733b7f15 feat: improve filterRecordIn24Hours() logic 2024-09-29 11:45:15 +08:00
034f28def9 feat: logout if app.conf's inactiveTimeoutMinutes is reached (#3244)
* feat: logout if there's no activities for a long time

* fix: change the implementation of updating LastTime

* fix: add logoutMinites to app.conf

* fix: change the implementation of judgment statement

* fix: use sync.Map to ensure thread safety

* fix: syntax standards and Apache headers

* fix: change the implementation of obtaining logoutMinutes in app.conf

* fix: follow community code standards

* fix: <=0 or empty means no restriction

* Update logout_filter.go

* Update app.conf

* Update main.go

* Update and rename logout_filter.go to timeout_filter.go

* Update app.conf

* Update timeout_filter.go

* fix: update app.conf

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-09-27 01:18:02 +08:00
c86ac8e6ad feat: fix UTF-8 charset for Alipay IdP (#3247) 2024-09-27 00:59:52 +08:00
d647eed22a feat: add OIDC WebFinger support (#3245)
* feat: add WebFinger support

* lint: used gofumpt

* oidc: ensure webfinger rel is checked
2024-09-26 13:06:36 +08:00
717c53f6e5 feat: support enableErrorMask2 config 2024-09-25 19:37:14 +08:00
097adac871 feat: support single-choice and multi-choices in signup page (#3234)
* feat: add custom signup field

* feat: support more field in signup page

* feat: support more field in signup page

* feat: support more field in signup page

* feat: Reduce code duplication in form item rendering

* feat: Simplify gender and info checks using includes

* feat: update translate

* Revert "feat: update translate"

This reverts commit 669334c716.

* feat: address feedback from hsluoyz
2024-09-25 12:48:37 +08:00
74543b9533 feat: improve QR code for casdoor-app (#3226)
* feat: simplify login url for casdoor-app

* feat: add token check

* fix: improve logic
2024-09-23 22:27:58 +08:00
110dc04179 feat: Revert "feat: fix permission problem in standard image" (#3231)
This reverts commit 6464bd10dc.
2024-09-23 22:19:27 +08:00
6464bd10dc feat: fix permission problem in standard image (#3228) 2024-09-23 18:40:39 +08:00
db878a890e feat: add type and options to signup items 2024-09-21 23:40:29 +08:00
12d6d8e6ce feat: fix cookie expire time too short bug 2024-09-21 22:45:13 +08:00
8ed6e4f934 feat: improve UI for "No account?" 2024-09-21 07:35:33 +08:00
ed9732caf9 feat: add condition for getWebBuildFolder function (#3219) 2024-09-20 23:59:13 +08:00
0de4e7da38 feat: fix organization pagination count error (#3215)
* fix(organization): ensure count includes shared organizations

Adjust the `GetOrganizationCount` function to account for shared organizations by adding
an additional parameter and modifying the count query accordingly. This change ensures that
the organization count correctly reflects shared organizations within the system.

* ```fix(organization): optimize GetOrganizationCount query

Refactor the GetOrganizationCount function to use a more efficient search
method by leveraging the 'is_shared' field directly in the query condition.
This change improves the performance for counting organizations by avoiding
unnecessary iteration over potentially large result sets.
```

---------

Co-authored-by: CuiJing <cuijing@tul.com.cn>
2024-09-20 23:58:46 +08:00
a330fbc11f docs: fix Docker link 2024-09-17 20:45:32 +08:00
ed158d4981 feat: support advanced editor in model edit page (#3176)
* feat: integrate external model editor and handle message events for model updates

* feat: add CasbinEditor and IframeEditor components for model editing

* feat: add tabbed editor interface for CasbinEditor

* fix: Synchronize content between basic and advanced editors

* refactor: simplify CasbinEditor and ModelEditPage components

* refactor: Refactor CasbinEditor for improved iframe initialization and model synchronization

* refactor: update default state of CasbinEditor active tab to "advanced

* chore: add Apache License header to CasbinEditor.js and IframeEditor.js files

* refactor: update CasbinEditor class names for consistency
2024-09-16 22:25:25 +08:00
8df965b98d feat: improve SAML XML's xmlns to fix SAML support for some clouds (#3207) 2024-09-16 08:01:28 +08:00
2c3749820e feat: add application.UseEmailAsSamlNameId field for SAML (#3203)
* feat: Add option to use email as SAML NameID based on application config

- Updated NewSamlResponse11 to accept an application parameter.
- Conditionally set SAML NameIdentifier to user's email or username based on application.UseEmailAsNameId.

* refactor: Update GetValidationBySaml to pass application to NewSamlResponse11

- Modified GetValidationBySaml function to include application parameter in NewSamlResponse11 call.

* feat: Rename field and update logic for using Email as SAML NameID

- Renamed the `UseEmailAsNameId` field to `UseEmailAsSamlNameId` in the `Application` struct.
- Updated `NewSamlResponse` and `NewSamlResponse11` functions to use `UseEmailAsSamlNameId` for setting the NameID value.
- Modified `ApplicationEditPage.js` to reflect the field name change and update the corresponding logic.
2024-09-15 23:00:50 +08:00
0b17cb9746 feat: make Organization.EnableSoftDeletion and User.IsDeleted work (#3205)
* feat: make Organization.EnableSoftDeletion and User.IsDeleted work

* fix: add handling of the situation where organization is nil
2024-09-15 14:35:44 +08:00
e2ce9ad625 feat: handle null account item issue in CheckPermissionForUpdateUser() (#3202)
* feat: improve the logic of the permission check code for users to modify account items

* fix: add skip operation for deleted account items in update-user API

* fix: add the function of removing deleted account item
2024-09-14 15:00:10 +08:00
64491abc64 feat: fix CORS issue of /api/acs for SAML IdP (#3200)
* fix: fix CORS problem of /api/acs when login with saml idp

* fix: fix origin get null when receive post with http protocol
2024-09-14 12:48:51 +08:00
934a8947c8 feat: fix CAS logout failure caused by Beego session update problem (#3194)
* feat: fix the cas logout failure caused by beego session update problem

* fix: simplify the implementation of logout timer

* fix: change the location of the login success code

* fix: add i18n to CasLogout.js
2024-09-10 21:31:37 +08:00
943edfb48b feat: support QR login for casdoor app (#3190)
* feat: add MFA devices QR code to UserEditPage

* chore: remove mfa devices
2024-09-08 22:38:13 +08:00
0d02b5e768 feat: remove disabled state in syncer.table 2024-09-07 21:08:21 +08:00
ba8d0b5f46 feat: Revert "feat: Users added through LDAP cannot log in using the set password" (#3186)
This reverts commit 973a1df6c2.
2024-09-07 20:55:14 +08:00
973a1df6c2 feat: Users added through LDAP cannot log in using the set password (#3175)
* fix: login will prioritize the use of password set in casdoor and use ldap when use LDAP option in login form or user never change their password in casdoor after sync

* fix: promote if statement
2024-09-06 10:31:34 +08:00
05bfd3a3a3 feat: fix bug that custom SAML providers are removed by GetMaskedApplication() (#3165) 2024-09-05 20:08:56 +08:00
69aa3c8a8b feat: Revert "feat: add Casbin editor's checking in model editor" (#3167)
This reverts commit a1b010a406.
2024-09-03 21:59:06 +08:00
87 changed files with 1804 additions and 215 deletions

View File

@ -13,7 +13,7 @@
<a href="https://github.com/casdoor/casdoor/releases/latest">
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casdoor/casdoor.svg">
</a>
<a href="https://hub.docker.com/repository/docker/casbin/casdoor">
<a href="https://hub.docker.com/r/casbin/casdoor">
<img alt="Docker Image Version (latest semver)" src="https://img.shields.io/badge/Docker%20Hub-latest-brightgreen">
</a>
</p>

View File

@ -77,6 +77,7 @@ p, *, *, POST, /api/verify-code, *, *
p, *, *, POST, /api/reset-email-or-phone, *, *
p, *, *, POST, /api/upload-resource, *, *
p, *, *, GET, /.well-known/openid-configuration, *, *
p, *, *, GET, /.well-known/webfinger, *, *
p, *, *, *, /.well-known/jwks, *, *
p, *, *, GET, /api/get-saml-login, *, *
p, *, *, POST, /api/acs, *, *

View File

@ -23,6 +23,7 @@ isDemoMode = false
batchSize = 100
enableErrorMask = false
enableGzip = true
inactiveTimeoutMinutes =
ldapServerPort = 389
radiusServerPort = 1812
radiusSecret = "secret"

View File

@ -116,6 +116,13 @@ func (c *ApiController) Signup() {
return
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
err = object.CheckEntryIp(clientIp, nil, application, organization, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
msg := object.CheckUserSignup(application, organization, &authForm, c.GetAcceptLanguage())
if msg != "" {
c.ResponseError(msg)
@ -200,6 +207,10 @@ func (c *ApiController) Signup() {
Type: userType,
Password: authForm.Password,
DisplayName: authForm.Name,
Gender: authForm.Gender,
Bio: authForm.Bio,
Tag: authForm.Tag,
Education: authForm.Education,
Avatar: organization.DefaultAvatar,
Email: authForm.Email,
Phone: authForm.Phone,
@ -234,6 +245,10 @@ func (c *ApiController) Signup() {
}
}
if invitation != nil && invitation.SignupGroup != "" {
user.Groups = []string{invitation.SignupGroup}
}
affected, err := object.AddUser(user)
if err != nil {
c.ResponseError(err.Error())

View File

@ -110,6 +110,9 @@ func (c *ApiController) GetApplication() {
}
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
object.CheckEntryIp(clientIp, nil, application, nil, c.GetAcceptLanguage())
c.ResponseOk(object.GetMaskedApplication(application, userId))
}
@ -229,6 +232,11 @@ func (c *ApiController) UpdateApplication() {
return
}
if err = object.CheckIpWhitelist(application.IpWhitelist, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application))
c.ServeJSON()
}
@ -259,6 +267,11 @@ func (c *ApiController) AddApplication() {
return
}
if err = object.CheckIpWhitelist(application.IpWhitelist, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddApplication(&application))
c.ServeJSON()
}

View File

@ -55,6 +55,13 @@ func tokenToResponse(token *object.Token) *Response {
func (c *ApiController) HandleLoggedIn(application *object.Application, user *object.User, form *form.AuthForm) (resp *Response) {
userId := user.GetId()
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
err := object.CheckEntryIp(clientIp, user, application, application.OrganizationObj, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
allowed, err := object.CheckLoginPermission(userId, application)
if err != nil {
c.ResponseError(err.Error(), nil)
@ -256,6 +263,9 @@ func (c *ApiController) GetApplicationLogin() {
}
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
object.CheckEntryIp(clientIp, nil, application, nil, c.GetAcceptLanguage())
application = object.GetMaskedApplication(application, "")
if msg != "" {
c.ResponseError(msg, application)
@ -463,6 +473,15 @@ func (c *ApiController) Login() {
}
password := authForm.Password
if application.OrganizationObj != nil {
password, err = util.GetUnobfuscatedPassword(application.OrganizationObj.PasswordObfuscatorType, application.OrganizationObj.PasswordObfuscatorKey, authForm.Password)
if err != nil {
c.ResponseError(err.Error())
return
}
}
isSigninViaLdap := authForm.SigninMethod == "LDAP"
var isPasswordWithLdapEnabled bool
if authForm.SigninMethod == "Password" {

View File

@ -14,7 +14,11 @@
package controllers
import "github.com/casdoor/casdoor/object"
import (
"strings"
"github.com/casdoor/casdoor/object"
)
// GetOidcDiscovery
// @Title GetOidcDiscovery
@ -42,3 +46,31 @@ func (c *RootController) GetJwks() {
c.Data["json"] = jwks
c.ServeJSON()
}
// GetWebFinger
// @Title GetWebFinger
// @Tag OIDC API
// @Param resource query string true "resource"
// @Success 200 {object} object.WebFinger
// @router /.well-known/webfinger [get]
func (c *RootController) GetWebFinger() {
resource := c.Input().Get("resource")
rels := []string{}
host := c.Ctx.Request.Host
for key, value := range c.Input() {
if strings.HasPrefix(key, "rel") {
rels = append(rels, value...)
}
}
webfinger, err := object.GetWebFinger(resource, rels, host)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = webfinger
c.Ctx.Output.ContentType("application/jrd+json")
c.ServeJSON()
}

View File

@ -65,7 +65,7 @@ func (c *ApiController) GetOrganizations() {
c.ResponseOk(organizations)
} else {
limit := util.ParseInt(limit)
count, err := object.GetOrganizationCount(owner, field, value)
count, err := object.GetOrganizationCount(owner, organizationName, field, value)
if err != nil {
c.ResponseError(err.Error())
return
@ -119,6 +119,11 @@ func (c *ApiController) UpdateOrganization() {
return
}
if err = object.CheckIpWhitelist(organization.IpWhitelist, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateOrganization(id, &organization))
c.ServeJSON()
}
@ -138,7 +143,7 @@ func (c *ApiController) AddOrganization() {
return
}
count, err := object.GetOrganizationCount("", "", "")
count, err := object.GetOrganizationCount("", "", "", "")
if err != nil {
c.ResponseError(err.Error())
return
@ -149,6 +154,11 @@ func (c *ApiController) AddOrganization() {
return
}
if err = object.CheckIpWhitelist(organization.IpWhitelist, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddOrganization(&organization))
c.ServeJSON()
}

View File

@ -370,6 +370,11 @@ func (c *ApiController) AddUser() {
return
}
if err = object.CheckIpWhitelist(user.IpWhitelist, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddUser(&user))
c.ServeJSON()
}
@ -410,6 +415,12 @@ func (c *ApiController) GetEmailAndPhone() {
organization := c.Ctx.Request.Form.Get("organization")
username := c.Ctx.Request.Form.Get("username")
enableErrorMask2 := conf.GetConfigBool("enableErrorMask2")
if enableErrorMask2 {
c.ResponseError("Error")
return
}
user, err := object.GetUserByFields(organization, username)
if err != nil {
c.ResponseError(err.Error())
@ -529,6 +540,23 @@ func (c *ApiController) SetPassword() {
return
}
application, err := object.GetApplicationByUser(targetUser)
if err != nil {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:the application for user %s is not found"), userId))
return
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
err = object.CheckEntryIp(clientIp, targetUser, application, organization, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
targetUser.Password = newPassword
targetUser.UpdateUserPassword(organization)
targetUser.NeedUpdatePassword = false

View File

@ -45,6 +45,15 @@ func (c *ApiController) ResponseOk(data ...interface{}) {
// ResponseError ...
func (c *ApiController) ResponseError(error string, data ...interface{}) {
enableErrorMask2 := conf.GetConfigBool("enableErrorMask2")
if enableErrorMask2 {
error = c.T("subscription:Error")
resp := &Response{Status: "error", Msg: error}
c.ResponseJsonData(resp, data...)
return
}
enableErrorMask := conf.GetConfigBool("enableErrorMask")
if enableErrorMask {
if strings.HasPrefix(error, "The user: ") && strings.HasSuffix(error, " doesn't exist") || strings.HasPrefix(error, "用户: ") && strings.HasSuffix(error, "不存在") {

View File

@ -132,7 +132,8 @@ func (c *ApiController) SendVerificationCode() {
c.ResponseError(err.Error())
return
}
remoteAddr := util.GetIPFromRequest(c.Ctx.Request)
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
if msg := vform.CheckParameter(form.SendVerifyCode, c.GetAcceptLanguage()); msg != "" {
c.ResponseError(msg)
@ -259,7 +260,7 @@ func (c *ApiController) SendVerificationCode() {
return
}
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, remoteAddr, vform.Dest)
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, clientIp, vform.Dest)
case object.VerifyTypePhone:
if vform.Method == LoginVerification || vform.Method == ForgetVerification {
if user != nil && util.GetMaskedPhone(user.Phone) == vform.Dest {
@ -309,7 +310,7 @@ func (c *ApiController) SendVerificationCode() {
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), vform.CountryCode))
return
} else {
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, remoteAddr, phone)
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, clientIp, phone)
}
}

View File

@ -26,6 +26,10 @@ type AuthForm struct {
Name string `json:"name"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
Gender string `json:"gender"`
Bio string `json:"bio"`
Tag string `json:"tag"`
Education string `json:"education"`
Email string `json:"email"`
Phone string `json:"phone"`
Affiliation string `json:"affiliation"`

2
go.mod
View File

@ -11,6 +11,7 @@ require (
github.com/casbin/casbin/v2 v2.77.2
github.com/casdoor/go-sms-sender v0.24.0
github.com/casdoor/gomail/v2 v2.0.1
github.com/casdoor/ldapserver v1.2.0
github.com/casdoor/notify v0.45.0
github.com/casdoor/oss v1.8.0
github.com/casdoor/xorm-adapter/v3 v3.1.0
@ -20,7 +21,6 @@ require (
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
github.com/elimity-com/scim v0.0.0-20230426070224-941a5eac92f3
github.com/fogleman/gg v1.3.0
github.com/forestmgy/ldapserver v1.1.0
github.com/go-asn1-ber/asn1-ber v1.5.5
github.com/go-git/go-git/v5 v5.11.0
github.com/go-ldap/ldap/v3 v3.4.6

4
go.sum
View File

@ -1091,6 +1091,8 @@ github.com/casdoor/go-sms-sender v0.24.0 h1:LNLsce3EG/87I3JS6UiajF3LlQmdIiCgebEu
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/ldapserver v1.2.0 h1:HdSYe+ULU6z9K+2BqgTrJKQRR4//ERAXB64ttOun6Ow=
github.com/casdoor/ldapserver v1.2.0/go.mod h1:VwYU2vqQ2pA8sa00PRekH71R2XmgfzMKhmp1XrrDu2s=
github.com/casdoor/notify v0.45.0 h1:OlaFvcQFjGOgA4mRx07M8AH1gvb5xNo21mcqrVGlLgk=
github.com/casdoor/notify v0.45.0/go.mod h1:wNHQu0tiDROMBIvz0j3Om3Lhd5yZ+AIfnFb8MYb8OLQ=
github.com/casdoor/oss v1.8.0 h1:uuyKhDIp7ydOtV4lpqhAY23Ban2Ln8La8+QT36CwylM=
@ -1237,8 +1239,6 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/forestmgy/ldapserver v1.1.0 h1:gvil4nuLhqPEL8SugCkFhRyA0/lIvRdwZSqlrw63ll4=
github.com/forestmgy/ldapserver v1.1.0/go.mod h1:1RZ8lox1QSY7rmbjdmy+sYQXY4Lp7SpGzpdE3+j3IyM=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=

View File

@ -200,7 +200,7 @@ func (idp *AlipayIdProvider) postWithBody(body interface{}, targetUrl string) ([
formData.Set("sign", sign)
resp, err := idp.Client.PostForm(targetUrl, formData)
resp, err := idp.Client.Post(targetUrl, "application/x-www-form-urlencoded;charset=utf-8", strings.NewReader(formData.Encode()))
if err != nil {
return nil, err
}

View File

@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object"
ldap "github.com/forestmgy/ldapserver"
ldap "github.com/casdoor/ldapserver"
"github.com/lor00x/goldap/message"
)

View File

@ -23,7 +23,7 @@ import (
"github.com/casdoor/casdoor/util"
"github.com/lor00x/goldap/message"
ldap "github.com/forestmgy/ldapserver"
ldap "github.com/casdoor/ldapserver"
"github.com/xorm-io/builder"
)

View File

@ -56,6 +56,7 @@ func main() {
beego.InsertFilter("*", beego.BeforeRouter, routers.StaticFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.AutoSigninFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.TimeoutFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.ApiFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.PrometheusFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
@ -71,6 +72,7 @@ func main() {
beego.BConfig.WebConfig.Session.SessionProviderConfig = conf.GetConfigString("redisEndpoint")
}
beego.BConfig.WebConfig.Session.SessionCookieLifeTime = 3600 * 24 * 30
beego.BConfig.WebConfig.Session.SessionGCMaxLifetime = 3600 * 24 * 30
// beego.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteNoneMode
err := logs.SetLogger(logs.AdapterFile, conf.GetConfigString("logConfig"))

View File

@ -31,15 +31,17 @@ type SigninMethod struct {
}
type SignupItem struct {
Name string `json:"name"`
Visible bool `json:"visible"`
Required bool `json:"required"`
Prompted bool `json:"prompted"`
CustomCss string `json:"customCss"`
Label string `json:"label"`
Placeholder string `json:"placeholder"`
Regex string `json:"regex"`
Rule string `json:"rule"`
Name string `json:"name"`
Visible bool `json:"visible"`
Required bool `json:"required"`
Prompted bool `json:"prompted"`
Type string `json:"type"`
CustomCss string `json:"customCss"`
Label string `json:"label"`
Placeholder string `json:"placeholder"`
Options []string `json:"options"`
Regex string `json:"regex"`
Rule string `json:"rule"`
}
type SigninItem struct {
@ -78,13 +80,14 @@ type Application struct {
EnableSamlCompress bool `json:"enableSamlCompress"`
EnableSamlC14n10 bool `json:"enableSamlC14n10"`
EnableSamlPostBinding bool `json:"enableSamlPostBinding"`
UseEmailAsSamlNameId bool `json:"useEmailAsSamlNameId"`
EnableWebAuthn bool `json:"enableWebAuthn"`
EnableLinkWithEmail bool `json:"enableLinkWithEmail"`
OrgChoiceMode string `json:"orgChoiceMode"`
SamlReplyUrl string `xorm:"varchar(100)" json:"samlReplyUrl"`
Providers []*ProviderItem `xorm:"mediumtext" json:"providers"`
SigninMethods []*SigninMethod `xorm:"varchar(2000)" json:"signinMethods"`
SignupItems []*SignupItem `xorm:"varchar(2000)" json:"signupItems"`
SignupItems []*SignupItem `xorm:"varchar(3000)" json:"signupItems"`
SigninItems []*SigninItem `xorm:"mediumtext" json:"signinItems"`
GrantTypes []string `xorm:"varchar(1000)" json:"grantTypes"`
OrganizationObj *Organization `xorm:"-" json:"organizationObj"`
@ -92,6 +95,7 @@ type Application struct {
Tags []string `xorm:"mediumtext" json:"tags"`
SamlAttributes []*SamlItem `xorm:"varchar(1000)" json:"samlAttributes"`
IsShared bool `json:"isShared"`
IpRestriction string `json:"ipRestriction"`
ClientId string `xorm:"varchar(100)" json:"clientId"`
ClientSecret string `xorm:"varchar(100)" json:"clientSecret"`
@ -105,6 +109,7 @@ type Application struct {
SigninUrl string `xorm:"varchar(200)" json:"signinUrl"`
ForgetUrl string `xorm:"varchar(200)" json:"forgetUrl"`
AffiliationUrl string `xorm:"varchar(100)" json:"affiliationUrl"`
IpWhitelist string `xorm:"varchar(200)" json:"ipWhitelist"`
TermsOfUse string `xorm:"varchar(100)" json:"termsOfUse"`
SignupHtml string `xorm:"mediumtext" json:"signupHtml"`
SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
@ -531,7 +536,7 @@ func GetMaskedApplication(application *Application, userId string) *Application
providerItems := []*ProviderItem{}
for _, providerItem := range application.Providers {
if providerItem.Provider != nil && (providerItem.Provider.Category == "OAuth" || providerItem.Provider.Category == "Web3" || providerItem.Provider.Category == "Captcha") {
if providerItem.Provider != nil && (providerItem.Provider.Category == "OAuth" || providerItem.Provider.Category == "Web3" || providerItem.Provider.Category == "Captcha" || providerItem.Provider.Category == "SAML") {
providerItems = append(providerItems, providerItem)
}
}

View File

@ -539,6 +539,11 @@ func CheckUpdateUser(oldUser, user *User, lang string) string {
return i18n.Translate(lang, "check:Phone already exists")
}
}
if oldUser.IpWhitelist != user.IpWhitelist {
if err := CheckIpWhitelist(user.IpWhitelist, lang); err != nil {
return err.Error()
}
}
return ""
}

100
object/check_ip.go Normal file
View File

@ -0,0 +1,100 @@
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"net"
"strings"
"github.com/casdoor/casdoor/i18n"
)
func CheckEntryIp(clientIp string, user *User, application *Application, organization *Organization, lang string) error {
entryIp := net.ParseIP(clientIp)
if entryIp == nil {
return fmt.Errorf(i18n.Translate(lang, "check:Failed to parse client IP: %s"), clientIp)
} else if entryIp.IsLoopback() {
return nil
}
var err error
if user != nil {
err = isEntryIpAllowd(user.IpWhitelist, entryIp, lang)
if err != nil {
return fmt.Errorf(err.Error() + user.Name)
}
}
if application != nil {
err = isEntryIpAllowd(application.IpWhitelist, entryIp, lang)
if err != nil {
application.IpRestriction = err.Error() + application.Name
return fmt.Errorf(err.Error() + application.Name)
}
}
if organization == nil && application.OrganizationObj != nil {
organization = application.OrganizationObj
}
if organization != nil {
err = isEntryIpAllowd(organization.IpWhitelist, entryIp, lang)
if err != nil {
organization.IpRestriction = err.Error() + organization.Name
return fmt.Errorf(err.Error() + organization.Name)
}
}
return nil
}
func isEntryIpAllowd(ipWhitelistStr string, entryIp net.IP, lang string) error {
if ipWhitelistStr == "" {
return nil
}
ipWhitelist := strings.Split(ipWhitelistStr, ",")
for _, ip := range ipWhitelist {
_, ipNet, err := net.ParseCIDR(ip)
if err != nil {
return err
}
if ipNet == nil {
return fmt.Errorf(i18n.Translate(lang, "check:CIDR for IP: %s should not be empty"), entryIp.String())
}
if ipNet.Contains(entryIp) {
return nil
}
}
return fmt.Errorf(i18n.Translate(lang, "check:Your IP address: %s has been banned according to the configuration of: "), entryIp.String())
}
func CheckIpWhitelist(ipWhitelistStr string, lang string) error {
if ipWhitelistStr == "" {
return nil
}
ipWhiteList := strings.Split(ipWhitelistStr, ",")
for _, ip := range ipWhiteList {
if _, _, err := net.ParseCIDR(ip); err != nil {
return fmt.Errorf(i18n.Translate(lang, "check:%s does not meet the CIDR format requirements: %s"), ip, err.Error())
}
}
return nil
}

View File

@ -182,6 +182,9 @@ func readInitDataFromFile(filePath string) (*InitData, error) {
if organization.Tags == nil {
organization.Tags = []string{}
}
if organization.AccountItems == nil {
organization.AccountItems = []*AccountItem{}
}
}
for _, application := range data.Applications {
if application.Providers == nil {
@ -275,7 +278,9 @@ func initDefinedOrganization(organization *Organization) {
}
}
organization.CreatedTime = util.GetCurrentTime()
organization.AccountItems = getBuiltInAccountItems()
if len(organization.AccountItems) == 0 {
organization.AccountItems = getBuiltInAccountItems()
}
_, err = AddOrganization(organization)
if err != nil {

View File

@ -44,6 +44,18 @@ type OidcDiscovery struct {
EndSessionEndpoint string `json:"end_session_endpoint"`
}
type WebFinger struct {
Subject string `json:"subject"`
Links []WebFingerLink `json:"links"`
Aliases *[]string `json:"aliases,omitempty"`
Properties *map[string]string `json:"properties,omitempty"`
}
type WebFingerLink struct {
Rel string `json:"rel"`
Href string `json:"href"`
}
func isIpAddress(host string) bool {
// Attempt to split the host and port, ignoring the error
hostWithoutPort, _, err := net.SplitHostPort(host)
@ -160,3 +172,43 @@ func GetJsonWebKeySet() (jose.JSONWebKeySet, error) {
return jwks, nil
}
func GetWebFinger(resource string, rels []string, host string) (WebFinger, error) {
wf := WebFinger{}
resourceSplit := strings.Split(resource, ":")
if len(resourceSplit) != 2 {
return wf, fmt.Errorf("invalid resource")
}
resourceType := resourceSplit[0]
resourceValue := resourceSplit[1]
oidcDiscovery := GetOidcDiscovery(host)
switch resourceType {
case "acct":
user, err := GetUserByEmailOnly(resourceValue)
if err != nil {
return wf, err
}
if user == nil {
return wf, fmt.Errorf("user not found")
}
wf.Subject = resource
for _, rel := range rels {
if rel == "http://openid.net/specs/connect/1.0/issuer" {
wf.Links = append(wf.Links, WebFingerLink{
Rel: "http://openid.net/specs/connect/1.0/issuer",
Href: oidcDiscovery.Issuer,
})
}
}
}
return wf, nil
}

View File

@ -56,10 +56,12 @@ type Organization struct {
WebsiteUrl string `xorm:"varchar(100)" json:"websiteUrl"`
Logo string `xorm:"varchar(200)" json:"logo"`
LogoDark string `xorm:"varchar(200)" json:"logoDark"`
Favicon string `xorm:"varchar(100)" json:"favicon"`
Favicon string `xorm:"varchar(200)" json:"favicon"`
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
PasswordOptions []string `xorm:"varchar(100)" json:"passwordOptions"`
PasswordObfuscatorType string `xorm:"varchar(100)" json:"passwordObfuscatorType"`
PasswordObfuscatorKey string `xorm:"varchar(100)" json:"passwordObfuscatorKey"`
CountryCodes []string `xorm:"varchar(200)" json:"countryCodes"`
DefaultAvatar string `xorm:"varchar(200)" json:"defaultAvatar"`
DefaultApplication string `xorm:"varchar(100)" json:"defaultApplication"`
@ -69,19 +71,21 @@ type Organization struct {
MasterPassword string `xorm:"varchar(100)" json:"masterPassword"`
DefaultPassword string `xorm:"varchar(100)" json:"defaultPassword"`
MasterVerificationCode string `xorm:"varchar(100)" json:"masterVerificationCode"`
IpWhitelist string `xorm:"varchar(200)" json:"ipWhitelist"`
InitScore int `json:"initScore"`
EnableSoftDeletion bool `json:"enableSoftDeletion"`
IsProfilePublic bool `json:"isProfilePublic"`
UseEmailAsUsername bool `json:"useEmailAsUsername"`
EnableTour bool `json:"enableTour"`
IpRestriction string `json:"ipRestriction"`
MfaItems []*MfaItem `xorm:"varchar(300)" json:"mfaItems"`
AccountItems []*AccountItem `xorm:"varchar(5000)" json:"accountItems"`
}
func GetOrganizationCount(owner, field, value string) (int64, error) {
func GetOrganizationCount(owner, name, field, value string) (int64, error) {
session := GetSession(owner, -1, -1, field, value, "", "")
return session.Count(&Organization{})
return session.Count(&Organization{Name: name})
}
func GetOrganizations(owner string, name ...string) ([]*Organization, error) {

View File

@ -50,7 +50,7 @@ func maskPassword(recordString string) string {
}
func NewRecord(ctx *context.Context) (*casvisorsdk.Record, error) {
ip := strings.Replace(util.GetIPFromRequest(ctx.Request), ": ", "", -1)
clientIp := strings.Replace(util.GetClientIpFromRequest(ctx.Request), ": ", "", -1)
action := strings.Replace(ctx.Request.URL.Path, "/api/", "", -1)
requestUri := util.FilterQuery(ctx.Request.RequestURI, []string{"accessToken"})
if len(requestUri) > 1000 {
@ -83,7 +83,7 @@ func NewRecord(ctx *context.Context) (*casvisorsdk.Record, error) {
record := casvisorsdk.Record{
Name: util.GenerateId(),
CreatedTime: util.GetCurrentTime(),
ClientIp: ip,
ClientIp: clientIp,
User: "",
Method: ctx.Request.Method,
RequestUri: requestUri,

View File

@ -65,7 +65,11 @@ func NewSamlResponse(application *Application, user *User, host string, certific
assertion.CreateAttr("IssueInstant", now)
assertion.CreateElement("saml:Issuer").SetText(host)
subject := assertion.CreateElement("saml:Subject")
subject.CreateElement("saml:NameID").SetText(user.Name)
nameIDValue := user.Name
if application.UseEmailAsSamlNameId {
nameIDValue = user.Email
}
subject.CreateElement("saml:NameID").SetText(nameIDValue)
subjectConfirmation := subject.CreateElement("saml:SubjectConfirmation")
subjectConfirmation.CreateAttr("Method", "urn:oasis:names:tc:SAML:2.0:cm:bearer")
subjectConfirmationData := subjectConfirmation.CreateElement("saml:SubjectConfirmationData")
@ -184,17 +188,17 @@ type NameIDFormat struct {
}
type SingleSignOnService struct {
XMLName xml.Name
// XMLName xml.Name
Binding string `xml:"Binding,attr"`
Location string `xml:"Location,attr"`
}
type Attribute struct {
// XMLName xml.Name
Xmlns string `xml:"xmlns,attr"`
Name string `xml:"Name,attr"`
NameFormat string `xml:"NameFormat,attr"`
FriendlyName string `xml:"FriendlyName,attr"`
Xmlns string `xml:"xmlns,attr"`
Values []string `xml:"AttributeValue"`
}
@ -386,7 +390,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
}
// NewSamlResponse11 return a saml1.1 response(not 2.0)
func NewSamlResponse11(user *User, requestID string, host string) (*etree.Element, error) {
func NewSamlResponse11(application *Application, user *User, requestID string, host string) (*etree.Element, error) {
samlResponse := &etree.Element{
Space: "samlp",
Tag: "Response",
@ -430,7 +434,11 @@ func NewSamlResponse11(user *User, requestID string, host string) (*etree.Elemen
// nameIdentifier inside subject
nameIdentifier := subject.CreateElement("saml:NameIdentifier")
// nameIdentifier.CreateAttr("Format", "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")
nameIdentifier.SetText(user.Name)
if application.UseEmailAsSamlNameId {
nameIdentifier.SetText(user.Email)
} else {
nameIdentifier.SetText(user.Name)
}
// subjectConfirmation inside subject
subjectConfirmation := subject.CreateElement("saml:SubjectConfirmation")
@ -439,7 +447,11 @@ func NewSamlResponse11(user *User, requestID string, host string) (*etree.Elemen
attributeStatement := assertion.CreateElement("saml:AttributeStatement")
subjectInAttribute := attributeStatement.CreateElement("saml:Subject")
nameIdentifierInAttribute := subjectInAttribute.CreateElement("saml:NameIdentifier")
nameIdentifierInAttribute.SetText(user.Name)
if application.UseEmailAsSamlNameId {
nameIdentifierInAttribute.SetText(user.Email)
} else {
nameIdentifierInAttribute.SetText(user.Name)
}
subjectConfirmationInAttribute := subjectInAttribute.CreateElement("saml:SubjectConfirmation")
subjectConfirmationInAttribute.CreateElement("saml:ConfirmationMethod").SetText("urn:oasis:names:tc:SAML:1.0:cm:artifact")

View File

@ -281,7 +281,7 @@ func GetValidationBySaml(samlRequest string, host string) (string, string, error
return "", "", fmt.Errorf("the application for user %s is not found", userId)
}
samlResponse, err := NewSamlResponse11(user, request.RequestID, host)
samlResponse, err := NewSamlResponse11(application, user, request.RequestID, host)
if err != nil {
return "", "", err
}

View File

@ -206,6 +206,7 @@ type User struct {
ManagedAccounts []ManagedAccount `xorm:"managedAccounts blob" json:"managedAccounts"`
MfaAccounts []MfaAccount `xorm:"mfaAccounts blob" json:"mfaAccounts"`
NeedUpdatePassword bool `json:"needUpdatePassword"`
IpWhitelist string `xorm:"varchar(200)" json:"ipWhitelist"`
}
type Userinfo struct {
@ -696,7 +697,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", "need_update_password",
"yammer", "yandex", "zoom", "custom", "need_update_password", "ip_whitelist",
}
}
if isAdmin {
@ -950,7 +951,17 @@ func DeleteUser(user *User) (bool, error) {
return false, err
}
return deleteUser(user)
organization, err := GetOrganizationByUser(user)
if err != nil {
return false, err
}
if organization != nil && organization.EnableSoftDeletion {
user.IsDeleted = true
user.DeletedTime = util.GetCurrentTime()
return UpdateUser(user.GetId(), user, []string{"is_deleted", "deleted_time"}, false)
} else {
return deleteUser(user)
}
}
func GetUserInfo(user *User, scope string, aud string, host string) (*Userinfo, error) {

View File

@ -271,113 +271,213 @@ func CheckPermissionForUpdateUser(oldUser, newUser *User, isAdmin bool, lang str
if oldUser.Owner != newUser.Owner {
item := GetAccountItemByName("Organization", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Owner = oldUser.Owner
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Name != newUser.Name {
item := GetAccountItemByName("Name", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Name = oldUser.Name
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Id != newUser.Id {
item := GetAccountItemByName("ID", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Id = oldUser.Id
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.DisplayName != newUser.DisplayName {
item := GetAccountItemByName("Display name", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.DisplayName = oldUser.DisplayName
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Avatar != newUser.Avatar {
item := GetAccountItemByName("Avatar", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Avatar = oldUser.Avatar
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Type != newUser.Type {
item := GetAccountItemByName("User type", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Type = oldUser.Type
} else {
itemsChanged = append(itemsChanged, item)
}
}
// The password is *** when not modified
if oldUser.Password != newUser.Password && newUser.Password != "***" {
item := GetAccountItemByName("Password", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Password = oldUser.Password
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Email != newUser.Email {
item := GetAccountItemByName("Email", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Email = oldUser.Email
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Phone != newUser.Phone {
item := GetAccountItemByName("Phone", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Phone = oldUser.Phone
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.CountryCode != newUser.CountryCode {
item := GetAccountItemByName("Country code", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.CountryCode = oldUser.CountryCode
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Region != newUser.Region {
item := GetAccountItemByName("Country/Region", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Region = oldUser.Region
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Location != newUser.Location {
item := GetAccountItemByName("Location", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Location = oldUser.Location
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Affiliation != newUser.Affiliation {
item := GetAccountItemByName("Affiliation", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Affiliation = oldUser.Affiliation
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Title != newUser.Title {
item := GetAccountItemByName("Title", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Title = oldUser.Title
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Homepage != newUser.Homepage {
item := GetAccountItemByName("Homepage", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Homepage = oldUser.Homepage
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Bio != newUser.Bio {
item := GetAccountItemByName("Bio", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Bio = oldUser.Bio
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Tag != newUser.Tag {
item := GetAccountItemByName("Tag", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Tag = oldUser.Tag
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.SignupApplication != newUser.SignupApplication {
item := GetAccountItemByName("Signup application", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.SignupApplication = oldUser.SignupApplication
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Gender != newUser.Gender {
item := GetAccountItemByName("Gender", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Gender = oldUser.Gender
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Birthday != newUser.Birthday {
item := GetAccountItemByName("Birthday", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Birthday = oldUser.Birthday
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Education != newUser.Education {
item := GetAccountItemByName("Education", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Education = oldUser.Education
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.IdCard != newUser.IdCard {
item := GetAccountItemByName("ID card", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.IdCard = oldUser.IdCard
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.IdCardType != newUser.IdCardType {
item := GetAccountItemByName("ID card type", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.IdCardType = oldUser.IdCardType
} else {
itemsChanged = append(itemsChanged, item)
}
}
oldUserPropertiesJson, _ := json.Marshal(oldUser.Properties)
newUserPropertiesJson, _ := json.Marshal(newUser.Properties)
if string(oldUserPropertiesJson) != string(newUserPropertiesJson) {
item := GetAccountItemByName("Properties", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Properties = oldUser.Properties
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.PreferredMfaType != newUser.PreferredMfaType {
item := GetAccountItemByName("Multi-factor authentication", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.PreferredMfaType = oldUser.PreferredMfaType
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Groups == nil {
@ -390,7 +490,11 @@ func CheckPermissionForUpdateUser(oldUser, newUser *User, isAdmin bool, lang str
newUserGroupsJson, _ := json.Marshal(newUser.Groups)
if string(oldUserGroupsJson) != string(newUserGroupsJson) {
item := GetAccountItemByName("Groups", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Groups = oldUser.Groups
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Address == nil {
@ -404,65 +508,125 @@ func CheckPermissionForUpdateUser(oldUser, newUser *User, isAdmin bool, lang str
newUserAddressJson, _ := json.Marshal(newUser.Address)
if string(oldUserAddressJson) != string(newUserAddressJson) {
item := GetAccountItemByName("Address", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Address = oldUser.Address
} else {
itemsChanged = append(itemsChanged, item)
}
}
if newUser.FaceIds != nil {
item := GetAccountItemByName("Face ID", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.FaceIds = oldUser.FaceIds
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.IsAdmin != newUser.IsAdmin {
item := GetAccountItemByName("Is admin", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.IsAdmin = oldUser.IsAdmin
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.IsForbidden != newUser.IsForbidden {
item := GetAccountItemByName("Is forbidden", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.IsForbidden = oldUser.IsForbidden
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.IsDeleted != newUser.IsDeleted {
item := GetAccountItemByName("Is deleted", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.IsDeleted = oldUser.IsDeleted
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.NeedUpdatePassword != newUser.NeedUpdatePassword {
item := GetAccountItemByName("Need update password", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.NeedUpdatePassword = oldUser.NeedUpdatePassword
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.IpWhitelist != newUser.IpWhitelist {
item := GetAccountItemByName("IP whitelist", organization)
if item == nil {
newUser.IpWhitelist = oldUser.IpWhitelist
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Balance != newUser.Balance {
item := GetAccountItemByName("Balance", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Balance = oldUser.Balance
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Score != newUser.Score {
item := GetAccountItemByName("Score", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Score = oldUser.Score
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Karma != newUser.Karma {
item := GetAccountItemByName("Karma", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Karma = oldUser.Karma
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Language != newUser.Language {
item := GetAccountItemByName("Language", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Language = oldUser.Language
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Ranking != newUser.Ranking {
item := GetAccountItemByName("Ranking", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Ranking = oldUser.Ranking
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Currency != newUser.Currency {
item := GetAccountItemByName("Currency", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Currency = oldUser.Currency
} else {
itemsChanged = append(itemsChanged, item)
}
}
if oldUser.Hash != newUser.Hash {
item := GetAccountItemByName("Hash", organization)
itemsChanged = append(itemsChanged, item)
if item == nil {
newUser.Hash = oldUser.Hash
} else {
itemsChanged = append(itemsChanged, item)
}
}
for _, accountItem := range itemsChanged {

View File

@ -166,19 +166,76 @@ func AddToVerificationRecord(user *User, provider *Provider, remoteAddr, recordT
return nil
}
func filterRecordIn24Hours(record *VerificationRecord) *VerificationRecord {
if record == nil {
return nil
}
now := time.Now().Unix()
if now-record.Time > 60*60*24 {
return nil
}
return record
}
func getVerificationRecord(dest string) (*VerificationRecord, error) {
var record VerificationRecord
record := &VerificationRecord{}
record.Receiver = dest
has, err := ormer.Engine.Desc("time").Where("is_used = false").Get(&record)
has, err := ormer.Engine.Desc("time").Where("is_used = false").Get(record)
if err != nil {
return nil, err
}
record = filterRecordIn24Hours(record)
if record == nil {
has = false
}
if !has {
record = &VerificationRecord{}
record.Receiver = dest
has, err = ormer.Engine.Desc("time").Get(record)
if err != nil {
return nil, err
}
record = filterRecordIn24Hours(record)
if record == nil {
has = false
}
if !has {
return nil, nil
}
return record, nil
}
return record, nil
}
func getUnusedVerificationRecord(dest string) (*VerificationRecord, error) {
record := &VerificationRecord{}
record.Receiver = dest
has, err := ormer.Engine.Desc("time").Where("is_used = false").Get(record)
if err != nil {
return nil, err
}
record = filterRecordIn24Hours(record)
if record == nil {
has = false
}
if !has {
return nil, nil
}
return &record, nil
return record, nil
}
func CheckVerificationCode(dest string, code string, lang string) (*VerifyResult, error) {
@ -187,7 +244,9 @@ func CheckVerificationCode(dest string, code string, lang string) (*VerifyResult
return nil, err
}
if record == nil {
return &VerifyResult{noRecordError, i18n.Translate(lang, "verification:The verification code has not been sent yet, or has already been used!")}, nil
return &VerifyResult{noRecordError, i18n.Translate(lang, "verification:The verification code has not been sent yet!")}, nil
} else if record.IsUsed {
return &VerifyResult{noRecordError, i18n.Translate(lang, "verification:The verification code has already been used!")}, nil
}
timeoutInMinutes, err := conf.GetConfigInt64("verificationCodeTimeout")
@ -196,9 +255,6 @@ func CheckVerificationCode(dest string, code string, lang string) (*VerifyResult
}
now := time.Now().Unix()
if now-record.Time > timeoutInMinutes*60*10 {
return &VerifyResult{noRecordError, i18n.Translate(lang, "verification:The verification code has not been sent yet!")}, nil
}
if now-record.Time > timeoutInMinutes*60 {
return &VerifyResult{timeoutError, fmt.Sprintf(i18n.Translate(lang, "verification:You should verify your code in %d min!"), timeoutInMinutes)}, nil
}
@ -211,7 +267,7 @@ func CheckVerificationCode(dest string, code string, lang string) (*VerifyResult
}
func DisableVerificationCode(dest string) error {
record, err := getVerificationRecord(dest)
record, err := getUnusedVerificationRecord(dest)
if record == nil || err != nil {
return nil
}

View File

@ -48,6 +48,10 @@ func CorsFilter(ctx *context.Context) {
originHostname := getHostname(origin)
host := removePort(ctx.Request.Host)
if origin == "null" {
origin = ""
}
if strings.HasPrefix(origin, "http://localhost") || strings.HasPrefix(origin, "https://localhost") || strings.HasPrefix(origin, "http://127.0.0.1") || strings.HasPrefix(origin, "http://casdoor-app") || strings.Contains(origin, ".chromiumapp.org") {
setCorsHeaders(ctx, origin)
return

View File

@ -290,6 +290,7 @@ func initAPI() {
beego.Router("/.well-known/openid-configuration", &controllers.RootController{}, "GET:GetOidcDiscovery")
beego.Router("/.well-known/jwks", &controllers.RootController{}, "*:GetJwks")
beego.Router("/.well-known/webfinger", &controllers.RootController{}, "GET:GetWebFinger")
beego.Router("/cas/:organization/:application/serviceValidate", &controllers.RootController{}, "GET:CasServiceValidate")
beego.Router("/cas/:organization/:application/proxyValidate", &controllers.RootController{}, "GET:CasProxyValidate")

View File

@ -43,6 +43,10 @@ func getWebBuildFolder() string {
return path
}
if util.FileExist(filepath.Join(frontendBaseDir, "index.html")) {
return frontendBaseDir
}
path = filepath.Join(frontendBaseDir, "web/build")
return path
}

64
routers/timeout_filter.go Normal file
View File

@ -0,0 +1,64 @@
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package routers
import (
"fmt"
"sync"
"time"
"github.com/beego/beego/context"
"github.com/casdoor/casdoor/conf"
)
var (
inactiveTimeoutMinutes int64
requestTimeMap sync.Map
)
func init() {
var err error
inactiveTimeoutMinutes, err = conf.GetConfigInt64("inactiveTimeoutMinutes")
if err != nil {
inactiveTimeoutMinutes = 0
}
}
func timeoutLogout(ctx *context.Context, sessionId string) {
requestTimeMap.Delete(sessionId)
ctx.Input.CruSession.Set("username", "")
ctx.Input.CruSession.Set("accessToken", "")
ctx.Input.CruSession.Delete("SessionData")
responseError(ctx, fmt.Sprintf(T(ctx, "auth:Timeout for inactivity of %d minutes"), inactiveTimeoutMinutes))
}
func TimeoutFilter(ctx *context.Context) {
if inactiveTimeoutMinutes <= 0 {
return
}
owner, name := getSubject(ctx)
if owner == "anonymous" || name == "anonymous" {
return
}
sessionId := ctx.Input.CruSession.SessionID()
currentTime := time.Now()
preRequestTime, has := requestTimeMap.Load(sessionId)
requestTimeMap.Store(sessionId, currentTime)
if has && preRequestTime.(time.Time).Add(time.Minute*time.Duration(inactiveTimeoutMinutes)).Before(currentTime) {
timeoutLogout(ctx, sessionId)
}
}

View File

@ -23,50 +23,50 @@ import (
"github.com/beego/beego/logs"
)
func GetIPInfo(clientIP string) string {
if clientIP == "" {
func getIpInfo(clientIp string) string {
if clientIp == "" {
return ""
}
ips := strings.Split(clientIP, ",")
res := ""
for i := range ips {
ip := strings.TrimSpace(ips[i])
// desc := GetDescFromIP(ip)
ipstr := fmt.Sprintf("%s: %s", ip, "")
if i != len(ips)-1 {
res += ipstr + " -> "
} else {
res += ipstr
}
}
ips := strings.Split(clientIp, ",")
res := strings.TrimSpace(ips[0])
//res := ""
//for i := range ips {
// ip := strings.TrimSpace(ips[i])
// ipstr := fmt.Sprintf("%s: %s", ip, "")
// if i != len(ips)-1 {
// res += ipstr + " -> "
// } else {
// res += ipstr
// }
//}
return res
}
func GetIPFromRequest(req *http.Request) string {
clientIP := req.Header.Get("x-forwarded-for")
if clientIP == "" {
func GetClientIpFromRequest(req *http.Request) string {
clientIp := req.Header.Get("x-forwarded-for")
if clientIp == "" {
ipPort := strings.Split(req.RemoteAddr, ":")
if len(ipPort) >= 1 && len(ipPort) <= 2 {
clientIP = ipPort[0]
clientIp = ipPort[0]
} else if len(ipPort) > 2 {
idx := strings.LastIndex(req.RemoteAddr, ":")
clientIP = req.RemoteAddr[0:idx]
clientIP = strings.TrimLeft(clientIP, "[")
clientIP = strings.TrimRight(clientIP, "]")
clientIp = req.RemoteAddr[0:idx]
clientIp = strings.TrimLeft(clientIp, "[")
clientIp = strings.TrimRight(clientIp, "]")
}
}
return GetIPInfo(clientIP)
return getIpInfo(clientIp)
}
func LogInfo(ctx *context.Context, f string, v ...interface{}) {
ipString := fmt.Sprintf("(%s) ", GetIPFromRequest(ctx.Request))
ipString := fmt.Sprintf("(%s) ", GetClientIpFromRequest(ctx.Request))
logs.Info(ipString+f, v...)
}
func LogWarning(ctx *context.Context, f string, v ...interface{}) {
ipString := fmt.Sprintf("(%s) ", GetIPFromRequest(ctx.Request))
ipString := fmt.Sprintf("(%s) ", GetClientIpFromRequest(ctx.Request))
logs.Warning(ipString+f, v...)
}

76
util/obfuscator.go Normal file
View File

@ -0,0 +1,76 @@
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (
"crypto/aes"
"crypto/cipher"
"crypto/des"
"encoding/hex"
"fmt"
)
func unPaddingPkcs7(s []byte) []byte {
length := len(s)
if length == 0 {
return s
}
unPadding := int(s[length-1])
return s[:(length - unPadding)]
}
func decryptDesOrAes(passwordCipher string, block cipher.Block) (string, error) {
passwordCipherBytes, err := hex.DecodeString(passwordCipher)
if err != nil {
return "", err
}
if len(passwordCipherBytes) < block.BlockSize() {
return "", fmt.Errorf("the password ciphertext should contain a random hexadecimal string of length %d at the beginning", block.BlockSize()*2)
}
iv := passwordCipherBytes[:block.BlockSize()]
password := make([]byte, len(passwordCipherBytes)-block.BlockSize())
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(password, passwordCipherBytes[block.BlockSize():])
return string(unPaddingPkcs7(password)), nil
}
func GetUnobfuscatedPassword(passwordObfuscatorType string, passwordObfuscatorKey string, passwordCipher string) (string, error) {
if passwordObfuscatorType == "Plain" || passwordObfuscatorType == "" {
return passwordCipher, nil
} else if passwordObfuscatorType == "DES" || passwordObfuscatorType == "AES" {
key, err := hex.DecodeString(passwordObfuscatorKey)
if err != nil {
return "", err
}
var block cipher.Block
if passwordObfuscatorType == "DES" {
block, err = des.NewCipher(key)
} else {
block, err = aes.NewCipher(key)
}
if err != nil {
return "", err
}
return decryptDesOrAes(passwordCipher, block)
} else {
return "", fmt.Errorf("unsupported password obfuscator type: %s", passwordObfuscatorType)
}
}

View File

@ -51,6 +51,9 @@ func IsPhoneValid(phone string, countryCode string) bool {
}
func IsPhoneAllowInRegin(countryCode string, allowRegions []string) bool {
if ContainsString(allowRegions, "All") {
return true
}
return ContainsString(allowRegions, countryCode)
}

View File

@ -27,6 +27,7 @@
"copy-to-clipboard": "^3.3.1",
"core-js": "^3.25.0",
"craco-less": "^2.0.0",
"crypto-js": "^4.2.0",
"echarts": "^5.4.3",
"ethers": "5.6.9",
"face-api.js": "^0.22.2",

View File

@ -362,7 +362,11 @@ class App extends Component {
if (this.isDoorPages()) {
return (
<ConfigProvider theme={{
algorithm: Setting.getAlgorithm(["default"]),
token: {
colorPrimary: this.state.themeData.colorPrimary,
borderRadius: this.state.themeData.borderRadius,
},
algorithm: Setting.getAlgorithm(this.state.themeAlgorithm),
}}>
<StyleProvider hashPriority="high" transformers={[legacyLogicalPropertiesTransformer]}>
<Layout id="parent-area">
@ -372,6 +376,7 @@ class App extends Component {
<EntryPage
account={this.state.account}
theme={this.state.themeData}
themeAlgorithm={this.state.themeAlgorithm}
updateApplication={(application) => {
this.setState({
application: application,
@ -446,7 +451,6 @@ class App extends Component {
setLogoutState={() => {
this.setState({
account: null,
themeAlgorithm: ["default"],
});
}}
/>

View File

@ -129,6 +129,15 @@ img {
background-attachment: fixed;
}
.loginBackgroundDark {
flex: auto;
display: flex;
align-items: center;
background: #000 no-repeat;
background-size: 100% 100%;
background-attachment: fixed;
}
.ant-menu-horizontal {
border-bottom: none !important;
}

View File

@ -46,12 +46,18 @@ require("codemirror/mode/css/css");
const {Option} = Select;
const template = `<style>
.login-panel{
.login-panel {
padding: 40px 70px 0 70px;
border-radius: 10px;
background-color: #ffffff;
box-shadow: 0 0 30px 20px rgba(0, 0, 0, 0.20);
}
}
.login-panel-dark {
padding: 40px 70px 0 70px;
border-radius: 10px;
background-color: #333333;
box-shadow: 0 0 30px 20px rgba(255, 255, 255, 0.20);
}
</style>`;
const previewGrid = Setting.isMobile() ? 22 : 11;
@ -592,6 +598,16 @@ class ApplicationEditPage extends React.Component {
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:IP whitelist"), i18next.t("general:IP whitelist - Tooltip"))} :
</Col>
<Col span={22} >
<Input placeholder = {this.state.application.organizationObj?.ipWhitelist} value={this.state.application.ipWhiteList} onChange={e => {
this.updateApplicationField("ipWhitelist", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("signup:Terms of Use"), i18next.t("signup:Terms of Use - Tooltip"))} :
@ -703,6 +719,16 @@ class ApplicationEditPage extends React.Component {
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}}>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
{Setting.getLabel(i18next.t("application:Use Email as NameID"), i18next.t("application:Use Email as NameID - Tooltip"))} :
</Col>
<Col span={1}>
<Switch checked={this.state.application.useEmailAsSamlNameId} onChange={checked => {
this.updateApplicationField("useEmailAsSamlNameId", checked);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
{Setting.getLabel(i18next.t("application:Enable SAML POST binding"), i18next.t("application:Enable SAML POST binding - Tooltip"))} :
@ -967,6 +993,7 @@ class ApplicationEditPage extends React.Component {
<SigninTable
title={i18next.t("application:Signin items")}
table={this.state.application.signinItems}
themeAlgorithm={this.state.themeAlgorithm}
onUpdateTable={(value) => {
this.updateApplicationField("signinItems", value);
}}

97
web/src/CasbinEditor.js Normal file
View File

@ -0,0 +1,97 @@
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React, {useCallback, useEffect, useRef, useState} from "react";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";
import "codemirror/mode/properties/properties";
import * as Setting from "./Setting";
import IframeEditor from "./IframeEditor";
import {Tabs} from "antd";
const {TabPane} = Tabs;
const CasbinEditor = ({model, onModelTextChange}) => {
const [activeKey, setActiveKey] = useState("advanced");
const iframeRef = useRef(null);
const [localModelText, setLocalModelText] = useState(model.modelText);
const handleModelTextChange = useCallback((newModelText) => {
if (!Setting.builtInObject(model)) {
setLocalModelText(newModelText);
onModelTextChange(newModelText);
}
}, [model, onModelTextChange]);
const syncModelText = useCallback(() => {
return new Promise((resolve) => {
if (activeKey === "advanced" && iframeRef.current) {
const handleSyncMessage = (event) => {
if (event.data.type === "modelUpdate") {
window.removeEventListener("message", handleSyncMessage);
handleModelTextChange(event.data.modelText);
resolve();
}
};
window.addEventListener("message", handleSyncMessage);
iframeRef.current.getModelText();
} else {
resolve();
}
});
}, [activeKey, handleModelTextChange]);
const handleTabChange = (key) => {
syncModelText().then(() => {
setActiveKey(key);
if (key === "advanced" && iframeRef.current) {
iframeRef.current.updateModelText(localModelText);
}
});
};
useEffect(() => {
setLocalModelText(model.modelText);
}, [model.modelText]);
return (
<div style={{height: "100%", width: "100%", display: "flex", flexDirection: "column"}}>
<Tabs activeKey={activeKey} onChange={handleTabChange} style={{flex: "0 0 auto", marginTop: "-10px"}}>
<TabPane tab="Basic Editor" key="basic" />
<TabPane tab="Advanced Editor" key="advanced" />
</Tabs>
<div style={{flex: "1 1 auto", overflow: "hidden"}}>
{activeKey === "advanced" ? (
<IframeEditor
ref={iframeRef}
initialModelText={localModelText}
onModelTextChange={handleModelTextChange}
style={{width: "100%", height: "100%"}}
/>
) : (
<CodeMirror
value={localModelText}
className="full-height-editor no-horizontal-scroll-editor"
options={{mode: "properties", theme: "default"}}
onBeforeChange={(editor, data, value) => {
handleModelTextChange(value);
}}
/>
)}
</div>
</div>
);
};
export default CasbinEditor;

View File

@ -34,6 +34,7 @@ import PaymentResultPage from "./PaymentResultPage";
import QrCodePage from "./QrCodePage";
import CaptchaPage from "./CaptchaPage";
import CustomHead from "./basic/CustomHead";
import * as Util from "./auth/Util";
class EntryPage extends React.Component {
constructor(props) {
@ -94,10 +95,20 @@ class EntryPage extends React.Component {
});
};
if (this.state.application?.ipRestriction) {
return Util.renderMessageLarge(this, this.state.application.ipRestriction);
}
if (this.state.application?.organizationObj?.ipRestriction) {
return Util.renderMessageLarge(this, this.state.application.organizationObj.ipRestriction);
}
const isDarkMode = this.props.themeAlgorithm.includes("dark");
return (
<React.Fragment>
<CustomHead headerHtml={this.state.application?.headerHtml} />
<div className="loginBackground"
<div className={`${isDarkMode ? "loginBackgroundDark" : "loginBackground"}`}
style={{backgroundImage: Setting.inIframe() || Setting.isMobile() ? null : `url(${this.state.application?.formBackgroundUrl})`}}>
<Spin size="large" spinning={this.state.application === undefined && this.state.pricing === undefined} tip={i18next.t("login:Loading")}
style={{margin: "0 auto"}} />
@ -124,6 +135,7 @@ class EntryPage extends React.Component {
<Route exact path="/captcha" render={(props) => <CaptchaPage {...props} />} />
</Switch>
</div>
</React.Fragment>
);
}

66
web/src/IframeEditor.js Normal file
View File

@ -0,0 +1,66 @@
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React, {forwardRef, useEffect, useImperativeHandle, useRef, useState} from "react";
const IframeEditor = forwardRef(({initialModelText, onModelTextChange}, ref) => {
const iframeRef = useRef(null);
const [iframeReady, setIframeReady] = useState(false);
useEffect(() => {
const handleMessage = (event) => {
if (event.origin !== "https://editor.casbin.org") {return;}
if (event.data.type === "modelUpdate") {
onModelTextChange(event.data.modelText);
} else if (event.data.type === "iframeReady") {
setIframeReady(true);
iframeRef.current?.contentWindow.postMessage({
type: "initializeModel",
modelText: initialModelText,
}, "*");
}
};
window.addEventListener("message", handleMessage);
return () => window.removeEventListener("message", handleMessage);
}, [onModelTextChange, initialModelText]);
useImperativeHandle(ref, () => ({
getModelText: () => {
iframeRef.current?.contentWindow.postMessage({type: "getModelText"}, "*");
},
updateModelText: (newModelText) => {
if (iframeReady) {
iframeRef.current?.contentWindow.postMessage({
type: "updateModelText",
modelText: newModelText,
}, "*");
}
},
}));
return (
<iframe
ref={iframeRef}
src="https://editor.casbin.org/model-editor"
frameBorder="0"
width="100%"
height="500px"
title="Casbin Model Editor"
/>
);
});
export default IframeEditor;

View File

@ -20,6 +20,7 @@ import * as ApplicationBackend from "./backend/ApplicationBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import copy from "copy-to-clipboard";
import * as GroupBackend from "./backend/GroupBackend";
const {Option} = Select;
@ -33,6 +34,7 @@ class InvitationEditPage extends React.Component {
invitation: null,
organizations: [],
applications: [],
groups: [],
mode: props.location.mode !== undefined ? props.location.mode : "edit",
};
}
@ -41,6 +43,7 @@ class InvitationEditPage extends React.Component {
this.getInvitation();
this.getOrganizations();
this.getApplicationsByOrganization(this.state.organizationName);
this.getGroupsByOrganization(this.state.organizationName);
}
getInvitation() {
@ -75,6 +78,17 @@ class InvitationEditPage extends React.Component {
});
}
getGroupsByOrganization(organizationName) {
GroupBackend.getGroups(organizationName)
.then((res) => {
if (res.status === "ok") {
this.setState({
groups: res.data,
});
}
});
}
parseInvitationField(key, value) {
if ([""].includes(key)) {
value = Setting.myParseInt(value);
@ -120,7 +134,7 @@ class InvitationEditPage extends React.Component {
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
</Col>
<Col span={22} >
<Select virtual={false} style={{width: "100%"}} disabled={!Setting.isAdminUser(this.props.account) || isCreatedByPlan} value={this.state.invitation.owner} onChange={(value => {this.updateInvitationField("owner", value); this.getApplicationsByOrganization(value);})}>
<Select virtual={false} style={{width: "100%"}} disabled={!Setting.isAdminUser(this.props.account) || isCreatedByPlan} value={this.state.invitation.owner} onChange={(value => {this.updateInvitationField("owner", value); this.getApplicationsByOrganization(value);this.getGroupsByOrganization(value);})}>
{
this.state.organizations.map((organization, index) => <Option key={index} value={organization.name}>{organization.name}</Option>)
}
@ -204,6 +218,21 @@ class InvitationEditPage extends React.Component {
]} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Signup group"), i18next.t("provider:Signup group - Tooltip"))} :
</Col>
<Col span={22} >
<Select virtual={false} style={{width: "100%"}} value={this.state.invitation.signupGroup} onChange={(value => {this.updateInvitationField("signupGroup", value);})}>
<Option key={""} value={""}>
{i18next.t("general:Default")}
</Option>
{
this.state.groups.map((group, index) => <Option key={index} value={`${group.owner}/${group.name}`}>{group.name}</Option>)
}
</Select>
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("signup:Username"), i18next.t("signup:Username - Tooltip"))} :

View File

@ -18,11 +18,7 @@ import * as ModelBackend from "./backend/ModelBackend";
import * as OrganizationBackend from "./backend/OrganizationBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";
require("codemirror/mode/properties/properties");
import ModelEditor from "./CasbinEditor";
const {Option} = Select;
@ -147,16 +143,10 @@ class ModelEditPage extends React.Component {
{Setting.getLabel(i18next.t("model:Model text"), i18next.t("model:Model text - Tooltip"))} :
</Col>
<Col span={22}>
<div style={{width: "100%"}} >
<CodeMirror
value={this.state.model.modelText}
options={{mode: "properties", theme: "default"}}
onBeforeChange={(editor, data, value) => {
if (Setting.builtInObject(this.state.model)) {
return;
}
this.updateModelField("modelText", value);
}}
<div style={{position: "relative", height: "500px"}} >
<ModelEditor
model={this.state.model}
onModelTextChange={(value) => this.updateModelField("modelText", value)}
/>
</div>
</Col>

View File

@ -19,6 +19,7 @@ import * as ApplicationBackend from "./backend/ApplicationBackend";
import * as LdapBackend from "./backend/LdapBackend";
import * as Setting from "./Setting";
import * as Conf from "./Conf";
import * as Obfuscator from "./auth/Obfuscator";
import i18next from "i18next";
import {LinkOutlined} from "@ant-design/icons";
import LdapTable from "./table/LdapTable";
@ -112,6 +113,22 @@ class OrganizationEditPage extends React.Component {
});
}
updatePasswordObfuscator(key, value) {
const organization = this.state.organization;
if (organization.passwordObfuscatorType === "") {
organization.passwordObfuscatorType = "Plain";
}
if (key === "type") {
organization.passwordObfuscatorType = value;
organization.passwordObfuscatorKey = Obfuscator.getRandomKeyForObfuscator(value);
} else if (key === "key") {
organization.passwordObfuscatorKey = value;
}
this.setState({
organization: organization,
});
}
renderOrganization() {
return (
<Card size="small" title={
@ -294,6 +311,34 @@ class OrganizationEditPage extends React.Component {
/>
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Password obfuscator"), i18next.t("general:Password obfuscator - Tooltip"))} :
</Col>
<Col span={22} >
<Select virtual={false} style={{width: "100%"}}
value={this.state.organization.passwordObfuscatorType}
onChange={(value => {this.updatePasswordObfuscator("type", value);})}>
{
[
{id: "Plain", name: "Plain"},
{id: "AES", name: "AES"},
{id: "DES", name: "DES"},
].map((obfuscatorType, index) => <Option key={index} value={obfuscatorType.id}>{obfuscatorType.name}</Option>)
}
</Select>
</Col>
</Row>
{
(this.state.organization.passwordObfuscatorType === "Plain" || this.state.organization.passwordObfuscatorType === "") ? null : (<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Password obf key"), i18next.t("general:Password obf key - Tooltip"))} :
</Col>
<Col span={22} >
<Input value={this.state.organization.passwordObfuscatorKey} onChange={(e) => {this.updatePasswordObfuscator("key", e.target.value);}} />
</Col>
</Row>)
}
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Supported country codes"), i18next.t("general:Supported country codes - Tooltip"))} :
@ -305,6 +350,7 @@ class OrganizationEditPage extends React.Component {
}}
filterOption={(input, option) => (option?.text ?? "").toLowerCase().includes(input.toLowerCase())}
>
{Setting.getCountryCodeOption({name: i18next.t("organization:All"), code: "All", phone: 0})}
{
Setting.getCountryCodeData().map((country) => Setting.getCountryCodeOption(country))
}
@ -406,6 +452,16 @@ class OrganizationEditPage extends React.Component {
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:IP whitelist"), i18next.t("general:IP whitelist - Tooltip"))} :
</Col>
<Col span={22} >
<Input value={this.state.organization.ipWhitelist} onChange={e => {
this.updateOrganizationField("ipWhitelist", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
{Setting.getLabel(i18next.t("organization:Init score"), i18next.t("organization:Init score - Tooltip"))} :
@ -528,6 +584,12 @@ class OrganizationEditPage extends React.Component {
const organization = Setting.deepCopy(this.state.organization);
organization.accountItems = organization.accountItems?.filter(accountItem => accountItem.name !== "Please select an account item");
const passwordObfuscatorErrorMessage = Obfuscator.checkPasswordObfuscator(organization.passwordObfuscatorType, organization.passwordObfuscatorKey);
if (passwordObfuscatorErrorMessage.length > 0) {
Setting.showMessage("error", passwordObfuscatorErrorMessage);
return;
}
OrganizationBackend.updateOrganization(this.state.organization.owner, this.state.organizationName, organization)
.then((res) => {
if (res.status === "ok") {

View File

@ -35,6 +35,8 @@ class OrganizationListPage extends BaseListPage {
passwordType: "plain",
PasswordSalt: "",
passwordOptions: [],
passwordObfuscatorType: "Plain",
passwordObfuscatorKey: "",
countryCodes: ["US"],
defaultAvatar: `${Setting.StaticBaseUrl}/img/casbin.svg`,
defaultApplication: "",

View File

@ -418,6 +418,9 @@ export function getCountryCode(country) {
}
export function getCountryCodeData(countryCodes = phoneNumber.getCountries()) {
if (countryCodes?.includes("All")) {
countryCodes = phoneNumber.getCountries();
}
return countryCodes?.map((countryCode) => {
if (phoneNumber.isSupportedCountry(countryCode)) {
const name = initCountries().getName(countryCode, getLanguage());
@ -436,10 +439,10 @@ export function getCountryCodeOption(country) {
<Option key={country.code} value={country.code} label={`+${country.phone}`} text={`${country.name}, ${country.code}, ${country.phone}`} >
<div style={{display: "flex", justifyContent: "space-between", marginRight: "10px"}}>
<div>
{getCountryImage(country)}
{country.code === "All" ? null : getCountryImage(country)}
{`${country.name}`}
</div>
{`+${country.phone}`}
{country.code === "All" ? null : `+${country.phone}`}
</div>
</Option>
);
@ -1168,7 +1171,7 @@ export function renderLogo(application) {
function isSigninMethodEnabled(application, signinMethod) {
if (application && application.signinMethods) {
return application.signinMethods.filter(item => item.name === signinMethod).length > 0;
return application.signinMethods.filter(item => item.name === signinMethod && item.rule !== "Hide-Password").length > 0;
} else {
return false;
}
@ -1554,3 +1557,7 @@ export function getCurrencyText(product) {
return "(Unknown currency)";
}
}
export function isDarkTheme(themeAlgorithm) {
return themeAlgorithm && themeAlgorithm.includes("dark");
}

View File

@ -434,10 +434,9 @@ class SyncerEditPage extends React.Component {
{Setting.getLabel(i18next.t("syncer:Table"), i18next.t("syncer:Table - Tooltip"))} :
</Col>
<Col span={22} >
<Input value={this.state.syncer.table}
disabled={this.state.syncer.type === "Keycloak"} onChange={e => {
this.updateSyncerField("table", e.target.value);
}} />
<Input value={this.state.syncer.table} onChange={e => {
this.updateSyncerField("table", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >

View File

@ -1050,6 +1050,8 @@ class UserEditPage extends React.Component {
<MfaAccountTable
title={i18next.t("user:MFA accounts")}
table={this.state.user.mfaAccounts}
accessToken={this.props.account?.accessToken}
icon={this.state.user.avatar}
onUpdateTable={(table) => {this.updateUserField("mfaAccounts", table);}}
/>
</Col>
@ -1068,6 +1070,19 @@ class UserEditPage extends React.Component {
</Col>
</Row>
);
} else if (accountItem.name === "IP whitelist") {
return (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:IP whitelist"), i18next.t("general:IP whitelist - Tooltip"))} :
</Col>
<Col span={22}>
<Input value={this.state.user.ipWhitelist} onChange={e => {
this.updateUserField("ipWhitelist", e.target.value);
}} />
</Col>
</Row>
);
}
}

View File

@ -34,25 +34,42 @@ class CasLogout extends React.Component {
UNSAFE_componentWillMount() {
const params = new URLSearchParams(this.props.location.search);
const logoutInterval = 100;
const logoutTimeOut = (redirectUri) => {
setTimeout(() => {
AuthBackend.getAccount().then((accountRes) => {
if (accountRes.status === "ok") {
AuthBackend.logout().then((logoutRes) => {
if (logoutRes.status === "ok") {
logoutTimeOut(logoutRes.data2);
} else {
Setting.showMessage("error", `${i18next.t("login:Failed to log out")}: ${logoutRes.msg}`);
}
});
} else {
Setting.showMessage("success", i18next.t("application:Logged out successfully"));
this.props.onUpdateAccount(null);
if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") {
Setting.goToLink(redirectUri);
} else if (params.has("service")) {
Setting.goToLink(params.get("service"));
} else {
Setting.goToLinkSoft(this, `/cas/${this.state.owner}/${this.state.applicationName}/login`);
}
}
});
}, logoutInterval);
};
AuthBackend.logout()
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", "Logged out successfully");
this.props.onUpdateAccount(null);
const redirectUri = res.data2;
if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") {
Setting.goToLink(redirectUri);
} else if (params.has("service")) {
Setting.goToLink(params.get("service"));
} else {
Setting.goToLinkSoft(this, `/cas/${this.state.owner}/${this.state.applicationName}/login`);
}
logoutTimeOut(res.data2);
} else {
Setting.showMessage("error", `Failed to log out: ${res.msg}`);
Setting.showMessage("error", `${i18next.t("login:Failed to log out")}: ${res.msg}`);
}
});
}
render() {

View File

@ -19,6 +19,7 @@ import {withRouter} from "react-router-dom";
import * as UserWebauthnBackend from "../backend/UserWebauthnBackend";
import OrganizationSelect from "../common/select/OrganizationSelect";
import * as Conf from "../Conf";
import * as Obfuscator from "./Obfuscator";
import * as AuthBackend from "./AuthBackend";
import * as OrganizationBackend from "../backend/OrganizationBackend";
import * as ApplicationBackend from "../backend/ApplicationBackend";
@ -51,7 +52,6 @@ class LoginPage extends React.Component {
username: null,
validEmailOrPhone: false,
validEmail: false,
enableCaptchaModal: CaptchaRule.Never,
openCaptchaModal: false,
openFaceRecognitionModal: false,
verifyCaptcha: undefined,
@ -92,17 +92,6 @@ class LoginPage extends React.Component {
}
if (prevProps.application !== this.props.application) {
this.setState({loginMethod: this.getDefaultLoginMethod(this.props.application)});
const captchaProviderItems = this.getCaptchaProviderItems(this.props.application);
if (captchaProviderItems) {
if (captchaProviderItems.some(providerItem => providerItem.rule === "Always")) {
this.setState({enableCaptchaModal: CaptchaRule.Always});
} else if (captchaProviderItems.some(providerItem => providerItem.rule === "Dynamic")) {
this.setState({enableCaptchaModal: CaptchaRule.Dynamic});
} else {
this.setState({enableCaptchaModal: CaptchaRule.Never});
}
}
}
if (prevProps.account !== this.props.account && this.props.account !== undefined) {
@ -132,6 +121,19 @@ class LoginPage extends React.Component {
}
}
getCaptchaRule(application) {
const captchaProviderItems = this.getCaptchaProviderItems(application);
if (captchaProviderItems) {
if (captchaProviderItems.some(providerItem => providerItem.rule === "Always")) {
return CaptchaRule.Always;
} else if (captchaProviderItems.some(providerItem => providerItem.rule === "Dynamic")) {
return CaptchaRule.Dynamic;
} else {
return CaptchaRule.Never;
}
}
}
checkCaptchaStatus(values) {
AuthBackend.getCaptchaStatus(values)
.then((res) => {
@ -379,13 +381,22 @@ class LoginPage extends React.Component {
return;
}
if (this.state.loginMethod === "password" || this.state.loginMethod === "ldap") {
if (this.state.enableCaptchaModal === CaptchaRule.Always) {
const organization = this.getApplicationObj()?.organizationObj;
const [passwordCipher, errorMessage] = Obfuscator.encryptByPasswordObfuscator(organization?.passwordObfuscatorType, organization?.passwordObfuscatorKey, values["password"]);
if (errorMessage.length > 0) {
Setting.showMessage("error", errorMessage);
return;
} else {
values["password"] = passwordCipher;
}
const captchaRule = this.getCaptchaRule(this.getApplicationObj());
if (captchaRule === CaptchaRule.Always) {
this.setState({
openCaptchaModal: true,
values: values,
});
return;
} else if (this.state.enableCaptchaModal === CaptchaRule.Dynamic) {
} else if (captchaRule === CaptchaRule.Dynamic) {
this.checkCaptchaStatus(values);
return;
}
@ -902,7 +913,7 @@ class LoginPage extends React.Component {
}
renderCaptchaModal(application) {
if (this.state.enableCaptchaModal === CaptchaRule.Never) {
if (this.getCaptchaRule(this.getApplicationObj()) === CaptchaRule.Never) {
return null;
}
const captchaProviderItems = this.getCaptchaProviderItems(application);
@ -938,7 +949,7 @@ class LoginPage extends React.Component {
signinItem.label ? Setting.renderSignupLink(application, signinItem.label) :
(
<React.Fragment>
{i18next.t("login:No account?")}
{i18next.t("login:No account?")}&nbsp;
{
Setting.renderSignupLink(application, i18next.t("login:sign up now"))
}
@ -1125,6 +1136,9 @@ class LoginPage extends React.Component {
]);
application?.signinMethods?.forEach((signinMethod) => {
if (signinMethod.rule === "Hide-Password") {
return;
}
const item = itemsMap.get(generateItemKey(signinMethod.name, signinMethod.rule));
if (item) {
let label = signinMethod.name === signinMethod.displayName ? item.label : signinMethod.displayName;
@ -1279,7 +1293,7 @@ class LoginPage extends React.Component {
<div className="login-content" style={{margin: this.props.preview ?? this.parseOffset(application.formOffset)}}>
{Setting.inIframe() || Setting.isMobile() ? null : <div dangerouslySetInnerHTML={{__html: application.formCss}} />}
{Setting.inIframe() || !Setting.isMobile() ? null : <div dangerouslySetInnerHTML={{__html: application.formCssMobile}} />}
<div className="login-panel">
<div className={Setting.isDarkTheme(this.props.themeAlgorithm) ? "login-panel-dark" : "login-panel"}>
<div className="side-image" style={{display: application.formOffset !== 4 ? "none" : null}}>
<div dangerouslySetInnerHTML={{__html: application.formSideHtml}} />
</div>

View File

@ -0,0 +1,95 @@
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import CryptoJS from "crypto-js";
import i18next from "i18next";
export function getRandomKeyForObfuscator(obfuscatorType) {
if (obfuscatorType === "DES") {
return getRandomHexKey(16);
} else if (obfuscatorType === "AES") {
return getRandomHexKey(32);
} else {
return "";
}
}
export const passwordObfuscatorKeyRegexes = {
"DES": /^[1-9a-f]{16}$/,
"AES": /^[1-9a-f]{32}$/,
};
function encrypt(cipher, key, iv, password) {
const encrypted = cipher.encrypt(
CryptoJS.enc.Hex.parse(Buffer.from(password, "utf-8").toString("hex")),
CryptoJS.enc.Hex.parse(key),
{
iv: iv,
mode: CryptoJS.mode.CBC,
pad: CryptoJS.pad.Pkcs7,
}
);
return iv.concat(encrypted.ciphertext).toString(CryptoJS.enc.Hex);
}
export function checkPasswordObfuscator(passwordObfuscatorType, passwordObfuscatorKey) {
if (passwordObfuscatorType === undefined) {
return i18next.t("organization:failed to get password obfuscator");
} else if (passwordObfuscatorType === "Plain" || passwordObfuscatorType === "") {
return "";
} else if (passwordObfuscatorType === "AES" || passwordObfuscatorType === "DES") {
if (passwordObfuscatorKeyRegexes[passwordObfuscatorType].test(passwordObfuscatorKey)) {
return "";
} else {
return `${i18next.t("organization:The password obfuscator key doesn't match the regex")}: ${passwordObfuscatorKeyRegexes[passwordObfuscatorType].source}`;
}
} else {
return `${i18next.t("organization:unsupported password obfuscator type")}: ${passwordObfuscatorType}`;
}
}
export function encryptByPasswordObfuscator(passwordObfuscatorType, passwordObfuscatorKey, password) {
const passwordObfuscatorErrorMessage = checkPasswordObfuscator(passwordObfuscatorType, passwordObfuscatorKey);
if (passwordObfuscatorErrorMessage.length > 0) {
return ["", passwordObfuscatorErrorMessage];
} else {
if (passwordObfuscatorType === "Plain" || passwordObfuscatorType === "") {
return [password, ""];
} else if (passwordObfuscatorType === "AES") {
return [encryptByAes(passwordObfuscatorKey, password), ""];
} else if (passwordObfuscatorType === "DES") {
return [encryptByDes(passwordObfuscatorKey, password), ""];
}
}
}
function encryptByDes(key, password) {
const iv = CryptoJS.lib.WordArray.random(8);
return encrypt(CryptoJS.DES, key, iv, password);
}
function encryptByAes(key, password) {
const iv = CryptoJS.lib.WordArray.random(16);
return encrypt(CryptoJS.AES, key, iv, password);
}
function getRandomHexKey(length) {
const characters = "123456789abcdef";
let key = "";
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * characters.length);
key += characters[randomIndex];
}
return key;
}

View File

@ -13,7 +13,7 @@
// limitations under the License.
import React from "react";
import {Button, Form, Input, Radio, Result, Row, message} from "antd";
import {Button, Form, Input, Radio, Result, Row, Select, message} from "antd";
import * as Setting from "../Setting";
import * as AuthBackend from "./AuthBackend";
import * as ProviderButton from "./ProviderButton";
@ -50,6 +50,38 @@ const formItemLayout = {
},
};
const renderFormItem = (signupItem) => {
const commonProps = {
name: signupItem.name.toLowerCase(),
label: signupItem.label || signupItem.name,
rules: [
{
required: signupItem.required,
message: i18next.t(`signup:Please input your ${signupItem.label || signupItem.name}!`),
},
],
};
if (!signupItem.type || signupItem.type === "Input") {
return (
<Form.Item {...commonProps}>
<Input placeholder={signupItem.placeholder} />
</Form.Item>
);
} else if (signupItem.type === "Single Choice" || signupItem.type === "Multiple Choices") {
return (
<Form.Item {...commonProps}>
<Select
mode={signupItem.type === "Multiple Choices" ? "multiple" : "single"}
placeholder={signupItem.placeholder}
showSearch={false}
options={signupItem.options.map(option => ({label: option, value: option}))}
/>
</Form.Item>
);
}
};
export const tailFormItemLayout = {
wrapperCol: {
xs: {
@ -198,6 +230,22 @@ class SignupPage extends React.Component {
onFinish(values) {
const application = this.getApplicationObj();
if (Array.isArray(values.gender)) {
values.gender = values.gender.join(", ");
}
if (Array.isArray(values.bio)) {
values.bio = values.bio.join(", ");
}
if (Array.isArray(values.tag)) {
values.tag = values.tag.join(", ");
}
if (Array.isArray(values.education)) {
values.education = values.education.join(", ");
}
const params = new URLSearchParams(window.location.search);
values.plan = params.get("plan");
values.pricing = params.get("pricing");
@ -238,6 +286,7 @@ class SignupPage extends React.Component {
}
renderFormItem(application, signupItem) {
const validItems = ["Gender", "Bio", "Tag", "Education"];
if (!signupItem.visible) {
return null;
}
@ -366,7 +415,9 @@ class SignupPage extends React.Component {
},
]}
>
<RegionSelect className="signup-region-select" onChange={(value) => {this.setState({region: value});}} />
<RegionSelect className="signup-region-select" onChange={(value) => {
this.setState({region: value});
}} />
</Form.Item>
);
} else if (signupItem.name === "Email" || signupItem.name === "Phone" || signupItem.name === "Email or Phone" || signupItem.name === "Phone or Email") {
@ -669,8 +720,9 @@ class SignupPage extends React.Component {
</span>
);
})
);
} else if (validItems.includes(signupItem.name)) {
return renderFormItem(signupItem);
}
}
@ -790,7 +842,7 @@ class SignupPage extends React.Component {
<div className="login-content" style={{margin: this.props.preview ?? this.parseOffset(application.formOffset)}}>
{Setting.inIframe() || Setting.isMobile() ? null : <div dangerouslySetInnerHTML={{__html: application.formCss}} />}
{Setting.inIframe() || !Setting.isMobile() ? null : <div dangerouslySetInnerHTML={{__html: application.formCssMobile}} />}
<div className="login-panel" >
<div className={Setting.isDarkTheme(this.props.themeAlgorithm) ? "login-panel-dark" : "login-panel"}>
<div className="side-image" style={{display: application.formOffset !== 4 ? "none" : null}}>
<div dangerouslySetInnerHTML={{__html: application.formSideHtml}} />
</div>

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import React, {useState} from "react";
import React, {Fragment, useState} from "react";
import i18next from "i18next";
import {Button, Input} from "antd";
import * as AuthBackend from "../AuthBackend";
@ -67,24 +67,32 @@ export function MfaAuthVerifyForm({formValues, authParams, mfaProps, application
if (mfaType !== RecoveryMfaType) {
return (
<div style={{width: 300, height: 350}}>
<div style={{width: 320, height: 350}}>
<div style={{marginBottom: 24, textAlign: "center", fontSize: "24px"}}>
{i18next.t("mfa:Multi-factor authentication")}
</div>
<div style={{marginBottom: 24}}>
{i18next.t("mfa:Multi-factor authentication description")}
</div>
{mfaType === SmsMfaType || mfaType === EmailMfaType ? (
<MfaVerifySmsForm
mfaProps={mfaProps}
method={mfaAuth}
onFinish={verify}
application={application}
/>) : (
<MfaVerifyTotpForm
mfaProps={mfaProps}
onFinish={verify}
/>
<Fragment>
<div style={{marginBottom: 24}}>
{i18next.t("mfa:You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue")}
</div>
<MfaVerifySmsForm
mfaProps={mfaProps}
method={mfaAuth}
onFinish={verify}
application={application}
/>
</Fragment>
) : (
<Fragment>
<div style={{marginBottom: 24}}>
{i18next.t("mfa:You have enabled Multi-Factor Authentication, please enter the TOTP code")}
</div>
<MfaVerifyTotpForm
mfaProps={mfaProps}
onFinish={verify}
/>
</Fragment>
)}
<span style={{float: "right"}}>
{i18next.t("mfa:Have problems?")}

View File

@ -51,3 +51,19 @@ code {
.custom-link:hover {
color: rgb(64 64 64) !important;
}
.full-height-editor {
height: 100%;
}
.full-height-editor [class*="CodeMirror"] {
height: 100%;
}
.no-horizontal-scroll-editor [class*="CodeMirror-hscrollbar"] {
display: none !important;
}
.no-horizontal-scroll-editor [class*="CodeMirror-scroll"] {
overflow-x: hidden !important;
}

View File

@ -74,6 +74,7 @@
"Left": "Left",
"Logged in successfully": "Logged in successfully",
"Logged out successfully": "Logged out successfully",
"Multiple Choices": "Multiple Choices",
"New Application": "New Application",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
@ -123,6 +125,8 @@
"Token format - Tooltip": "The format of access token",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adapter",
"Adapter - Tooltip": "Table name of the policy store",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Payment providers to be configured, including PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Providers",
"Providers - Tooltip": "Providers to be configured, including 3rd-party login, object storage, verification code, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Real name",
"Records": "Records",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Prompted",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Provider URL",
"Provider URL - Tooltip": "URL for configuring the service provider, this field is only used for reference and is not used in Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",

View File

@ -74,6 +74,7 @@
"Left": "Vlevo",
"Logged in successfully": "Úspěšně přihlášen",
"Logged out successfully": "Úspěšně odhlášen",
"Multiple Choices": "Multiple Choices",
"New Application": "Nová aplikace",
"No verification": "Bez ověření",
"Normal": "Normální",
@ -112,6 +113,7 @@
"Signin session": "Přihlašovací relace",
"Signup items": "Položky registrace",
"Signup items - Tooltip": "Položky, které uživatelé vyplňují při registraci nových účtů",
"Single Choice": "Single Choice",
"Small icon": "Malá ikona",
"Tags - Tooltip": "Pouze uživatelé s tagem uvedeným v tazích aplikace se mohou přihlásit",
"The application does not allow to sign up new account": "Aplikace neumožňuje registraci nového účtu",
@ -123,6 +125,8 @@
"Token format - Tooltip": "Formát přístupového tokenu",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "Nečekali jste, že uvidíte tuto výzvu"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Přístupový klíč - Tooltip",
"Access secret": "Přístupové tajemství",
"Access secret - Tooltip": "Přístupové tajemství - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Akce",
"Adapter": "Adaptér",
"Adapter - Tooltip": "Název tabulky úložiště politiky",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Poskytovatelé plateb, které mají být nakonfigurovány, včetně PayPal, Alipay, WeChat Pay, atd.",
"Providers": "Poskytovatelé",
"Providers - Tooltip": "Poskytovatelé, kteří mají být nakonfigurováni, včetně přihlášení třetích stran, objektového úložiště, ověřovacího kódu, atd.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Skutečné jméno",
"Records": "Záznamy",
"Request URI": "Požadavek URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Rozpoznávání obličeje",
"Face recognition failed": "Rozpoznávání obličeje selhalo",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Nepodařilo se získat autorizaci MetaMask",
"Failed to obtain Web3-Onboard authorization": "Nepodařilo se získat autorizaci Web3-Onboard",
"Forgot password?": "Zapomněli jste heslo?",
@ -530,7 +538,6 @@
"Have problems?": "Máte problémy?",
"Multi-factor authentication": "Vícefaktorové ověřování",
"Multi-factor authentication - Tooltip ": "Dvoufaktorové ověřování - Tooltip",
"Multi-factor authentication description": "Popis dvoufaktorového ověřování",
"Multi-factor methods": "Metody dvoufaktorového ověřování",
"Multi-factor recover": "Obnovení dvoufaktorového ověřování",
"Multi-factor recover description": "Popis obnovení dvoufaktorového ověřování",
@ -555,6 +562,8 @@
"Verification failed": "Ověření selhalo",
"Verify Code": "Ověřit kód",
"Verify Password": "Ověřit heslo",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Váš email je",
"Your phone is": "Váš telefon je",
"preferred": "preferované"
@ -831,6 +840,7 @@
"Project Id": "ID projektu",
"Project Id - Tooltip": "Nápověda k ID projektu",
"Prompted": "Vyzván",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "URL poskytovatele",
"Provider URL - Tooltip": "URL pro konfiguraci poskytovatele služby, toto pole je pouze pro referenci a není použito v Casdoor",
"Public key": "Veřejný klíč",
@ -950,6 +960,7 @@
"Have account?": "Máte účet?",
"Label": "Štítek",
"Label HTML": "HTML štítek",
"Options": "Options",
"Placeholder": "Zástupný text",
"Please accept the agreement!": "Prosím přijměte smlouvu!",
"Please click the below button to sign in": "Prosím klikněte na tlačítko níže pro přihlášení",

View File

@ -74,6 +74,7 @@
"Left": "Links",
"Logged in successfully": "Erfolgreich eingeloggt",
"Logged out successfully": "Erfolgreich ausgeloggt",
"Multiple Choices": "Multiple Choices",
"New Application": "Neue Anwendung",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Anmeldesession",
"Signup items": "Registrierungs Items",
"Signup items - Tooltip": "Items, die Benutzer ausfüllen müssen, wenn sie neue Konten registrieren",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "Die Anwendung erlaubt es nicht, ein neues Konto zu registrieren",
@ -123,6 +125,8 @@
"Token format - Tooltip": "Das Format des Access-Tokens",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "Sie sind unerwartet auf diese Aufforderungsseite gelangt"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Aktion",
"Adapter": "Adapter",
"Adapter - Tooltip": "Tabellenname des Policy Stores",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Zahlungsprovider, die konfiguriert werden müssen, inkl. PayPal, Alipay, WeChat Pay usw.",
"Providers": "Provider",
"Providers - Tooltip": "Provider, die konfiguriert werden müssen, einschließlich Drittanbieter-Logins, Objektspeicherung, Verifizierungscode usw.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Echter Name",
"Records": "Datensätze",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Passwort vergessen?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "ausgelöst",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Anbieter-URL",
"Provider URL - Tooltip": "URL zur Konfiguration des Dienstanbieters, dieses Feld dient nur als Referenz und wird in Casdoor nicht verwendet",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Haben Sie ein Konto?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Bitte akzeptieren Sie die Vereinbarung!",
"Please click the below button to sign in": "Bitte klicken Sie auf den untenstehenden Button, um sich anzumelden",

View File

@ -74,6 +74,7 @@
"Left": "Left",
"Logged in successfully": "Logged in successfully",
"Logged out successfully": "Logged out successfully",
"Multiple Choices": "Multiple Choices",
"New Application": "New Application",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
@ -123,6 +125,8 @@
"Token format - Tooltip": "The format of access token",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adapter",
"Adapter - Tooltip": "Table name of the policy store",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Payment providers to be configured, including PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Providers",
"Providers - Tooltip": "Providers to be configured, including 3rd-party login, object storage, verification code, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Real name",
"Records": "Records",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Prompted",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Provider URL",
"Provider URL - Tooltip": "URL for configuring the service provider, this field is only used for reference and is not used in Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",

View File

@ -74,6 +74,7 @@
"Left": "Izquierda",
"Logged in successfully": "Acceso satisfactorio",
"Logged out successfully": "Cerró sesión exitosamente",
"Multiple Choices": "Multiple Choices",
"New Application": "Nueva aplicación",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Sesión de inicio de sesión",
"Signup items": "Artículos de registro",
"Signup items - Tooltip": "Elementos para que los usuarios los completen al registrar nuevas cuentas",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "La aplicación no permite registrarse una cuenta nueva",
@ -123,6 +125,8 @@
"Token format - Tooltip": "El formato del token de acceso",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "Es inesperado ver esta página de inicio"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Acción",
"Adapter": "Adaptador",
"Adapter - Tooltip": "Nombre de la tabla de la tienda de políticas",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Proveedores de pago a configurar, incluyendo PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Proveedores",
"Providers - Tooltip": "Proveedores a configurar, incluyendo inicio de sesión de terceros, almacenamiento de objetos, código de verificación, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Nombre real",
"Records": "Registros",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "¿Olvidaste tu contraseña?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Estimulado",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "URL del proveedor",
"Provider URL - Tooltip": "Dirección URL para configurar el proveedor de servicios, este campo sólo se utiliza como referencia y no se utiliza en Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "¿Tiene una cuenta?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "¡Por favor, acepta el acuerdo!",
"Please click the below button to sign in": "Por favor, haga clic en el botón de abajo para iniciar sesión",

View File

@ -74,6 +74,7 @@
"Left": "Left",
"Logged in successfully": "Logged in successfully",
"Logged out successfully": "Logged out successfully",
"Multiple Choices": "Multiple Choices",
"New Application": "New Application",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
@ -123,6 +125,8 @@
"Token format - Tooltip": "The format of access token",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adapter",
"Adapter - Tooltip": "Table name of the policy store",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Payment providers to be configured, including PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Providers",
"Providers - Tooltip": "Providers to be configured, including 3rd-party login, object storage, verification code, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Real name",
"Records": "Records",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Prompted",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Provider URL",
"Provider URL - Tooltip": "URL for configuring the service provider, this field is only used for reference and is not used in Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",

View File

@ -74,6 +74,7 @@
"Left": "Left",
"Logged in successfully": "Logged in successfully",
"Logged out successfully": "Logged out successfully",
"Multiple Choices": "Multiple Choices",
"New Application": "New Application",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
@ -123,6 +125,8 @@
"Token format - Tooltip": "The format of access token",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adapter",
"Adapter - Tooltip": "Table name of the policy store",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Payment providers to be configured, including PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Providers",
"Providers - Tooltip": "Providers to be configured, including 3rd-party login, object storage, verification code, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Real name",
"Records": "Records",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Prompted",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Provider URL",
"Provider URL - Tooltip": "URL for configuring the service provider, this field is only used for reference and is not used in Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",

View File

@ -74,6 +74,7 @@
"Left": "Gauche",
"Logged in successfully": "Connexion réussie",
"Logged out successfully": "Déconnexion réussie",
"Multiple Choices": "Multiple Choices",
"New Application": "Nouvelle application",
"No verification": "Aucune vérification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Session de connexion",
"Signup items": "Champs d'inscription",
"Signup items - Tooltip": "Champs à remplir lors de l'enregistrement de nouveaux comptes",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Seuls les comptes ayant leur étiquette listée dans les étiquettes de l'application peuvent se connecter",
"The application does not allow to sign up new account": "L'application ne permet pas de créer un nouveau compte",
@ -123,6 +125,8 @@
"Token format - Tooltip": "Le format du jeton d'accès",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "Il n'était pas prévu que vous voyez cette page de saisie"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Clé d'accès - Infobulle",
"Access secret": "Clé secrète",
"Access secret - Tooltip": "Clé secrète - Info-bulle",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adaptateur",
"Adapter - Tooltip": "Nom de la table du magasin de règle",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Les fournisseurs de paiement à configurer, tels que PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Fournisseurs",
"Providers - Tooltip": "Les fournisseurs à configurer, tels que la connexion via un service tiers, le stockage d'objets, le code de vérification, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Nom complet",
"Records": "Enregistrements",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Échec de l'obtention de l'autorisation MetaMask",
"Failed to obtain Web3-Onboard authorization": "Échec de l'obtention de l'autorisation MetaMask",
"Forgot password?": "Mot de passe oublié ?",
@ -530,7 +538,6 @@
"Have problems?": "Des problèmes ?",
"Multi-factor authentication": "Authentification multifacteur",
"Multi-factor authentication - Tooltip ": "Authentification multifacteur - infobulle ",
"Multi-factor authentication description": "Description de l'authentification multifacteur",
"Multi-factor methods": "Méthodes d'authentification multifacteur",
"Multi-factor recover": "Restauration de l'authentification multifacteur",
"Multi-factor recover description": "Description de la restauration de l'authentification multifacteur",
@ -555,6 +562,8 @@
"Verification failed": "Échec de la vérification",
"Verify Code": "Vérifier le code",
"Verify Password": "Confirmez le mot de passe",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Votre e-mail est",
"Your phone is": "Votre téléphone est",
"preferred": "préféré"
@ -831,6 +840,7 @@
"Project Id": "ID du projet",
"Project Id - Tooltip": "ID du projet - Infobulle",
"Prompted": "Incité",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "URL du fournisseur",
"Provider URL - Tooltip": "URL pour configurer le fournisseur de services, ce champ est uniquement utilisé à titre de référence et n'est pas utilisé dans Casdoor",
"Public key": "Clé publique",
@ -950,6 +960,7 @@
"Have account?": "Avez-vous un compte ?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Veuillez accepter l'accord !",
"Please click the below button to sign in": "Veuillez cliquer sur le bouton ci-dessous pour vous connecter",

View File

@ -74,6 +74,7 @@
"Left": "Left",
"Logged in successfully": "Logged in successfully",
"Logged out successfully": "Logged out successfully",
"Multiple Choices": "Multiple Choices",
"New Application": "New Application",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
@ -123,6 +125,8 @@
"Token format - Tooltip": "The format of access token",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adapter",
"Adapter - Tooltip": "Table name of the policy store",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Payment providers to be configured, including PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Providers",
"Providers - Tooltip": "Providers to be configured, including 3rd-party login, object storage, verification code, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Real name",
"Records": "Records",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Prompted",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Provider URL",
"Provider URL - Tooltip": "URL for configuring the service provider, this field is only used for reference and is not used in Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",

View File

@ -74,6 +74,7 @@
"Left": "Kiri",
"Logged in successfully": "Berhasil masuk",
"Logged out successfully": "Berhasil keluar dari sistem",
"Multiple Choices": "Multiple Choices",
"New Application": "Aplikasi Baru",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Sesi masuk",
"Signup items": "Item pendaftaran",
"Signup items - Tooltip": "Item-item yang harus diisi pengguna saat mendaftar untuk akun baru",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "Aplikasi tidak memperbolehkan untuk mendaftar akun baru",
@ -123,6 +125,8 @@
"Token format - Tooltip": "Format dari token akses",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "Anda tidak mengharapkan untuk melihat halaman prompt ini"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Aksi",
"Adapter": "Adapter",
"Adapter - Tooltip": "Nama tabel dari penyimpanan kebijakan",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Penyedia pembayaran harus dikonfigurasi, termasuk PayPal, Alipay, WeChat Pay, dan sebagainya.",
"Providers": "Penyedia-penyedia",
"Providers - Tooltip": "Penyedia harus dikonfigurasi, termasuk login pihak ketiga, penyimpanan objek, kode verifikasi, dan lain-lain.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Nama asli",
"Records": "Catatan",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Lupa kata sandi?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Mendorong",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "URL penyedia",
"Provider URL - Tooltip": "URL untuk melakukan konfigurasi service provider, kolom ini hanya digunakan sebagai referensi dan tidak digunakan dalam Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Punya akun?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Tolong terima perjanjian ini!",
"Please click the below button to sign in": "Silakan klik tombol di bawah ini untuk masuk",

View File

@ -74,6 +74,7 @@
"Left": "Left",
"Logged in successfully": "Logged in successfully",
"Logged out successfully": "Logged out successfully",
"Multiple Choices": "Multiple Choices",
"New Application": "New Application",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
@ -123,6 +125,8 @@
"Token format - Tooltip": "The format of access token",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adapter",
"Adapter - Tooltip": "Table name of the policy store",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Payment providers to be configured, including PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Providers",
"Providers - Tooltip": "Providers to be configured, including 3rd-party login, object storage, verification code, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Real name",
"Records": "Records",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Prompted",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Provider URL",
"Provider URL - Tooltip": "URL for configuring the service provider, this field is only used for reference and is not used in Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",

View File

@ -74,6 +74,7 @@
"Left": "左",
"Logged in successfully": "正常にログインしました",
"Logged out successfully": "正常にログアウトしました",
"Multiple Choices": "Multiple Choices",
"New Application": "新しいアプリケーション",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "サインインセッション",
"Signup items": "サインアップアイテム",
"Signup items - Tooltip": "新しいアカウントを登録する際にユーザーが入力するアイテム",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "アプリケーションでは新しいアカウントの登録ができません",
@ -123,6 +125,8 @@
"Token format - Tooltip": "アクセストークンのフォーマット",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "このプロンプトページを見ることは予期せぬことである"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "アクション",
"Adapter": "アダプター",
"Adapter - Tooltip": "ポリシー・ストアのテーブル名",
@ -334,6 +339,8 @@
"Provider - Tooltip": "支払いプロバイダーを設定する必要があります。これには、PayPal、Alipay、WeChat Payなどが含まれます。",
"Providers": "プロバイダー",
"Providers - Tooltip": "設定するプロバイダーには、サードパーティのログイン、オブジェクトストレージ、検証コードなどが含まれます。",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "本名",
"Records": "記録",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "パスワードを忘れましたか?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "促された",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "プロバイダーURL",
"Provider URL - Tooltip": "サービスプロバイダーの設定用URL。このフィールドは参照用にのみ使用され、Casdoorでは使用されません",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "アカウントはありますか?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "合意に同意してください!",
"Please click the below button to sign in": "以下のボタンをクリックしてログインしてください",

View File

@ -74,6 +74,7 @@
"Left": "Left",
"Logged in successfully": "Logged in successfully",
"Logged out successfully": "Logged out successfully",
"Multiple Choices": "Multiple Choices",
"New Application": "New Application",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
@ -123,6 +125,8 @@
"Token format - Tooltip": "The format of access token",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adapter",
"Adapter - Tooltip": "Table name of the policy store",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Payment providers to be configured, including PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Providers",
"Providers - Tooltip": "Providers to be configured, including 3rd-party login, object storage, verification code, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Real name",
"Records": "Records",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Prompted",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Provider URL",
"Provider URL - Tooltip": "URL for configuring the service provider, this field is only used for reference and is not used in Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",

View File

@ -74,6 +74,7 @@
"Left": "왼쪽",
"Logged in successfully": "성공적으로 로그인했습니다",
"Logged out successfully": "로그아웃이 성공적으로 되었습니다",
"Multiple Choices": "Multiple Choices",
"New Application": "새로운 응용 프로그램",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "로그인 세션",
"Signup items": "가입 항목",
"Signup items - Tooltip": "새로운 계정 등록시 사용자가 작성해야하는 항목들",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "이 어플리케이션은 새 계정 등록을 허용하지 않습니다",
@ -123,6 +125,8 @@
"Token format - Tooltip": "접근 토큰의 형식",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "당신은 이 프롬프트 페이지를 볼 것을 예상하지 못했습니다"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "동작",
"Adapter": "어댑터",
"Adapter - Tooltip": "정책 저장소의 테이블 이름",
@ -334,6 +339,8 @@
"Provider - Tooltip": "지불 공급자를 구성해야합니다. PayPal, Alipay, WeChat Pay 등이 포함됩니다.",
"Providers": "제공자들",
"Providers - Tooltip": "공급 업체는 구성되어야합니다. 3rd-party 로그인, 객체 저장소, 검증 코드 등을 포함합니다.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "실명",
"Records": "기록",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "비밀번호를 잊으셨나요?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "자극 받은",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "제공자 URL",
"Provider URL - Tooltip": "서비스 제공 업체 구성을 위한 URL이며, 이 필드는 참조 용도로만 사용되며 Casdoor에서 사용되지 않습니다",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "계정이 있나요?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "계약서를 승인해주세요!",
"Please click the below button to sign in": "아래 버튼을 클릭하여 로그인하세요",

View File

@ -74,6 +74,7 @@
"Left": "Left",
"Logged in successfully": "Logged in successfully",
"Logged out successfully": "Logged out successfully",
"Multiple Choices": "Multiple Choices",
"New Application": "New Application",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
@ -123,6 +125,8 @@
"Token format - Tooltip": "The format of access token",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adapter",
"Adapter - Tooltip": "Table name of the policy store",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Payment providers to be configured, including PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Providers",
"Providers - Tooltip": "Providers to be configured, including 3rd-party login, object storage, verification code, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Real name",
"Records": "Records",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Prompted",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Provider URL",
"Provider URL - Tooltip": "URL for configuring the service provider, this field is only used for reference and is not used in Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",

View File

@ -74,6 +74,7 @@
"Left": "Left",
"Logged in successfully": "Logged in successfully",
"Logged out successfully": "Logged out successfully",
"Multiple Choices": "Multiple Choices",
"New Application": "New Application",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
@ -123,6 +125,8 @@
"Token format - Tooltip": "The format of access token",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adapter",
"Adapter - Tooltip": "Table name of the policy store",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Payment providers to be configured, including PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Providers",
"Providers - Tooltip": "Providers to be configured, including 3rd-party login, object storage, verification code, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Real name",
"Records": "Records",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Prompted",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Provider URL",
"Provider URL - Tooltip": "URL for configuring the service provider, this field is only used for reference and is not used in Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",

View File

@ -74,6 +74,7 @@
"Left": "Left",
"Logged in successfully": "Logged in successfully",
"Logged out successfully": "Logged out successfully",
"Multiple Choices": "Multiple Choices",
"New Application": "New Application",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
@ -123,6 +125,8 @@
"Token format - Tooltip": "The format of access token",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adapter",
"Adapter - Tooltip": "Table name of the policy store",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Payment providers to be configured, including PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Providers",
"Providers - Tooltip": "Providers to be configured, including 3rd-party login, object storage, verification code, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Real name",
"Records": "Records",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Prompted",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Provider URL",
"Provider URL - Tooltip": "URL for configuring the service provider, this field is only used for reference and is not used in Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",

View File

@ -74,6 +74,7 @@
"Left": "Esquerda",
"Logged in successfully": "Login realizado com sucesso",
"Logged out successfully": "Logout realizado com sucesso",
"Multiple Choices": "Multiple Choices",
"New Application": "Nova Aplicação",
"No verification": "Sem verificação",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Sessão de login",
"Signup items": "Itens de registro",
"Signup items - Tooltip": "Itens para os usuários preencherem ao registrar novas contas",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Apenas usuários com a tag listada nas tags do aplicativo podem acessar",
"The application does not allow to sign up new account": "A aplicação não permite o registro de novas contas",
@ -123,6 +125,8 @@
"Token format - Tooltip": "O formato do token de acesso",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "Você não deveria ver esta página de prompt"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Ação",
"Adapter": "Adaptador",
"Adapter - Tooltip": "Nome da tabela do armazenamento de políticas",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Provedores de pagamento a serem configurados, incluindo PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Provedores",
"Providers - Tooltip": "Provedores a serem configurados, incluindo login de terceiros, armazenamento de objetos, código de verificação, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Nome real",
"Records": "Registros",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Esqueceu a senha?",
@ -530,7 +538,6 @@
"Have problems?": "Tem problemas?",
"Multi-factor authentication": "Autenticação de vários fatores",
"Multi-factor authentication - Tooltip ": "Autenticação de múltiplos fatores - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Solicitado",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "URL do Provedor",
"Provider URL - Tooltip": "URL para configurar o provedor de serviço, este campo é apenas usado para referência e não é usado no Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Já possui uma conta?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Por favor, aceite o acordo!",
"Please click the below button to sign in": "Por favor, clique no botão abaixo para fazer login",

View File

@ -74,6 +74,7 @@
"Left": "Левый",
"Logged in successfully": "Успешный вход в систему",
"Logged out successfully": "Успешный выход из системы",
"Multiple Choices": "Multiple Choices",
"New Application": "Новое приложение",
"No verification": "Нет верификации",
"Normal": "Обычный",
@ -112,6 +113,7 @@
"Signin session": "Сессия входа в систему",
"Signup items": "Элементы регистрации",
"Signup items - Tooltip": "Элементы, которые пользователи должны заполнить при регистрации новых аккаунтов",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Только пользователи с тегом, указанным в тегах приложения могут войти в систему",
"The application does not allow to sign up new account": "Приложение не позволяет зарегистрироваться новому аккаунту",
@ -123,6 +125,8 @@
"Token format - Tooltip": "Формат токена доступа",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "Вы не ожидали увидеть эту страницу-подсказку"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Действие",
"Adapter": "Адаптер",
"Adapter - Tooltip": "Имя таблицы хранилища политик",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Провайдеры платежей должны быть настроены, включая PayPal, Alipay, WeChat Pay и т.д.",
"Providers": "Провайдеры",
"Providers - Tooltip": "Провайдеры должны быть настроены, включая вход с помощью сторонних сервисов, объектное хранилище, код подтверждения и т.д.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Реальное имя",
"Records": "Записи",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Не удалось получить авторизацию MetaMask",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Забыли пароль?",
@ -530,7 +538,6 @@
"Have problems?": "Возникли проблемы?",
"Multi-factor authentication": "Многофакторная аутентификация",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Проверка не удалась",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Ваш email",
"Your phone is": "Ваш телефон",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Побудил",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "URL поставщика",
"Provider URL - Tooltip": "URL для настройки поставщика услуг, это поле используется только для ссылки и не используется в Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "У вас есть аккаунт?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Пожалуйста, примите соглашение!",
"Please click the below button to sign in": "Пожалуйста, нажмите на кнопку ниже, чтобы авторизоваться",

View File

@ -74,6 +74,7 @@
"Left": "Vľavo",
"Logged in successfully": "Úspešne prihlásený",
"Logged out successfully": "Úspešne odhlásený",
"Multiple Choices": "Multiple Choices",
"New Application": "Nová aplikácia",
"No verification": "Bez overenia",
"Normal": "Normálny",
@ -112,6 +113,7 @@
"Signin session": "Relácia prihlásenia",
"Signup items": "Položky registrácie",
"Signup items - Tooltip": "Položky, ktoré majú používatelia vyplniť pri registrácii nových účtov",
"Single Choice": "Single Choice",
"Small icon": "Malá ikona",
"Tags - Tooltip": "Prihlásiť sa môžu iba používatelia s tagom uvedeným v tagoch aplikácie",
"The application does not allow to sign up new account": "Aplikácia neumožňuje vytvoriť nový účet",
@ -123,6 +125,8 @@
"Token format - Tooltip": "Formát prístupového tokenu",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "Neočekávali ste, že uvidíte túto výzvu"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Prístupový kľúč",
"Access secret": "Prístupové tajomstvo",
"Access secret - Tooltip": "Prístupové tajomstvo",
"Access token is empty": "Access token is empty",
"Action": "Akcia",
"Adapter": "Adaptér",
"Adapter - Tooltip": "Názov tabuľky úložiska pravidiel",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Poskytovatelia platieb na konfiguráciu, vrátane PayPal, Alipay, WeChat Pay atď.",
"Providers": "Poskytovatelia",
"Providers - Tooltip": "Poskytovatelia na konfiguráciu, vrátane prihlásenia cez tretie strany, ukladania objektov, overovacích kódov atď.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Skutočné meno",
"Records": "Záznamy",
"Request URI": "URI požiadavky",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Rozpoznávanie tváre",
"Face recognition failed": "Zlyhalo rozpoznávanie tváre",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Nepodarilo sa získať autorizáciu MetaMask",
"Failed to obtain Web3-Onboard authorization": "Nepodarilo sa získať autorizáciu Web3-Onboard",
"Forgot password?": "Zabudli ste heslo?",
@ -530,7 +538,6 @@
"Have problems?": "Máte problémy?",
"Multi-factor authentication": "Viacfaktorová autentifikácia",
"Multi-factor authentication - Tooltip ": "Viacfaktorová autentifikácia - Nápoveda ",
"Multi-factor authentication description": "Popis viacfaktorovej autentifikácie",
"Multi-factor methods": "Metódy viacfaktorovej autentifikácie",
"Multi-factor recover": "Obnova viacfaktorovej autentifikácie",
"Multi-factor recover description": "Popis obnovy viacfaktorovej autentifikácie",
@ -555,6 +562,8 @@
"Verification failed": "Overenie zlyhalo",
"Verify Code": "Overiť kód",
"Verify Password": "Overiť heslo",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Váš email je",
"Your phone is": "Váš telefón je",
"preferred": "preferované"
@ -831,6 +840,7 @@
"Project Id": "ID projektu",
"Project Id - Tooltip": "ID projektu",
"Prompted": "Vyžiadané",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "URL poskytovateľa",
"Provider URL - Tooltip": "URL na konfiguráciu poskytovateľa služby, toto pole sa používa len na referenciu a v Casdoor sa nepoužíva",
"Public key": "Verejný kľúč",
@ -950,6 +960,7 @@
"Have account?": "Máte účet?",
"Label": "Štítok",
"Label HTML": "HTML štítok",
"Options": "Options",
"Placeholder": "Miesto na vyplnenie",
"Please accept the agreement!": "Prosím, akceptujte dohodu!",
"Please click the below button to sign in": "Prosím, kliknite na nižšie uvedené tlačidlo na prihlásenie",

View File

@ -74,6 +74,7 @@
"Left": "Left",
"Logged in successfully": "Logged in successfully",
"Logged out successfully": "Logged out successfully",
"Multiple Choices": "Multiple Choices",
"New Application": "New Application",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
@ -123,6 +125,8 @@
"Token format - Tooltip": "The format of access token",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adapter",
"Adapter - Tooltip": "Table name of the policy store",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Payment providers to be configured, including PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Providers",
"Providers - Tooltip": "Providers to be configured, including 3rd-party login, object storage, verification code, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Real name",
"Records": "Records",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Forgot password?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Prompted",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Provider URL",
"Provider URL - Tooltip": "URL for configuring the service provider, this field is only used for reference and is not used in Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",

View File

@ -74,6 +74,7 @@
"Left": "Sol",
"Logged in successfully": "Başarıyla giriş yapıldı",
"Logged out successfully": "Başarıyla çıkış yapıldı",
"Multiple Choices": "Multiple Choices",
"New Application": "New Application",
"No verification": "No verification",
"Normal": "Normal",
@ -112,6 +113,7 @@
"Signin session": "Signin session",
"Signup items": "Signup items",
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
@ -123,6 +125,8 @@
"Token format - Tooltip": "The format of access token",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "You are unexpected to see this prompt page"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Action",
"Adapter": "Adapter",
"Adapter - Tooltip": "Table name of the policy store",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Payment providers to be configured, including PayPal, Alipay, WeChat Pay, etc.",
"Providers": "Providers",
"Providers - Tooltip": "Providers to be configured, including 3rd-party login, object storage, verification code, etc.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Gerçek isim",
"Records": "Records",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Metamask yetkilendirmesi başarısız",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Şifrenizi mi unuttunuz?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Doğrulama başarısız",
"Verify Code": "Kodu doğrula",
"Verify Password": "Parolayı Doğrula",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "E-postanız",
"Your phone is": "Telefon numaranız",
"preferred": "tercih edilen"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Prompted",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Provider URL",
"Provider URL - Tooltip": "URL for configuring the service provider, this field is only used for reference and is not used in Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Zaten bir hesabınız var mı?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Lütfen, kullanım koşullarını kabul ediniz",
"Please click the below button to sign in": "Please click the below button to sign in",

View File

@ -74,6 +74,7 @@
"Left": "Ліворуч",
"Logged in successfully": "Успішно ввійшли",
"Logged out successfully": "Успішно вийшов",
"Multiple Choices": "Multiple Choices",
"New Application": "Нова заявка",
"No verification": "Без підтвердження",
"Normal": "нормальний",
@ -112,6 +113,7 @@
"Signin session": "Сеанс входу",
"Signup items": "Пункти реєстрації",
"Signup items - Tooltip": "Пункти, які користувачі повинні заповнити під час реєстрації нових облікових записів",
"Single Choice": "Single Choice",
"Small icon": "Маленький значок",
"Tags - Tooltip": "Увійти можуть лише користувачі з тегом, указаним у тегах програми",
"The application does not allow to sign up new account": "Програма не дозволяє зареєструвати новий обліковий запис",
@ -123,6 +125,8 @@
"Token format - Tooltip": "Формат маркера доступу",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "Ви неочікувано побачите цю сторінку запиту"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Ключ доступу - підказка",
"Access secret": "Секрет доступу",
"Access secret - Tooltip": "Секрет доступу - підказка",
"Access token is empty": "Access token is empty",
"Action": "Дія",
"Adapter": "Перехідник",
"Adapter - Tooltip": "Назва таблиці сховища полісів",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Платіжні постачальники, які потрібно налаштувати, зокрема PayPal, Alipay, WeChat Pay тощо.",
"Providers": "Провайдери",
"Providers - Tooltip": "Постачальники, які потрібно налаштувати, включаючи вхід сторонніх розробників, зберігання об’єктів, код підтвердження тощо.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Справжнє ім'я",
"Records": "Записи",
"Request URI": "URI запиту",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Розпізнавання обличчя",
"Face recognition failed": "Помилка розпізнавання обличчя",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Не вдалося отримати авторизацію MetaMask",
"Failed to obtain Web3-Onboard authorization": "Не вдалося отримати авторизацію Web3-Onboard",
"Forgot password?": "Забули пароль?",
@ -530,7 +538,6 @@
"Have problems?": "Є проблеми?",
"Multi-factor authentication": "Багатофакторна аутентифікація",
"Multi-factor authentication - Tooltip ": "Багатофакторна автентифікація підказка ",
"Multi-factor authentication description": "Опис багатофакторної автентифікації",
"Multi-factor methods": "Багатофакторні методи",
"Multi-factor recover": "Багатофакторне відновлення",
"Multi-factor recover description": "Опис багатофакторного відновлення",
@ -555,6 +562,8 @@
"Verification failed": "Не вдалося перевірити",
"Verify Code": "Підтвердити код",
"Verify Password": "Підтвердіть пароль",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Ваша електронна адреса",
"Your phone is": "Ваш телефон",
"preferred": "бажаний"
@ -831,6 +840,7 @@
"Project Id": "Ідентифікатор проекту",
"Project Id - Tooltip": "Ідентифікатор проекту підказка",
"Prompted": "Запропоновано",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "URL-адреса постачальника",
"Provider URL - Tooltip": "URL-адреса для налаштування постачальника послуг, це поле використовується лише для довідки та не використовується в Casdoor",
"Public key": "Відкритий ключ",
@ -950,6 +960,7 @@
"Have account?": "Є акаунт?",
"Label": "Мітка",
"Label HTML": "Мітка HTML",
"Options": "Options",
"Placeholder": "Заповнювач",
"Please accept the agreement!": "Будь ласка, прийміть угоду!",
"Please click the below button to sign in": "Натисніть кнопку нижче, щоб увійти",

View File

@ -74,6 +74,7 @@
"Left": "Trái",
"Logged in successfully": "Đăng nhập thành công",
"Logged out successfully": "Đã đăng xuất thành công",
"Multiple Choices": "Multiple Choices",
"New Application": "Ứng dụng mới",
"No verification": "Không xác minh",
"Normal": "Bình thường",
@ -112,6 +113,7 @@
"Signin session": "Phiên đăng nhập",
"Signup items": "Các mục đăng ký",
"Signup items - Tooltip": "Các thông tin cần được người dùng điền khi đăng ký tài khoản mới",
"Single Choice": "Single Choice",
"Small icon": "Small icon",
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
"The application does not allow to sign up new account": "Ứng dụng không cho phép đăng ký tài khoản mới",
@ -123,6 +125,8 @@
"Token format - Tooltip": "Định dạng của mã thông báo truy cập",
"Token signing method": "Token signing method",
"Token signing method - Tooltip": "Signing method of JWT token, needs to be the same algorithm as the certificate",
"Use Email as NameID": "Use Email as NameID",
"Use Email as NameID - Tooltip": "Use Email as NameID - Tooltip",
"You are unexpected to see this prompt page": "Bạn không mong đợi thấy trang này hiện lên"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "Access key - Tooltip",
"Access secret": "Access secret",
"Access secret - Tooltip": "Access secret - Tooltip",
"Access token is empty": "Access token is empty",
"Action": "Hành động",
"Adapter": "Bộ chuyển đổi",
"Adapter - Tooltip": "Tên bảng của kho lưu trữ chính sách",
@ -334,6 +339,8 @@
"Provider - Tooltip": "Cung cấp thanh toán được cấu hình, bao gồm PayPal, Alipay, WeChat Pay, vv.",
"Providers": "Nhà cung cấp",
"Providers - Tooltip": "Các nhà cung cấp phải được cấu hình, bao gồm đăng nhập bên thứ ba, lưu trữ đối tượng, mã xác minh, v.v.",
"QR Code": "QR Code",
"QR code is too large": "QR code is too large",
"Real name": "Tên thật",
"Records": "Hồ sơ",
"Request URI": "Request URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "Face Recognition",
"Face recognition failed": "Face recognition failed",
"Failed to log out": "Failed to log out",
"Failed to obtain MetaMask authorization": "Failed to obtain MetaMask authorization",
"Failed to obtain Web3-Onboard authorization": "Failed to obtain Web3-Onboard authorization",
"Forgot password?": "Quên mật khẩu?",
@ -530,7 +538,6 @@
"Have problems?": "Have problems?",
"Multi-factor authentication": "Multi-factor authentication",
"Multi-factor authentication - Tooltip ": "Multi-factor authentication - Tooltip ",
"Multi-factor authentication description": "Multi-factor authentication description",
"Multi-factor methods": "Multi-factor methods",
"Multi-factor recover": "Multi-factor recover",
"Multi-factor recover description": "Multi-factor recover description",
@ -555,6 +562,8 @@
"Verification failed": "Verification failed",
"Verify Code": "Verify Code",
"Verify Password": "Verify Password",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "You have enabled Multi-Factor Authentication, please enter the TOTP code",
"Your email is": "Your email is",
"Your phone is": "Your phone is",
"preferred": "preferred"
@ -831,6 +840,7 @@
"Project Id": "Project Id",
"Project Id - Tooltip": "Project Id - Tooltip",
"Prompted": "Thúc đẩy",
"Provider - Tooltip": "Provider - Tooltip",
"Provider URL": "Địa chỉ URL nhà cung cấp",
"Provider URL - Tooltip": "URL để cấu hình nhà cung cấp dịch vụ, trường này chỉ được sử dụng để tham khảo và không được sử dụng trong Casdoor",
"Public key": "Public key",
@ -950,6 +960,7 @@
"Have account?": "Có tài khoản không?",
"Label": "Label",
"Label HTML": "Label HTML",
"Options": "Options",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Vui lòng chấp nhận thỏa thuận!",
"Please click the below button to sign in": "Xin vui lòng nhấn vào nút bên dưới để đăng nhập",

View File

@ -74,6 +74,7 @@
"Left": "居左",
"Logged in successfully": "登录成功",
"Logged out successfully": "登出成功",
"Multiple Choices": "多选",
"New Application": "添加应用",
"No verification": "不校验",
"Normal": "标准",
@ -112,6 +113,7 @@
"Signin session": "保持登录会话",
"Signup items": "注册项",
"Signup items - Tooltip": "注册用户注册时需要填写的项目",
"Single Choice": "单选",
"Small icon": "小图标",
"Tags - Tooltip": "用户的标签在应用的标签集合中时,用户才可以登录该应用",
"The application does not allow to sign up new account": "该应用不允许注册新账户",
@ -123,6 +125,8 @@
"Token format - Tooltip": "Access Token格式",
"Token signing method": "Token签名算法",
"Token signing method - Tooltip": "JWT token的签名算法需要与证书算法相匹配",
"Use Email as NameID": "使用邮箱作为NameID",
"Use Email as NameID - Tooltip": "使用邮箱作为NameID - Tooltip",
"You are unexpected to see this prompt page": "错误:该提醒页面不应出现"
},
"cert": {
@ -179,6 +183,7 @@
"Access key - Tooltip": "访问密钥",
"Access secret": "访问密码",
"Access secret - Tooltip": "访问密码",
"Access token is empty": "Access token为空",
"Action": "操作",
"Adapter": "适配器",
"Adapter - Tooltip": "策略存储的表名",
@ -334,6 +339,8 @@
"Provider - Tooltip": "需要配置的支付提供商包括PayPal、支付宝、微信支付等",
"Providers": "提供商",
"Providers - Tooltip": "需要配置的提供商,包括第三方登录、对象存储、验证码等",
"QR Code": "QR Code",
"QR code is too large": "二维码过大",
"Real name": "姓名",
"Records": "日志",
"Request URI": "请求URI",
@ -478,6 +485,7 @@
"Face ID": "Face ID",
"Face Recognition": "人脸识别",
"Face recognition failed": "人脸识别失败",
"Failed to log out": "注销失败",
"Failed to obtain MetaMask authorization": "获取MetaMask授权失败",
"Failed to obtain Web3-Onboard authorization": "获取 Web3-Onboard 授权失败",
"Forgot password?": "忘记密码?",
@ -530,7 +538,6 @@
"Have problems?": "遇到问题?",
"Multi-factor authentication": "多因素认证",
"Multi-factor authentication - Tooltip ": "多因素认证 - Tooltip ",
"Multi-factor authentication description": "您已经启用多因素认证,请输入认证码",
"Multi-factor methods": "多因素认证方式",
"Multi-factor recover": "重置多因素认证",
"Multi-factor recover description": "如果您无法访问您的设备,输入您的多因素认证恢复代码来确认您的身份",
@ -555,6 +562,8 @@
"Verification failed": "验证失败",
"Verify Code": "验证码",
"Verify Password": "验证密码",
"You have enabled Multi-Factor Authentication, Please click 'Send Code' to continue": "您已经启用多因素认证, 请点击 '发送验证码' 继续",
"You have enabled Multi-Factor Authentication, please enter the TOTP code": "您已经启用多因素认证请输入TOTP认证码",
"Your email is": "你的电子邮件",
"Your phone is": "你的手机号",
"preferred": "首选"
@ -831,6 +840,7 @@
"Project Id": "项目 Id",
"Project Id - Tooltip": "项目 Id - 工具提示",
"Prompted": "注册后提醒绑定",
"Provider - Tooltip": "提供商 - Tooltip",
"Provider URL": "提供商URL",
"Provider URL - Tooltip": "提供商网址配置对应的URL该字段仅用来方便跳转在Casdoor平台中未使用",
"Public key": "公钥",
@ -950,6 +960,7 @@
"Have account?": "已有账号?",
"Label": "标签",
"Label HTML": "标签HTML",
"Options": "选项",
"Placeholder": "占位符",
"Please accept the agreement!": "请先同意用户协议!",
"Please click the below button to sign in": "请点击下方按钮登录",

View File

@ -104,6 +104,7 @@ class AccountTable extends React.Component {
{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: "IP whitelist", label: i18next.t("general:IP whitelist")},
{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")},

View File

@ -14,7 +14,7 @@
import React from "react";
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Image, Input, Row, Table, Tooltip} from "antd";
import {Alert, Button, Col, Image, Input, Popover, QRCode, Row, Table, Tooltip} from "antd";
import * as Setting from "../Setting";
import i18next from "i18next";
@ -23,6 +23,7 @@ class MfaAccountTable extends React.Component {
super(props);
this.state = {
classes: props,
icon: this.props.icon,
mfaAccounts: this.props.table !== null ? this.props.table.map((item, index) => {
item.key = index;
return item;
@ -75,6 +76,42 @@ class MfaAccountTable extends React.Component {
this.updateTable(table);
}
getQrUrl() {
const {accessToken} = this.props;
let qrUrl = `casdoor-app://login?serverUrl=${window.location.origin}&accessToken=${accessToken}`;
let error = null;
if (!accessToken) {
qrUrl = "";
error = i18next.t("general:Access token is empty");
}
if (qrUrl.length >= 2000) {
qrUrl = "";
error = i18next.t("general:QR code is too large");
}
return {qrUrl, error};
}
renderQrCode() {
const {qrUrl, error} = this.getQrUrl();
if (error) {
return <Alert message={error} type="error" showIcon />;
} else {
return (
<QRCode
value={qrUrl}
icon={this.state.icon}
errorLevel="M"
size={230}
bordered={false}
/>
);
}
}
renderTable(table) {
const columns = [
{
@ -157,7 +194,11 @@ class MfaAccountTable extends React.Component {
title={() => (
<div>
{this.props.title}&nbsp;&nbsp;&nbsp;&nbsp;
<Button style={{marginRight: "5px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{i18next.t("general:Add")}</Button>
<Button style={{marginRight: "10px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{i18next.t("general:Add")}</Button>
<Popover trigger="focus" overlayInnerStyle={{padding: 0}}
content={this.renderQrCode()}>
<Button style={{marginLeft: "5px"}} type="primary" size="small">{i18next.t("general:QR Code")}</Button>
</Popover>
</div>
)}
/>

View File

@ -136,6 +136,7 @@ class SigninMethodTable extends React.Component {
options = [
{id: "All", name: i18next.t("general:All")},
{id: "Non-LDAP", name: i18next.t("general:Non-LDAP")},
{id: "Hide-Password", name: i18next.t("general:Hide-Password")},
];
}

View File

@ -65,7 +65,7 @@ class SignupTable extends React.Component {
}
addRow(table) {
const row = {name: Setting.getNewRowNameForTable(table, "Please select a signup item"), visible: true, required: true, rule: "None", customCss: ""};
const row = {name: Setting.getNewRowNameForTable(table, "Please select a signup item"), visible: true, required: true, options: [], rule: "None", customCss: ""};
if (table === undefined) {
table = [];
}
@ -100,6 +100,10 @@ class SignupTable extends React.Component {
{name: "ID", displayName: i18next.t("general:ID")},
{name: "Display name", displayName: i18next.t("general:Display name")},
{name: "Affiliation", displayName: i18next.t("user:Affiliation")},
{name: "Gender", displayName: i18next.t("user:Gender")},
{name: "Bio", displayName: i18next.t("user:Bio")},
{name: "Tag", displayName: i18next.t("user:Tag")},
{name: "Education", displayName: i18next.t("user:Education")},
{name: "Country/Region", displayName: i18next.t("user:Country/Region")},
{name: "ID card", displayName: i18next.t("user:ID card")},
{name: "Password", displayName: i18next.t("general:Password")},
@ -201,6 +205,25 @@ class SignupTable extends React.Component {
);
},
},
{
title: i18next.t("provider:Type"),
dataIndex: "type",
key: "type",
width: "160px",
render: (text, record, index) => {
const options = [
{id: "Input", name: i18next.t("application:Input")},
{id: "Single Choice", name: i18next.t("application:Single Choice")},
{id: "Multiple Choices", name: i18next.t("application:Multiple Choices")},
];
return (
<Select virtual={false} style={{width: "100%"}} value={text} onChange={(value => {
this.updateField(table, index, "type", value);
})} options={options.map(item => Setting.getOption(item.name, item.id))} />
);
},
},
{
title: i18next.t("signup:Label"),
dataIndex: "label",
@ -261,7 +284,7 @@ class SignupTable extends React.Component {
title: i18next.t("signup:Placeholder"),
dataIndex: "placeholder",
key: "placeholder",
width: "200px",
width: "110px",
render: (text, record, index) => {
if (record.name.startsWith("Text ")) {
return null;
@ -274,6 +297,26 @@ class SignupTable extends React.Component {
);
},
},
{
title: i18next.t("signup:Options"),
dataIndex: "options",
key: "options",
width: "180px",
render: (text, record, index) => {
if (record.type !== "Single Choice" && record.type !== "Multiple Choices") {
return null;
}
return (
<Select virtual={false} mode="tags" style={{width: "100%"}} value={text}
onChange={(value => {
this.updateField(table, index, "options", value);
})}
options={text?.map((option) => Setting.getOption(option, option))}
/>
);
},
},
{
title: i18next.t("signup:Regex"),
dataIndex: "regex",

View File

@ -6101,6 +6101,11 @@ crypto-es@^1.2.2:
resolved "https://registry.yarnpkg.com/crypto-es/-/crypto-es-1.2.7.tgz#754a6d52319a94fb4eb1f119297f17196b360f88"
integrity sha512-UUqiVJ2gUuZFmbFsKmud3uuLcNP2+Opt+5ysmljycFCyhA0+T16XJmo1ev/t5kMChMqWh7IEvURNCqsg+SjZGQ==
crypto-js@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
crypto-random-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"