mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-15 12:53:50 +08:00
Compare commits
52 Commits
Author | SHA1 | Date | |
---|---|---|---|
f14711d315 | |||
58e1c28f7c | |||
922b19c64b | |||
1d21c3fa90 | |||
6175fd6764 | |||
2ceb54f058 | |||
aaeaa7fefa | |||
d522247552 | |||
79dbdab6c9 | |||
fe40910e3b | |||
2d1736f13a | |||
12b4d1c7cd | |||
a45d2b87c1 | |||
8484465d09 | |||
dff65eee20 | |||
596016456c | |||
673261c258 | |||
3c5985a3c0 | |||
4f3d62520a | |||
96f8b3d937 | |||
7ab5a5ade1 | |||
5cbd0a96ca | |||
7ccd8c4d4f | |||
b0fa3fc484 | |||
af01c4226a | |||
7a3d85a29a | |||
fd5ccd8d41 | |||
a439c5195d | |||
ba2e997d54 | |||
0818de85d1 | |||
457c6098a4 | |||
60f979fbb5 | |||
ff53e44fa6 | |||
1832de47db | |||
535eb0c465 | |||
c190634cf3 | |||
f7559aa040 | |||
1e0b709c73 | |||
c0800b7fb3 | |||
6fcdad2100 | |||
69d26d5c21 | |||
94e6b5ecb8 | |||
95e8bdcd36 | |||
6f1f93725e | |||
7ae067e369 | |||
dde936e935 | |||
fb561a98c8 | |||
7cd8f030ee | |||
a3f8ded10c | |||
e3d135bc6e | |||
fc864b0de4 | |||
3211bcc777 |
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@ -114,12 +114,12 @@ jobs:
|
||||
wait-on-timeout: 210
|
||||
working-directory: ./web
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: cypress-screenshots
|
||||
path: ./web/cypress/screenshots
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: cypress-videos
|
||||
@ -147,7 +147,7 @@ jobs:
|
||||
- name: Release
|
||||
run: yarn global add semantic-release@17.4.4 && semantic-release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Fetch Current version
|
||||
id: get-current-tag
|
||||
|
@ -98,6 +98,7 @@ p, *, *, GET, /api/get-organization-names, *, *
|
||||
p, *, *, GET, /api/get-all-objects, *, *
|
||||
p, *, *, GET, /api/get-all-actions, *, *
|
||||
p, *, *, GET, /api/get-all-roles, *, *
|
||||
p, *, *, GET, /api/run-casbin-command, *, *
|
||||
p, *, *, GET, /api/get-invitation-info, *, *
|
||||
p, *, *, GET, /api/faceid-signin-begin, *, *
|
||||
`
|
||||
|
@ -25,9 +25,12 @@ enableErrorMask = false
|
||||
enableGzip = true
|
||||
inactiveTimeoutMinutes =
|
||||
ldapServerPort = 389
|
||||
ldapsCertId = ""
|
||||
ldapsServerPort = 636
|
||||
radiusServerPort = 1812
|
||||
radiusSecret = "secret"
|
||||
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}
|
||||
logConfig = {"filename": "logs/casdoor.log", "maxdays":99999, "perm":"0770"}
|
||||
initDataNewOnly = false
|
||||
initDataFile = "./init_data.json"
|
||||
frontendBaseDir = "../casdoor"
|
||||
frontendBaseDir = "../cc_0"
|
@ -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)
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
@ -844,6 +854,7 @@ func (c *ApiController) Login() {
|
||||
}
|
||||
|
||||
if authForm.Passcode != "" {
|
||||
user.CountryCode = user.GetCountryCode(user.CountryCode)
|
||||
mfaUtil := object.GetMfaUtil(authForm.MfaType, user.GetPreferredMfaProps(false))
|
||||
if mfaUtil == nil {
|
||||
c.ResponseError("Invalid multi-factor authentication type")
|
||||
|
114
controllers/casbin_cli_api.go
Normal file
114
controllers/casbin_cli_api.go
Normal file
@ -0,0 +1,114 @@
|
||||
// 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 controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func processArgsToTempFiles(args []string) ([]string, []string, error) {
|
||||
tempFiles := []string{}
|
||||
newArgs := []string{}
|
||||
for i := 0; i < len(args); i++ {
|
||||
if (args[i] == "-m" || args[i] == "-p") && i+1 < len(args) {
|
||||
pattern := fmt.Sprintf("casbin_temp_%s_*.conf", args[i])
|
||||
tempFile, err := os.CreateTemp("", pattern)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create temp file: %v", err)
|
||||
}
|
||||
|
||||
_, err = tempFile.WriteString(args[i+1])
|
||||
if err != nil {
|
||||
tempFile.Close()
|
||||
return nil, nil, fmt.Errorf("failed to write to temp file: %v", err)
|
||||
}
|
||||
|
||||
tempFile.Close()
|
||||
tempFiles = append(tempFiles, tempFile.Name())
|
||||
newArgs = append(newArgs, args[i], tempFile.Name())
|
||||
i++
|
||||
} else {
|
||||
newArgs = append(newArgs, args[i])
|
||||
}
|
||||
}
|
||||
return tempFiles, newArgs, nil
|
||||
}
|
||||
|
||||
// RunCasbinCommand
|
||||
// @Title RunCasbinCommand
|
||||
// @Tag Enforcer API
|
||||
// @Description Call Casbin CLI commands
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /run-casbin-command [get]
|
||||
func (c *ApiController) RunCasbinCommand() {
|
||||
language := c.Input().Get("language")
|
||||
argString := c.Input().Get("args")
|
||||
|
||||
if language == "" {
|
||||
language = "go"
|
||||
}
|
||||
// use "casbin-go-cli" by default, can be also "casbin-java-cli", "casbin-node-cli", etc.
|
||||
// the pre-built binary of "casbin-go-cli" can be found at: https://github.com/casbin/casbin-go-cli/releases
|
||||
binaryName := fmt.Sprintf("casbin-%s-cli", language)
|
||||
|
||||
_, err := exec.LookPath(binaryName)
|
||||
if err != nil {
|
||||
c.ResponseError(fmt.Sprintf("executable file: %s not found in PATH", binaryName))
|
||||
return
|
||||
}
|
||||
|
||||
// RBAC model & policy example:
|
||||
// https://door.casdoor.com/api/run-casbin-command?language=go&args=["enforce", "-m", "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n[matchers]\nm = g(r.sub, p.sub) %26%26 r.obj == p.obj %26%26 r.act == p.act", "-p", "p, alice, data1, read\np, bob, data2, write\np, data2_admin, data2, read\np, data2_admin, data2, write\ng, alice, data2_admin", "alice", "data1", "read"]
|
||||
// Casbin CLI usage:
|
||||
// https://github.com/jcasbin/casbin-java-cli?tab=readme-ov-file#get-started
|
||||
var args []string
|
||||
err = json.Unmarshal([]byte(argString), &args)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
tempFiles, processedArgs, err := processArgsToTempFiles(args)
|
||||
defer func() {
|
||||
for _, file := range tempFiles {
|
||||
os.Remove(file)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
command := exec.Command(binaryName, processedArgs...)
|
||||
outputBytes, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
errorString := err.Error()
|
||||
if outputBytes != nil {
|
||||
output := string(outputBytes)
|
||||
errorString = fmt.Sprintf("%s, error: %s", output, err.Error())
|
||||
}
|
||||
|
||||
c.ResponseError(errorString)
|
||||
return
|
||||
}
|
||||
|
||||
output := string(outputBytes)
|
||||
output = strings.TrimSuffix(output, "\n")
|
||||
c.ResponseOk(output)
|
||||
}
|
@ -22,13 +22,6 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
MfaRecoveryCodesSession = "mfa_recovery_codes"
|
||||
MfaCountryCodeSession = "mfa_country_code"
|
||||
MfaDestSession = "mfa_dest"
|
||||
MfaTotpSecretSession = "mfa_totp_secret"
|
||||
)
|
||||
|
||||
// MfaSetupInitiate
|
||||
// @Title MfaSetupInitiate
|
||||
// @Tag MFA API
|
||||
@ -72,11 +65,6 @@ func (c *ApiController) MfaSetupInitiate() {
|
||||
}
|
||||
|
||||
recoveryCode := uuid.NewString()
|
||||
c.SetSession(MfaRecoveryCodesSession, recoveryCode)
|
||||
if mfaType == object.TotpType {
|
||||
c.SetSession(MfaTotpSecretSession, mfaProps.Secret)
|
||||
}
|
||||
|
||||
mfaProps.RecoveryCodes = []string{recoveryCode}
|
||||
|
||||
resp := mfaProps
|
||||
@ -94,6 +82,9 @@ func (c *ApiController) MfaSetupInitiate() {
|
||||
func (c *ApiController) MfaSetupVerify() {
|
||||
mfaType := c.Ctx.Request.Form.Get("mfaType")
|
||||
passcode := c.Ctx.Request.Form.Get("passcode")
|
||||
secret := c.Ctx.Request.Form.Get("secret")
|
||||
dest := c.Ctx.Request.Form.Get("dest")
|
||||
countryCode := c.Ctx.Request.Form.Get("countryCode")
|
||||
|
||||
if mfaType == "" || passcode == "" {
|
||||
c.ResponseError("missing auth type or passcode")
|
||||
@ -104,32 +95,28 @@ func (c *ApiController) MfaSetupVerify() {
|
||||
MfaType: mfaType,
|
||||
}
|
||||
if mfaType == object.TotpType {
|
||||
secret := c.GetSession(MfaTotpSecretSession)
|
||||
if secret == nil {
|
||||
if secret == "" {
|
||||
c.ResponseError("totp secret is missing")
|
||||
return
|
||||
}
|
||||
config.Secret = secret.(string)
|
||||
config.Secret = secret
|
||||
} else if mfaType == object.SmsType {
|
||||
dest := c.GetSession(MfaDestSession)
|
||||
if dest == nil {
|
||||
if dest == "" {
|
||||
c.ResponseError("destination is missing")
|
||||
return
|
||||
}
|
||||
config.Secret = dest.(string)
|
||||
countryCode := c.GetSession(MfaCountryCodeSession)
|
||||
if countryCode == nil {
|
||||
config.Secret = dest
|
||||
if countryCode == "" {
|
||||
c.ResponseError("country code is missing")
|
||||
return
|
||||
}
|
||||
config.CountryCode = countryCode.(string)
|
||||
config.CountryCode = countryCode
|
||||
} else if mfaType == object.EmailType {
|
||||
dest := c.GetSession(MfaDestSession)
|
||||
if dest == nil {
|
||||
if dest == "" {
|
||||
c.ResponseError("destination is missing")
|
||||
return
|
||||
}
|
||||
config.Secret = dest.(string)
|
||||
config.Secret = dest
|
||||
}
|
||||
|
||||
mfaUtil := object.GetMfaUtil(mfaType, config)
|
||||
@ -159,6 +146,10 @@ func (c *ApiController) MfaSetupEnable() {
|
||||
owner := c.Ctx.Request.Form.Get("owner")
|
||||
name := c.Ctx.Request.Form.Get("name")
|
||||
mfaType := c.Ctx.Request.Form.Get("mfaType")
|
||||
secret := c.Ctx.Request.Form.Get("secret")
|
||||
dest := c.Ctx.Request.Form.Get("dest")
|
||||
countryCode := c.Ctx.Request.Form.Get("secret")
|
||||
recoveryCodes := c.Ctx.Request.Form.Get("recoveryCodes")
|
||||
|
||||
user, err := object.GetUser(util.GetId(owner, name))
|
||||
if err != nil {
|
||||
@ -176,43 +167,39 @@ func (c *ApiController) MfaSetupEnable() {
|
||||
}
|
||||
|
||||
if mfaType == object.TotpType {
|
||||
secret := c.GetSession(MfaTotpSecretSession)
|
||||
if secret == nil {
|
||||
if secret == "" {
|
||||
c.ResponseError("totp secret is missing")
|
||||
return
|
||||
}
|
||||
config.Secret = secret.(string)
|
||||
config.Secret = secret
|
||||
} else if mfaType == object.EmailType {
|
||||
if user.Email == "" {
|
||||
dest := c.GetSession(MfaDestSession)
|
||||
if dest == nil {
|
||||
if dest == "" {
|
||||
c.ResponseError("destination is missing")
|
||||
return
|
||||
}
|
||||
user.Email = dest.(string)
|
||||
user.Email = dest
|
||||
}
|
||||
} else if mfaType == object.SmsType {
|
||||
if user.Phone == "" {
|
||||
dest := c.GetSession(MfaDestSession)
|
||||
if dest == nil {
|
||||
if dest == "" {
|
||||
c.ResponseError("destination is missing")
|
||||
return
|
||||
}
|
||||
user.Phone = dest.(string)
|
||||
countryCode := c.GetSession(MfaCountryCodeSession)
|
||||
if countryCode == nil {
|
||||
user.Phone = dest
|
||||
if countryCode == "" {
|
||||
c.ResponseError("country code is missing")
|
||||
return
|
||||
}
|
||||
user.CountryCode = countryCode.(string)
|
||||
user.CountryCode = countryCode
|
||||
}
|
||||
}
|
||||
recoveryCodes := c.GetSession(MfaRecoveryCodesSession)
|
||||
if recoveryCodes == nil {
|
||||
|
||||
if recoveryCodes == "" {
|
||||
c.ResponseError("recovery codes is missing")
|
||||
return
|
||||
}
|
||||
config.RecoveryCodes = []string{recoveryCodes.(string)}
|
||||
config.RecoveryCodes = []string{recoveryCodes}
|
||||
|
||||
mfaUtil := object.GetMfaUtil(mfaType, config)
|
||||
if mfaUtil == nil {
|
||||
@ -226,14 +213,6 @@ func (c *ApiController) MfaSetupEnable() {
|
||||
return
|
||||
}
|
||||
|
||||
c.DelSession(MfaRecoveryCodesSession)
|
||||
if mfaType == object.TotpType {
|
||||
c.DelSession(MfaTotpSecretSession)
|
||||
} else {
|
||||
c.DelSession(MfaCountryCodeSession)
|
||||
c.DelSession(MfaDestSession)
|
||||
}
|
||||
|
||||
c.ResponseOk(http.StatusText(http.StatusOK))
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
|
@ -182,6 +182,10 @@ func (c *ApiController) BuyProduct() {
|
||||
paidUserName := c.Input().Get("userName")
|
||||
owner, _ := util.GetOwnerAndNameFromId(id)
|
||||
userId := util.GetId(owner, paidUserName)
|
||||
if paidUserName != "" && !c.IsAdmin() {
|
||||
c.ResponseError(c.T("general:Only admin user can specify user"))
|
||||
return
|
||||
}
|
||||
if paidUserName == "" {
|
||||
userId = c.GetSessionUsername()
|
||||
}
|
||||
|
@ -322,17 +322,22 @@ func (c *ApiController) IntrospectToken() {
|
||||
}
|
||||
|
||||
tokenTypeHint := c.Input().Get("token_type_hint")
|
||||
token, err := object.GetTokenByTokenValue(tokenValue, tokenTypeHint)
|
||||
if err != nil {
|
||||
c.ResponseTokenError(err.Error())
|
||||
return
|
||||
}
|
||||
if token == nil {
|
||||
c.Data["json"] = &object.IntrospectionResponse{Active: false}
|
||||
c.ServeJSON()
|
||||
return
|
||||
var token *object.Token
|
||||
if tokenTypeHint != "" {
|
||||
token, err = object.GetTokenByTokenValue(tokenValue, tokenTypeHint)
|
||||
if err != nil {
|
||||
c.ResponseTokenError(err.Error())
|
||||
return
|
||||
}
|
||||
if token == nil {
|
||||
c.Data["json"] = &object.IntrospectionResponse{Active: false}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var introspectionResponse object.IntrospectionResponse
|
||||
|
||||
if application.TokenFormat == "JWT-Standard" {
|
||||
jwtToken, err := object.ParseStandardJwtTokenByApplication(tokenValue, application)
|
||||
if err != nil || jwtToken.Valid() != nil {
|
||||
@ -344,12 +349,37 @@ func (c *ApiController) IntrospectToken() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = &object.IntrospectionResponse{
|
||||
introspectionResponse = object.IntrospectionResponse{
|
||||
Active: true,
|
||||
Scope: jwtToken.Scope,
|
||||
ClientId: clientId,
|
||||
Username: token.User,
|
||||
TokenType: token.TokenType,
|
||||
Username: jwtToken.Name,
|
||||
TokenType: jwtToken.TokenType,
|
||||
Exp: jwtToken.ExpiresAt.Unix(),
|
||||
Iat: jwtToken.IssuedAt.Unix(),
|
||||
Nbf: jwtToken.NotBefore.Unix(),
|
||||
Sub: jwtToken.Subject,
|
||||
Aud: jwtToken.Audience,
|
||||
Iss: jwtToken.Issuer,
|
||||
Jti: jwtToken.ID,
|
||||
}
|
||||
} else {
|
||||
jwtToken, err := object.ParseJwtTokenByApplication(tokenValue, application)
|
||||
if err != nil || jwtToken.Valid() != nil {
|
||||
// and token revoked case. but we not implement
|
||||
// TODO: 2022-03-03 add token revoked check, when we implemented the Token Revocation(rfc7009) Specs.
|
||||
// refs: https://tools.ietf.org/html/rfc7009
|
||||
c.Data["json"] = &object.IntrospectionResponse{Active: false}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
introspectionResponse = object.IntrospectionResponse{
|
||||
Active: true,
|
||||
Scope: jwtToken.Scope,
|
||||
ClientId: clientId,
|
||||
Username: jwtToken.Name,
|
||||
TokenType: jwtToken.TokenType,
|
||||
Exp: jwtToken.ExpiresAt.Unix(),
|
||||
Iat: jwtToken.IssuedAt.Unix(),
|
||||
Nbf: jwtToken.NotBefore.Unix(),
|
||||
@ -358,33 +388,22 @@ func (c *ApiController) IntrospectToken() {
|
||||
Iss: jwtToken.Issuer,
|
||||
Jti: jwtToken.ID,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
jwtToken, err := object.ParseJwtTokenByApplication(tokenValue, application)
|
||||
if err != nil || jwtToken.Valid() != nil {
|
||||
// and token revoked case. but we not implement
|
||||
// TODO: 2022-03-03 add token revoked check, when we implemented the Token Revocation(rfc7009) Specs.
|
||||
// refs: https://tools.ietf.org/html/rfc7009
|
||||
c.Data["json"] = &object.IntrospectionResponse{Active: false}
|
||||
c.ServeJSON()
|
||||
return
|
||||
if tokenTypeHint == "" {
|
||||
token, err = object.GetTokenByTokenValue(tokenValue, introspectionResponse.TokenType)
|
||||
if err != nil {
|
||||
c.ResponseTokenError(err.Error())
|
||||
return
|
||||
}
|
||||
if token == nil {
|
||||
c.Data["json"] = &object.IntrospectionResponse{Active: false}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
}
|
||||
introspectionResponse.TokenType = token.TokenType
|
||||
|
||||
c.Data["json"] = &object.IntrospectionResponse{
|
||||
Active: true,
|
||||
Scope: jwtToken.Scope,
|
||||
ClientId: clientId,
|
||||
Username: token.User,
|
||||
TokenType: token.TokenType,
|
||||
Exp: jwtToken.ExpiresAt.Unix(),
|
||||
Iat: jwtToken.IssuedAt.Unix(),
|
||||
Nbf: jwtToken.NotBefore.Unix(),
|
||||
Sub: jwtToken.Subject,
|
||||
Aud: jwtToken.Audience,
|
||||
Iss: jwtToken.Issuer,
|
||||
Jti: jwtToken.ID,
|
||||
}
|
||||
c.Data["json"] = introspectionResponse
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
@ -364,7 +364,8 @@ func (c *ApiController) AddUser() {
|
||||
return
|
||||
}
|
||||
|
||||
msg := object.CheckUsername(user.Name, c.GetAcceptLanguage())
|
||||
emptyUser := object.User{}
|
||||
msg := object.CheckUpdateUser(&emptyUser, &user, c.GetAcceptLanguage())
|
||||
if msg != "" {
|
||||
c.ResponseError(msg)
|
||||
return
|
||||
@ -489,7 +490,12 @@ func (c *ApiController) SetPassword() {
|
||||
c.ResponseError(c.T("general:Missing parameter"))
|
||||
return
|
||||
}
|
||||
if userId != c.GetSession("verifiedUserId") {
|
||||
c.ResponseError(c.T("general:Wrong userId"))
|
||||
return
|
||||
}
|
||||
c.SetSession("verifiedCode", "")
|
||||
c.SetSession("verifiedUserId", "")
|
||||
}
|
||||
|
||||
targetUser, err := object.GetUser(userId)
|
||||
@ -535,11 +541,29 @@ 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
|
||||
targetUser.LastChangePasswordTime = util.GetCurrentTime()
|
||||
|
||||
_, err = object.UpdateUser(userId, targetUser, []string{"password", "need_update_password", "password_type"}, false)
|
||||
_, err = object.UpdateUser(userId, targetUser, []string{"password", "need_update_password", "password_type", "last_change_password_time"}, false)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
@ -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)
|
||||
@ -245,8 +246,6 @@ func (c *ApiController) SendVerificationCode() {
|
||||
if user != nil && util.GetMaskedEmail(mfaProps.Secret) == vform.Dest {
|
||||
vform.Dest = mfaProps.Secret
|
||||
}
|
||||
} else if vform.Method == MfaSetupVerification {
|
||||
c.SetSession(MfaDestSession, vform.Dest)
|
||||
}
|
||||
|
||||
provider, err = application.GetEmailProvider(vform.Method)
|
||||
@ -259,7 +258,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 {
|
||||
@ -281,11 +280,6 @@ func (c *ApiController) SendVerificationCode() {
|
||||
vform.CountryCode = user.GetCountryCode(vform.CountryCode)
|
||||
}
|
||||
}
|
||||
|
||||
if vform.Method == MfaSetupVerification {
|
||||
c.SetSession(MfaCountryCodeSession, vform.CountryCode)
|
||||
c.SetSession(MfaDestSession, vform.Dest)
|
||||
}
|
||||
} else if vform.Method == MfaAuthVerification {
|
||||
mfaProps := user.GetPreferredMfaProps(false)
|
||||
if user != nil && util.GetMaskedPhone(mfaProps.Secret) == vform.Dest {
|
||||
@ -293,6 +287,7 @@ func (c *ApiController) SendVerificationCode() {
|
||||
}
|
||||
|
||||
vform.CountryCode = mfaProps.CountryCode
|
||||
vform.CountryCode = user.GetCountryCode(vform.CountryCode)
|
||||
}
|
||||
|
||||
provider, err = application.GetSmsProvider(vform.Method, vform.CountryCode)
|
||||
@ -309,7 +304,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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -532,5 +527,6 @@ func (c *ApiController) VerifyCode() {
|
||||
}
|
||||
|
||||
c.SetSession("verifiedCode", authForm.Code)
|
||||
c.SetSession("verifiedUserId", user.GetId())
|
||||
c.ResponseOk()
|
||||
}
|
||||
|
2
go.mod
2
go.mod
@ -9,7 +9,7 @@ require (
|
||||
github.com/beego/beego v1.12.12
|
||||
github.com/beevik/etree v1.1.0
|
||||
github.com/casbin/casbin/v2 v2.77.2
|
||||
github.com/casdoor/go-sms-sender v0.24.0
|
||||
github.com/casdoor/go-sms-sender v0.25.0
|
||||
github.com/casdoor/gomail/v2 v2.0.1
|
||||
github.com/casdoor/ldapserver v1.2.0
|
||||
github.com/casdoor/notify v0.45.0
|
||||
|
4
go.sum
4
go.sum
@ -1087,8 +1087,8 @@ github.com/casdoor/casdoor-go-sdk v0.50.0 h1:bUYbz/MzJuWfLKJbJM0+U0YpYewAur+THp5
|
||||
github.com/casdoor/casdoor-go-sdk v0.50.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4=
|
||||
github.com/casdoor/go-reddit/v2 v2.1.0 h1:kIbfdJ7AA7H0uTQ8s0q4GGZqSS5V9wVE74RrXyD9XPs=
|
||||
github.com/casdoor/go-reddit/v2 v2.1.0/go.mod h1:eagkvwlZ4Hcsuc/uQsLHYEulz5jN65SVSwV/AIE7zsc=
|
||||
github.com/casdoor/go-sms-sender v0.24.0 h1:LNLsce3EG/87I3JS6UiajF3LlQmdIiCgebEu0IE4wSM=
|
||||
github.com/casdoor/go-sms-sender v0.24.0/go.mod h1:bOm4H8/YfJmEHjBatEVQFOnAf0OOn1B0Wi5B7zDhws0=
|
||||
github.com/casdoor/go-sms-sender v0.25.0 h1:eF4cOCSbjVg7+0uLlJQnna/FQ0BWW+Fp/x4cXhzQu1Y=
|
||||
github.com/casdoor/go-sms-sender v0.25.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=
|
||||
|
@ -1,167 +1,167 @@
|
||||
{
|
||||
"account": {
|
||||
"Failed to add user": "Failed to add user",
|
||||
"Get init score failed, error: %w": "Get init score failed, error: %w",
|
||||
"Please sign out first": "Please sign out first",
|
||||
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
|
||||
"Failed to add user": "عدم موفقیت در افزودن کاربر",
|
||||
"Get init score failed, error: %w": "عدم موفقیت در دریافت امتیاز اولیه، خطا: %w",
|
||||
"Please sign out first": "لطفاً ابتدا خارج شوید",
|
||||
"The application does not allow to sign up new account": "برنامه اجازه ثبتنام حساب جدید را نمیدهد"
|
||||
},
|
||||
"auth": {
|
||||
"Challenge method should be S256": "Challenge method should be S256",
|
||||
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
|
||||
"Failed to login in: %s": "Failed to login in: %s",
|
||||
"Invalid token": "Invalid token",
|
||||
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||
"The application: %s does not exist": "The application: %s does not exist",
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing"
|
||||
"Challenge method should be S256": "روش چالش باید S256 باشد",
|
||||
"Failed to create user, user information is invalid: %s": "عدم موفقیت در ایجاد کاربر، اطلاعات کاربر نامعتبر است: %s",
|
||||
"Failed to login in: %s": "عدم موفقیت در ورود: %s",
|
||||
"Invalid token": "توکن نامعتبر",
|
||||
"State expected: %s, but got: %s": "وضعیت مورد انتظار: %s، اما دریافت شد: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "حساب برای ارائهدهنده: %s و نام کاربری: %s (%s) وجود ندارد و مجاز به ثبتنام بهعنوان حساب جدید از طریق %%s نیست، لطفاً از روش دیگری برای ثبتنام استفاده کنید",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "حساب برای ارائهدهنده: %s و نام کاربری: %s (%s) وجود ندارد و مجاز به ثبتنام بهعنوان حساب جدید نیست، لطفاً با پشتیبانی IT خود تماس بگیرید",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "حساب برای ارائهدهنده: %s و نام کاربری: %s (%s) در حال حاضر به حساب دیگری مرتبط است: %s (%s)",
|
||||
"The application: %s does not exist": "برنامه: %s وجود ندارد",
|
||||
"The login method: login with LDAP is not enabled for the application": "روش ورود: ورود با LDAP برای برنامه فعال نیست",
|
||||
"The login method: login with SMS is not enabled for the application": "روش ورود: ورود با پیامک برای برنامه فعال نیست",
|
||||
"The login method: login with email is not enabled for the application": "روش ورود: ورود با ایمیل برای برنامه فعال نیست",
|
||||
"The login method: login with face is not enabled for the application": "روش ورود: ورود با چهره برای برنامه فعال نیست",
|
||||
"The login method: login with password is not enabled for the application": "روش ورود: ورود با رمز عبور برای برنامه فعال نیست",
|
||||
"The organization: %s does not exist": "سازمان: %s وجود ندارد",
|
||||
"The provider: %s is not enabled for the application": "ارائهدهنده: %s برای برنامه فعال نیست",
|
||||
"Unauthorized operation": "عملیات غیرمجاز",
|
||||
"Unknown authentication type (not password or provider), form = %s": "نوع احراز هویت ناشناخته (نه رمز عبور و نه ارائهدهنده)، فرم = %s",
|
||||
"User's tag: %s is not listed in the application's tags": "برچسب کاربر: %s در برچسبهای برنامه فهرست نشده است",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "کاربر پرداختی %s اشتراک فعال یا در انتظار ندارد و برنامه: %s قیمتگذاری پیشفرض ندارد"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "Service %s and %s do not match"
|
||||
"Service %s and %s do not match": "سرویس %s و %s مطابقت ندارند"
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
"Invitation code is invalid": "Invitation code is invalid",
|
||||
"Invitation code suspended": "Invitation code suspended",
|
||||
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
|
||||
"LastName cannot be blank": "LastName cannot be blank",
|
||||
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
|
||||
"Organization does not exist": "Organization does not exist",
|
||||
"Phone already exists": "Phone already exists",
|
||||
"Phone cannot be empty": "Phone cannot be empty",
|
||||
"Phone number is invalid": "Phone number is invalid",
|
||||
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
|
||||
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
|
||||
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
|
||||
"Session outdated, please login again": "Session outdated, please login again",
|
||||
"The invitation code has already been used": "The invitation code has already been used",
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
"Username cannot contain white spaces": "Username cannot contain white spaces",
|
||||
"Username cannot start with a digit": "Username cannot start with a digit",
|
||||
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
|
||||
"Username must have at least 2 characters": "Username must have at least 2 characters",
|
||||
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
|
||||
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
|
||||
"password or code is incorrect": "password or code is incorrect",
|
||||
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
|
||||
"unsupported password type: %s": "unsupported password type: %s"
|
||||
"Affiliation cannot be blank": "وابستگی نمیتواند خالی باشد",
|
||||
"Default code does not match the code's matching rules": "کد پیشفرض با قوانین تطبیق کد مطابقت ندارد",
|
||||
"DisplayName cannot be blank": "نام نمایشی نمیتواند خالی باشد",
|
||||
"DisplayName is not valid real name": "نام نمایشی یک نام واقعی معتبر نیست",
|
||||
"Email already exists": "ایمیل قبلاً وجود دارد",
|
||||
"Email cannot be empty": "ایمیل نمیتواند خالی باشد",
|
||||
"Email is invalid": "ایمیل نامعتبر است",
|
||||
"Empty username.": "نام کاربری خالی است.",
|
||||
"Face data does not exist, cannot log in": "دادههای چهره وجود ندارد، نمیتوان وارد شد",
|
||||
"Face data mismatch": "عدم تطابق دادههای چهره",
|
||||
"FirstName cannot be blank": "نام نمیتواند خالی باشد",
|
||||
"Invitation code cannot be blank": "کد دعوت نمیتواند خالی باشد",
|
||||
"Invitation code exhausted": "کد دعوت استفاده شده است",
|
||||
"Invitation code is invalid": "کد دعوت نامعتبر است",
|
||||
"Invitation code suspended": "کد دعوت معلق است",
|
||||
"LDAP user name or password incorrect": "نام کاربری یا رمز عبور LDAP نادرست است",
|
||||
"LastName cannot be blank": "نام خانوادگی نمیتواند خالی باشد",
|
||||
"Multiple accounts with same uid, please check your ldap server": "چندین حساب با uid یکسان، لطفاً سرور LDAP خود را بررسی کنید",
|
||||
"Organization does not exist": "سازمان وجود ندارد",
|
||||
"Phone already exists": "تلفن قبلاً وجود دارد",
|
||||
"Phone cannot be empty": "تلفن نمیتواند خالی باشد",
|
||||
"Phone number is invalid": "شماره تلفن نامعتبر است",
|
||||
"Please register using the email corresponding to the invitation code": "لطفاً با استفاده از ایمیل مربوط به کد دعوت ثبتنام کنید",
|
||||
"Please register using the phone corresponding to the invitation code": "لطفاً با استفاده از تلفن مربوط به کد دعوت ثبتنام کنید",
|
||||
"Please register using the username corresponding to the invitation code": "لطفاً با استفاده از نام کاربری مربوط به کد دعوت ثبتنام کنید",
|
||||
"Session outdated, please login again": "جلسه منقضی شده است، لطفاً دوباره وارد شوید",
|
||||
"The invitation code has already been used": "کد دعوت قبلاً استفاده شده است",
|
||||
"The user is forbidden to sign in, please contact the administrator": "ورود کاربر ممنوع است، لطفاً با مدیر تماس بگیرید",
|
||||
"The user: %s doesn't exist in LDAP server": "کاربر: %s در سرور LDAP وجود ندارد",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "نام کاربری فقط میتواند حاوی کاراکترهای الفبایی عددی، زیرخط یا خط تیره باشد، نمیتواند خط تیره یا زیرخط متوالی داشته باشد، و نمیتواند با خط تیره یا زیرخط شروع یا پایان یابد.",
|
||||
"The value \"%s\" for account field \"%s\" doesn't match the account item regex": "مقدار \"%s\" برای فیلد حساب \"%s\" با عبارت منظم مورد حساب مطابقت ندارد",
|
||||
"The value \"%s\" for signup field \"%s\" doesn't match the signup item regex of the application \"%s\"": "مقدار \"%s\" برای فیلد ثبتنام \"%s\" با عبارت منظم مورد ثبتنام برنامه \"%s\" مطابقت ندارد",
|
||||
"Username already exists": "نام کاربری قبلاً وجود دارد",
|
||||
"Username cannot be an email address": "نام کاربری نمیتواند یک آدرس ایمیل باشد",
|
||||
"Username cannot contain white spaces": "نام کاربری نمیتواند حاوی فاصله باشد",
|
||||
"Username cannot start with a digit": "نام کاربری نمیتواند با یک رقم شروع شود",
|
||||
"Username is too long (maximum is 39 characters).": "نام کاربری بیش از حد طولانی است (حداکثر ۳۹ کاراکتر).",
|
||||
"Username must have at least 2 characters": "نام کاربری باید حداقل ۲ کاراکتر داشته باشد",
|
||||
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "شما رمز عبور یا کد اشتباه را بیش از حد وارد کردهاید، لطفاً %d دقیقه صبر کنید و دوباره تلاش کنید",
|
||||
"Your region is not allow to signup by phone": "منطقه شما اجازه ثبتنام با تلفن را ندارد",
|
||||
"password or code is incorrect": "رمز عبور یا کد نادرست است",
|
||||
"password or code is incorrect, you have %d remaining chances": "رمز عبور یا کد نادرست است، شما %d فرصت باقیمانده دارید",
|
||||
"unsupported password type: %s": "نوع رمز عبور پشتیبانی نشده: %s"
|
||||
},
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
|
||||
"this operation requires administrator to perform": "this operation requires administrator to perform"
|
||||
"Missing parameter": "پارامتر گمشده",
|
||||
"Please login first": "لطفاً ابتدا وارد شوید",
|
||||
"The organization: %s should have one application at least": "سازمان: %s باید حداقل یک برنامه داشته باشد",
|
||||
"The user: %s doesn't exist": "کاربر: %s وجود ندارد",
|
||||
"don't support captchaProvider: ": "از captchaProvider پشتیبانی نمیشود: ",
|
||||
"this operation is not allowed in demo mode": "این عملیات در حالت دمو مجاز نیست",
|
||||
"this operation requires administrator to perform": "این عملیات نیاز به مدیر برای انجام دارد"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Ldap server exist"
|
||||
"Ldap server exist": "سرور LDAP وجود دارد"
|
||||
},
|
||||
"link": {
|
||||
"Please link first": "Please link first",
|
||||
"This application has no providers": "This application has no providers",
|
||||
"This application has no providers of type": "This application has no providers of type",
|
||||
"This provider can't be unlinked": "This provider can't be unlinked",
|
||||
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
|
||||
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
|
||||
"Please link first": "لطفاً ابتدا پیوند دهید",
|
||||
"This application has no providers": "این برنامه ارائهدهندهای ندارد",
|
||||
"This application has no providers of type": "این برنامه ارائهدهندهای از نوع ندارد",
|
||||
"This provider can't be unlinked": "این ارائهدهنده نمیتواند لغو پیوند شود",
|
||||
"You are not the global admin, you can't unlink other users": "شما مدیر جهانی نیستید، نمیتوانید کاربران دیگر را لغو پیوند کنید",
|
||||
"You can't unlink yourself, you are not a member of any application": "شما نمیتوانید خودتان را لغو پیوند کنید، شما عضو هیچ برنامهای نیستید"
|
||||
},
|
||||
"organization": {
|
||||
"Only admin can modify the %s.": "Only admin can modify the %s.",
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
"Only admin can modify the %s.": "فقط مدیر میتواند %s را تغییر دهد.",
|
||||
"The %s is immutable.": "%s غیرقابل تغییر است.",
|
||||
"Unknown modify rule %s.": "قانون تغییر ناشناخته %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
"The permission: \"%s\" doesn't exist": "مجوز: \"%s\" وجود ندارد"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
"Invalid application id": "شناسه برنامه نامعتبر",
|
||||
"the provider: %s does not exist": "ارائهدهنده: %s وجود ندارد"
|
||||
},
|
||||
"resource": {
|
||||
"User is nil for tag: avatar": "User is nil for tag: avatar",
|
||||
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
|
||||
"User is nil for tag: avatar": "کاربر برای برچسب: آواتار تهی است",
|
||||
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "نام کاربری یا مسیر کامل فایل خالی است: نام کاربری = %s، مسیر کامل فایل = %s"
|
||||
},
|
||||
"saml": {
|
||||
"Application %s not found": "Application %s not found"
|
||||
"Application %s not found": "برنامه %s یافت نشد"
|
||||
},
|
||||
"saml_sp": {
|
||||
"provider %s's category is not SAML": "provider %s's category is not SAML"
|
||||
"provider %s's category is not SAML": "دستهبندی ارائهدهنده %s SAML نیست"
|
||||
},
|
||||
"service": {
|
||||
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
|
||||
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
|
||||
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
|
||||
"Empty parameters for emailForm: %v": "پارامترهای خالی برای emailForm: %v",
|
||||
"Invalid Email receivers: %s": "گیرندگان ایمیل نامعتبر: %s",
|
||||
"Invalid phone receivers: %s": "گیرندگان تلفن نامعتبر: %s"
|
||||
},
|
||||
"storage": {
|
||||
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
"The objectKey: %s is not allowed": "objectKey: %s مجاز نیست",
|
||||
"The provider type: %s is not supported": "نوع ارائهدهنده: %s پشتیبانی نمیشود"
|
||||
},
|
||||
"token": {
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
|
||||
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
||||
"Grant_type: %s is not supported in this application": "grant_type: %s در این برنامه پشتیبانی نمیشود",
|
||||
"Invalid application or wrong clientSecret": "برنامه نامعتبر یا clientSecret نادرست",
|
||||
"Invalid client_id": "client_id نامعتبر",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "آدرس بازگشت: %s در لیست آدرسهای بازگشت مجاز وجود ندارد",
|
||||
"Token not found, invalid accessToken": "توکن یافت نشد، accessToken نامعتبر"
|
||||
},
|
||||
"user": {
|
||||
"Display name cannot be empty": "Display name cannot be empty",
|
||||
"New password cannot contain blank space.": "New password cannot contain blank space."
|
||||
"Display name cannot be empty": "نام نمایشی نمیتواند خالی باشد",
|
||||
"New password cannot contain blank space.": "رمز عبور جدید نمیتواند حاوی فاصله خالی باشد."
|
||||
},
|
||||
"user_upload": {
|
||||
"Failed to import users": "Failed to import users"
|
||||
"Failed to import users": "عدم موفقیت در وارد کردن کاربران"
|
||||
},
|
||||
"util": {
|
||||
"No application is found for userId: %s": "No application is found for userId: %s",
|
||||
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
|
||||
"The provider: %s is not found": "The provider: %s is not found"
|
||||
"No application is found for userId: %s": "هیچ برنامهای برای userId: %s یافت نشد",
|
||||
"No provider for category: %s is found for application: %s": "هیچ ارائهدهندهای برای دستهبندی: %s برای برنامه: %s یافت نشد",
|
||||
"The provider: %s is not found": "ارائهدهنده: %s یافت نشد"
|
||||
},
|
||||
"verification": {
|
||||
"Invalid captcha provider.": "Invalid captcha provider.",
|
||||
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
|
||||
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"Turing test failed.": "Turing test failed.",
|
||||
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
||||
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
"Invalid captcha provider.": "ارائهدهنده کپچا نامعتبر.",
|
||||
"Phone number is invalid in your region %s": "شماره تلفن در منطقه شما نامعتبر است %s",
|
||||
"The verification code has not been sent yet!": "کد تأیید هنوز ارسال نشده است!",
|
||||
"The verification code has not been sent yet, or has already been used!": "کد تأیید هنوز ارسال نشده است، یا قبلاً استفاده شده است!",
|
||||
"Turing test failed.": "تست تورینگ ناموفق بود.",
|
||||
"Unable to get the email modify rule.": "عدم توانایی در دریافت قانون تغییر ایمیل.",
|
||||
"Unable to get the phone modify rule.": "عدم توانایی در دریافت قانون تغییر تلفن.",
|
||||
"Unknown type": "نوع ناشناخته",
|
||||
"Wrong verification code!": "کد تأیید اشتباه!",
|
||||
"You should verify your code in %d min!": "شما باید کد خود را در %d دقیقه تأیید کنید!",
|
||||
"please add a SMS provider to the \"Providers\" list for the application: %s": "لطفاً یک ارائهدهنده پیامک به لیست \"ارائهدهندگان\" برای برنامه: %s اضافه کنید",
|
||||
"please add an Email provider to the \"Providers\" list for the application: %s": "لطفاً یک ارائهدهنده ایمیل به لیست \"ارائهدهندگان\" برای برنامه: %s اضافه کنید",
|
||||
"the user does not exist, please sign up first": "کاربر وجود ندارد، لطفاً ابتدا ثبتنام کنید"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
|
||||
"Found no credentials for this user": "هیچ اعتباری برای این کاربر یافت نشد",
|
||||
"Please call WebAuthnSigninBegin first": "لطفاً ابتدا WebAuthnSigninBegin را فراخوانی کنید"
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,10 @@
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Аккаунт для провайдера: %s и имя пользователя: %s (%s) не существует и не может быть зарегистрирован как новый аккаунт. Пожалуйста, обратитесь в службу поддержки IT",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Аккаунт поставщика: %s и имя пользователя: %s (%s) уже связаны с другим аккаунтом: %s (%s)",
|
||||
"The application: %s does not exist": "Приложение: %s не существует",
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with LDAP is not enabled for the application": "Метод входа в систему: вход с помощью LDAP не включен для приложения",
|
||||
"The login method: login with SMS is not enabled for the application": "Метод входа: вход с помощью SMS не включен для приложения",
|
||||
"The login method: login with email is not enabled for the application": "Метод входа: вход с помощью электронной почты не включен для приложения",
|
||||
"The login method: login with face is not enabled for the application": "Метод входа: вход с помощью лица не включен для приложения",
|
||||
"The login method: login with password is not enabled for the application": "Метод входа: вход с паролем не включен для приложения",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "Провайдер: %s не включен для приложения",
|
||||
@ -53,16 +53,16 @@
|
||||
"Phone already exists": "Телефон уже существует",
|
||||
"Phone cannot be empty": "Телефон не может быть пустым",
|
||||
"Phone number is invalid": "Номер телефона является недействительным",
|
||||
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
|
||||
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
|
||||
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
|
||||
"Please register using the email corresponding to the invitation code": "Пожалуйста, зарегистрируйтесь, используя электронную почту, соответствующую коду приглашения",
|
||||
"Please register using the phone corresponding to the invitation code": "Пожалуйста, зарегистрируйтесь по телефону, соответствующему коду приглашения",
|
||||
"Please register using the username corresponding to the invitation code": "Пожалуйста, зарегистрируйтесь, используя имя пользователя, соответствующее коду приглашения",
|
||||
"Session outdated, please login again": "Сессия устарела, пожалуйста, войдите снова",
|
||||
"The invitation code has already been used": "The invitation code has already been used",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Пользователю запрещен вход, пожалуйста, обратитесь к администратору",
|
||||
"The user: %s doesn't exist in LDAP server": "Пользователь %s не существует на LDAP сервере",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Имя пользователя может состоять только из буквенно-цифровых символов, нижних подчеркиваний или дефисов, не может содержать последовательные дефисы или подчеркивания, а также не может начинаться или заканчиваться на дефис или подчеркивание.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "Значение \\\"%s\\\" для поля аккаунта \\\"%s\\\" не соответствует регулярному значению",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "Значение \\\"%s\\\" поля регистрации \\\"%s\\\" не соответствует регулярному выражению приложения \\\"%s\\\"",
|
||||
"Username already exists": "Имя пользователя уже существует",
|
||||
"Username cannot be an email address": "Имя пользователя не может быть адресом электронной почты",
|
||||
"Username cannot contain white spaces": "Имя пользователя не может содержать пробелы",
|
||||
@ -78,11 +78,11 @@
|
||||
"general": {
|
||||
"Missing parameter": "Отсутствующий параметр",
|
||||
"Please login first": "Пожалуйста, сначала войдите в систему",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The organization: %s should have one application at least": "Организация: %s должна иметь хотя бы одно приложение",
|
||||
"The user: %s doesn't exist": "Пользователь %s не существует",
|
||||
"don't support captchaProvider: ": "неподдерживаемый captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "эта операция не разрешена в демо-режиме",
|
||||
"this operation requires administrator to perform": "this operation requires administrator to perform"
|
||||
"this operation requires administrator to perform": "для выполнения этой операции требуется администратор"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP-сервер существует"
|
||||
@ -101,11 +101,11 @@
|
||||
"Unknown modify rule %s.": "Неизвестное изменение правила %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
"The permission: \\\"%s\\\" doesn't exist": "Разрешение: \\\"%s\\\" не существует"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Неверный идентификатор приложения",
|
||||
"the provider: %s does not exist": "провайдер: %s не существует"
|
||||
"the provider: %s does not exist": "Провайдер: %s не существует"
|
||||
},
|
||||
"resource": {
|
||||
"User is nil for tag: avatar": "Пользователь равен нулю для тега: аватар",
|
||||
@ -115,7 +115,7 @@
|
||||
"Application %s not found": "Приложение %s не найдено"
|
||||
},
|
||||
"saml_sp": {
|
||||
"provider %s's category is not SAML": "категория провайдера %s не является SAML"
|
||||
"provider %s's category is not SAML": "Категория провайдера %s не является SAML"
|
||||
},
|
||||
"service": {
|
||||
"Empty parameters for emailForm: %v": "Пустые параметры для emailForm: %v",
|
||||
@ -148,7 +148,7 @@
|
||||
"verification": {
|
||||
"Invalid captcha provider.": "Недействительный поставщик CAPTCHA.",
|
||||
"Phone number is invalid in your region %s": "Номер телефона недействителен в вашем регионе %s",
|
||||
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet!": "Код проверки еще не отправлен!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"Turing test failed.": "Тест Тьюринга не удался.",
|
||||
"Unable to get the email modify rule.": "Невозможно получить правило изменения электронной почты.",
|
||||
@ -156,8 +156,8 @@
|
||||
"Unknown type": "Неизвестный тип",
|
||||
"Wrong verification code!": "Неправильный код подтверждения!",
|
||||
"You should verify your code in %d min!": "Вы должны проверить свой код через %d минут!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "Пожалуйста, добавьте поставщика SMS в список \\\"Провайдеры\\\" для приложения: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "Пожалуйста, добавьте поставщика электронной почты в список \\\"Провайдеры\\\" для приложения: %s",
|
||||
"the user does not exist, please sign up first": "Пользователь не существует, пожалуйста, сначала зарегистрируйтесь"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -15,6 +15,7 @@
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"log"
|
||||
@ -27,21 +28,68 @@ import (
|
||||
|
||||
func StartLdapServer() {
|
||||
ldapServerPort := conf.GetConfigString("ldapServerPort")
|
||||
if ldapServerPort == "" || ldapServerPort == "0" {
|
||||
return
|
||||
}
|
||||
ldapsServerPort := conf.GetConfigString("ldapsServerPort")
|
||||
|
||||
server := ldap.NewServer()
|
||||
serverSsl := ldap.NewServer()
|
||||
routes := ldap.NewRouteMux()
|
||||
|
||||
routes.Bind(handleBind)
|
||||
routes.Search(handleSearch).Label(" SEARCH****")
|
||||
|
||||
server.Handle(routes)
|
||||
err := server.ListenAndServe("0.0.0.0:" + ldapServerPort)
|
||||
serverSsl.Handle(routes)
|
||||
go func() {
|
||||
if ldapServerPort == "" || ldapServerPort == "0" {
|
||||
return
|
||||
}
|
||||
err := server.ListenAndServe("0.0.0.0:" + ldapServerPort)
|
||||
if err != nil {
|
||||
log.Printf("StartLdapServer() failed, err = %s", err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
if ldapsServerPort == "" || ldapsServerPort == "0" {
|
||||
return
|
||||
}
|
||||
ldapsCertId := conf.GetConfigString("ldapsCertId")
|
||||
if ldapsCertId == "" {
|
||||
return
|
||||
}
|
||||
config, err := getTLSconfig(ldapsCertId)
|
||||
if err != nil {
|
||||
log.Printf("StartLdapsServer() failed, err = %s", err.Error())
|
||||
return
|
||||
}
|
||||
secureConn := func(s *ldap.Server) {
|
||||
s.Listener = tls.NewListener(s.Listener, config)
|
||||
}
|
||||
err = serverSsl.ListenAndServe("0.0.0.0:"+ldapsServerPort, secureConn)
|
||||
if err != nil {
|
||||
log.Printf("StartLdapsServer() failed, err = %s", err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func getTLSconfig(ldapsCertId string) (*tls.Config, error) {
|
||||
rawCert, err := object.GetCert(ldapsCertId)
|
||||
if err != nil {
|
||||
log.Printf("StartLdapServer() failed, err = %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
if rawCert == nil {
|
||||
return nil, fmt.Errorf("cert is empty")
|
||||
}
|
||||
cert, err := tls.X509KeyPair([]byte(rawCert.Certificate), []byte(rawCert.PrivateKey))
|
||||
if err != nil {
|
||||
return &tls.Config{}, err
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
MinVersion: tls.VersionTLS10,
|
||||
MaxVersion: tls.VersionTLS13,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
|
||||
@ -142,7 +190,7 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
e.AddAttribute(message.AttributeDescription(attr), getAttribute(string(attr), user))
|
||||
if string(attr) == "cn" {
|
||||
if string(attr) == "title" {
|
||||
e.AddAttribute(message.AttributeDescription(attr), getAttribute("title", user))
|
||||
}
|
||||
}
|
||||
|
@ -95,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"`
|
||||
@ -108,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"`
|
||||
@ -721,8 +723,15 @@ func (application *Application) GetId() string {
|
||||
}
|
||||
|
||||
func (application *Application) IsRedirectUriValid(redirectUri string) bool {
|
||||
redirectUris := append([]string{"http://localhost:", "https://localhost:", "http://127.0.0.1:", "http://casdoor-app", ".chromiumapp.org"}, application.RedirectUris...)
|
||||
for _, targetUri := range redirectUris {
|
||||
isValid, err := util.IsValidOrigin(redirectUri)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if isValid {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, targetUri := range application.RedirectUris {
|
||||
targetUriRegex := regexp.MustCompile(targetUri)
|
||||
if targetUriRegex.MatchString(redirectUri) || strings.Contains(redirectUri, targetUri) {
|
||||
return true
|
||||
|
@ -381,7 +381,13 @@ func CheckUserPassword(organization string, username string, password string, la
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = checkPasswordExpired(user, lang)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
@ -520,11 +526,46 @@ func CheckUsername(username string, lang string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func CheckUsernameWithEmail(username string, lang string) string {
|
||||
if username == "" {
|
||||
return i18n.Translate(lang, "check:Empty username.")
|
||||
} else if len(username) > 39 {
|
||||
return i18n.Translate(lang, "check:Username is too long (maximum is 39 characters).")
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/58726546/github-username-convention-using-regex
|
||||
|
||||
if !util.ReUserNameWithEmail.MatchString(username) {
|
||||
return i18n.Translate(lang, "check:Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func CheckUpdateUser(oldUser, user *User, lang string) string {
|
||||
if oldUser.Name != user.Name {
|
||||
if msg := CheckUsername(user.Name, lang); msg != "" {
|
||||
return msg
|
||||
organizationName := oldUser.Owner
|
||||
if organizationName == "" {
|
||||
organizationName = user.Owner
|
||||
}
|
||||
|
||||
organization, err := getOrganization("admin", organizationName)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
if organization == nil {
|
||||
return fmt.Sprintf(i18n.Translate(lang, "auth:The organization: %s does not exist"), organizationName)
|
||||
}
|
||||
|
||||
if organization.UseEmailAsUsername {
|
||||
if msg := CheckUsernameWithEmail(user.Name, lang); msg != "" {
|
||||
return msg
|
||||
}
|
||||
} else {
|
||||
if msg := CheckUsername(user.Name, lang); msg != "" {
|
||||
return msg
|
||||
}
|
||||
}
|
||||
|
||||
if HasUserByField(user.Owner, "name", user.Name) {
|
||||
return i18n.Translate(lang, "check:Username already exists")
|
||||
}
|
||||
@ -539,6 +580,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 ""
|
||||
}
|
||||
|
104
object/check_ip.go
Normal file
104
object/check_ip.go
Normal file
@ -0,0 +1,104 @@
|
||||
// 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)
|
||||
} else {
|
||||
application.IpRestriction = ""
|
||||
}
|
||||
|
||||
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)
|
||||
} else {
|
||||
organization.IpRestriction = ""
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
53
object/check_password_expired.go
Normal file
53
object/check_password_expired.go
Normal file
@ -0,0 +1,53 @@
|
||||
// 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"
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/casdoor/i18n"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
func checkPasswordExpired(user *User, lang string) error {
|
||||
organization, err := GetOrganizationByUser(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if organization == nil {
|
||||
return fmt.Errorf(i18n.Translate(lang, "check:Organization does not exist"))
|
||||
}
|
||||
|
||||
passwordExpireDays := organization.PasswordExpireDays
|
||||
if passwordExpireDays <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
lastChangePasswordTime := user.LastChangePasswordTime
|
||||
if lastChangePasswordTime == "" {
|
||||
if user.CreatedTime == "" {
|
||||
return fmt.Errorf(i18n.Translate(lang, "check:Your password has expired. Please reset your password by clicking \"Forgot password\""))
|
||||
}
|
||||
lastChangePasswordTime = user.CreatedTime
|
||||
}
|
||||
|
||||
lastTime := util.String2Time(lastChangePasswordTime)
|
||||
expireTime := lastTime.AddDate(0, 0, passwordExpireDays)
|
||||
if time.Now().After(expireTime) {
|
||||
return fmt.Errorf(i18n.Translate(lang, "check:Your password has expired. Please reset your password by clicking \"Forgot password\""))
|
||||
}
|
||||
return nil
|
||||
}
|
@ -25,6 +25,12 @@ type Dashboard struct {
|
||||
ProviderCounts []int `json:"providerCounts"`
|
||||
ApplicationCounts []int `json:"applicationCounts"`
|
||||
SubscriptionCounts []int `json:"subscriptionCounts"`
|
||||
RoleCounts []int `json:"roleCounts"`
|
||||
GroupCounts []int `json:"groupCounts"`
|
||||
ResourceCounts []int `json:"resourceCounts"`
|
||||
CertCounts []int `json:"certCounts"`
|
||||
PermissionCounts []int `json:"permissionCounts"`
|
||||
TransactionCounts []int `json:"transactionCounts"`
|
||||
}
|
||||
|
||||
func GetDashboard(owner string) (*Dashboard, error) {
|
||||
@ -38,6 +44,12 @@ func GetDashboard(owner string) (*Dashboard, error) {
|
||||
ProviderCounts: make([]int, 31),
|
||||
ApplicationCounts: make([]int, 31),
|
||||
SubscriptionCounts: make([]int, 31),
|
||||
RoleCounts: make([]int, 31),
|
||||
GroupCounts: make([]int, 31),
|
||||
ResourceCounts: make([]int, 31),
|
||||
CertCounts: make([]int, 31),
|
||||
PermissionCounts: make([]int, 31),
|
||||
TransactionCounts: make([]int, 31),
|
||||
}
|
||||
|
||||
organizations := []Organization{}
|
||||
@ -45,9 +57,15 @@ func GetDashboard(owner string) (*Dashboard, error) {
|
||||
providers := []Provider{}
|
||||
applications := []Application{}
|
||||
subscriptions := []Subscription{}
|
||||
roles := []Role{}
|
||||
groups := []Group{}
|
||||
resources := []Resource{}
|
||||
certs := []Cert{}
|
||||
permissions := []Permission{}
|
||||
transactions := []Transaction{}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(5)
|
||||
wg.Add(11)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := ormer.Engine.Find(&organizations, &Organization{Owner: owner}); err != nil {
|
||||
@ -86,6 +104,50 @@ func GetDashboard(owner string) (*Dashboard, error) {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
if err := ormer.Engine.Find(&roles, &Role{Owner: owner}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
if err := ormer.Engine.Find(&groups, &Group{Owner: owner}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := ormer.Engine.Find(&resources, &Resource{Owner: owner}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := ormer.Engine.Find(&certs, &Cert{Owner: owner}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := ormer.Engine.Find(&permissions, &Permission{Owner: owner}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := ormer.Engine.Find(&transactions, &Transaction{Owner: owner}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
nowTime := time.Now()
|
||||
@ -96,6 +158,12 @@ func GetDashboard(owner string) (*Dashboard, error) {
|
||||
dashboard.ProviderCounts[30-i] = countCreatedBefore(providers, cutTime)
|
||||
dashboard.ApplicationCounts[30-i] = countCreatedBefore(applications, cutTime)
|
||||
dashboard.SubscriptionCounts[30-i] = countCreatedBefore(subscriptions, cutTime)
|
||||
dashboard.RoleCounts[30-i] = countCreatedBefore(roles, cutTime)
|
||||
dashboard.GroupCounts[30-i] = countCreatedBefore(groups, cutTime)
|
||||
dashboard.ResourceCounts[30-i] = countCreatedBefore(resources, cutTime)
|
||||
dashboard.CertCounts[30-i] = countCreatedBefore(certs, cutTime)
|
||||
dashboard.PermissionCounts[30-i] = countCreatedBefore(permissions, cutTime)
|
||||
dashboard.TransactionCounts[30-i] = countCreatedBefore(transactions, cutTime)
|
||||
}
|
||||
return dashboard, nil
|
||||
}
|
||||
@ -138,6 +206,48 @@ func countCreatedBefore(objects interface{}, before time.Time) int {
|
||||
count++
|
||||
}
|
||||
}
|
||||
case []Role:
|
||||
for _, r := range obj {
|
||||
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", r.CreatedTime)
|
||||
if createdTime.Before(before) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
case []Group:
|
||||
for _, g := range obj {
|
||||
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", g.CreatedTime)
|
||||
if createdTime.Before(before) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
case []Resource:
|
||||
for _, r := range obj {
|
||||
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", r.CreatedTime)
|
||||
if createdTime.Before(before) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
case []Cert:
|
||||
for _, c := range obj {
|
||||
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", c.CreatedTime)
|
||||
if createdTime.Before(before) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
case []Permission:
|
||||
for _, p := range obj {
|
||||
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", p.CreatedTime)
|
||||
if createdTime.Before(before) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
case []Transaction:
|
||||
for _, t := range obj {
|
||||
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", t.CreatedTime)
|
||||
if createdTime.Before(before) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
@ -48,12 +48,16 @@ type InitData struct {
|
||||
Transactions []*Transaction `json:"transactions"`
|
||||
}
|
||||
|
||||
var initDataNewOnly bool
|
||||
|
||||
func InitFromFile() {
|
||||
initDataFile := conf.GetConfigString("initDataFile")
|
||||
if initDataFile == "" {
|
||||
return
|
||||
}
|
||||
|
||||
initDataNewOnly = conf.GetConfigBool("initDataNewOnly")
|
||||
|
||||
initData, err := readInitDataFromFile(initDataFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -269,6 +273,9 @@ func initDefinedOrganization(organization *Organization) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := deleteOrganization(organization)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -295,6 +302,9 @@ func initDefinedApplication(application *Application) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := deleteApplication(application)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -316,6 +326,9 @@ func initDefinedUser(user *User) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := deleteUser(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -342,6 +355,9 @@ func initDefinedCert(cert *Cert) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteCert(cert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -364,6 +380,9 @@ func initDefinedLdap(ldap *Ldap) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteLdap(ldap)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -385,6 +404,9 @@ func initDefinedProvider(provider *Provider) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteProvider(provider)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -406,6 +428,9 @@ func initDefinedModel(model *Model) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteModel(model)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -428,6 +453,9 @@ func initDefinedPermission(permission *Permission) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := deletePermission(permission)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -450,6 +478,9 @@ func initDefinedPayment(payment *Payment) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeletePayment(payment)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -472,6 +503,9 @@ func initDefinedProduct(product *Product) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteProduct(product)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -494,6 +528,9 @@ func initDefinedResource(resource *Resource) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteResource(resource)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -516,6 +553,9 @@ func initDefinedRole(role *Role) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := deleteRole(role)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -538,6 +578,9 @@ func initDefinedSyncer(syncer *Syncer) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteSyncer(syncer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -560,6 +603,9 @@ func initDefinedToken(token *Token) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteToken(token)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -582,6 +628,9 @@ func initDefinedWebhook(webhook *Webhook) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteWebhook(webhook)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -603,6 +652,9 @@ func initDefinedGroup(group *Group) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := deleteGroup(group)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -624,6 +676,9 @@ func initDefinedAdapter(adapter *Adapter) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteAdapter(adapter)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -645,6 +700,9 @@ func initDefinedEnforcer(enforcer *Enforcer) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteEnforcer(enforcer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -666,6 +724,9 @@ func initDefinedPlan(plan *Plan) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeletePlan(plan)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -687,6 +748,9 @@ func initDefinedPricing(pricing *Pricing) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeletePricing(pricing)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -708,6 +772,9 @@ func initDefinedInvitation(invitation *Invitation) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteInvitation(invitation)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -743,6 +810,9 @@ func initDefinedSubscription(subscription *Subscription) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteSubscription(subscription)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -764,6 +834,9 @@ func initDefinedTransaction(transaction *Transaction) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteTransaction(transaction)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -62,6 +62,7 @@ type Organization struct {
|
||||
PasswordOptions []string `xorm:"varchar(100)" json:"passwordOptions"`
|
||||
PasswordObfuscatorType string `xorm:"varchar(100)" json:"passwordObfuscatorType"`
|
||||
PasswordObfuscatorKey string `xorm:"varchar(100)" json:"passwordObfuscatorKey"`
|
||||
PasswordExpireDays int `json:"passwordExpireDays"`
|
||||
CountryCodes []string `xorm:"varchar(200)" json:"countryCodes"`
|
||||
DefaultAvatar string `xorm:"varchar(200)" json:"defaultAvatar"`
|
||||
DefaultApplication string `xorm:"varchar(100)" json:"defaultApplication"`
|
||||
@ -71,11 +72,13 @@ 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"`
|
||||
|
@ -364,7 +364,7 @@ func GetAllActions(userId string) ([]string, error) {
|
||||
|
||||
res := []string{}
|
||||
for _, enforcer := range enforcers {
|
||||
items := enforcer.GetAllObjects()
|
||||
items := enforcer.GetAllActions()
|
||||
res = append(res, items...)
|
||||
}
|
||||
return res, nil
|
||||
|
@ -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,
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/beevik/etree"
|
||||
@ -222,10 +223,13 @@ func GetSamlMeta(application *Application, host string, enablePostBinding bool)
|
||||
originFrontend, originBackend := getOriginFromHost(host)
|
||||
|
||||
idpLocation := ""
|
||||
idpBinding := ""
|
||||
if enablePostBinding {
|
||||
idpLocation = fmt.Sprintf("%s/api/saml/redirect/%s/%s", originBackend, application.Owner, application.Name)
|
||||
idpBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||
} else {
|
||||
idpLocation = fmt.Sprintf("%s/login/saml/authorize/%s/%s", originFrontend, application.Owner, application.Name)
|
||||
idpBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
}
|
||||
|
||||
d := IdpEntityDescriptor{
|
||||
@ -258,7 +262,7 @@ func GetSamlMeta(application *Application, host string, enablePostBinding bool)
|
||||
{Xmlns: "urn:oasis:names:tc:SAML:2.0:assertion", Name: "Name", NameFormat: "urn:oasis:names:tc:SAML:2.0:attrname-format:basic", FriendlyName: "Name"},
|
||||
},
|
||||
SingleSignOnService: SingleSignOnService{
|
||||
Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
|
||||
Binding: idpBinding,
|
||||
Location: idpLocation,
|
||||
},
|
||||
ProtocolSupportEnumeration: "urn:oasis:names:tc:SAML:2.0:protocol",
|
||||
@ -273,29 +277,38 @@ func GetSamlMeta(application *Application, host string, enablePostBinding bool)
|
||||
func GetSamlResponse(application *Application, user *User, samlRequest string, host string) (string, string, string, error) {
|
||||
// request type
|
||||
method := "GET"
|
||||
|
||||
samlRequest = strings.ReplaceAll(samlRequest, " ", "+")
|
||||
// base64 decode
|
||||
defated, err := base64.StdEncoding.DecodeString(samlRequest)
|
||||
if err != nil {
|
||||
return "", "", "", fmt.Errorf("err: Failed to decode SAML request, %s", err.Error())
|
||||
}
|
||||
|
||||
// decompress
|
||||
var buffer bytes.Buffer
|
||||
rdr := flate.NewReader(bytes.NewReader(defated))
|
||||
var requestByte []byte
|
||||
|
||||
for {
|
||||
_, err = io.CopyN(&buffer, rdr, 1024)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
if strings.Contains(string(defated), "xmlns:") {
|
||||
requestByte = defated
|
||||
} else {
|
||||
// decompress
|
||||
var buffer bytes.Buffer
|
||||
rdr := flate.NewReader(bytes.NewReader(defated))
|
||||
|
||||
for {
|
||||
|
||||
_, err = io.CopyN(&buffer, rdr, 1024)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return "", "", "", err
|
||||
}
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
requestByte = buffer.Bytes()
|
||||
}
|
||||
|
||||
var authnRequest saml.AuthNRequest
|
||||
err = xml.Unmarshal(buffer.Bytes(), &authnRequest)
|
||||
err = xml.Unmarshal(requestByte, &authnRequest)
|
||||
if err != nil {
|
||||
return "", "", "", fmt.Errorf("err: Failed to unmarshal AuthnRequest, please check the SAML request, %s", err.Error())
|
||||
}
|
||||
|
@ -102,14 +102,6 @@ func GetTokenByAccessToken(accessToken string) (*Token, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !existed {
|
||||
token = Token{AccessToken: accessToken}
|
||||
existed, err = ormer.Engine.Get(&token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if !existed {
|
||||
return nil, nil
|
||||
}
|
||||
@ -123,14 +115,6 @@ func GetTokenByRefreshToken(refreshToken string) (*Token, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !existed {
|
||||
token = Token{RefreshToken: refreshToken}
|
||||
existed, err = ormer.Engine.Get(&token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if !existed {
|
||||
return nil, nil
|
||||
}
|
||||
@ -140,6 +124,7 @@ func GetTokenByRefreshToken(refreshToken string) (*Token, error) {
|
||||
func GetTokenByTokenValue(tokenValue, tokenTypeHint string) (*Token, error) {
|
||||
switch tokenTypeHint {
|
||||
case "access_token":
|
||||
case "access-token":
|
||||
token, err := GetTokenByAccessToken(tokenValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -148,6 +133,7 @@ func GetTokenByTokenValue(tokenValue, tokenTypeHint string) (*Token, error) {
|
||||
return token, nil
|
||||
}
|
||||
case "refresh_token":
|
||||
case "refresh-token":
|
||||
token, err := GetTokenByRefreshToken(tokenValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -332,6 +332,9 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user == nil {
|
||||
return "", fmt.Errorf("The user: %s doesn't exist", util.GetId(application.Organization, token.User))
|
||||
}
|
||||
|
||||
if user.IsForbidden {
|
||||
return &TokenError{
|
||||
|
@ -200,12 +200,14 @@ type User struct {
|
||||
Permissions []*Permission `json:"permissions"`
|
||||
Groups []string `xorm:"groups varchar(1000)" json:"groups"`
|
||||
|
||||
LastSigninWrongTime string `xorm:"varchar(100)" json:"lastSigninWrongTime"`
|
||||
SigninWrongTimes int `json:"signinWrongTimes"`
|
||||
LastChangePasswordTime string `xorm:"varchar(100)" json:"lastChangePasswordTime"`
|
||||
LastSigninWrongTime string `xorm:"varchar(100)" json:"lastSigninWrongTime"`
|
||||
SigninWrongTimes int `json:"signinWrongTimes"`
|
||||
|
||||
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 {
|
||||
@ -689,14 +691,14 @@ func UpdateUser(id string, user *User, columns []string, isAdmin bool) (bool, er
|
||||
"owner", "display_name", "avatar", "first_name", "last_name",
|
||||
"location", "address", "country_code", "region", "language", "affiliation", "title", "id_card_type", "id_card", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application",
|
||||
"is_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts", "face_ids", "mfaAccounts",
|
||||
"signin_wrong_times", "last_signin_wrong_time", "groups", "access_key", "access_secret", "mfa_phone_enabled", "mfa_email_enabled",
|
||||
"signin_wrong_times", "last_change_password_time", "last_signin_wrong_time", "groups", "access_key", "access_secret", "mfa_phone_enabled", "mfa_email_enabled",
|
||||
"github", "google", "qq", "wechat", "facebook", "dingtalk", "weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs",
|
||||
"baidu", "alipay", "casdoor", "infoflow", "apple", "azuread", "azureadb2c", "slack", "steam", "bilibili", "okta", "douyin", "line", "amazon",
|
||||
"auth0", "battlenet", "bitbucket", "box", "cloudfoundry", "dailymotion", "deezer", "digitalocean", "discord", "dropbox",
|
||||
"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 {
|
||||
@ -815,6 +817,10 @@ func AddUser(user *User) (bool, error) {
|
||||
user.UpdateUserPassword(organization)
|
||||
}
|
||||
|
||||
if user.CreatedTime == "" {
|
||||
user.CreatedTime = util.GetCurrentTime()
|
||||
}
|
||||
|
||||
err = user.UpdateUserHash()
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
@ -557,6 +557,14 @@ func CheckPermissionForUpdateUser(oldUser, newUser *User, isAdmin bool, lang str
|
||||
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)
|
||||
|
@ -16,11 +16,11 @@ package routers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego/context"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -52,7 +52,13 @@ func CorsFilter(ctx *context.Context) {
|
||||
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") {
|
||||
isValid, err := util.IsValidOrigin(origin)
|
||||
if err != nil {
|
||||
ctx.ResponseWriter.WriteHeader(http.StatusForbidden)
|
||||
responseError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
if isValid {
|
||||
setCorsHeaders(ctx, origin)
|
||||
return
|
||||
}
|
||||
|
@ -174,6 +174,8 @@ func initAPI() {
|
||||
beego.Router("/api/get-all-actions", &controllers.ApiController{}, "GET:GetAllActions")
|
||||
beego.Router("/api/get-all-roles", &controllers.ApiController{}, "GET:GetAllRoles")
|
||||
|
||||
beego.Router("/api/run-casbin-command", &controllers.ApiController{}, "GET:RunCasbinCommand")
|
||||
|
||||
beego.Router("/api/get-sessions", &controllers.ApiController{}, "GET:GetSessions")
|
||||
beego.Router("/api/get-session", &controllers.ApiController{}, "GET:GetSingleSession")
|
||||
beego.Router("/api/update-session", &controllers.ApiController{}, "POST:UpdateSession")
|
||||
|
48
util/log.go
48
util/log.go
@ -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...)
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ package util
|
||||
import (
|
||||
"fmt"
|
||||
"net/mail"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@ -24,10 +25,11 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
rePhone *regexp.Regexp
|
||||
ReWhiteSpace *regexp.Regexp
|
||||
ReFieldWhiteList *regexp.Regexp
|
||||
ReUserName *regexp.Regexp
|
||||
rePhone *regexp.Regexp
|
||||
ReWhiteSpace *regexp.Regexp
|
||||
ReFieldWhiteList *regexp.Regexp
|
||||
ReUserName *regexp.Regexp
|
||||
ReUserNameWithEmail *regexp.Regexp
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -35,6 +37,7 @@ func init() {
|
||||
ReWhiteSpace, _ = regexp.Compile(`\s`)
|
||||
ReFieldWhiteList, _ = regexp.Compile(`^[A-Za-z0-9]+$`)
|
||||
ReUserName, _ = regexp.Compile("^[a-zA-Z0-9]+([-._][a-zA-Z0-9]+)*$")
|
||||
ReUserNameWithEmail, _ = regexp.Compile(`^([a-zA-Z0-9]+([-._][a-zA-Z0-9]+)*)|([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$`) // Add support for email formats
|
||||
}
|
||||
|
||||
func IsEmailValid(email string) bool {
|
||||
@ -100,3 +103,21 @@ func GetCountryCode(prefix string, phone string) (string, error) {
|
||||
func FilterField(field string) bool {
|
||||
return ReFieldWhiteList.MatchString(field)
|
||||
}
|
||||
|
||||
func IsValidOrigin(origin string) (bool, error) {
|
||||
urlObj, err := url.Parse(origin)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if urlObj == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
originHostOnly := ""
|
||||
if urlObj.Host != "" {
|
||||
originHostOnly = fmt.Sprintf("%s://%s", urlObj.Scheme, urlObj.Hostname())
|
||||
}
|
||||
|
||||
res := originHostOnly == "http://localhost" || originHostOnly == "https://localhost" || originHostOnly == "http://127.0.0.1" || originHostOnly == "http://casdoor-app" || strings.HasSuffix(originHostOnly, ".chromiumapp.org")
|
||||
return res, nil
|
||||
}
|
||||
|
@ -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"))} :
|
||||
@ -749,7 +765,7 @@ class ApplicationEditPage extends React.Component {
|
||||
/>
|
||||
<br />
|
||||
<Button style={{marginBottom: "10px"}} type="primary" shape="round" icon={<CopyOutlined />} onClick={() => {
|
||||
copy(`${window.location.origin}/api/saml/metadata?application=admin/${encodeURIComponent(this.state.applicationName)}&post=${this.state.application.enableSamlPostBinding}`);
|
||||
copy(`${window.location.origin}/api/saml/metadata?application=admin/${encodeURIComponent(this.state.applicationName)}&enablePostBinding=${this.state.application.enableSamlPostBinding}`);
|
||||
Setting.showMessage("success", i18next.t("general:Copied to clipboard successfully"));
|
||||
}}
|
||||
>
|
||||
|
@ -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,6 +95,14 @@ 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 (
|
||||
|
@ -198,11 +198,11 @@ function ManagementPage(props) {
|
||||
</div>
|
||||
</Tooltip>
|
||||
<OpenTour />
|
||||
{Setting.isAdminUser(props.account) && !Setting.isMobile() && (props.uri.indexOf("/trees") === -1) &&
|
||||
{Setting.isAdminUser(props.account) && (props.uri.indexOf("/trees") === -1) &&
|
||||
<OrganizationSelect
|
||||
initValue={Setting.getOrganization()}
|
||||
withAll={true}
|
||||
style={{marginRight: "20px", width: "180px", display: "flex"}}
|
||||
style={{marginRight: "20px", width: "180px", display: !Setting.isMobile() ? "flex" : "none"}}
|
||||
onChange={(value) => {
|
||||
Setting.setOrganization(value);
|
||||
}}
|
||||
|
@ -339,6 +339,16 @@ class OrganizationEditPage extends React.Component {
|
||||
</Col>
|
||||
</Row>)
|
||||
}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("organization:Password expire days"), i18next.t("organization:Password expire days - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={4} >
|
||||
<InputNumber value={this.state.organization.passwordExpireDays} onChange={value => {
|
||||
this.updateOrganizationField("passwordExpireDays", 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"))} :
|
||||
@ -452,6 +462,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"))} :
|
||||
|
@ -37,6 +37,7 @@ class OrganizationListPage extends BaseListPage {
|
||||
passwordOptions: [],
|
||||
passwordObfuscatorType: "Plain",
|
||||
passwordObfuscatorKey: "",
|
||||
passwordExpireDays: 0,
|
||||
countryCodes: ["US"],
|
||||
defaultAvatar: `${Setting.StaticBaseUrl}/img/casbin.svg`,
|
||||
defaultApplication: "",
|
||||
|
@ -123,6 +123,22 @@ class ProductBuyPage extends React.Component {
|
||||
return "$";
|
||||
} else if (product?.currency === "CNY") {
|
||||
return "¥";
|
||||
} else if (product?.currency === "EUR") {
|
||||
return "€";
|
||||
} else if (product?.currency === "JPY") {
|
||||
return "¥";
|
||||
} else if (product?.currency === "GBP") {
|
||||
return "£";
|
||||
} else if (product?.currency === "AUD") {
|
||||
return "A$";
|
||||
} else if (product?.currency === "CAD") {
|
||||
return "C$";
|
||||
} else if (product?.currency === "CHF") {
|
||||
return "CHF";
|
||||
} else if (product?.currency === "HKD") {
|
||||
return "HK$";
|
||||
} else if (product?.currency === "SGD") {
|
||||
return "S$";
|
||||
} else {
|
||||
return "(Unknown currency)";
|
||||
}
|
||||
|
@ -209,6 +209,14 @@ class ProductEditPage extends React.Component {
|
||||
[
|
||||
{id: "USD", name: "USD"},
|
||||
{id: "CNY", name: "CNY"},
|
||||
{id: "EUR", name: "EUR"},
|
||||
{id: "JPY", name: "JPY"},
|
||||
{id: "GBP", name: "GBP"},
|
||||
{id: "AUD", name: "AUD"},
|
||||
{id: "CAD", name: "CAD"},
|
||||
{id: "CHF", name: "CHF"},
|
||||
{id: "HKD", name: "HKD"},
|
||||
{id: "SGD", name: "SGD"},
|
||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
|
@ -908,7 +908,7 @@ class ProviderEditPage extends React.Component {
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
{["Custom HTTP SMS", "Qiniu Cloud Kodo", "Synology", "Casdoor"].includes(this.state.provider.type) ? null : (
|
||||
{["Custom HTTP SMS", "Synology", "Casdoor"].includes(this.state.provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} :
|
||||
|
@ -187,7 +187,7 @@ class RoleEditPage extends React.Component {
|
||||
{Setting.getLabel(i18next.t("role:Sub users"), i18next.t("role:Sub users - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="multiple" style={{width: "100%"}} value={this.state.role.users}
|
||||
<Select virtual={true} mode="multiple" style={{width: "100%"}} value={this.state.role.users}
|
||||
onChange={(value => {this.updateRoleField("users", value);})}
|
||||
options={this.state.users.map((user) => Setting.getOption(`${user.owner}/${user.name}`, `${user.owner}/${user.name}`))}
|
||||
/>
|
||||
|
@ -920,7 +920,7 @@ export function getClickable(text) {
|
||||
return (
|
||||
<a onClick={() => {
|
||||
copy(text);
|
||||
showMessage("success", "Copied to clipboard");
|
||||
showMessage("success", i18next.t("general:Copied to clipboard successfully"));
|
||||
}}>
|
||||
{text}
|
||||
</a>
|
||||
@ -1171,7 +1171,7 @@ export function renderLogo(application) {
|
||||
|
||||
function isSigninMethodEnabled(application, signinMethod) {
|
||||
if (application && application.signinMethods) {
|
||||
return application.signinMethods.filter(item => item.name === signinMethod && item.rule !== "Hide-Password").length > 0;
|
||||
return application.signinMethods.filter(item => item.name === signinMethod && item.rule !== "Hide password").length > 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -1550,10 +1550,30 @@ export function getDefaultHtmlEmailContent() {
|
||||
|
||||
export function getCurrencyText(product) {
|
||||
if (product?.currency === "USD") {
|
||||
return i18next.t("product:USD");
|
||||
return i18next.t("currency:USD");
|
||||
} else if (product?.currency === "CNY") {
|
||||
return i18next.t("product:CNY");
|
||||
return i18next.t("currency:CNY");
|
||||
} else if (product?.currency === "EUR") {
|
||||
return i18next.t("currency:EUR");
|
||||
} else if (product?.currency === "JPY") {
|
||||
return i18next.t("currency:JPY");
|
||||
} else if (product?.currency === "GBP") {
|
||||
return i18next.t("currency:GBP");
|
||||
} else if (product?.currency === "AUD") {
|
||||
return i18next.t("currency:AUD");
|
||||
} else if (product?.currency === "CAD") {
|
||||
return i18next.t("currency:CAD");
|
||||
} else if (product?.currency === "CHF") {
|
||||
return i18next.t("currency:CHF");
|
||||
} else if (product?.currency === "HKD") {
|
||||
return i18next.t("currency:HKD");
|
||||
} else if (product?.currency === "SGD") {
|
||||
return i18next.t("currency:SGD");
|
||||
} else {
|
||||
return "(Unknown currency)";
|
||||
}
|
||||
}
|
||||
|
||||
export function isDarkTheme(themeAlgorithm) {
|
||||
return themeAlgorithm && themeAlgorithm.includes("dark");
|
||||
}
|
||||
|
@ -1009,6 +1009,19 @@ class UserEditPage extends React.Component {
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
} else if (accountItem.name === "Last change password time") {
|
||||
return (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("user:Last change password time"), i18next.t("user:Last change password time"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Input value={this.state.user.lastChangePasswordTime} onChange={e => {
|
||||
this.updateUserField("lastChangePasswordTime", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
} else if (accountItem.name === "Managed accounts") {
|
||||
return (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
@ -1070,6 +1083,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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,6 @@ class LoginPage extends React.Component {
|
||||
username: null,
|
||||
validEmailOrPhone: false,
|
||||
validEmail: false,
|
||||
enableCaptchaModal: CaptchaRule.Never,
|
||||
openCaptchaModal: false,
|
||||
openFaceRecognitionModal: false,
|
||||
verifyCaptcha: undefined,
|
||||
@ -93,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) {
|
||||
@ -133,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) => {
|
||||
@ -226,7 +227,26 @@ class LoginPage extends React.Component {
|
||||
return "password";
|
||||
}
|
||||
|
||||
getPlaceholder() {
|
||||
getCurrentLoginMethod() {
|
||||
if (this.state.loginMethod === "password") {
|
||||
return "Password";
|
||||
} else if (this.state.loginMethod?.includes("verificationCode")) {
|
||||
return "Verification code";
|
||||
} else if (this.state.loginMethod === "webAuthn") {
|
||||
return "WebAuthn";
|
||||
} else if (this.state.loginMethod === "ldap") {
|
||||
return "LDAP";
|
||||
} else if (this.state.loginMethod === "faceId") {
|
||||
return "Face ID";
|
||||
} else {
|
||||
return "Password";
|
||||
}
|
||||
}
|
||||
|
||||
getPlaceholder(defaultPlaceholder = null) {
|
||||
if (defaultPlaceholder) {
|
||||
return defaultPlaceholder;
|
||||
}
|
||||
switch (this.state.loginMethod) {
|
||||
case "verificationCode": return i18next.t("login:Email or phone");
|
||||
case "verificationCodeEmail": return i18next.t("login:Email");
|
||||
@ -261,17 +281,7 @@ class LoginPage extends React.Component {
|
||||
values["organization"] = this.getApplicationObj().organization;
|
||||
}
|
||||
|
||||
if (this.state.loginMethod === "password") {
|
||||
values["signinMethod"] = "Password";
|
||||
} else if (this.state.loginMethod?.includes("verificationCode")) {
|
||||
values["signinMethod"] = "Verification code";
|
||||
} else if (this.state.loginMethod === "webAuthn") {
|
||||
values["signinMethod"] = "WebAuthn";
|
||||
} else if (this.state.loginMethod === "ldap") {
|
||||
values["signinMethod"] = "LDAP";
|
||||
} else if (this.state.loginMethod === "faceId") {
|
||||
values["signinMethod"] = "Face ID";
|
||||
}
|
||||
values["signinMethod"] = this.getCurrentLoginMethod();
|
||||
const oAuthParams = Util.getOAuthGetParameters();
|
||||
|
||||
values["type"] = oAuthParams?.responseType ?? this.state.type;
|
||||
@ -388,13 +398,14 @@ class LoginPage extends React.Component {
|
||||
} else {
|
||||
values["password"] = passwordCipher;
|
||||
}
|
||||
if (this.state.enableCaptchaModal === CaptchaRule.Always) {
|
||||
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;
|
||||
}
|
||||
@ -407,6 +418,7 @@ class LoginPage extends React.Component {
|
||||
if (this.state.type === "cas") {
|
||||
// CAS
|
||||
const casParams = Util.getCasParameters();
|
||||
values["signinMethod"] = this.getCurrentLoginMethod();
|
||||
values["type"] = this.state.type;
|
||||
AuthBackend.loginCas(values, casParams).then((res) => {
|
||||
const loginHandler = (res) => {
|
||||
@ -435,8 +447,8 @@ class LoginPage extends React.Component {
|
||||
formValues={values}
|
||||
authParams={casParams}
|
||||
application={this.getApplicationObj()}
|
||||
onFail={() => {
|
||||
Setting.showMessage("error", i18next.t("mfa:Verification failed"));
|
||||
onFail={(errorMessage) => {
|
||||
Setting.showMessage("error", errorMessage);
|
||||
}}
|
||||
onSuccess={(res) => loginHandler(res)}
|
||||
/>);
|
||||
@ -476,6 +488,10 @@ class LoginPage extends React.Component {
|
||||
const accessToken = res.data;
|
||||
Setting.goToLink(`${oAuthParams.redirectUri}#${amendatoryResponseType}=${accessToken}&state=${oAuthParams.state}&token_type=bearer`);
|
||||
} else if (responseType === "saml") {
|
||||
if (res.data === RequiredMfa) {
|
||||
this.props.onLoginSuccess(window.location.href);
|
||||
return;
|
||||
}
|
||||
if (res.data2.needUpdatePassword) {
|
||||
sessionStorage.setItem("signinUrl", window.location.href);
|
||||
Setting.goToLink(this, `/forget/${this.state.applicationName}`);
|
||||
@ -504,8 +520,8 @@ class LoginPage extends React.Component {
|
||||
formValues={values}
|
||||
authParams={oAuthParams}
|
||||
application={this.getApplicationObj()}
|
||||
onFail={() => {
|
||||
Setting.showMessage("error", i18next.t("mfa:Verification failed"));
|
||||
onFail={(errorMessage) => {
|
||||
Setting.showMessage("error", errorMessage);
|
||||
}}
|
||||
onSuccess={(res) => loginHandler(res)}
|
||||
/>);
|
||||
@ -670,7 +686,7 @@ class LoginPage extends React.Component {
|
||||
id="input"
|
||||
className="login-username-input"
|
||||
prefix={<UserOutlined className="site-form-item-icon" />}
|
||||
placeholder={this.getPlaceholder()}
|
||||
placeholder={this.getPlaceholder(signinItem.placeholder)}
|
||||
onChange={e => {
|
||||
this.setState({
|
||||
username: e.target.value,
|
||||
@ -911,7 +927,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);
|
||||
@ -1084,7 +1100,7 @@ class LoginPage extends React.Component {
|
||||
className="login-password-input"
|
||||
prefix={<LockOutlined className="site-form-item-icon" />}
|
||||
type="password"
|
||||
placeholder={i18next.t("general:Password")}
|
||||
placeholder={signinItem.placeholder ? signinItem.placeholder : i18next.t("general:Password")}
|
||||
disabled={this.state.loginMethod === "password" ? !Setting.isPasswordEnabled(application) : !Setting.isLdapEnabled(application)}
|
||||
/>
|
||||
</Form.Item>
|
||||
@ -1134,7 +1150,7 @@ class LoginPage extends React.Component {
|
||||
]);
|
||||
|
||||
application?.signinMethods?.forEach((signinMethod) => {
|
||||
if (signinMethod.rule === "Hide-Password") {
|
||||
if (signinMethod.rule === "Hide password") {
|
||||
return;
|
||||
}
|
||||
const item = itemsMap.get(generateItemKey(signinMethod.name, signinMethod.rule));
|
||||
@ -1291,7 +1307,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>
|
||||
|
@ -37,7 +37,7 @@ class MfaSetupPage extends React.Component {
|
||||
this.state = {
|
||||
account: props.account,
|
||||
application: null,
|
||||
applicationName: props.account.signupApplication ?? "",
|
||||
applicationName: props.account.signupApplication ?? localStorage.getItem("applicationName") ?? "",
|
||||
current: location.state?.from !== undefined ? 1 : 0,
|
||||
mfaProps: null,
|
||||
mfaType: params.get("mfaType") ?? SmsMfaType,
|
||||
@ -179,8 +179,10 @@ class MfaSetupPage extends React.Component {
|
||||
mfaProps={this.state.mfaProps}
|
||||
application={this.state.application}
|
||||
user={this.props.account}
|
||||
onSuccess={() => {
|
||||
onSuccess={(res) => {
|
||||
this.setState({
|
||||
dest: res.dest,
|
||||
countryCode: res.countryCode,
|
||||
current: this.state.current + 1,
|
||||
});
|
||||
}}
|
||||
@ -195,7 +197,7 @@ class MfaSetupPage extends React.Component {
|
||||
);
|
||||
case 2:
|
||||
return (
|
||||
<MfaEnableForm user={this.getUser()} mfaType={this.state.mfaType} recoveryCodes={this.state.mfaProps.recoveryCodes}
|
||||
<MfaEnableForm user={this.getUser()} mfaType={this.state.mfaType} secret={this.state.mfaProps.secret} recoveryCodes={this.state.mfaProps.recoveryCodes} dest={this.state.dest} countryCode={this.state.countryCode}
|
||||
onSuccess={() => {
|
||||
Setting.showMessage("success", i18next.t("general:Enabled successfully"));
|
||||
this.props.onfinish();
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
import CryptoJS from "crypto-js";
|
||||
import i18next from "i18next";
|
||||
import {Buffer} from "buffer";
|
||||
|
||||
export function getRandomKeyForObfuscator(obfuscatorType) {
|
||||
if (obfuscatorType === "DES") {
|
||||
@ -45,17 +45,17 @@ function encrypt(cipher, key, iv, password) {
|
||||
|
||||
export function checkPasswordObfuscator(passwordObfuscatorType, passwordObfuscatorKey) {
|
||||
if (passwordObfuscatorType === undefined) {
|
||||
return i18next.t("organization:failed to get password obfuscator");
|
||||
return "passwordObfuscatorType should not be undefined";
|
||||
} 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}`;
|
||||
return `The password obfuscator key doesn't match the regex: ${passwordObfuscatorKeyRegexes[passwordObfuscatorType].source}`;
|
||||
}
|
||||
} else {
|
||||
return `${i18next.t("organization:unsupported password obfuscator type")}: ${passwordObfuscatorType}`;
|
||||
return `unsupported password obfuscator type: ${passwordObfuscatorType}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -842,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>
|
||||
|
@ -113,6 +113,9 @@ export function getCasLoginParameters(owner, name) {
|
||||
|
||||
export function getOAuthGetParameters(params) {
|
||||
const queries = (params !== undefined) ? params : new URLSearchParams(window.location.search);
|
||||
const lowercaseQueries = {};
|
||||
queries.forEach((val, key) => {lowercaseQueries[key.toLowerCase()] = val;});
|
||||
|
||||
const clientId = getRefinedValue(queries.get("client_id"));
|
||||
const responseType = getRefinedValue(queries.get("response_type"));
|
||||
|
||||
@ -138,9 +141,9 @@ export function getOAuthGetParameters(params) {
|
||||
const nonce = getRefinedValue(queries.get("nonce"));
|
||||
const challengeMethod = getRefinedValue(queries.get("code_challenge_method"));
|
||||
const codeChallenge = getRefinedValue(queries.get("code_challenge"));
|
||||
const samlRequest = getRefinedValue(queries.get("SAMLRequest"));
|
||||
const relayState = getRefinedValue(queries.get("RelayState"));
|
||||
const noRedirect = getRefinedValue(queries.get("noRedirect"));
|
||||
const samlRequest = getRefinedValue(lowercaseQueries["samlRequest".toLowerCase()]);
|
||||
const relayState = getRefinedValue(lowercaseQueries["RelayState".toLowerCase()]);
|
||||
const noRedirect = getRefinedValue(lowercaseQueries["noRedirect".toLowerCase()]);
|
||||
|
||||
if (clientId === "" && samlRequest === "") {
|
||||
// login
|
||||
|
@ -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:You have enabled multi-factor authentication, please enter the authentication code")}
|
||||
</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?")}
|
||||
|
@ -3,11 +3,15 @@ import i18next from "i18next";
|
||||
import React, {useState} from "react";
|
||||
import * as MfaBackend from "../../backend/MfaBackend";
|
||||
|
||||
export function MfaEnableForm({user, mfaType, recoveryCodes, onSuccess, onFail}) {
|
||||
export function MfaEnableForm({user, mfaType, secret, recoveryCodes, dest, countryCode, onSuccess, onFail}) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const requestEnableMfa = () => {
|
||||
const data = {
|
||||
mfaType,
|
||||
secret,
|
||||
recoveryCodes,
|
||||
dest,
|
||||
countryCode,
|
||||
...user,
|
||||
};
|
||||
setLoading(true);
|
||||
|
@ -26,11 +26,13 @@ export const mfaSetup = "mfaSetup";
|
||||
|
||||
export function MfaVerifyForm({mfaProps, application, user, onSuccess, onFail}) {
|
||||
const [form] = Form.useForm();
|
||||
const onFinish = ({passcode}) => {
|
||||
const data = {passcode, mfaType: mfaProps.mfaType, ...user};
|
||||
const onFinish = ({passcode, countryCode, dest}) => {
|
||||
const data = {passcode, mfaType: mfaProps.mfaType, secret: mfaProps.secret, dest: dest, countryCode: countryCode, ...user};
|
||||
MfaBackend.MfaSetupVerify(data)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
res.dest = dest;
|
||||
res.countryCode = countryCode;
|
||||
onSuccess(res);
|
||||
} else {
|
||||
onFail(res);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {UserOutlined} from "@ant-design/icons";
|
||||
import {Button, Form, Input} from "antd";
|
||||
import {Button, Form, Input, Space} from "antd";
|
||||
import i18next from "i18next";
|
||||
import React, {useEffect} from "react";
|
||||
import {CountryCodeSelect} from "../../common/select/CountryCodeSelect";
|
||||
@ -15,15 +15,18 @@ export const MfaVerifySmsForm = ({mfaProps, application, onFinish, method, user}
|
||||
useEffect(() => {
|
||||
if (method === mfaAuth) {
|
||||
setDest(mfaProps.secret);
|
||||
form.setFieldValue("dest", mfaProps.secret);
|
||||
return;
|
||||
}
|
||||
if (mfaProps.mfaType === SmsMfaType) {
|
||||
setDest(user.phone);
|
||||
form.setFieldValue("dest", user.phone);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mfaProps.mfaType === EmailMfaType) {
|
||||
setDest(user.email);
|
||||
form.setFieldValue("dest", user.email);
|
||||
}
|
||||
}, [mfaProps.mfaType]);
|
||||
|
||||
@ -57,45 +60,44 @@ export const MfaVerifySmsForm = ({mfaProps, application, onFinish, method, user}
|
||||
<div style={{marginBottom: 20, textAlign: "left", gap: 8}}>
|
||||
{isEmail() ? i18next.t("mfa:Your email is") : i18next.t("mfa:Your phone is")} {dest}
|
||||
</div> :
|
||||
(<React.Fragment>
|
||||
(
|
||||
<p>{isEmail() ? i18next.t("mfa:Please bind your email first, the system will automatically uses the mail for multi-factor authentication") :
|
||||
i18next.t("mfa:Please bind your phone first, the system automatically uses the phone for multi-factor authentication")}
|
||||
</p>
|
||||
<Input.Group compact style={{width: "300Px", marginBottom: "30px"}}>
|
||||
{isEmail() ? null :
|
||||
<Form.Item
|
||||
name="countryCode"
|
||||
noStyle
|
||||
rules={[
|
||||
{
|
||||
required: false,
|
||||
message: i18next.t("signup:Please select your country code!"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CountryCodeSelect
|
||||
initValue={mfaProps.countryCode}
|
||||
style={{width: "30%"}}
|
||||
countryCodes={application.organizationObj.countryCodes}
|
||||
/>
|
||||
</Form.Item>
|
||||
}
|
||||
<Form.Item
|
||||
name="dest"
|
||||
noStyle
|
||||
rules={[{required: true, message: i18next.t("login:Please input your Email or Phone!")}]}
|
||||
>
|
||||
<Input
|
||||
style={{width: isEmail() ? "100% " : "70%"}}
|
||||
onChange={(e) => {setDest(e.target.value);}}
|
||||
prefix={<UserOutlined />}
|
||||
placeholder={isEmail() ? i18next.t("general:Email") : i18next.t("general:Phone")}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Input.Group>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
<Space.Compact style={{width: "300Px", marginBottom: "30px", display: isShowText() ? "none" : ""}}>
|
||||
{isEmail() || isShowText() ? null :
|
||||
<Form.Item
|
||||
name="countryCode"
|
||||
noStyle
|
||||
rules={[
|
||||
{
|
||||
required: false,
|
||||
message: i18next.t("signup:Please select your country code!"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CountryCodeSelect
|
||||
initValue={mfaProps.countryCode}
|
||||
style={{width: "30%"}}
|
||||
countryCodes={application.organizationObj.countryCodes}
|
||||
/>
|
||||
</Form.Item>
|
||||
}
|
||||
<Form.Item
|
||||
name="dest"
|
||||
noStyle
|
||||
rules={[{required: true, message: i18next.t("login:Please input your Email or Phone!")}]}
|
||||
>
|
||||
<Input
|
||||
style={{width: isEmail() ? "100% " : "70%"}}
|
||||
onChange={(e) => {setDest(e.target.value);}}
|
||||
prefix={<UserOutlined />}
|
||||
placeholder={isEmail() ? i18next.t("general:Email") : i18next.t("general:Phone")}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Space.Compact>
|
||||
<Form.Item
|
||||
name="passcode"
|
||||
rules={[{required: true, message: i18next.t("login:Please input your code!")}]}
|
||||
|
@ -32,6 +32,9 @@ export function MfaSetupVerify(values) {
|
||||
formData.append("name", values.name);
|
||||
formData.append("mfaType", values.mfaType);
|
||||
formData.append("passcode", values.passcode);
|
||||
formData.append("secret", values.secret);
|
||||
formData.append("dest", values.dest);
|
||||
formData.append("countryCode", values.countryCode);
|
||||
return fetch(`${Setting.ServerUrl}/api/mfa/setup/verify`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
@ -44,6 +47,10 @@ export function MfaSetupEnable(values) {
|
||||
formData.append("mfaType", values.mfaType);
|
||||
formData.append("owner", values.owner);
|
||||
formData.append("name", values.name);
|
||||
formData.append("secret", values.secret);
|
||||
formData.append("recoveryCodes", values.recoveryCodes);
|
||||
formData.append("dest", values.dest);
|
||||
formData.append("countryCode", values.countryCode);
|
||||
return fetch(`${Setting.ServerUrl}/api/mfa/setup/enable`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
|
@ -135,6 +135,12 @@ const Dashboard = (props) => {
|
||||
i18next.t("general:Applications"),
|
||||
i18next.t("general:Organizations"),
|
||||
i18next.t("general:Subscriptions"),
|
||||
i18next.t("general:Roles"),
|
||||
i18next.t("general:Groups"),
|
||||
i18next.t("general:Resources"),
|
||||
i18next.t("general:Certs"),
|
||||
i18next.t("general:Permissions"),
|
||||
i18next.t("general:Transactions"),
|
||||
], top: "10%"},
|
||||
grid: {left: "3%", right: "4%", bottom: "0", top: "25%", containLabel: true},
|
||||
xAxis: {type: "category", boundaryGap: false, data: dateArray},
|
||||
@ -145,6 +151,12 @@ const Dashboard = (props) => {
|
||||
{name: i18next.t("general:Providers"), type: "line", data: dashboardData.providerCounts},
|
||||
{name: i18next.t("general:Applications"), type: "line", data: dashboardData.applicationCounts},
|
||||
{name: i18next.t("general:Subscriptions"), type: "line", data: dashboardData.subscriptionCounts},
|
||||
{name: i18next.t("general:Roles"), type: "line", data: dashboardData.roleCounts},
|
||||
{name: i18next.t("general:Groups"), type: "line", data: dashboardData.groupCounts},
|
||||
{name: i18next.t("general:Resources"), type: "line", data: dashboardData.resourceCounts},
|
||||
{name: i18next.t("general:Certs"), type: "line", data: dashboardData.certCounts},
|
||||
{name: i18next.t("general:Permissions"), type: "line", data: dashboardData.permissionCounts},
|
||||
{name: i18next.t("general:Transactions"), type: "line", data: dashboardData.transactionCounts},
|
||||
],
|
||||
};
|
||||
myChart.setOption(option);
|
||||
|
113
web/src/common/CasdoorAppConnector.js
Normal file
113
web/src/common/CasdoorAppConnector.js
Normal file
@ -0,0 +1,113 @@
|
||||
// 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 from "react";
|
||||
import {Alert, Button, QRCode} from "antd";
|
||||
import copy from "copy-to-clipboard";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
|
||||
export const generateCasdoorAppUrl = (accessToken, forQrCode = true) => {
|
||||
let qrUrl = "";
|
||||
let error = null;
|
||||
|
||||
if (!accessToken) {
|
||||
error = i18next.t("general:Access token is empty");
|
||||
return {qrUrl, error};
|
||||
}
|
||||
|
||||
qrUrl = `casdoor-app://login?serverUrl=${window.location.origin}&accessToken=${accessToken}`;
|
||||
|
||||
if (forQrCode && qrUrl.length >= 2000) {
|
||||
qrUrl = "";
|
||||
error = i18next.t("general:QR code is too large");
|
||||
}
|
||||
|
||||
return {qrUrl, error};
|
||||
};
|
||||
|
||||
export const CasdoorAppQrCode = ({accessToken, icon}) => {
|
||||
const {qrUrl, error} = generateCasdoorAppUrl(accessToken, true);
|
||||
|
||||
if (error) {
|
||||
return <Alert message={error} type="error" showIcon />;
|
||||
}
|
||||
|
||||
return (
|
||||
<QRCode
|
||||
value={qrUrl}
|
||||
icon={icon}
|
||||
errorLevel="M"
|
||||
size={230}
|
||||
bordered={false}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const CasdoorAppUrl = ({accessToken}) => {
|
||||
const {qrUrl, error} = generateCasdoorAppUrl(accessToken, false);
|
||||
|
||||
const handleCopyUrl = async() => {
|
||||
if (!window.isSecureContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
copy(qrUrl);
|
||||
Setting.showMessage("success", i18next.t("general:Copied to clipboard successfully"));
|
||||
};
|
||||
|
||||
if (error) {
|
||||
return <Alert message={error} type="error" showIcon />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: "10px",
|
||||
}}>
|
||||
{window.isSecureContext && (
|
||||
<Button size="small" type="primary" onClick={handleCopyUrl} style={{marginLeft: "10px"}}>
|
||||
{i18next.t("resource:Copy Link")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
padding: "10px",
|
||||
maxWidth: "400px",
|
||||
maxHeight: "100px",
|
||||
overflow: "auto",
|
||||
wordBreak: "break-all",
|
||||
whiteSpace: "pre-wrap",
|
||||
cursor: "pointer",
|
||||
userSelect: "all",
|
||||
backgroundColor: "#f5f5f5",
|
||||
borderRadius: "4px",
|
||||
}}
|
||||
onClick={(e) => {
|
||||
const selection = window.getSelection();
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(e.target);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}}
|
||||
>
|
||||
{qrUrl}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Sending",
|
||||
"Submit and complete": "Submit and complete"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Go to writable demo site?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Home",
|
||||
"Home - Tooltip": "Home page of the application",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Unique random string",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Is enabled",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Make sure the password is correct",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Different combinations of password complexity options",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Password salt - Tooltip": "Random parameter used for password encryption",
|
||||
"Password type": "Password type",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modify rule",
|
||||
"New Organization": "New Organization",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Soft deletion",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Buy",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail of product",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Site key",
|
||||
"Site key - Tooltip": "Site key",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Keys",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "City of residence",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Odesílání",
|
||||
"Submit and complete": "Odeslat a dokončit"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Upravit Enforcer",
|
||||
"New Enforcer": "Nový Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Přejít na zapisovatelnou demo stránku?",
|
||||
"Groups": "Skupiny",
|
||||
"Groups - Tooltip": "Skupiny - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Domů",
|
||||
"Home - Tooltip": "Domovská stránka aplikace",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Unikátní náhodný řetězec",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identita",
|
||||
"Invitations": "Pozvánky",
|
||||
"Is enabled": "Je povoleno",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Ujistěte se, že heslo je správné",
|
||||
"Password complexity options": "Možnosti složitosti hesla",
|
||||
"Password complexity options - Tooltip": "Různé kombinace možností složitosti hesla",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Heslová sůl",
|
||||
"Password salt - Tooltip": "Náhodný parametr použitý pro šifrování hesla",
|
||||
"Password type": "Typ hesla",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Použít SMS",
|
||||
"Use SMS verification code": "Použít ověřovací kód SMS",
|
||||
"Use a recovery code": "Použít obnovovací kód",
|
||||
"Verification failed": "Ověření selhalo",
|
||||
"Verify Code": "Ověřit kód",
|
||||
"Verify Password": "Ověřit heslo",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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é"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Upravit pravidlo",
|
||||
"New Organization": "Nová organizace",
|
||||
"Optional": "Volitelný",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Výzva",
|
||||
"Required": "Povinné",
|
||||
"Soft deletion": "Měkké smazání",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Koupit",
|
||||
"Buy Product": "Koupit produkt",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail produktu",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Testovací stránka nákupu..",
|
||||
"There is no payment channel for this product.": "Pro tento produkt neexistuje žádný platební kanál.",
|
||||
"This product is currently not in sale.": "Tento produkt není momentálně v prodeji.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Upravit HTML pro registraci",
|
||||
"Signup HTML - Tooltip": "Vlastní HTML pro nahrazení výchozího stylu registrační stránky",
|
||||
"Signup group": "Skupina pro registraci",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Tiché",
|
||||
"Site key": "Klíč stránky",
|
||||
"Site key - Tooltip": "Nápověda ke klíči stránky",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Klíče",
|
||||
"Language": "Jazyk",
|
||||
"Language - Tooltip": "Jazyk - Nápověda",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Odkaz",
|
||||
"Location": "Místo",
|
||||
"Location - Tooltip": "Město bydliště",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Sendet",
|
||||
"Submit and complete": "Einreichen und abschließen"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Gehe zur beschreibbaren Demo-Website?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Zuhause",
|
||||
"Home - Tooltip": "Homepage der Anwendung",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Einzigartiger Zufallsstring",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Ist aktiviert",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Stellen Sie sicher, dass das Passwort korrekt ist",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Password complexity options - Tooltip",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Passwort-Salt",
|
||||
"Password salt - Tooltip": "Zufälliger Parameter, der für die Verschlüsselung von Passwörtern verwendet wird",
|
||||
"Password type": "Passworttyp",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Regel ändern",
|
||||
"New Organization": "Neue Organisation",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Softe Löschung",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Kaufen",
|
||||
"Buy Product": "Produkt kaufen",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail des Produkts",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Testkaufseite.",
|
||||
"There is no payment channel for this product.": "Es gibt keinen Zahlungskanal für dieses Produkt.",
|
||||
"This product is currently not in sale.": "Dieses Produkt steht derzeit nicht zum Verkauf.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Registrierung HTML - Bearbeiten",
|
||||
"Signup HTML - Tooltip": "Benutzerdefiniertes HTML zur Ersetzung des Standard-Registrierungs-Seitenstils",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Site-Key",
|
||||
"Site key - Tooltip": "Seitenschlüssel",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Schlüssel",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Ort",
|
||||
"Location - Tooltip": "Stadt des Wohnsitzes",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Sending",
|
||||
"Submit and complete": "Submit and complete"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Go to writable demo site?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Home",
|
||||
"Home - Tooltip": "Home page of the application",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Unique random string",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Is enabled",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Make sure the password is correct",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Different combinations of password complexity options",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Password salt - Tooltip": "Random parameter used for password encryption",
|
||||
"Password type": "Password type",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modify rule",
|
||||
"New Organization": "New Organization",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Soft deletion",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Buy",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail of product",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Site key",
|
||||
"Site key - Tooltip": "Site key",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Keys",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "City of residence",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Envío",
|
||||
"Submit and complete": "Enviar y completar"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "¿Ir al sitio demo editable?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Hogar",
|
||||
"Home - Tooltip": "Página de inicio de la aplicación",
|
||||
"ID": "identificación",
|
||||
"ID - Tooltip": "Cadena aleatoria única",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Está habilitado",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Asegúrate de que la contraseña sea correcta",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Password complexity options - Tooltip",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Sal de contraseña",
|
||||
"Password salt - Tooltip": "Parámetro aleatorio utilizado para la encriptación de contraseñas",
|
||||
"Password type": "Tipo de contraseña",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modificar regla",
|
||||
"New Organization": "Nueva organización",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Eliminación suave",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Comprar",
|
||||
"Buy Product": "Comprar producto",
|
||||
"CNY": "Año Nuevo Chino (ANC)",
|
||||
"Detail": "Detalle",
|
||||
"Detail - Tooltip": "Detalle del producto",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Página de compra de prueba.",
|
||||
"There is no payment channel for this product.": "No hay canal de pago para este producto.",
|
||||
"This product is currently not in sale.": "Este producto actualmente no está a la venta.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Registro HTML - Editar",
|
||||
"Signup HTML - Tooltip": "HTML personalizado para reemplazar el estilo predeterminado de la página de registro",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Clave del sitio",
|
||||
"Site key - Tooltip": "Clave del sitio",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Claves",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Enlace",
|
||||
"Location": "Ubicación",
|
||||
"Location - Tooltip": "Ciudad de residencia",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -161,6 +161,18 @@
|
||||
"Sending": "Sending",
|
||||
"Submit and complete": "Submit and complete"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Go to writable demo site?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Home",
|
||||
"Home - Tooltip": "Home page of the application",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Unique random string",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Is enabled",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Make sure the password is correct",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Different combinations of password complexity options",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Password salt - Tooltip": "Random parameter used for password encryption",
|
||||
"Password type": "Password type",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modify rule",
|
||||
"New Organization": "New Organization",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Soft deletion",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Buy",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail of product",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Site key",
|
||||
"Site key - Tooltip": "Site key",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Keys",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "City of residence",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Envoi en cours",
|
||||
"Submit and complete": "Soumettre et compléter"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Éditer l'exécuteur",
|
||||
"New Enforcer": "Ajouter un exécuteur"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Allez sur le site de démonstration modifiable ?",
|
||||
"Groups": "Groupes",
|
||||
"Groups - Tooltip": "Groupes - infobulle",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Accueil",
|
||||
"Home - Tooltip": "Page d'accueil de l'application",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Chaîne unique aléatoire",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identité",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Est activé",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Assurez-vous que le mot de passe soit correct",
|
||||
"Password complexity options": "Options de complexité du mot de passe",
|
||||
"Password complexity options - Tooltip": "Différentes combinaisons d'options de complexité de mot de passe",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Sel de mot de passe",
|
||||
"Password salt - Tooltip": "Paramètre aléatoire utilisé pour le chiffrement des mots de passe",
|
||||
"Password type": "Type de mot de passe",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Utiliser les SMS",
|
||||
"Use SMS verification code": "Utiliser la vérification par code SMS",
|
||||
"Use a recovery code": "Utiliser un code de récupération",
|
||||
"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 enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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é"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Règle de modification",
|
||||
"New Organization": "Nouvelle organisation",
|
||||
"Optional": "Optionnel",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Requis",
|
||||
"Soft deletion": "Suppression douce",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Acheter",
|
||||
"Buy Product": "Acheter un produit",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Détail",
|
||||
"Detail - Tooltip": "Détail du produit",
|
||||
"Dummy": "Exemple",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Page d'achat de test.",
|
||||
"There is no payment channel for this product.": "Il n'y a aucun canal de paiement pour ce produit.",
|
||||
"This product is currently not in sale.": "Ce produit n'est actuellement pas en vente.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "HTML de la page d'inscription - Modifier",
|
||||
"Signup HTML - Tooltip": "HTML personnalisé pour remplacer le style par défaut de la page d'inscription",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silencieux",
|
||||
"Site key": "Clé de site",
|
||||
"Site key - Tooltip": "Clé de site",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Clés",
|
||||
"Language": "Langue",
|
||||
"Language - Tooltip": "Langue - Infobulle",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Lier",
|
||||
"Location": "Localisation",
|
||||
"Location - Tooltip": "Ville de résidence",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Sending",
|
||||
"Submit and complete": "Submit and complete"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Go to writable demo site?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Home",
|
||||
"Home - Tooltip": "Home page of the application",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Unique random string",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Is enabled",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Make sure the password is correct",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Different combinations of password complexity options",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Password salt - Tooltip": "Random parameter used for password encryption",
|
||||
"Password type": "Password type",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modify rule",
|
||||
"New Organization": "New Organization",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Soft deletion",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Buy",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail of product",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Site key",
|
||||
"Site key - Tooltip": "Site key",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Keys",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "City of residence",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Mengirimkan",
|
||||
"Submit and complete": "Kirim dan selesaikan"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Pergi ke situs demo yang dapat ditulis?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Rumah",
|
||||
"Home - Tooltip": "Halaman utama aplikasi",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Karakter acak unik",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Diaktifkan",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Pastikan kata sandi yang benar",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Password complexity options - Tooltip",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Garam sandi",
|
||||
"Password salt - Tooltip": "Parameter acak yang digunakan untuk enkripsi kata sandi",
|
||||
"Password type": "Jenis kata sandi",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Mengubah aturan",
|
||||
"New Organization": "Organisasi baru",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Penghapusan lunak",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Beli",
|
||||
"Buy Product": "Beli Produk",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Rincian",
|
||||
"Detail - Tooltip": "Detail produk",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Halaman pembelian uji coba.",
|
||||
"There is no payment channel for this product.": "Tidak ada saluran pembayaran untuk produk ini.",
|
||||
"This product is currently not in sale.": "Produk ini saat ini tidak dijual.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Pendaftaran HTML - Sunting",
|
||||
"Signup HTML - Tooltip": "HTML khusus untuk mengganti gaya halaman pendaftaran bawaan",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Kunci situs",
|
||||
"Site key - Tooltip": "Kunci situs atau kunci halaman web",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Kunci",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Tautan",
|
||||
"Location": "Lokasi",
|
||||
"Location - Tooltip": "Kota tempat tinggal",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Sending",
|
||||
"Submit and complete": "Submit and complete"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Go to writable demo site?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Home",
|
||||
"Home - Tooltip": "Home page of the application",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Unique random string",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Is enabled",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Make sure the password is correct",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Different combinations of password complexity options",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Password salt - Tooltip": "Random parameter used for password encryption",
|
||||
"Password type": "Password type",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modify rule",
|
||||
"New Organization": "New Organization",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Soft deletion",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Buy",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail of product",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Site key",
|
||||
"Site key - Tooltip": "Site key",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Keys",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "City of residence",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "送信",
|
||||
"Submit and complete": "提出して完了してください"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "書き込み可能なデモサイトに移動しますか?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "ホーム",
|
||||
"Home - Tooltip": "アプリケーションのホームページ",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "ユニークなランダム文字列",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "可能になっています",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "パスワードが正しいことを確認してください",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Password complexity options - Tooltip",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "パスワードのソルト",
|
||||
"Password salt - Tooltip": "ランダムパラメーターは、パスワードの暗号化に使用されます",
|
||||
"Password type": "パスワードタイプ",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "ルールを変更する",
|
||||
"New Organization": "新しい組織",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "ソフト削除",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "購入",
|
||||
"Buy Product": "製品を購入する",
|
||||
"CNY": "CNY",
|
||||
"Detail": "詳細",
|
||||
"Detail - Tooltip": "製品の詳細",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "テスト購入ページ。",
|
||||
"There is no payment channel for this product.": "この製品には支払いチャネルがありません。",
|
||||
"This product is currently not in sale.": "この製品は現在販売されていません。",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "サインアップ HTML - 編集",
|
||||
"Signup HTML - Tooltip": "デフォルトのサインアップページスタイルを置き換えるためのカスタムHTML",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "サイトキー",
|
||||
"Site key - Tooltip": "サイトキー",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "鍵",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "リンク",
|
||||
"Location": "場所",
|
||||
"Location - Tooltip": "居住都市",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Sending",
|
||||
"Submit and complete": "Submit and complete"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Go to writable demo site?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Home",
|
||||
"Home - Tooltip": "Home page of the application",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Unique random string",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Is enabled",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Make sure the password is correct",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Different combinations of password complexity options",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Password salt - Tooltip": "Random parameter used for password encryption",
|
||||
"Password type": "Password type",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modify rule",
|
||||
"New Organization": "New Organization",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Soft deletion",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Buy",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail of product",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Site key",
|
||||
"Site key - Tooltip": "Site key",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Keys",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "City of residence",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "전송하기",
|
||||
"Submit and complete": "제출하고 완료하십시오"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "쓰기 가능한 데모 사이트로 이동하시겠습니까?",
|
||||
"Groups": "그룹",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "집",
|
||||
"Home - Tooltip": "어플리케이션 홈 페이지",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "유일한 랜덤 문자열",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "활성화됩니다",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "비밀번호가 올바른지 확인하세요",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Password complexity options - Tooltip",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "비밀번호 솔트",
|
||||
"Password salt - Tooltip": "암호화에 사용되는 임의 매개변수",
|
||||
"Password type": "암호 유형",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "규칙 수정",
|
||||
"New Organization": "새로운 조직",
|
||||
"Optional": "선택사항",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "소프트 삭제",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "구매하다",
|
||||
"Buy Product": "제품을 구입하세요",
|
||||
"CNY": "CNY",
|
||||
"Detail": "세부사항",
|
||||
"Detail - Tooltip": "제품의 세부사항",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "시험 구매 페이지.",
|
||||
"There is no payment channel for this product.": "이 제품에 대한 결제 채널이 없습니다.",
|
||||
"This product is currently not in sale.": "이 제품은 현재 판매되지 않고 있습니다.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "가입 HTML - 수정",
|
||||
"Signup HTML - Tooltip": "기본 가입 페이지 스타일을 바꾸기 위한 사용자 지정 HTML",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "사이트 키",
|
||||
"Site key - Tooltip": "사이트 키",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "열쇠",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "링크",
|
||||
"Location": "장소",
|
||||
"Location - Tooltip": "거주 도시",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Sending",
|
||||
"Submit and complete": "Submit and complete"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Go to writable demo site?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Home",
|
||||
"Home - Tooltip": "Home page of the application",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Unique random string",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Is enabled",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Make sure the password is correct",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Different combinations of password complexity options",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Password salt - Tooltip": "Random parameter used for password encryption",
|
||||
"Password type": "Password type",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modify rule",
|
||||
"New Organization": "New Organization",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Soft deletion",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Buy",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail of product",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Site key",
|
||||
"Site key - Tooltip": "Site key",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Keys",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "City of residence",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Sending",
|
||||
"Submit and complete": "Submit and complete"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Go to writable demo site?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Home",
|
||||
"Home - Tooltip": "Home page of the application",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Unique random string",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Is enabled",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Make sure the password is correct",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Different combinations of password complexity options",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Password salt - Tooltip": "Random parameter used for password encryption",
|
||||
"Password type": "Password type",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modify rule",
|
||||
"New Organization": "New Organization",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Soft deletion",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Buy",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail of product",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Site key",
|
||||
"Site key - Tooltip": "Site key",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Keys",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "City of residence",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Sending",
|
||||
"Submit and complete": "Submit and complete"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Go to writable demo site?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Home",
|
||||
"Home - Tooltip": "Home page of the application",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Unique random string",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Is enabled",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Make sure the password is correct",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Different combinations of password complexity options",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Password salt - Tooltip": "Random parameter used for password encryption",
|
||||
"Password type": "Password type",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modify rule",
|
||||
"New Organization": "New Organization",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Soft deletion",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Buy",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail of product",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Site key",
|
||||
"Site key - Tooltip": "Site key",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Keys",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "City of residence",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Enviando",
|
||||
"Submit and complete": "Enviar e concluir"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Editar Executor",
|
||||
"New Enforcer": "Novo Executor"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Acessar o site de demonstração gravável?",
|
||||
"Groups": "Grupos",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Página Inicial",
|
||||
"Home - Tooltip": "Página inicial do aplicativo",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "String única aleatória",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identidade",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Está habilitado",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Certifique-se de que a senha está correta",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Password complexity options - Tooltip",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Salt de senha",
|
||||
"Password salt - Tooltip": "Parâmetro aleatório usado para criptografia de senha",
|
||||
"Password type": "Tipo de senha",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modificar regra",
|
||||
"New Organization": "Nova Organização",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Exclusão suave",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Comprar",
|
||||
"Buy Product": "Comprar Produto",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detalhe",
|
||||
"Detail - Tooltip": "Detalhes do produto",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Página de teste de compra...",
|
||||
"There is no payment channel for this product.": "Não há canal de pagamento disponível para este produto.",
|
||||
"This product is currently not in sale.": "Este produto não está disponível para venda no momento.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Editar HTML de inscrição",
|
||||
"Signup HTML - Tooltip": "HTML personalizado para substituir o estilo padrão da página de inscrição",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silencioso",
|
||||
"Site key": "Chave do site",
|
||||
"Site key - Tooltip": "Chave do site",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Chaves",
|
||||
"Language": "Idioma",
|
||||
"Language - Tooltip": "Idioma - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Localização",
|
||||
"Location - Tooltip": "Cidade de residência",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Отправка",
|
||||
"Submit and complete": "Отправить и завершить"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Редактировать контролёра доступа",
|
||||
"New Enforcer": "Новый контролёр доступа"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Перейти на демонстрационный сайт для записи данных?",
|
||||
"Groups": "Группы",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Дом",
|
||||
"Home - Tooltip": "Главная страница приложения",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Уникальная случайная строка",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Включен",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Убедитесь, что пароль правильный",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Password complexity options - Tooltip",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Соль пароля",
|
||||
"Password salt - Tooltip": "Случайный параметр, используемый для шифрования пароля",
|
||||
"Password type": "Тип пароля",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Использовать SMS",
|
||||
"Use SMS verification code": "Использовать SMS код для проверки",
|
||||
"Use a recovery code": "Использовать код восстановления",
|
||||
"Verification failed": "Проверка не удалась",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Изменить правило",
|
||||
"New Organization": "Новая организация",
|
||||
"Optional": "Опционально",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Мягкое удаление",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Купить",
|
||||
"Buy Product": "Купить продукт",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Деталь",
|
||||
"Detail - Tooltip": "Деталь продукта",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Страница для тестовой покупки.",
|
||||
"There is no payment channel for this product.": "Для этого продукта нет канала оплаты.",
|
||||
"This product is currently not in sale.": "Этот продукт в настоящее время не продается.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Регистрационная форма HTML - Редактировать",
|
||||
"Signup HTML - Tooltip": "Пользовательский HTML для замены стиля стандартной страницы регистрации",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Ключ сайта",
|
||||
"Site key - Tooltip": "Ключ сайта",
|
||||
@ -971,7 +991,7 @@
|
||||
"Please input your affiliation!": "Пожалуйста, укажите свою принадлежность!",
|
||||
"Please input your display name!": "Пожалуйста, введите своё отображаемое имя!",
|
||||
"Please input your first name!": "Пожалуйста, введите свое имя!",
|
||||
"Please input your invitation code!": "Please input your invitation code!",
|
||||
"Please input your invitation code!": "Пожалуйста, введите код приглашения!",
|
||||
"Please input your last name!": "Введите свою фамилию!",
|
||||
"Please input your phone number!": "Пожалуйста, введите свой номер телефона!",
|
||||
"Please input your real name!": "Пожалуйста, введите своё настоящее имя!",
|
||||
@ -1156,15 +1176,16 @@
|
||||
"Keys": "Ключи",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Ссылка",
|
||||
"Location": "Местоположение",
|
||||
"Location - Tooltip": "Город проживания",
|
||||
"MFA accounts": "MFA accounts",
|
||||
"Managed accounts": "Управляемые аккаунты",
|
||||
"Modify password...": "Изменить пароль...",
|
||||
"Multi-factor authentication": "Multi-factor authentication",
|
||||
"Need update password": "Need update password",
|
||||
"Need update password - Tooltip": "Force user update password after login",
|
||||
"Multi-factor authentication": "Многофакторная аутентификация",
|
||||
"Need update password": "Необходимо обновить пароль",
|
||||
"Need update password - Tooltip": "Заставить пользователя обновить пароль после входа в систему",
|
||||
"New Email": "Новое электронное письмо",
|
||||
"New Password": "Новый пароль",
|
||||
"New User": "Новый пользователь",
|
||||
@ -1188,26 +1209,26 @@
|
||||
"Set password...": "Установить пароль...",
|
||||
"Tag": "Метка",
|
||||
"Tag - Tooltip": "Тег пользователя",
|
||||
"The password must contain at least one special character": "The password must contain at least one special character",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "The password must contain at least one uppercase letter, one lowercase letter and one digit",
|
||||
"The password must have at least 6 characters": "The password must have at least 6 characters",
|
||||
"The password must have at least 8 characters": "The password must have at least 8 characters",
|
||||
"The password must not contain any repeated characters": "The password must not contain any repeated characters",
|
||||
"This field value doesn't match the pattern rule": "This field value doesn't match the pattern rule",
|
||||
"The password must contain at least one special character": "Пароль должен содержать хотя бы один специальный символ",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Пароль должен содержать как минимум одну заглавную букву, одну строчную букву и одну цифру",
|
||||
"The password must have at least 6 characters": "Пароль должен быть минимум 6 символов",
|
||||
"The password must have at least 8 characters": "Пароль должен быть минимум 8 символов",
|
||||
"The password must not contain any repeated characters": "Пароль не должен содержать повторяющиеся символы",
|
||||
"This field value doesn't match the pattern rule": "Значение поля не соответствует шаблону",
|
||||
"Title": "Заголовок",
|
||||
"Title - Tooltip": "Положение в аффилиации",
|
||||
"Two passwords you typed do not match.": "Два введенных вами пароля не совпадают.",
|
||||
"Unlink": "Отсоединить",
|
||||
"Upload (.xlsx)": "Загрузить (.xlsx)",
|
||||
"Upload ID card back picture": "Upload ID card back picture",
|
||||
"Upload ID card front picture": "Upload ID card front picture",
|
||||
"Upload ID card with person picture": "Upload ID card with person picture",
|
||||
"Upload ID card back picture": "Загрузите заднюю сторону удостоверения личности",
|
||||
"Upload ID card front picture": "Загрузите переднюю сторону удостоверения личности",
|
||||
"Upload ID card with person picture": "Загрузите удостоверение личности с фотографией",
|
||||
"Upload a photo": "Загрузить фото",
|
||||
"User Profile": "User Profile",
|
||||
"User Profile": "Профиль пользователя",
|
||||
"Values": "Значения",
|
||||
"Verification code sent": "Код подтверждения отправлен",
|
||||
"WebAuthn credentials": "WebAuthn удостоверения",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"You have changed the username, please save your change first before modifying the password": "Имя было изменено, сохраните изменения перед сменой пароля",
|
||||
"input password": "введите пароль"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Odosielanie",
|
||||
"Submit and complete": "Odoslať a dokončiť"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Upraviť vynútiteľa",
|
||||
"New Enforcer": "Nový vynútiteľ"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Prejsť na zapisovateľnú demo stránku?",
|
||||
"Groups": "Skupiny",
|
||||
"Groups - Tooltip": "Skupiny",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Domov",
|
||||
"Home - Tooltip": "Domovská stránka aplikácie",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Jedinečný náhodný reťazec",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identita",
|
||||
"Invitations": "Pozvánky",
|
||||
"Is enabled": "Je povolené",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Uistite sa, že heslo je správne",
|
||||
"Password complexity options": "Možnosti zložitosti hesla",
|
||||
"Password complexity options - Tooltip": "Rôzne kombinácie možností zložitosti hesla",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Soľ hesla",
|
||||
"Password salt - Tooltip": "Náhodný parameter používaný na šifrovanie hesla",
|
||||
"Password type": "Typ hesla",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Použiť SMS",
|
||||
"Use SMS verification code": "Použiť overovací kód SMS",
|
||||
"Use a recovery code": "Použiť obnovovací kód",
|
||||
"Verification failed": "Overenie zlyhalo",
|
||||
"Verify Code": "Overiť kód",
|
||||
"Verify Password": "Overiť heslo",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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é"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Upraviť pravidlo",
|
||||
"New Organization": "Nová organizácia",
|
||||
"Optional": "Voliteľné",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Výzva",
|
||||
"Required": "Povinné",
|
||||
"Soft deletion": "Mäkké vymazanie",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Kúpiť",
|
||||
"Buy Product": "Kúpiť produkt",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail produktu",
|
||||
"Dummy": "Vzorkový",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Testovať stránku nákupu..",
|
||||
"There is no payment channel for this product.": "Pre tento produkt neexistuje platobný kanál.",
|
||||
"This product is currently not in sale.": "Tento produkt momentálne nie je v predaji.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Upraviť HTML registrácie",
|
||||
"Signup HTML - Tooltip": "Vlastné HTML na nahradenie predvoleného štýlu registračnej stránky",
|
||||
"Signup group": "Skupina registrácie",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Tichý",
|
||||
"Site key": "Kľúč stránky",
|
||||
"Site key - Tooltip": "Kľúč stránky",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Kľúče",
|
||||
"Language": "Jazyk",
|
||||
"Language - Tooltip": "Jazyk - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Odkaz",
|
||||
"Location": "Miesto",
|
||||
"Location - Tooltip": "Mesto bydliska",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Sending",
|
||||
"Submit and complete": "Submit and complete"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Go to writable demo site?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Home",
|
||||
"Home - Tooltip": "Home page of the application",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Unique random string",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Is enabled",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Make sure the password is correct",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Different combinations of password complexity options",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Password salt - Tooltip": "Random parameter used for password encryption",
|
||||
"Password type": "Password type",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modify rule",
|
||||
"New Organization": "New Organization",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Soft deletion",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Buy",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail of product",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Site key",
|
||||
"Site key - Tooltip": "Site key",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Keys",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "City of residence",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Gönderiliyor",
|
||||
"Submit and complete": "Gönder ve Tamamla"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Go to writable demo site?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Ana sayfa",
|
||||
"Home - Tooltip": "Home page of the application",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Unique random string",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Davetler",
|
||||
"Is enabled": "Aktif Mi?",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Şifrenizin doğru olduğundan emin olun",
|
||||
"Password complexity options": "Şifre karmaşıklık seçenekleri",
|
||||
"Password complexity options - Tooltip": "Different combinations of password complexity options",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Password salt",
|
||||
"Password salt - Tooltip": "Random parameter used for password encryption",
|
||||
"Password type": "Password type",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "SMS kullan",
|
||||
"Use SMS verification code": "SMS doğrulama kodunu kullan",
|
||||
"Use a recovery code": "Kurtarma kodu kullan",
|
||||
"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 enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Modify rule",
|
||||
"New Organization": "New Organization",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Gerekli",
|
||||
"Soft deletion": "Soft deletion",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Buy",
|
||||
"Buy Product": "Buy Product",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Detail",
|
||||
"Detail - Tooltip": "Detail of product",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Test buy page..",
|
||||
"There is no payment channel for this product.": "There is no payment channel for this product.",
|
||||
"This product is currently not in sale.": "This product is currently not in sale.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Signup HTML - Edit",
|
||||
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Silent",
|
||||
"Site key": "Site key",
|
||||
"Site key - Tooltip": "Site key",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Keys",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Link",
|
||||
"Location": "Location",
|
||||
"Location - Tooltip": "City of residence",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Відправка",
|
||||
"Submit and complete": "Надішліть і заповніть"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Редагувати Enforcer",
|
||||
"New Enforcer": "Новий Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Перейти на демонстраційний сайт для запису?",
|
||||
"Groups": "Групи",
|
||||
"Groups - Tooltip": "Групи – підказка",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "додому",
|
||||
"Home - Tooltip": "Домашня сторінка програми",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Унікальний випадковий рядок",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Ідентичність",
|
||||
"Invitations": "Запрошення",
|
||||
"Is enabled": "Увімкнено",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Переконайтеся, що пароль правильний",
|
||||
"Password complexity options": "Параметри складності пароля",
|
||||
"Password complexity options - Tooltip": "Різні комбінації параметрів складності пароля",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Сіль пароля",
|
||||
"Password salt - Tooltip": "Випадковий параметр, який використовується для шифрування пароля",
|
||||
"Password type": "Тип пароля",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Використовуйте SMS",
|
||||
"Use SMS verification code": "Використовуйте код підтвердження SMS",
|
||||
"Use a recovery code": "Використовуйте код відновлення",
|
||||
"Verification failed": "Не вдалося перевірити",
|
||||
"Verify Code": "Підтвердити код",
|
||||
"Verify Password": "Підтвердіть пароль",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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": "бажаний"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Змінити правило",
|
||||
"New Organization": "Нова організація",
|
||||
"Optional": "Додатково",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Підкажіть",
|
||||
"Required": "вимагається",
|
||||
"Soft deletion": "М'яке видалення",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "купити",
|
||||
"Buy Product": "Купити товар",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Деталь",
|
||||
"Detail - Tooltip": "Деталь продукту",
|
||||
"Dummy": "манекен",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Сторінка тестової покупки..",
|
||||
"There is no payment channel for this product.": "Для цього продукту немає платіжного каналу.",
|
||||
"This product is currently not in sale.": "Цей товар наразі відсутній у продажу.",
|
||||
"USD": "доларів США",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Реєстраційний HTML - Редагувати",
|
||||
"Signup HTML - Tooltip": "Спеціальний HTML для заміни стилю сторінки реєстрації за умовчанням",
|
||||
"Signup group": "Група реєстрації",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Мовчазний",
|
||||
"Site key": "Ключ сайту",
|
||||
"Site key - Tooltip": "Ключ сайту",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Ключі",
|
||||
"Language": "Мова",
|
||||
"Language - Tooltip": "Мова – підказка",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Посилання",
|
||||
"Location": "Місцезнаходження",
|
||||
"Location - Tooltip": "Місто проживання",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "Gửi",
|
||||
"Submit and complete": "Nộp và hoàn thành"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "Edit Enforcer",
|
||||
"New Enforcer": "New Enforcer"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "Bạn có muốn đi đến trang demo có thể viết được không?",
|
||||
"Groups": "Groups",
|
||||
"Groups - Tooltip": "Groups - Tooltip",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "Nhà",
|
||||
"Home - Tooltip": "Trang chủ của ứng dụng",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "Chuỗi ngẫu nhiên độc nhất",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "Identity",
|
||||
"Invitations": "Invitations",
|
||||
"Is enabled": "Đã được kích hoạt",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "Hãy đảm bảo rằng mật khẩu là chính xác",
|
||||
"Password complexity options": "Password complexity options",
|
||||
"Password complexity options - Tooltip": "Password complexity options - Tooltip",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "Muối mật khẩu",
|
||||
"Password salt - Tooltip": "Tham số ngẫu nhiên được sử dụng để mã hóa mật khẩu",
|
||||
"Password type": "Loại mật khẩu",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
"Use a recovery code": "Use a recovery code",
|
||||
"Verification failed": "Verification failed",
|
||||
"Verify Code": "Verify Code",
|
||||
"Verify Password": "Verify Password",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "You have enabled multi-factor authentication, please enter the authentication code",
|
||||
"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"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "Sửa đổi quy tắc",
|
||||
"New Organization": "Tổ chức mới",
|
||||
"Optional": "Optional",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Xóa mềm",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "Alipay",
|
||||
"Buy": "Mua",
|
||||
"Buy Product": "Mua sản phẩm",
|
||||
"CNY": "CNY",
|
||||
"Detail": "Chi tiết",
|
||||
"Detail - Tooltip": "Chi tiết sản phẩm",
|
||||
"Dummy": "Dummy",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "Trang mua thử.",
|
||||
"There is no payment channel for this product.": "Không có kênh thanh toán cho sản phẩm này.",
|
||||
"This product is currently not in sale.": "Sản phẩm này hiện không được bán.",
|
||||
"USD": "USD",
|
||||
"WeChat Pay": "WeChat Pay"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "Đăng ký HTML - Chỉnh sửa",
|
||||
"Signup HTML - Tooltip": "Trang HTML tùy chỉnh để thay thế phong cách trang đăng ký mặc định",
|
||||
"Signup group": "Signup group",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "Im lặng",
|
||||
"Site key": "Khóa trang web",
|
||||
"Site key - Tooltip": "Khóa trang web",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "Chìa khóa",
|
||||
"Language": "Language",
|
||||
"Language - Tooltip": "Language - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "Liên kết",
|
||||
"Location": "Vị trí",
|
||||
"Location - Tooltip": "Thành phố cư trú",
|
||||
|
@ -161,6 +161,18 @@
|
||||
"Sending": "发送中",
|
||||
"Submit and complete": "完成提交"
|
||||
},
|
||||
"currency": {
|
||||
"AUD": "AUD",
|
||||
"CAD": "CAD",
|
||||
"CHF": "CHF",
|
||||
"CNY": "CNY",
|
||||
"EUR": "EUR",
|
||||
"GBP": "GBP",
|
||||
"HKD": "HKD",
|
||||
"JPY": "JPY",
|
||||
"SGD": "SGD",
|
||||
"USD": "USD"
|
||||
},
|
||||
"enforcer": {
|
||||
"Edit Enforcer": "编辑Casbin执行器",
|
||||
"New Enforcer": "新建Casbin执行器"
|
||||
@ -266,10 +278,13 @@
|
||||
"Go to writable demo site?": "跳转至可写演示站点?",
|
||||
"Groups": "群组",
|
||||
"Groups - Tooltip": "组",
|
||||
"Hide password": "Hide password",
|
||||
"Home": "首页",
|
||||
"Home - Tooltip": "应用的首页",
|
||||
"ID": "ID",
|
||||
"ID - Tooltip": "唯一的随机字符串",
|
||||
"IP whitelist": "IP whitelist",
|
||||
"IP whitelist - Tooltip": "IP whitelist - Tooltip",
|
||||
"Identity": "身份认证",
|
||||
"Invitations": "邀请码",
|
||||
"Is enabled": "已启用",
|
||||
@ -312,6 +327,10 @@
|
||||
"Password - Tooltip": "请确认密码正确",
|
||||
"Password complexity options": "密码复杂度选项",
|
||||
"Password complexity options - Tooltip": "密码复杂度组合,登录密码复杂度必须符合该规范",
|
||||
"Password obf key": "Password obf key",
|
||||
"Password obf key - Tooltip": "Password obf key - Tooltip",
|
||||
"Password obfuscator": "Password obfuscator",
|
||||
"Password obfuscator - Tooltip": "Password obfuscator - Tooltip",
|
||||
"Password salt": "密码Salt值",
|
||||
"Password salt - Tooltip": "用于密码加密的随机参数",
|
||||
"Password type": "密码类型",
|
||||
@ -559,10 +578,10 @@
|
||||
"Use SMS": "使用短信",
|
||||
"Use SMS verification code": "使用手机或电子邮件发送验证码认证",
|
||||
"Use a recovery code": "使用恢复代码",
|
||||
"Verification failed": "验证失败",
|
||||
"Verify Code": "验证码",
|
||||
"Verify Password": "验证密码",
|
||||
"You have enabled multi-factor authentication, please enter the authentication code": "您已经启用多因素认证,请输入认证码",
|
||||
"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": "首选"
|
||||
@ -591,6 +610,8 @@
|
||||
"Modify rule": "修改规则",
|
||||
"New Organization": "添加组织",
|
||||
"Optional": "可选",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "提示",
|
||||
"Required": "必须",
|
||||
"Soft deletion": "软删除",
|
||||
@ -708,7 +729,6 @@
|
||||
"Alipay": "支付宝",
|
||||
"Buy": "购买",
|
||||
"Buy Product": "购买商品",
|
||||
"CNY": "人民币",
|
||||
"Detail": "详情",
|
||||
"Detail - Tooltip": "商品详情",
|
||||
"Dummy": "虚拟",
|
||||
@ -739,7 +759,6 @@
|
||||
"Test buy page..": "测试购买页面..",
|
||||
"There is no payment channel for this product.": "该商品没有付款方式。",
|
||||
"This product is currently not in sale.": "该商品目前未在售。",
|
||||
"USD": "美元",
|
||||
"WeChat Pay": "微信支付"
|
||||
},
|
||||
"provider": {
|
||||
@ -892,6 +911,7 @@
|
||||
"Signup HTML - Edit": "注册页面HTML - 编辑",
|
||||
"Signup HTML - Tooltip": "自定义HTML,用于替换默认的注册页面样式",
|
||||
"Signup group": "注册后的群组",
|
||||
"Signup group - Tooltip": "Signup group - Tooltip",
|
||||
"Silent": "静默",
|
||||
"Site key": "Site key",
|
||||
"Site key - Tooltip": "站点密钥",
|
||||
@ -1156,6 +1176,7 @@
|
||||
"Keys": "键",
|
||||
"Language": "语言",
|
||||
"Language - Tooltip": "语言 - Tooltip",
|
||||
"Last change password time": "Last change password time",
|
||||
"Link": "绑定",
|
||||
"Location": "城市",
|
||||
"Location - Tooltip": "居住地址所在的城市",
|
||||
|
@ -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")},
|
||||
|
@ -14,9 +14,10 @@
|
||||
|
||||
import React from "react";
|
||||
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
|
||||
import {Alert, Button, Col, Image, Input, Popover, QRCode, Row, Table, Tooltip} from "antd";
|
||||
import {Button, Col, Image, Input, Popover, Row, Table, Tooltip} from "antd";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import {CasdoorAppQrCode, CasdoorAppUrl} from "../common/CasdoorAppConnector";
|
||||
|
||||
class MfaAccountTable extends React.Component {
|
||||
constructor(props) {
|
||||
@ -76,42 +77,6 @@ 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 = [
|
||||
{
|
||||
@ -194,10 +159,25 @@ class MfaAccountTable extends React.Component {
|
||||
title={() => (
|
||||
<div>
|
||||
{this.props.title}
|
||||
<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>
|
||||
<Button style={{marginRight: "10px"}} type="primary" size="small" onClick={() => this.addRow(table)}>
|
||||
{i18next.t("general:Add")}
|
||||
</Button>
|
||||
<Popover
|
||||
trigger="focus"
|
||||
overlayInnerStyle={{padding: 0}}
|
||||
content={<CasdoorAppQrCode accessToken={this.props.accessToken} icon={this.state.icon} />}
|
||||
>
|
||||
<Button style={{marginRight: "10px"}} type="primary" size="small">
|
||||
{i18next.t("general:QR Code")}
|
||||
</Button>
|
||||
</Popover>
|
||||
<Popover
|
||||
trigger="click"
|
||||
content={<CasdoorAppUrl accessToken={this.props.accessToken} />}
|
||||
>
|
||||
<Button type="primary" size="small">
|
||||
{i18next.t("general:URL")}
|
||||
</Button>
|
||||
</Popover>
|
||||
</div>
|
||||
)}
|
||||
|
@ -136,7 +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")},
|
||||
{id: "Hide password", name: i18next.t("general:Hide password")},
|
||||
];
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user