Compare commits

...

40 Commits

Author SHA1 Message Date
Yang Luo
698f24f762 feat: fix template code bug in SMS provider of Amazon SNS 2023-12-21 23:32:55 +08:00
HGZ-20
5499e62d7f feat: add the FailedSigninLimit and FailedSigninfrozenTime configuration options to the application (#2552)
Add configuration items to the application to limit the number of logins and the login wait time after the maximum number of errors is reached
feat: #2272

fix: fixed the issue where the token parameter could be set to a negative value
2023-12-20 22:29:53 +08:00
Yang Luo
f8905ae64c Fix S3-compliant storage providers support 2023-12-20 14:38:32 +08:00
Yang Luo
a42594859f feat: improve enforce() and batchEnforce() API response 2023-12-20 11:41:54 +08:00
Yang Luo
46e0bc1a39 Improve i18n texts 2023-12-20 10:09:00 +08:00
Gucheng Wang
ffe2330238 Fix tag field in user list page 2023-12-20 01:57:56 +08:00
Gucheng
ec53616dc8 Update README.md 2023-12-20 01:52:29 +08:00
Gucheng Wang
067276d739 Add new B2C provider 2023-12-17 16:29:29 +08:00
Yang Luo
468ceb6b71 Fix get-all-objects API 403 issue 2023-12-15 21:32:45 +08:00
Satinder Singh
b31a317585 feat: add helm release github action (#2546) 2023-12-15 19:30:10 +08:00
Yang Luo
396b6fb65f feat: refactor custom HTTP related filenames 2023-12-15 00:06:05 +08:00
Yang Luo
be637fca81 fix: fix wrong POST param logic in custom HTTP providers 2023-12-15 00:00:47 +08:00
link89
374928e719 feat: add custom HTTP Email provider (#2542)
* feat: implement Custom HTTP Email provider

* Update Setting.js

* Update ProviderEditPage.js

* Update http.go

* Update provider.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-12-14 22:35:25 +08:00
Yang Luo
5c103e8cd3 Improve error handling in GenerateIdForNewUser() 2023-12-14 10:12:00 +08:00
Lars Lehtonen
85b86e8831 fix: dropped object group errors (#2545) 2023-12-14 09:00:25 +08:00
Yang Luo
08864686f3 feat: fix Google cloud storage provider bug 2023-12-14 00:25:50 +08:00
HGZ-20
dc06eb9948 feat: fix secret information issue in the CAPTCHA provider code (#2531) 2023-12-11 18:01:56 +08:00
Yang Luo
b068202e74 Improve Radius username handling 2023-12-11 18:01:28 +08:00
Satinder Singh
cb16567c7b feat: helm support extra containers (#2530) 2023-12-10 14:41:56 +08:00
Yang Luo
4eb725d47a Improve image upload UI 2023-12-08 19:42:20 +08:00
Yang Luo
ce72a172b0 feat: add back Custom HTTP SMS provider 2023-12-07 16:59:41 +08:00
Yang Luo
5521962e0c feat: update go-sms-sender to v0.17.0 to improve error handling 2023-12-07 14:25:21 +08:00
Yang Luo
37b8b09cc0 feat: update go-sms-sender to v0.16.0 to fix first number missing bug in AmazonSNSClient.SendMessage 2023-12-06 20:05:48 +08:00
Yang Luo
482eb61168 feat: improve StaticFilter() 2023-12-05 18:33:06 +08:00
Lars Lehtonen
8819a8697b feat: fix dropped error in stripe.go (#2525) 2023-12-05 16:02:33 +08:00
Yang Luo
85cb68eb66 feat: unbind LDAP clients if not used any more 2023-12-02 17:51:25 +08:00
Yang Luo
b25b5f0249 Support original accessToken in token APIs 2023-12-02 16:56:18 +08:00
Yang Luo
947dcf6e75 Fix "All" roles bug in permission edit page 2023-12-02 15:26:52 +08:00
Yang Luo
113c27db73 Improve logout's id_token_hint logic 2023-12-02 02:13:34 +08:00
Nex Zhu
badfe34755 feat: add "nonce" into the OAuth and OIDC tokens, for some apps require "nonce" to integrate (#2522) 2023-12-01 18:29:39 +08:00
Yang Luo
a5f9f61381 feat: add token hash to improve performance 2023-11-30 18:05:30 +08:00
Daniil Mikhaylov
2ce8c93ead feat: Improve LDAP filter support (#2519) 2023-11-26 23:11:49 +08:00
Yang Luo
da41ac7275 Improve error handling in getFaviconFileBuffer() 2023-11-25 18:31:33 +08:00
hsluoyz
fd0c70a827 feat: Revert "feat: fix login page path after logout" (#2516)
This reverts commit 23d4488b64.
2023-11-24 15:52:59 +08:00
Yang Luo
c4a6f07672 Allow app user in demo mode 2023-11-24 01:04:23 +08:00
Nex Zhu
a67f541171 feat: in LDAP, search '*' should return all properties (#2511) 2023-11-22 23:52:40 +08:00
Yang Luo
192968bac8 Improve permission.State 2023-11-22 00:03:33 +08:00
aiden
23d4488b64 feat: fix login page path after logout (#2493)
Co-authored-by: aidenlu <aiden_lu@wochacha.com>
2023-11-21 23:37:35 +08:00
songjf
23f4684e1d feat: make MFA works for CAS login (#2506)
* feat: make MFA works for CAS login

* fix: Reduced code redundancy

* fix: Modified the format of the code.

* fix: fix an error with the 'res' variable

* Update LoginPage.js

* Update LoginPage.js

* Update LoginPage.js

* Update MfaAuthVerifyForm.js

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-11-21 21:35:19 +08:00
xzgan
1a91e7b0f9 feat: support LDAP in Linux (#2508) 2023-11-21 14:01:27 +08:00
115 changed files with 3448 additions and 761 deletions

40
.github/workflows/helm.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: Helm Release
on:
push:
branches:
- master
paths:
- 'manifests/casdoor/Chart.yaml'
jobs:
release-helm-chart:
name: Release Helm Chart
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Helm
uses: azure/setup-helm@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Release Helm Chart
run: |
cd manifests/casdoor
REGISTRY=oci://registry-1.docker.io/casbin
helm package .
PKG_NAME=$(ls *.tgz)
helm repo index . --url $REGISTRY --merge index.yaml
helm push $PKG_NAME $REGISTRY
rm $PKG_NAME
- name: Commit updated helm index.yaml
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: 'ci: update helm index.yaml'

View File

@@ -42,6 +42,20 @@
</a>
</p>
<p align="center">
<sup>Sponsored by</sup>
<br>
<a href="https://stytch.com/docs?utm_source=oss-sponsorship&utm_medium=paid_sponsorship&utm_campaign=casbin">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.casbin.org/img/stytch-white.png">
<source media="(prefers-color-scheme: light)" srcset="https://cdn.casbin.org/img/stytch-charcoal.png">
<img src="https://cdn.casbin.org/img/stytch-charcoal.png" width="275">
</picture>
</a><br/>
<a href="https://stytch.com/docs?utm_source=oss-sponsorship&utm_medium=paid_sponsorship&utm_campaign=casbin"><b>Build auth with fraud prevention, faster.</b><br/> Try Stytch for API-first authentication, user & org management, multi-tenant SSO, MFA, device fingerprinting, and more.</a>
<br>
</p>
## Online demo
- Read-only site: https://door.casdoor.com (any modification operation will fail)

View File

@@ -92,6 +92,9 @@ p, *, *, GET, /api/get-plan, *, *
p, *, *, GET, /api/get-subscription, *, *
p, *, *, GET, /api/get-provider, *, *
p, *, *, GET, /api/get-organization-names, *, *
p, *, *, GET, /api/get-all-objects, *, *
p, *, *, GET, /api/get-all-actions, *, *
p, *, *, GET, /api/get-all-roles, *, *
`
sa := stringadapter.NewAdapter(ruleText)
@@ -151,7 +154,7 @@ func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath
return true
} else if urlPath == "/api/update-user" {
// Allow ordinary users to update their own information
if subOwner == objOwner && subName == objName && !(subOwner == "built-in" && subName == "admin") {
if (subOwner == objOwner && subName == objName || subOwner == "app") && !(subOwner == "built-in" && subName == "admin") {
return true
}
return false

View File

@@ -282,17 +282,15 @@ func (c *ApiController) Logout() {
return
}
affected, application, token, err := object.ExpireTokenByAccessToken(accessToken)
_, application, token, err := object.ExpireTokenByAccessToken(accessToken)
if err != nil {
c.ResponseError(err.Error())
return
}
if !affected {
if token == nil {
c.ResponseError(c.T("token:Token not found, invalid accessToken"))
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist")), token.Application)
return
@@ -319,7 +317,15 @@ func (c *ApiController) Logout() {
return
} else {
if application.IsRedirectUriValid(redirectUri) {
c.Ctx.Redirect(http.StatusFound, fmt.Sprintf("%s?state=%s", strings.TrimRight(redirectUri, "/"), state))
redirectUrl := redirectUri
if state != "" {
if strings.Contains(redirectUri, "?") {
redirectUrl = fmt.Sprintf("%s&state=%s", strings.TrimSuffix(redirectUri, "/"), state)
} else {
redirectUrl = fmt.Sprintf("%s?state=%s", strings.TrimSuffix(redirectUri, "/"), state)
}
}
c.Ctx.Redirect(http.StatusFound, redirectUrl)
} else {
c.ResponseError(fmt.Sprintf(c.T("token:Redirect URI: %s doesn't exist in the allowed Redirect URI list"), redirectUri))
return
@@ -473,7 +479,7 @@ func (c *ApiController) GetCaptcha() {
Type: captchaProvider.Type,
SubType: captchaProvider.SubType,
ClientId: captchaProvider.ClientId,
ClientSecret: captchaProvider.ClientSecret,
ClientSecret: "***",
ClientId2: captchaProvider.ClientId2,
ClientSecret2: captchaProvider.ClientSecret2,
})

View File

@@ -110,6 +110,14 @@ func (c *ApiController) GetApplication() {
}
}
// 0 as an initialization value, corresponding to the default configuration parameters
if application.FailedSigninLimit == 0 {
application.FailedSigninLimit = object.DefaultFailedSigninLimit
}
if application.FailedSigninfrozenTime == 0 {
application.FailedSigninfrozenTime = object.DefaultFailedSigninfrozenTime
}
c.ResponseOk(object.GetMaskedApplication(application, userId))
}

View File

@@ -155,7 +155,8 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
resp = &Response{Status: "error", Msg: fmt.Sprintf("error: grant_type: %s is not supported in this application", form.Type), Data: ""}
} else {
scope := c.Input().Get("scope")
token, _ := object.GetTokenByUser(application, user, scope, c.Ctx.Request.Host)
nonce := c.Input().Get("nonce")
token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host)
resp = tokenToResponse(token)
}
} else if form.Type == ResponseTypeSaml { // saml flow
@@ -386,6 +387,16 @@ func (c *ApiController) Login() {
c.ResponseError(err.Error())
return
} else if enableCaptcha {
captchaProvider, err := object.GetCaptchaProviderByApplication(util.GetId(application.Owner, application.Name), "false", c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
if captchaProvider.Type != "Default" {
authForm.ClientSecret = captchaProvider.ClientSecret
}
var isHuman bool
isHuman, err = captcha.VerifyCaptchaByCaptchaType(authForm.CaptchaType, authForm.CaptchaToken, authForm.ClientSecret)
if err != nil {
@@ -935,8 +946,14 @@ func (c *ApiController) GetCaptchaStatus() {
return
}
failedSigninLimit, _, err := object.GetFailedSigninConfigByUser(user)
if err != nil {
c.ResponseError(err.Error())
return
}
var captchaEnabled bool
if user != nil && user.SigninWrongTimes >= object.SigninWrongTimesLimit {
if user != nil && user.SigninWrongTimes >= failedSigninLimit {
captchaEnabled = true
}
c.ResponseOk(captchaEnabled)

View File

@@ -16,6 +16,7 @@ package controllers
import (
"encoding/json"
"fmt"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
@@ -56,13 +57,19 @@ func (c *ApiController) Enforce() {
return
}
res, err := enforcer.Enforce(request...)
res := []bool{}
keyRes := []string{}
enforceResult, err := enforcer.Enforce(request...)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(res)
res = append(res, enforceResult)
keyRes = append(keyRes, enforcer.GetModelAndAdapter())
c.ResponseOk(res, keyRes)
return
}
@@ -72,22 +79,24 @@ func (c *ApiController) Enforce() {
c.ResponseError(err.Error())
return
}
res := []bool{}
if permission == nil {
res = append(res, false)
} else {
enforceResult, err := object.Enforce(permission, &request)
if err != nil {
c.ResponseError(err.Error())
return
}
res = append(res, enforceResult)
c.ResponseError(fmt.Sprintf("permission: %s doesn't exist", permissionId))
return
}
c.ResponseOk(res)
res := []bool{}
keyRes := []string{}
enforceResult, err := object.Enforce(permission, &request)
if err != nil {
c.ResponseError(err.Error())
return
}
res = append(res, enforceResult)
keyRes = append(keyRes, permission.GetModelAndAdapter())
c.ResponseOk(res, keyRes)
return
}
@@ -111,9 +120,9 @@ func (c *ApiController) Enforce() {
}
res := []bool{}
keyRes := []string{}
listPermissionIdMap := object.GroupPermissionsByModelAdapter(permissions)
for _, permissionIds := range listPermissionIdMap {
for key, permissionIds := range listPermissionIdMap {
firstPermission, err := object.GetPermission(permissionIds[0])
if err != nil {
c.ResponseError(err.Error())
@@ -127,9 +136,10 @@ func (c *ApiController) Enforce() {
}
res = append(res, enforceResult)
keyRes = append(keyRes, key)
}
c.ResponseOk(res)
c.ResponseOk(res, keyRes)
}
// BatchEnforce
@@ -160,13 +170,19 @@ func (c *ApiController) BatchEnforce() {
return
}
res, err := enforcer.BatchEnforce(requests)
res := [][]bool{}
keyRes := []string{}
enforceResult, err := enforcer.BatchEnforce(requests)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(res)
res = append(res, enforceResult)
keyRes = append(keyRes, enforcer.GetModelAndAdapter())
c.ResponseOk(res, keyRes)
return
}
@@ -176,28 +192,24 @@ func (c *ApiController) BatchEnforce() {
c.ResponseError(err.Error())
return
}
res := [][]bool{}
if permission == nil {
l := len(requests)
resRequest := make([]bool, l)
for i := 0; i < l; i++ {
resRequest[i] = false
}
res = append(res, resRequest)
} else {
enforceResult, err := object.BatchEnforce(permission, &requests)
if err != nil {
c.ResponseError(err.Error())
return
}
res = append(res, enforceResult)
c.ResponseError(fmt.Sprintf("permission: %s doesn't exist", permissionId))
return
}
c.ResponseOk(res)
res := [][]bool{}
keyRes := []string{}
enforceResult, err := object.BatchEnforce(permission, &requests)
if err != nil {
c.ResponseError(err.Error())
return
}
res = append(res, enforceResult)
keyRes = append(keyRes, permission.GetModelAndAdapter())
c.ResponseOk(res, keyRes)
return
}
@@ -215,7 +227,7 @@ func (c *ApiController) BatchEnforce() {
}
res := [][]bool{}
keyRes := []string{}
listPermissionIdMap := object.GroupPermissionsByModelAdapter(permissions)
for _, permissionIds := range listPermissionIdMap {
firstPermission, err := object.GetPermission(permissionIds[0])
@@ -231,9 +243,10 @@ func (c *ApiController) BatchEnforce() {
}
res = append(res, enforceResult)
keyRes = append(keyRes, firstPermission.GetModelAndAdapter())
}
c.ResponseOk(res)
c.ResponseOk(res, keyRes)
}
func (c *ApiController) GetAllObjects() {
@@ -243,7 +256,13 @@ func (c *ApiController) GetAllObjects() {
return
}
c.ResponseOk(object.GetAllObjects(userId))
objects, err := object.GetAllObjects(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(objects)
}
func (c *ApiController) GetAllActions() {
@@ -253,7 +272,13 @@ func (c *ApiController) GetAllActions() {
return
}
c.ResponseOk(object.GetAllActions(userId))
actions, err := object.GetAllActions(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(actions)
}
func (c *ApiController) GetAllRoles() {
@@ -263,5 +288,11 @@ func (c *ApiController) GetAllRoles() {
return
}
c.ResponseOk(object.GetAllRoles(userId))
roles, err := object.GetAllRoles(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(roles)
}

View File

@@ -59,6 +59,7 @@ func (c *ApiController) GetLdapUsers() {
c.ResponseError(err.Error())
return
}
defer conn.Close()
//groupsMap, err := conn.GetLdapGroups(ldapServer.BaseDn)
//if err != nil {

View File

@@ -53,17 +53,34 @@ func (c *ApiController) SendVerificationCode() {
return
}
if vform.CaptchaType != "none" {
if captchaProvider := captcha.GetCaptchaProvider(vform.CaptchaType); captchaProvider == nil {
c.ResponseError(c.T("general:don't support captchaProvider: ") + vform.CaptchaType)
return
} else if isHuman, err := captchaProvider.VerifyCaptcha(vform.CaptchaToken, vform.ClientSecret); err != nil {
c.ResponseError(err.Error())
return
} else if !isHuman {
provider, err := object.GetCaptchaProviderByApplication(vform.ApplicationId, "false", c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
if provider != nil {
if vform.CaptchaType != provider.Type {
c.ResponseError(c.T("verification:Turing test failed."))
return
}
if provider.Type != "Default" {
vform.ClientSecret = provider.ClientSecret
}
if vform.CaptchaType != "none" {
if captchaProvider := captcha.GetCaptchaProvider(vform.CaptchaType); captchaProvider == nil {
c.ResponseError(c.T("general:don't support captchaProvider: ") + vform.CaptchaType)
return
} else if isHuman, err := captchaProvider.VerifyCaptcha(vform.CaptchaToken, vform.ClientSecret); err != nil {
c.ResponseError(err.Error())
return
} else if !isHuman {
c.ResponseError(c.T("verification:Turing test failed."))
return
}
}
}
application, err := object.GetApplication(vform.ApplicationId)
@@ -225,6 +242,16 @@ func (c *ApiController) VerifyCaptcha() {
return
}
captchaProvider, err := object.GetCaptchaProviderByOwnerName(vform.ApplicationId, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
if captchaProvider.Type != "Default" {
vform.ClientSecret = captchaProvider.ClientSecret
}
provider := captcha.GetCaptchaProvider(vform.CaptchaType)
if provider == nil {
c.ResponseError(c.T("verification:Invalid captcha provider."))

82
email/custom_http.go Normal file
View File

@@ -0,0 +1,82 @@
// Copyright 2023 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 email
import (
"fmt"
"net/http"
"net/url"
"strings"
"github.com/casdoor/casdoor/proxy"
)
type HttpEmailProvider struct {
endpoint string
method string
}
func NewHttpEmailProvider(endpoint string, method string) *HttpEmailProvider {
client := &HttpEmailProvider{
endpoint: endpoint,
method: method,
}
return client
}
func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
var req *http.Request
var err error
if c.method == "POST" {
formValues := url.Values{}
formValues.Set("fromName", fromName)
formValues.Set("toAddress", toAddress)
formValues.Set("subject", subject)
formValues.Set("content", content)
req, err = http.NewRequest(c.method, c.endpoint, strings.NewReader(formValues.Encode()))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
} else if c.method == "GET" {
req, err = http.NewRequest(c.method, c.endpoint, nil)
if err != nil {
return err
}
q := req.URL.Query()
q.Add("fromName", fromName)
q.Add("toAddress", toAddress)
q.Add("subject", subject)
q.Add("content", content)
req.URL.RawQuery = q.Encode()
} else {
return fmt.Errorf("HttpEmailProvider's Send() error, unsupported method: %s", c.method)
}
httpClient := proxy.DefaultHttpClient
resp, err := httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("HttpEmailProvider's Send() error, custom HTTP Email request failed with status: %s", resp.Status)
}
return err
}

View File

@@ -18,9 +18,11 @@ type EmailProvider interface {
Send(fromAddress string, fromName, toAddress string, subject string, content string) error
}
func GetEmailProvider(typ string, clientId string, clientSecret string, host string, port int, disableSsl bool) EmailProvider {
func GetEmailProvider(typ string, clientId string, clientSecret string, host string, port int, disableSsl bool, endpoint string, method string) EmailProvider {
if typ == "Azure ACS" {
return NewAzureACSEmailProvider(clientSecret, host)
} else if typ == "Custom HTTP Email" {
return NewHttpEmailProvider(endpoint, method)
} else {
return NewSmtpEmailProvider(clientId, clientSecret, host, port, typ, disableSsl)
}

23
go.mod
View File

@@ -9,12 +9,11 @@ require (
github.com/aws/aws-sdk-go v1.45.5
github.com/beego/beego v1.12.12
github.com/beevik/etree v1.1.0
github.com/casbin/casbin v1.9.1 // indirect
github.com/casbin/casbin/v2 v2.77.2
github.com/casdoor/go-sms-sender v0.15.0
github.com/casdoor/go-sms-sender v0.18.0
github.com/casdoor/gomail/v2 v2.0.1
github.com/casdoor/notify v0.45.0
github.com/casdoor/oss v1.3.0
github.com/casdoor/oss v1.4.1
github.com/casdoor/xorm-adapter/v3 v3.1.0
github.com/casvisor/casvisor-go-sdk v1.0.3
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
@@ -23,16 +22,17 @@ require (
github.com/elimity-com/scim v0.0.0-20230426070224-941a5eac92f3
github.com/fogleman/gg v1.3.0
github.com/forestmgy/ldapserver v1.1.0
github.com/go-asn1-ber/asn1-ber v1.5.5
github.com/go-git/go-git/v5 v5.6.0
github.com/go-ldap/ldap/v3 v3.3.0
github.com/go-ldap/ldap/v3 v3.4.6
github.com/go-mysql-org/go-mysql v1.7.0
github.com/go-pay/gopay v1.5.72
github.com/go-sql-driver/mysql v1.6.0
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
github.com/go-webauthn/webauthn v0.6.0
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/google/uuid v1.3.1
github.com/json-iterator/go v1.1.12 // indirect
github.com/google/uuid v1.4.0
github.com/json-iterator/go v1.1.12
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/lestrrat-go/jwx v1.2.21
github.com/lib/pq v1.10.9
@@ -43,7 +43,7 @@ require (
github.com/nyaruka/phonenumbers v1.1.5
github.com/pquerna/otp v1.4.0
github.com/prometheus/client_golang v1.11.1
github.com/prometheus/client_model v0.3.0
github.com/prometheus/client_model v0.4.0
github.com/qiangmzsx/string-adapter/v2 v2.1.0
github.com/robfig/cron/v3 v3.0.1
github.com/russellhaering/gosaml2 v0.9.0
@@ -62,11 +62,10 @@ require (
github.com/xorm-io/core v0.7.4
github.com/xorm-io/xorm v1.1.6
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.12.0
golang.org/x/net v0.14.0
golang.org/x/oauth2 v0.11.0
golang.org/x/text v0.13.0 // indirect
google.golang.org/api v0.138.0
golang.org/x/crypto v0.14.0
golang.org/x/net v0.17.0
golang.org/x/oauth2 v0.13.0
google.golang.org/api v0.150.0
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0
layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68

296
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"The provider: %s is not enabled for the application": "Der Anbieter: %s ist nicht für die Anwendung aktiviert",
"Unauthorized operation": "Nicht autorisierte Operation",
"Unknown authentication type (not password or provider), form = %s": "Unbekannter Authentifizierungstyp (nicht Passwort oder Anbieter), Formular = %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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s und %s stimmen nicht überein"
@@ -33,11 +34,12 @@
"Email is invalid": "E-Mail ist ungültig",
"Empty username.": "Leerer Benutzername.",
"FirstName cannot be blank": "Vorname darf nicht leer sein",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"LDAP user name or password incorrect": "Ldap Benutzername oder Passwort falsch",
"LastName cannot be blank": "Nachname darf nicht leer sein",
"Multiple accounts with same uid, please check your ldap server": "Mehrere Konten mit derselben uid, bitte überprüfen Sie Ihren LDAP-Server",
"Organization does not exist": "Organisation existiert nicht",
"Password must have at least 6 characters": "Das Passwort muss mindestens 6 Zeichen enthalten",
"Phone already exists": "Telefon existiert bereits",
"Phone cannot be empty": "Das Telefon darf nicht leer sein",
"Phone number is invalid": "Die Telefonnummer ist ungültig",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"The provider: %s is not enabled for the application": "El proveedor: %s no está habilitado para la aplicación",
"Unauthorized operation": "Operación no autorizada",
"Unknown authentication type (not password or provider), form = %s": "Tipo de autenticación desconocido (no es contraseña o proveedor), formulario = %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"
"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"
},
"cas": {
"Service %s and %s do not match": "Los servicios %s y %s no coinciden"
@@ -33,11 +34,12 @@
"Email is invalid": "El correo electrónico no es válido",
"Empty username.": "Nombre de usuario vacío.",
"FirstName cannot be blank": "El nombre no puede estar en blanco",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"LDAP user name or password incorrect": "Nombre de usuario o contraseña de Ldap incorrectos",
"LastName cannot be blank": "El apellido no puede estar en blanco",
"Multiple accounts with same uid, please check your ldap server": "Cuentas múltiples con el mismo uid, por favor revise su servidor ldap",
"Organization does not exist": "La organización no existe",
"Password must have at least 6 characters": "La contraseña debe tener al menos 6 caracteres",
"Phone already exists": "El teléfono ya existe",
"Phone cannot be empty": "Teléfono no puede estar vacío",
"Phone number is invalid": "El número de teléfono no es válido",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"The provider: %s is not enabled for the application": "Le fournisseur :%s n'est pas activé pour l'application",
"Unauthorized operation": "Opération non autorisée",
"Unknown authentication type (not password or provider), form = %s": "Type d'authentification inconnu (pas de mot de passe ou de fournisseur), formulaire = %s",
"User's tag: %s is not listed in the application's tags": "Le tag de lutilisateur %s nest pas répertorié dans les tags de lapplication"
"User's tag: %s is not listed in the application's tags": "Le tag de lutilisateur %s nest pas répertorié dans les tags de lapplication",
"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"
},
"cas": {
"Service %s and %s do not match": "Les services %s et %s ne correspondent pas"
@@ -33,11 +34,12 @@
"Email is invalid": "L'adresse e-mail est invalide",
"Empty username.": "Nom d'utilisateur vide.",
"FirstName cannot be blank": "Le prénom ne peut pas être laissé vide",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"LDAP user name or password incorrect": "Nom d'utilisateur ou mot de passe LDAP incorrect",
"LastName cannot be blank": "Le nom de famille ne peut pas être vide",
"Multiple accounts with same uid, please check your ldap server": "Plusieurs comptes avec le même identifiant d'utilisateur, veuillez vérifier votre serveur LDAP",
"Organization does not exist": "L'organisation n'existe pas",
"Password must have at least 6 characters": "Le mot de passe doit comporter au moins 6 caractères",
"Phone already exists": "Le téléphone existe déjà",
"Phone cannot be empty": "Le téléphone ne peut pas être vide",
"Phone number is invalid": "Le numéro de téléphone est invalide",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"The provider: %s is not enabled for the application": "Penyedia: %s tidak diaktifkan untuk aplikasi ini",
"Unauthorized operation": "Operasi tidak sah",
"Unknown authentication type (not password or provider), form = %s": "Jenis otentikasi tidak diketahui (bukan kata sandi atau pemberi), formulir = %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"
"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"
},
"cas": {
"Service %s and %s do not match": "Layanan %s dan %s tidak cocok"
@@ -33,11 +34,12 @@
"Email is invalid": "Email tidak valid",
"Empty username.": "Nama pengguna kosong.",
"FirstName cannot be blank": "Nama depan tidak boleh kosong",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"LDAP user name or password incorrect": "Nama pengguna atau kata sandi Ldap salah",
"LastName cannot be blank": "Nama belakang tidak boleh kosong",
"Multiple accounts with same uid, please check your ldap server": "Beberapa akun dengan uid yang sama, harap periksa server ldap Anda",
"Organization does not exist": "Organisasi tidak ada",
"Password must have at least 6 characters": "Kata sandi harus memiliki minimal 6 karakter",
"Phone already exists": "Telepon sudah ada",
"Phone cannot be empty": "Telepon tidak boleh kosong",
"Phone number is invalid": "Nomor telepon tidak valid",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"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": "User's tag: %s is not listed in the application's tags"
"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"
},
"cas": {
"Service %s and %s do not match": "サービス%sと%sは一致しません"
@@ -33,11 +34,12 @@
"Email is invalid": "電子メールは無効です",
"Empty username.": "空のユーザー名。",
"FirstName cannot be blank": "ファーストネームは空白にできません",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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": "組織は存在しません",
"Password must have at least 6 characters": "パスワードは少なくとも6つの文字が必要です",
"Phone already exists": "電話はすでに存在しています",
"Phone cannot be empty": "電話は空っぽにできません",
"Phone number is invalid": "電話番号が無効です",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"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": "User's tag: %s is not listed in the application's tags"
"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"
},
"cas": {
"Service %s and %s do not match": "서비스 %s와 %s는 일치하지 않습니다"
@@ -33,11 +34,12 @@
"Email is invalid": "이메일이 유효하지 않습니다",
"Empty username.": "빈 사용자 이름.",
"FirstName cannot be blank": "이름은 공백일 수 없습니다",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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": "조직은 존재하지 않습니다",
"Password must have at least 6 characters": "암호는 적어도 6자 이상이어야 합니다",
"Phone already exists": "전화기는 이미 존재합니다",
"Phone cannot be empty": "전화는 비워 둘 수 없습니다",
"Phone number is invalid": "전화번호가 유효하지 않습니다",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"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": "User's tag: %s is not listed in the application's tags"
"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"
},
"cas": {
"Service %s and %s do not match": "Сервисы %s и %s не совпадают"
@@ -33,11 +34,12 @@
"Email is invalid": "Адрес электронной почты недействительный",
"Empty username.": "Пустое имя пользователя.",
"FirstName cannot be blank": "Имя не может быть пустым",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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": "Организация не существует",
"Password must have at least 6 characters": "Пароль должен содержать не менее 6 символов",
"Phone already exists": "Телефон уже существует",
"Phone cannot be empty": "Телефон не может быть пустым",
"Phone number is invalid": "Номер телефона является недействительным",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"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"
"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"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
@@ -33,11 +34,12 @@
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",

View File

@@ -19,7 +19,8 @@
"The provider: %s is not enabled for the application": "Nhà cung cấp: %s không được kích hoạt cho ứng dụng",
"Unauthorized operation": "Hoạt động không được ủy quyền",
"Unknown authentication type (not password or provider), form = %s": "Loại xác thực không xác định (không phải mật khẩu hoặc nhà cung cấp), biểu mẫu = %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"
"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"
},
"cas": {
"Service %s and %s do not match": "Dịch sang tiếng Việt: Dịch vụ %s và %s không khớp"
@@ -33,11 +34,12 @@
"Email is invalid": "Địa chỉ email không hợp lệ",
"Empty username.": "Tên đăng nhập trống.",
"FirstName cannot be blank": "Tên không được để trống",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"LDAP user name or password incorrect": "Tên người dùng hoặc mật khẩu Ldap không chính xác",
"LastName cannot be blank": "Họ không thể để trống",
"Multiple accounts with same uid, please check your ldap server": "Nhiều tài khoản với cùng một uid, vui lòng kiểm tra máy chủ ldap của bạn",
"Organization does not exist": "Tổ chức không tồn tại",
"Password must have at least 6 characters": "Mật khẩu phải ít nhất 6 ký tự",
"Phone already exists": "Điện thoại đã tồn tại",
"Phone cannot be empty": "Điện thoại không thể để trống",
"Phone number is invalid": "Số điện thoại không hợp lệ",

View File

@@ -19,7 +19,8 @@
"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不在该应用的标签列表中"
"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": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing"
},
"cas": {
"Service %s and %s do not match": "服务%s与%s不匹配"
@@ -33,11 +34,12 @@
"Email is invalid": "无效邮箱",
"Empty username.": "用户名不可为空",
"FirstName cannot be blank": "名不可以为空",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code is invalid": "Invitation code is invalid",
"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": "组织不存在",
"Password must have at least 6 characters": "新密码至少为6位",
"Phone already exists": "该手机号已存在",
"Phone cannot be empty": "手机号不可为空",
"Phone number is invalid": "无效手机号",

View File

@@ -85,10 +85,12 @@ func (idp *AdfsIdProvider) GetToken(code string) (*oauth2.Token, error) {
payload.Set("client_id", idp.Config.ClientID)
payload.Set("client_secret", idp.Config.ClientSecret)
payload.Set("redirect_uri", idp.Config.RedirectURL)
resp, err := idp.Client.PostForm(idp.Config.Endpoint.TokenURL, payload)
if err != nil {
return nil, err
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
@@ -97,10 +99,10 @@ func (idp *AdfsIdProvider) GetToken(code string) (*oauth2.Token, error) {
pToken := &AdfsToken{}
err = json.Unmarshal(data, pToken)
if err != nil {
return nil, fmt.Errorf("fail to unmarshal token response: %s", err.Error())
return nil, err
}
if pToken.ErrMsg != "" {
return nil, fmt.Errorf("pToken.Errmsg = %s", pToken.ErrMsg)
return nil, fmt.Errorf(pToken.ErrMsg)
}
token := &oauth2.Token{

126
idp/azuread_b2c.go Normal file
View File

@@ -0,0 +1,126 @@
// Copyright 2023 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 idp
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"time"
"golang.org/x/oauth2"
)
type AzureADB2CProvider struct {
Client *http.Client
Config *oauth2.Config
Tenant string
UserFlow string
}
func NewAzureAdB2cProvider(clientId, clientSecret, redirectUrl, tenant string, userFlow string) *AzureADB2CProvider {
return &AzureADB2CProvider{
Config: &oauth2.Config{
ClientID: clientId,
ClientSecret: clientSecret,
RedirectURL: redirectUrl,
Endpoint: oauth2.Endpoint{
AuthURL: fmt.Sprintf("https://%s.b2clogin.com/%s.onmicrosoft.com/%s/oauth2/v2.0/authorize", tenant, tenant, userFlow),
TokenURL: fmt.Sprintf("https://%s.b2clogin.com/%s.onmicrosoft.com/%s/oauth2/v2.0/token", tenant, tenant, userFlow),
},
Scopes: []string{"openid", "email"},
},
Tenant: tenant,
UserFlow: userFlow,
}
}
func (p *AzureADB2CProvider) SetHttpClient(client *http.Client) {
p.Client = client
}
type AzureadB2cToken struct {
IdToken string `json:"id_token"`
TokenType string `json:"token_type"`
NotBefore int `json:"not_before"`
IdTokenExpiresIn int `json:"id_token_expires_in"`
ProfileInfo string `json:"profile_info"`
Scope string `json:"scope"`
}
func (p *AzureADB2CProvider) GetToken(code string) (*oauth2.Token, error) {
payload := url.Values{}
payload.Set("code", code)
payload.Set("grant_type", "authorization_code")
payload.Set("client_id", p.Config.ClientID)
payload.Set("client_secret", p.Config.ClientSecret)
payload.Set("redirect_uri", p.Config.RedirectURL)
resp, err := p.Client.PostForm(p.Config.Endpoint.TokenURL, payload)
if err != nil {
return nil, err
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
pToken := &AzureadB2cToken{}
err = json.Unmarshal(data, pToken)
if err != nil {
return nil, err
}
token := &oauth2.Token{
AccessToken: pToken.IdToken,
Expiry: time.Unix(time.Now().Unix()+int64(pToken.IdTokenExpiresIn), 0),
}
return token, nil
}
func (p *AzureADB2CProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
userInfoEndpoint := fmt.Sprintf("https://%s.b2clogin.com/%s.onmicrosoft.com/%s/openid/v2.0/userinfo", p.Tenant, p.Tenant, p.UserFlow)
req, err := http.NewRequest("GET", userInfoEndpoint, nil)
if err != nil {
return nil, err
}
req.Header.Add("Authorization", "Bearer "+token.AccessToken)
resp, err := p.Client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error fetching user info: status code %d", resp.StatusCode)
}
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var userInfo UserInfo
err = json.Unmarshal(bodyBytes, &userInfo)
if err != nil {
return nil, err
}
return &userInfo, nil
}

View File

@@ -91,6 +91,8 @@ func GetIdProvider(idpInfo *ProviderInfo, redirectUrl string) (IdProvider, error
return NewGitlabIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil
case "ADFS":
return NewAdfsIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl), nil
case "AzureADB2C":
return NewAzureAdB2cProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl, idpInfo.AppId), nil
case "Baidu":
return NewBaiduIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil
case "Alipay":

View File

@@ -104,7 +104,9 @@
}
],
"redirectUris": [""],
"expireInHours": 168
"expireInHours": 168,
"failedSigninLimit": 5,
"failedSigninfrozenTime": 15
}
],
"users": [

View File

@@ -16,6 +16,7 @@ package ldap
import (
"fmt"
"hash/fnv"
"log"
"github.com/casdoor/casdoor/conf"
@@ -113,11 +114,22 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
}
for _, user := range users {
dn := fmt.Sprintf("cn=%s,%s", user.Name, string(r.BaseObject()))
dn := fmt.Sprintf("uid=%s,cn=%s,%s", user.Id, user.Name, string(r.BaseObject()))
e := ldap.NewSearchResultEntry(dn)
e.AddAttribute(message.AttributeDescription("uid"), message.AttributeValue(user.Id))
e.AddAttribute(message.AttributeDescription("cn"), message.AttributeValue(user.Name))
for _, attr := range r.Attributes() {
uidNumberStr := fmt.Sprintf("%v", hash(user.Name))
e.AddAttribute("uidNumber", message.AttributeValue(uidNumberStr))
e.AddAttribute("gidNumber", message.AttributeValue(uidNumberStr))
e.AddAttribute("homeDirectory", message.AttributeValue("/home/"+user.Name))
e.AddAttribute("cn", message.AttributeValue(user.Name))
e.AddAttribute("uid", message.AttributeValue(user.Id))
attrs := r.Attributes()
for _, attr := range attrs {
if string(attr) == "*" {
attrs = AdditionalLdapAttributes
break
}
}
for _, attr := range attrs {
e.AddAttribute(message.AttributeDescription(attr), getAttribute(string(attr), user))
if string(attr) == "cn" {
e.AddAttribute(message.AttributeDescription(attr), getAttribute("title", user))
@@ -128,3 +140,9 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
}
w.Write(res)
}
func hash(s string) uint32 {
h := fnv.New32a()
h.Write([]byte(s))
return h.Sum32()
}

View File

@@ -24,8 +24,72 @@ import (
"github.com/lor00x/goldap/message"
ldap "github.com/forestmgy/ldapserver"
"github.com/xorm-io/builder"
)
type AttributeMapper func(user *object.User) message.AttributeValue
type FieldRelation struct {
userField string
notSearchable bool
hideOnStarOp bool
fieldMapper AttributeMapper
}
func (rel FieldRelation) GetField() (string, error) {
if rel.notSearchable {
return "", fmt.Errorf("attribute %s not supported", rel.userField)
}
return rel.userField, nil
}
func (rel FieldRelation) GetAttributeValue(user *object.User) message.AttributeValue {
return rel.fieldMapper(user)
}
var ldapAttributesMapping = map[string]FieldRelation{
"cn": {userField: "name", hideOnStarOp: true, fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.Name)
}},
"uid": {userField: "name", hideOnStarOp: true, fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.Name)
}},
"displayname": {userField: "displayName", fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.DisplayName)
}},
"email": {userField: "email", fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.Email)
}},
"mail": {userField: "email", fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.Email)
}},
"mobile": {userField: "phone", fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.Phone)
}},
"title": {userField: "tag", fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.Tag)
}},
"userPassword": {
userField: "userPassword",
notSearchable: true,
fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(getUserPasswordWithType(user))
},
},
}
var AdditionalLdapAttributes []message.LDAPString
func init() {
for k, v := range ldapAttributesMapping {
if v.hideOnStarOp {
continue
}
AdditionalLdapAttributes = append(AdditionalLdapAttributes, message.LDAPString(k))
}
}
func getNameAndOrgFromDN(DN string) (string, string, error) {
DNFields := strings.Split(DN, ",")
params := make(map[string]string, len(DNFields))
@@ -87,6 +151,92 @@ func stringInSlice(value string, list []string) bool {
return false
}
func buildUserFilterCondition(filter interface{}) (builder.Cond, error) {
switch f := filter.(type) {
case message.FilterAnd:
conditions := make([]builder.Cond, len(f))
for i, v := range f {
cond, err := buildUserFilterCondition(v)
if err != nil {
return nil, err
}
conditions[i] = cond
}
return builder.And(conditions...), nil
case message.FilterOr:
conditions := make([]builder.Cond, len(f))
for i, v := range f {
cond, err := buildUserFilterCondition(v)
if err != nil {
return nil, err
}
conditions[i] = cond
}
return builder.Or(conditions...), nil
case message.FilterNot:
cond, err := buildUserFilterCondition(f.Filter)
if err != nil {
return nil, err
}
return builder.Not{cond}, nil
case message.FilterEqualityMatch:
field, err := getUserFieldFromAttribute(string(f.AttributeDesc()))
if err != nil {
return nil, err
}
return builder.Eq{field: string(f.AssertionValue())}, nil
case message.FilterPresent:
field, err := getUserFieldFromAttribute(string(f))
if err != nil {
return nil, err
}
return builder.NotNull{field}, nil
case message.FilterGreaterOrEqual:
field, err := getUserFieldFromAttribute(string(f.AttributeDesc()))
if err != nil {
return nil, err
}
return builder.Gte{field: string(f.AssertionValue())}, nil
case message.FilterLessOrEqual:
field, err := getUserFieldFromAttribute(string(f.AttributeDesc()))
if err != nil {
return nil, err
}
return builder.Lte{field: string(f.AssertionValue())}, nil
case message.FilterSubstrings:
field, err := getUserFieldFromAttribute(string(f.Type_()))
if err != nil {
return nil, err
}
var expr string
for _, substring := range f.Substrings() {
switch s := substring.(type) {
case message.SubstringInitial:
expr += string(s) + "%"
continue
case message.SubstringAny:
expr += string(s) + "%"
continue
case message.SubstringFinal:
expr += string(s)
continue
}
}
return builder.Expr(field+" LIKE ?", expr), nil
default:
return nil, fmt.Errorf("LDAP filter operation %#v not supported", f)
}
}
func buildSafeCondition(filter interface{}) builder.Cond {
condition, err := buildUserFilterCondition(filter)
if err != nil {
log.Printf("err = %v", err.Error())
return nil
}
return condition
}
func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int) {
var err error
r := m.GetSearchRequest()
@@ -98,15 +248,14 @@ func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int)
if name == "*" && m.Client.IsOrgAdmin { // get all users from organization 'org'
if m.Client.IsGlobalAdmin && org == "*" {
filteredUsers, err = object.GetGlobalUsers()
filteredUsers, err = object.GetGlobalUsersWithFilter(buildSafeCondition(r.Filter()))
if err != nil {
panic(err)
}
return filteredUsers, ldap.LDAPResultSuccess
}
if m.Client.IsGlobalAdmin || org == m.Client.OrgName {
filteredUsers, err = object.GetUsers(org)
filteredUsers, err = object.GetUsersWithFilter(org, buildSafeCondition(r.Filter()))
if err != nil {
panic(err)
}
@@ -148,7 +297,7 @@ func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int)
return nil, ldap.LDAPResultNoSuchObject
}
users, err := object.GetUsersByTag(org, name)
users, err := object.GetUsersByTagWithFilter(org, name, buildSafeCondition(r.Filter()))
if err != nil {
panic(err)
}
@@ -182,24 +331,17 @@ func getUserPasswordWithType(user *object.User) string {
}
func getAttribute(attributeName string, user *object.User) message.AttributeValue {
switch attributeName {
case "cn":
return message.AttributeValue(user.Name)
case "uid":
return message.AttributeValue(user.Name)
case "displayname":
return message.AttributeValue(user.DisplayName)
case "email":
return message.AttributeValue(user.Email)
case "mail":
return message.AttributeValue(user.Email)
case "mobile":
return message.AttributeValue(user.Phone)
case "title":
return message.AttributeValue(user.Tag)
case "userPassword":
return message.AttributeValue(getUserPasswordWithType(user))
default:
v, ok := ldapAttributesMapping[attributeName]
if !ok {
return ""
}
return v.GetAttributeValue(user)
}
func getUserFieldFromAttribute(attributeName string) (string, error) {
v, ok := ldapAttributesMapping[attributeName]
if !ok {
return "", fmt.Errorf("attribute %s not supported", attributeName)
}
return v.GetField()
}

87
ldap/util_test.go Normal file
View File

@@ -0,0 +1,87 @@
package ldap
import (
"testing"
"github.com/stretchr/testify/assert"
ber "github.com/go-asn1-ber/asn1-ber"
goldap "github.com/go-ldap/ldap/v3"
"github.com/lor00x/goldap/message"
"github.com/xorm-io/builder"
)
func args(exp ...interface{}) []interface{} {
return exp
}
func TestLdapFilterAsQuery(t *testing.T) {
scenarios := []struct {
description string
input string
expectedExpr string
expectedArgs []interface{}
}{
{"Should be SQL for FilterAnd", "(&(mail=2)(email=1))", "email=? AND email=?", args("2", "1")},
{"Should be SQL for FilterOr", "(|(mail=2)(email=1))", "email=? OR email=?", args("2", "1")},
{"Should be SQL for FilterNot", "(!(mail=2))", "NOT email=?", args("2")},
{"Should be SQL for FilterEqualityMatch", "(mail=2)", "email=?", args("2")},
{"Should be SQL for FilterPresent", "(mail=*)", "email IS NOT NULL", nil},
{"Should be SQL for FilterGreaterOrEqual", "(mail>=admin)", "email>=?", args("admin")},
{"Should be SQL for FilterLessOrEqual", "(mail<=admin)", "email<=?", args("admin")},
{"Should be SQL for FilterSubstrings", "(mail=admin*ex*c*m)", "email LIKE ?", args("admin%ex%c%m")},
}
for _, scenery := range scenarios {
t.Run(scenery.description, func(t *testing.T) {
searchRequest, err := buildLdapSearchRequest(scenery.input)
if err != nil {
assert.FailNow(t, "Unable to create searchRequest", err)
}
m, err := message.ReadLDAPMessage(message.NewBytes(0, searchRequest.Bytes()))
if err != nil {
assert.FailNow(t, "Unable to create searchRequest", err)
}
req := m.ProtocolOp().(message.SearchRequest)
cond, err := buildUserFilterCondition(req.Filter())
if err != nil {
assert.FailNow(t, "Unable to build condition", err)
}
expr, args, err := builder.ToSQL(cond)
if err != nil {
assert.FailNow(t, "Unable to build sql", err)
}
assert.Equal(t, scenery.expectedExpr, expr)
assert.Equal(t, scenery.expectedArgs, args)
})
}
}
func buildLdapSearchRequest(filter string) (*ber.Packet, error) {
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 1, "MessageID"))
pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, goldap.ApplicationSearchRequest, nil, "Search Request")
pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "Base DN"))
pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, 0, "Scope"))
pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, 0, "Deref Aliases"))
pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 0, "Size Limit"))
pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 0, "Time Limit"))
pkt.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, false, "Types Only"))
// compile and encode filter
filterPacket, err := goldap.CompileFilter(filter)
if err != nil {
return nil, err
}
pkt.AppendChild(filterPacket)
// encode attributes
attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "*", "Attribute"))
pkt.AppendChild(attributesPacket)
packet.AppendChild(pkt)
return packet, nil
}

View File

@@ -1,5 +1,5 @@
apiVersion: v2
name: casdoor
name: casdoor-helm-charts
description: A Helm chart for Kubernetes
# A chart can be either an 'application' or a 'library' chart.
@@ -15,10 +15,10 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
version: 0.3.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"
appVersion: "1.18.0"

View File

@@ -59,6 +59,9 @@ spec:
volumeMounts:
- name: config-volume
mountPath: /conf
{{ if .Values.extraContainersEnabled }}
{{- .Values.extraContainers | nindent 8 }}
{{- end }}
volumes:
- name: config-volume
projected:

View File

@@ -108,3 +108,10 @@ nodeSelector: {}
tolerations: []
affinity: {}
# -- Optionally add extra sidecar containers.
extraContainersEnabled: false
extraContainers: ""
# extraContainers: |
# - name: ...
# image: ...

View File

@@ -15,10 +15,11 @@
package notification
import (
"bytes"
"context"
"fmt"
"net/http"
"net/url"
"strings"
"github.com/casdoor/casdoor/proxy"
)
@@ -39,26 +40,29 @@ func NewCustomHttpProvider(endpoint string, method string, paramName string) (*H
}
func (c *HttpNotificationClient) Send(ctx context.Context, subject string, content string) error {
var req *http.Request
var err error
httpClient := proxy.DefaultHttpClient
req, err := http.NewRequest(c.method, c.endpoint, bytes.NewBufferString(content))
if err != nil {
return err
}
if c.method == "POST" {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.PostForm = map[string][]string{
c.paramName: {content},
formValues := url.Values{}
formValues.Set(c.paramName, content)
req, err = http.NewRequest(c.method, c.endpoint, strings.NewReader(formValues.Encode()))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
} else if c.method == "GET" {
req, err = http.NewRequest(c.method, c.endpoint, nil)
if err != nil {
return err
}
q := req.URL.Query()
q.Add(c.paramName, content)
req.URL.RawQuery = q.Encode()
}
httpClient := proxy.DefaultHttpClient
resp, err := httpClient.Do(req)
if err != nil {
return err
@@ -66,7 +70,7 @@ func (c *HttpNotificationClient) Send(ctx context.Context, subject string, conte
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("SendMessage() error, custom HTTP Notification request failed with status: %s", resp.Status)
return fmt.Errorf("HttpNotificationClient's SendMessage() error, custom HTTP Notification request failed with status: %s", resp.Status)
}
return err

View File

@@ -90,6 +90,9 @@ type Application struct {
FormOffset int `json:"formOffset"`
FormSideHtml string `xorm:"mediumtext" json:"formSideHtml"`
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
FailedSigninLimit int `json:"failedSigninLimit"`
FailedSigninfrozenTime int `json:"failedSigninfrozenTime"`
}
func GetApplicationCount(owner, field, value string) (int64, error) {

View File

@@ -28,8 +28,9 @@ import (
)
const (
SigninWrongTimesLimit = 5
LastSignWrongTimeDuration = time.Minute * 15
DefaultFailedSigninLimit = 5
// DefaultFailedSigninfrozenTime The unit of frozen time is minutes
DefaultFailedSigninfrozenTime = 15
)
func CheckUserSignup(application *Application, organization *Organization, form *form.AuthForm, lang string) string {
@@ -143,10 +144,15 @@ func CheckUserSignup(application *Application, organization *Organization, form
}
func checkSigninErrorTimes(user *User, lang string) error {
if user.SigninWrongTimes >= SigninWrongTimesLimit {
failedSigninLimit, failedSigninfrozenTime, err := GetFailedSigninConfigByUser(user)
if err != nil {
return err
}
if user.SigninWrongTimes >= failedSigninLimit {
lastSignWrongTime, _ := time.Parse(time.RFC3339, user.LastSigninWrongTime)
passedTime := time.Now().UTC().Sub(lastSignWrongTime)
minutes := int(LastSignWrongTimeDuration.Minutes() - passedTime.Minutes())
minutes := failedSigninfrozenTime - int(passedTime.Minutes())
// deny the login if the error times is greater than the limit and the last login time is less than the duration
if minutes > 0 {
@@ -237,22 +243,28 @@ func checkLdapUserPassword(user *User, password string, lang string) error {
searchResult, err := conn.Conn.Search(searchReq)
if err != nil {
conn.Close()
return err
}
if len(searchResult.Entries) == 0 {
conn.Close()
continue
}
if len(searchResult.Entries) > 1 {
conn.Close()
return fmt.Errorf(i18n.Translate(lang, "check:Multiple accounts with same uid, please check your ldap server"))
}
hit = true
dn := searchResult.Entries[0].DN
if err := conn.Conn.Bind(dn, password); err == nil {
if err = conn.Conn.Bind(dn, password); err == nil {
ldapLoginSuccess = true
conn.Close()
break
}
conn.Close()
}
if !ldapLoginSuccess {
@@ -368,7 +380,7 @@ func CheckLoginPermission(userId string, application *Application) (bool, error)
allowCount := 0
denyCount := 0
for _, permission := range permissions {
if !permission.IsEnabled || permission.ResourceType != "Application" || !permission.isResourceHit(application.Name) {
if !permission.IsEnabled || permission.State != "Approved" || permission.ResourceType != "Application" || !permission.isResourceHit(application.Name) {
continue
}
@@ -473,7 +485,14 @@ func CheckToEnableCaptcha(application *Application, organization, username strin
if err != nil {
return false, err
}
return user != nil && user.SigninWrongTimes >= SigninWrongTimesLimit, nil
var failedSigninLimit int
if application.FailedSigninLimit == 0 {
failedSigninLimit = 5
} else {
failedSigninLimit = application.FailedSigninLimit
}
return user != nil && user.SigninWrongTimes >= failedSigninLimit, nil
}
return providerItem.Rule == "Always", nil
}

View File

@@ -47,18 +47,42 @@ func resetUserSigninErrorTimes(user *User) error {
return err
}
func GetFailedSigninConfigByUser(user *User) (int, int, error) {
application, err := GetApplicationByUser(user)
if err != nil {
return 0, 0, err
}
failedSigninLimit := application.FailedSigninLimit
failedSigninfrozenTime := application.FailedSigninfrozenTime
// 0 as an initialization value, corresponding to the default configuration parameters
if failedSigninLimit == 0 {
failedSigninLimit = DefaultFailedSigninLimit
}
if failedSigninfrozenTime == 0 {
failedSigninfrozenTime = DefaultFailedSigninfrozenTime
}
return failedSigninLimit, failedSigninfrozenTime, nil
}
func recordSigninErrorInfo(user *User, lang string, options ...bool) error {
enableCaptcha := false
if len(options) > 0 {
enableCaptcha = options[0]
}
failedSigninLimit, failedSigninfrozenTime, errSignin := GetFailedSigninConfigByUser(user)
if errSignin != nil {
return errSignin
}
// increase failed login count
if user.SigninWrongTimes < SigninWrongTimesLimit {
if user.SigninWrongTimes < failedSigninLimit {
user.SigninWrongTimes++
}
if user.SigninWrongTimes >= SigninWrongTimesLimit {
if user.SigninWrongTimes >= failedSigninLimit {
// record the latest failed login time
user.LastSigninWrongTime = time.Now().UTC().Format(time.RFC3339)
}
@@ -69,7 +93,7 @@ func recordSigninErrorInfo(user *User, lang string, options ...bool) error {
return err
}
leftChances := SigninWrongTimesLimit - user.SigninWrongTimes
leftChances := failedSigninLimit - user.SigninWrongTimes
if leftChances == 0 && enableCaptcha {
return fmt.Errorf(i18n.Translate(lang, "check:password or code is incorrect"))
} else if leftChances >= 0 {
@@ -77,5 +101,5 @@ func recordSigninErrorInfo(user *User, lang string, options ...bool) error {
}
// don't show the chance error message if the user has no chance left
return fmt.Errorf(i18n.Translate(lang, "check:You have entered the wrong password or code too many times, please wait for %d minutes and try again"), int(LastSignWrongTimeDuration.Minutes()))
return fmt.Errorf(i18n.Translate(lang, "check:You have entered the wrong password or code too many times, please wait for %d minutes and try again"), failedSigninfrozenTime)
}

View File

@@ -36,7 +36,7 @@ func getDialer(provider *Provider) *gomail.Dialer {
}
func SendEmail(provider *Provider, title string, content string, dest string, sender string) error {
emailProvider := email.GetEmailProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, provider.Port, provider.DisableSsl)
emailProvider := email.GetEmailProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, provider.Port, provider.DisableSsl, provider.Endpoint, provider.Method)
fromAddress := provider.ClientId2
if fromAddress == "" {

View File

@@ -125,6 +125,10 @@ func (enforcer *Enforcer) GetId() string {
return fmt.Sprintf("%s/%s", enforcer.Owner, enforcer.Name)
}
func (enforcer *Enforcer) GetModelAndAdapter() string {
return util.GetId(enforcer.Model, enforcer.Adapter)
}
func (enforcer *Enforcer) InitEnforcer() error {
if enforcer.Enforcer != nil {
return nil

View File

@@ -271,7 +271,9 @@ func GetGroupUsers(groupId string) ([]*User, error) {
users := []*User{}
owner, _ := util.GetOwnerAndNameFromId(groupId)
names, err := userEnforcer.GetUserNamesByGroupName(groupId)
if err != nil {
return nil, err
}
err = ormer.Engine.Where("owner = ?", owner).In("name", names).Find(&users)
if err != nil {
return nil, err
@@ -303,6 +305,9 @@ func GroupChangeTrigger(oldName, newName string) error {
groups := []*Group{}
err = session.Where("parent_id = ?", oldName).Find(&groups)
if err != nil {
return err
}
for _, group := range groups {
group.ParentId = newName
_, err := session.ID(core.PK{group.Owner, group.Name}).Cols("parent_id").Update(group)

View File

@@ -396,15 +396,22 @@ func initBuiltInPermission() {
Name: "permission-built-in",
CreatedTime: util.GetCurrentTime(),
DisplayName: "Built-in Permission",
Description: "Built-in Permission",
Users: []string{"built-in/*"},
Groups: []string{},
Roles: []string{},
Domains: []string{},
Model: "model-built-in",
Adapter: "",
ResourceType: "Application",
Resources: []string{"app-built-in"},
Actions: []string{"Read", "Write", "Admin"},
Effect: "Allow",
IsEnabled: true,
Submitter: "admin",
Approver: "admin",
ApproveTime: util.GetCurrentTime(),
State: "Approved",
}
_, err = AddPermission(permission)
if err != nil {

View File

@@ -100,6 +100,7 @@ func (l *LdapAutoSynchronizer) syncRoutine(ldap *Ldap, stopChan chan struct{}) e
users, err := conn.GetLdapUsers(ldap)
if err != nil {
conn.Close()
logs.Warning(fmt.Sprintf("autoSync failed for %s, error %s", ldap.Id, err))
continue
}
@@ -111,6 +112,8 @@ func (l *LdapAutoSynchronizer) syncRoutine(ldap *Ldap, stopChan chan struct{}) e
} else {
logs.Info(fmt.Sprintf("ldap autosync success, %d new users, %d existing users", len(users)-len(existed), len(existed)))
}
conn.Close()
}
}

View File

@@ -81,6 +81,17 @@ func (ldap *Ldap) GetLdapConn() (c *LdapConn, err error) {
return &LdapConn{Conn: conn, IsAD: isAD}, nil
}
func (l *LdapConn) Close() {
if l.Conn == nil {
return
}
err := l.Conn.Unbind()
if err != nil {
panic(err)
}
}
func isMicrosoftAD(Conn *goldap.Conn) (bool, error) {
SearchFilter := "(objectClass=*)"
SearchAttributes := []string{"vendorname", "vendorversion", "isGlobalCatalogReady", "forestFunctionality"}

View File

@@ -120,7 +120,11 @@ func checkPermissionValid(permission *Permission) error {
return nil
}
groupingPolicies := getGroupingPolicies(permission)
groupingPolicies, err := getGroupingPolicies(permission)
if err != nil {
return err
}
if len(groupingPolicies) > 0 {
_, err = enforcer.AddGroupingPolicies(groupingPolicies)
if err != nil {
@@ -442,9 +446,8 @@ func GetMaskedPermissions(permissions []*Permission) []*Permission {
// as the policyFilter when the enforcer load policy).
func GroupPermissionsByModelAdapter(permissions []*Permission) map[string][]string {
m := make(map[string][]string)
for _, permission := range permissions {
key := permission.Model + permission.Adapter
key := permission.GetModelAndAdapter()
permissionIds, ok := m[key]
if !ok {
m[key] = []string{permission.GetId()}
@@ -460,6 +463,10 @@ func (p *Permission) GetId() string {
return util.GetId(p.Owner, p.Name)
}
func (p *Permission) GetModelAndAdapter() string {
return util.GetId(p.Model, p.Adapter)
}
func (p *Permission) isUserHit(name string) bool {
targetOrg, targetName := util.GetOwnerAndNameFromId(name)
for _, user := range p.Users {

View File

@@ -23,6 +23,7 @@ import (
"github.com/casbin/casbin/v2/log"
"github.com/casbin/casbin/v2/model"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
)
@@ -137,6 +138,16 @@ func getPolicies(permission *Permission) [][]string {
}
func getRolesInRole(roleId string, visited map[string]struct{}) ([]*Role, error) {
roleOwner, roleName := util.GetOwnerAndNameFromId(roleId)
if roleName == "*" {
roles, err := GetRoles(roleOwner)
if err != nil {
return []*Role{}, err
}
return roles, nil
}
role, err := GetRole(roleId)
if err != nil {
return []*Role{}, err
@@ -162,7 +173,7 @@ func getRolesInRole(roleId string, visited map[string]struct{}) ([]*Role, error)
return roles, nil
}
func getGroupingPolicies(permission *Permission) [][]string {
func getGroupingPolicies(permission *Permission) ([][]string, error) {
var groupingPolicies [][]string
domainExist := len(permission.Domains) > 0
@@ -170,12 +181,18 @@ func getGroupingPolicies(permission *Permission) [][]string {
for _, roleId := range permission.Roles {
visited := map[string]struct{}{}
if roleId == "*" {
roleId = util.GetId(permission.Owner, "*")
}
rolesInRole, err := getRolesInRole(roleId, visited)
if err != nil {
panic(err)
return nil, err
}
for _, role := range rolesInRole {
roleId := role.GetId()
roleId = role.GetId()
for _, subUser := range role.Users {
if domainExist {
for _, domain := range permission.Domains {
@@ -198,7 +215,7 @@ func getGroupingPolicies(permission *Permission) [][]string {
}
}
return groupingPolicies
return groupingPolicies, nil
}
func addPolicies(permission *Permission) error {
@@ -231,7 +248,10 @@ func addGroupingPolicies(permission *Permission) error {
return err
}
groupingPolicies := getGroupingPolicies(permission)
groupingPolicies, err := getGroupingPolicies(permission)
if err != nil {
return err
}
if len(groupingPolicies) > 0 {
_, err = enforcer.AddGroupingPolicies(groupingPolicies)
@@ -249,7 +269,10 @@ func removeGroupingPolicies(permission *Permission) error {
return err
}
groupingPolicies := getGroupingPolicies(permission)
groupingPolicies, err := getGroupingPolicies(permission)
if err != nil {
return err
}
if len(groupingPolicies) > 0 {
_, err = enforcer.RemoveGroupingPolicies(groupingPolicies)
@@ -287,7 +310,12 @@ func getAllValues(userId string, fn func(enforcer *casbin.Enforcer) []string) ([
return nil, err
}
for _, role := range GetAllRoles(userId) {
allRoles, err := GetAllRoles(userId)
if err != nil {
return nil, err
}
for _, role := range allRoles {
permissionsByRole, err := GetPermissionsByRole(role)
if err != nil {
return nil, err
@@ -321,17 +349,17 @@ func GetAllActions(userId string) ([]string, error) {
})
}
func GetAllRoles(userId string) []string {
func GetAllRoles(userId string) ([]string, error) {
roles, err := getRolesByUser(userId)
if err != nil {
panic(err)
return nil, err
}
var res []string
res := []string{}
for _, role := range roles {
res = append(res, role.Name)
}
return res
return res, nil
}
func GetBuiltInModel(modelText string) (model.Model, error) {

View File

@@ -37,7 +37,7 @@ type Provider struct {
SubType string `xorm:"varchar(100)" json:"subType"`
Method string `xorm:"varchar(100)" json:"method"`
ClientId string `xorm:"varchar(200)" json:"clientId"`
ClientSecret string `xorm:"varchar(2000)" json:"clientSecret"`
ClientSecret string `xorm:"varchar(3000)" json:"clientSecret"`
ClientId2 string `xorm:"varchar(100)" json:"clientId2"`
ClientSecret2 string `xorm:"varchar(500)" json:"clientSecret2"`
Cert string `xorm:"varchar(100)" json:"cert"`
@@ -417,7 +417,7 @@ func FromProviderToIdpInfo(ctx *context.Context, provider *Provider) *idp.Provid
providerInfo.ClientId = provider.ClientId2
providerInfo.ClientSecret = provider.ClientSecret2
}
} else if provider.Type == "AzureAD" || provider.Type == "ADFS" || provider.Type == "Okta" {
} else if provider.Type == "AzureAD" || provider.Type == "AzureADB2C" || provider.Type == "ADFS" || provider.Type == "Okta" {
providerInfo.HostUrl = provider.Domain
}

View File

@@ -9,7 +9,6 @@ import (
)
// https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/sec_usr_radatt/configuration/xe-16/sec-usr-radatt-xe-16-book/sec-rad-ov-ietf-attr.html
// https://support.huawei.com/enterprise/zh/doc/EDOC1000178159/35071f9a
type RadiusAccounting struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`

View File

@@ -271,6 +271,9 @@ func getRolesByUserInternal(userId string) ([]*Role, error) {
if err != nil {
return roles, err
}
if user == nil {
return nil, fmt.Errorf("The user: %s doesn't exist", userId)
}
query := ormer.Engine.Alias("r").Where("r.users like ?", fmt.Sprintf("%%%s%%", userId))
for _, group := range user.Groups {

View File

@@ -26,6 +26,8 @@ func getSmsClient(provider *Provider) (sender.SmsClient, error) {
if provider.Type == sender.HuaweiCloud || provider.Type == sender.AzureACS {
client, err = sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.ProviderUrl, provider.AppId)
} else if provider.Type == "Custom HTTP SMS" {
client, err = newHttpSmsClient(provider.Endpoint, provider.Method, provider.Title)
} else {
client, err = sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.AppId)
}

83
object/sms_custom_http.go Normal file
View File

@@ -0,0 +1,83 @@
// Copyright 2023 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/http"
"net/url"
"strings"
"github.com/casdoor/casdoor/proxy"
)
type HttpSmsClient struct {
endpoint string
method string
paramName string
}
func newHttpSmsClient(endpoint string, method string, paramName string) (*HttpSmsClient, error) {
client := &HttpSmsClient{
endpoint: endpoint,
method: method,
paramName: paramName,
}
return client, nil
}
func (c *HttpSmsClient) SendMessage(param map[string]string, targetPhoneNumber ...string) error {
phoneNumber := targetPhoneNumber[0]
content := param["code"]
var req *http.Request
var err error
if c.method == "POST" {
formValues := url.Values{}
formValues.Set("phoneNumber", phoneNumber)
formValues.Set(c.paramName, content)
req, err = http.NewRequest(c.method, c.endpoint, strings.NewReader(formValues.Encode()))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
} else if c.method == "GET" {
req, err = http.NewRequest(c.method, c.endpoint, nil)
if err != nil {
return err
}
q := req.URL.Query()
q.Add("phoneNumber", phoneNumber)
q.Add(c.paramName, content)
req.URL.RawQuery = q.Encode()
} else {
return fmt.Errorf("HttpSmsClient's SendMessage() error, unsupported method: %s", c.method)
}
httpClient := proxy.DefaultHttpClient
resp, err := httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("HttpSmsClient's SendMessage() error, custom HTTP SMS request failed with status: %s", resp.Status)
}
return err
}

View File

@@ -112,7 +112,10 @@ func getStorageProvider(provider *Provider, lang string) (oss.StorageInterface,
if provider.Domain == "" {
provider.Domain = storageProvider.GetEndpoint()
UpdateProvider(provider.GetId(), provider)
_, err := UpdateProvider(provider.GetId(), provider)
if err != nil {
return nil, err
}
}
return storageProvider, nil
@@ -126,7 +129,12 @@ func uploadFile(provider *Provider, fullFilePath string, fileBuffer *bytes.Buffe
fileUrl, objectKey := GetUploadFileUrl(provider, fullFilePath, true)
_, err = storageProvider.Put(objectKey, fileBuffer)
objectKeyRefined := objectKey
if provider.Type == "Google Cloud Storage" {
objectKeyRefined = strings.TrimPrefix(objectKeyRefined, "/")
}
_, err = storageProvider.Put(objectKeyRefined, fileBuffer)
if err != nil {
return "", "", err
}

View File

@@ -17,6 +17,7 @@ package object
import (
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"fmt"
"time"
@@ -51,15 +52,17 @@ type Token struct {
Organization string `xorm:"varchar(100)" json:"organization"`
User string `xorm:"varchar(100)" json:"user"`
Code string `xorm:"varchar(100) index" json:"code"`
AccessToken string `xorm:"mediumtext" json:"accessToken"`
RefreshToken string `xorm:"mediumtext" json:"refreshToken"`
ExpiresIn int `json:"expiresIn"`
Scope string `xorm:"varchar(100)" json:"scope"`
TokenType string `xorm:"varchar(100)" json:"tokenType"`
CodeChallenge string `xorm:"varchar(100)" json:"codeChallenge"`
CodeIsUsed bool `json:"codeIsUsed"`
CodeExpireIn int64 `json:"codeExpireIn"`
Code string `xorm:"varchar(100) index" json:"code"`
AccessToken string `xorm:"mediumtext" json:"accessToken"`
RefreshToken string `xorm:"mediumtext" json:"refreshToken"`
AccessTokenHash string `xorm:"varchar(100) index" json:"accessTokenHash"`
RefreshTokenHash string `xorm:"varchar(100) index" json:"refreshTokenHash"`
ExpiresIn int `json:"expiresIn"`
Scope string `xorm:"varchar(100)" json:"scope"`
TokenType string `xorm:"varchar(100)" json:"tokenType"`
CodeChallenge string `xorm:"varchar(100)" json:"codeChallenge"`
CodeIsUsed bool `json:"codeIsUsed"`
CodeExpireIn int64 `json:"codeExpireIn"`
}
type TokenWrapper struct {
@@ -141,6 +144,48 @@ func getTokenByCode(code string) (*Token, error) {
return nil, nil
}
func GetTokenByAccessToken(accessToken string) (*Token, error) {
token := Token{AccessTokenHash: getTokenHash(accessToken)}
existed, err := ormer.Engine.Get(&token)
if err != nil {
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
}
return &token, nil
}
func GetTokenByRefreshToken(refreshToken string) (*Token, error) {
token := Token{RefreshTokenHash: getTokenHash(refreshToken)}
existed, err := ormer.Engine.Get(&token)
if err != nil {
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
}
return &token, nil
}
func updateUsedByCode(token *Token) bool {
affected, err := ormer.Engine.Where("code=?", token.Code).Cols("code_is_used").Update(token)
if err != nil {
@@ -159,6 +204,24 @@ func (token *Token) GetId() string {
return fmt.Sprintf("%s/%s", token.Owner, token.Name)
}
func getTokenHash(input string) string {
hash := sha256.Sum256([]byte(input))
res := hex.EncodeToString(hash[:])
if len(res) > 64 {
return res[:64]
}
return res
}
func (token *Token) popularHashes() {
if token.AccessTokenHash == "" && token.AccessToken != "" {
token.AccessTokenHash = getTokenHash(token.AccessToken)
}
if token.RefreshTokenHash == "" && token.RefreshToken != "" {
token.RefreshTokenHash = getTokenHash(token.RefreshToken)
}
}
func UpdateToken(id string, token *Token) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
if t, err := getToken(owner, name); err != nil {
@@ -167,6 +230,8 @@ func UpdateToken(id string, token *Token) (bool, error) {
return false, nil
}
token.popularHashes()
affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(token)
if err != nil {
return false, err
@@ -176,6 +241,8 @@ func UpdateToken(id string, token *Token) (bool, error) {
}
func AddToken(token *Token) (bool, error) {
token.popularHashes()
affected, err := ormer.Engine.Insert(token)
if err != nil {
return false, err
@@ -194,18 +261,16 @@ func DeleteToken(token *Token) (bool, error) {
}
func ExpireTokenByAccessToken(accessToken string) (bool, *Application, *Token, error) {
token := Token{AccessToken: accessToken}
existed, err := ormer.Engine.Get(&token)
token, err := GetTokenByAccessToken(accessToken)
if err != nil {
return false, nil, nil, err
}
if !existed {
if token == nil {
return false, nil, nil, nil
}
token.ExpiresIn = 0
affected, err := ormer.Engine.ID(core.PK{token.Owner, token.Name}).Cols("expires_in").Update(&token)
affected, err := ormer.Engine.ID(core.PK{token.Owner, token.Name}).Cols("expires_in").Update(token)
if err != nil {
return false, nil, nil, err
}
@@ -215,22 +280,7 @@ func ExpireTokenByAccessToken(accessToken string) (bool, *Application, *Token, e
return false, nil, nil, err
}
return affected != 0, application, &token, nil
}
func GetTokenByAccessToken(accessToken string) (*Token, error) {
// Check if the accessToken is in the database
token := Token{AccessToken: accessToken}
existed, err := ormer.Engine.Get(&token)
if err != nil {
return nil, err
}
if !existed {
return nil, nil
}
return &token, nil
return affected != 0, application, token, nil
}
func GetTokenByTokenAndApplication(token string, application string) (*Token, error) {
@@ -432,16 +482,17 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
ErrorDescription: "client_id is invalid",
}, nil
}
if clientSecret != "" && application.ClientSecret != clientSecret {
return &TokenError{
Error: InvalidClient,
ErrorDescription: "client_secret is invalid",
}, nil
}
// check whether the refresh token is valid, and has not expired.
token := Token{RefreshToken: refreshToken}
existed, err := ormer.Engine.Get(&token)
if err != nil || !existed {
token, err := GetTokenByRefreshToken(refreshToken)
if err != nil || token == nil {
return &TokenError{
Error: InvalidGrant,
ErrorDescription: "refresh token is invalid, expired or revoked",
@@ -452,6 +503,12 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
if err != nil {
return nil, err
}
if cert == nil {
return &TokenError{
Error: InvalidGrant,
ErrorDescription: fmt.Sprintf("cert: %s cannot be found", application.Cert),
}, nil
}
_, err = ParseJwtToken(refreshToken, cert)
if err != nil {
@@ -460,6 +517,7 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
ErrorDescription: fmt.Sprintf("parse refresh token error: %s", err.Error()),
}, nil
}
// generate a new token
user, err := getUser(application.Organization, token.User)
if err != nil {
@@ -477,6 +535,7 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
if err != nil {
return nil, err
}
newAccessToken, newRefreshToken, tokenName, err := generateJwtToken(application, user, "", scope, host)
if err != nil {
return &TokenError{
@@ -504,7 +563,7 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
return nil, err
}
_, err = DeleteToken(&token)
_, err = DeleteToken(token)
if err != nil {
return nil, err
}
@@ -517,7 +576,6 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
ExpiresIn: newToken.ExpiresIn,
Scope: newToken.Scope,
}
return tokenWrapper, nil
}
@@ -729,13 +787,13 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
// GetTokenByUser
// Implicit flow
func GetTokenByUser(application *Application, user *User, scope string, host string) (*Token, error) {
func GetTokenByUser(application *Application, user *User, scope string, nonce string, host string) (*Token, error) {
err := ExtendUserWithRolesAndPermissions(user)
if err != nil {
return nil, err
}
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", scope, host)
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, nonce, scope, host)
if err != nil {
return nil, err
}

View File

@@ -22,6 +22,7 @@ import (
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util"
"github.com/go-webauthn/webauthn/webauthn"
"github.com/xorm-io/builder"
"github.com/xorm-io/core"
)
@@ -116,6 +117,7 @@ type User struct {
Infoflow string `xorm:"infoflow varchar(100)" json:"infoflow"`
Apple string `xorm:"apple varchar(100)" json:"apple"`
AzureAD string `xorm:"azuread varchar(100)" json:"azuread"`
AzureADB2c string `xorm:"azureadb2c varchar(100)" json:"azureadb2c"`
Slack string `xorm:"slack varchar(100)" json:"slack"`
Steam string `xorm:"steam varchar(100)" json:"steam"`
Bilibili string `xorm:"bilibili varchar(100)" json:"bilibili"`
@@ -231,6 +233,20 @@ func GetGlobalUsers() ([]*User, error) {
return users, nil
}
func GetGlobalUsersWithFilter(cond builder.Cond) ([]*User, error) {
users := []*User{}
session := ormer.Engine.Desc("created_time")
if cond != nil {
session = session.Where(cond)
}
err := session.Find(&users)
if err != nil {
return nil, err
}
return users, nil
}
func GetPaginationGlobalUsers(offset, limit int, field, value, sortField, sortOrder string) ([]*User, error) {
users := []*User{}
session := GetSessionForUser("", offset, limit, field, value, sortField, sortOrder)
@@ -266,9 +282,27 @@ func GetUsers(owner string) ([]*User, error) {
return users, nil
}
func GetUsersByTag(owner string, tag string) ([]*User, error) {
func GetUsersWithFilter(owner string, cond builder.Cond) ([]*User, error) {
users := []*User{}
err := ormer.Engine.Desc("created_time").Find(&users, &User{Owner: owner, Tag: tag})
session := ormer.Engine.Desc("created_time")
if cond != nil {
session = session.Where(cond)
}
err := session.Find(&users, &User{Owner: owner})
if err != nil {
return nil, err
}
return users, nil
}
func GetUsersByTagWithFilter(owner string, tag string, cond builder.Cond) ([]*User, error) {
users := []*User{}
session := ormer.Engine.Desc("created_time")
if cond != nil {
session = session.Where(cond)
}
err := session.Find(&users, &User{Owner: owner, Tag: tag})
if err != nil {
return nil, err
}
@@ -589,7 +623,7 @@ func UpdateUser(id string, user *User, columns []string, isAdmin bool) (bool, er
"is_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
"signin_wrong_times", "last_signin_wrong_time", "groups", "access_key", "access_secret",
"github", "google", "qq", "wechat", "facebook", "dingtalk", "weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs",
"baidu", "alipay", "casdoor", "infoflow", "apple", "azuread", "slack", "steam", "bilibili", "okta", "douyin", "line", "amazon",
"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",
@@ -988,7 +1022,10 @@ func GenerateIdForNewUser(application *Application) (string, error) {
lastUserId := -1
if lastUser != nil {
lastUserId = util.ParseInt(lastUser.Id)
lastUserId, err = util.ParseIntWithError(lastUser.Id)
if err != nil {
return util.GenerateId(), nil
}
}
res := strconv.Itoa(lastUserId + 1)

View File

@@ -240,11 +240,11 @@ func getFaviconFileBuffer(client *http.Client, email string) (*bytes.Buffer, str
if buffer != nil {
faviconUrl, err = GetFaviconUrl(buffer.String())
if err != nil {
return nil, "", err
}
if !strings.HasPrefix(faviconUrl, "http") {
faviconUrl = util.UrlJoin(htmlUrl, faviconUrl)
fmt.Printf("getFaviconFileBuffer() error, faviconUrl is empty, error = %s\n", err.Error())
} else {
if !strings.HasPrefix(faviconUrl, "http") {
faviconUrl = util.UrlJoin(htmlUrl, faviconUrl)
}
}
}

View File

@@ -132,6 +132,9 @@ func (pp *StripePaymentProvider) Notify(body []byte, orderId string) (*NotifyRes
}
// Once payment is successful, the Checkout Session will contain a reference to the successful `PaymentIntent`
sIntent, err := stripeIntent.Get(sCheckout.PaymentIntent.ID, nil)
if err != nil {
return nil, err
}
var (
productName string
productDisplayName string

View File

@@ -17,15 +17,16 @@ package radius
import (
"fmt"
"log"
"strings"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
"layeh.com/radius"
"layeh.com/radius/rfc2865"
"layeh.com/radius/rfc2866"
)
// https://support.huawei.com/enterprise/zh/doc/EDOC1000178159/35071f9a#tab_3
func StartRadiusServer() {
secret := conf.GetConfigString("radiusSecret")
server := radius.PacketServer{
@@ -74,6 +75,11 @@ func handleAccountingRequest(w radius.ResponseWriter, r *radius.Request) {
statusType := rfc2866.AcctStatusType_Get(r.Packet)
username := rfc2865.UserName_GetString(r.Packet)
organization := rfc2865.Class_GetString(r.Packet)
if strings.Contains(username, "/") {
organization, username = util.GetOwnerAndNameFromId(username)
}
log.Printf("handleAccountingRequest() username=%v, org=%v, statusType=%v", username, organization, statusType)
w.Write(r.Response(radius.CodeAccountingResponse))
var err error

View File

@@ -129,7 +129,7 @@ func StaticFilter(ctx *context.Context) {
path += urlPath
}
if !util.FileExist(path) {
if strings.Contains(path, "/../") || !util.FileExist(path) {
path = webBuildFolder + "/index.html"
}
if !util.FileExist(path) {

View File

@@ -22,12 +22,13 @@ import (
func NewAwsS3StorageProvider(clientId string, clientSecret string, region string, bucket string, endpoint string) oss.StorageInterface {
sp := s3.New(&s3.Config{
AccessID: clientId,
AccessKey: clientSecret,
Region: region,
Bucket: bucket,
Endpoint: endpoint,
ACL: awss3.BucketCannedACLPublicRead,
AccessID: clientId,
AccessKey: clientSecret,
Region: region,
Bucket: bucket,
Endpoint: endpoint,
S3Endpoint: endpoint,
ACL: awss3.BucketCannedACLPublicRead,
})
return sp

View File

@@ -19,13 +19,15 @@ import (
"github.com/casdoor/oss/googlecloud"
)
func NewGoogleCloudStorageProvider(clientId string, clientSecret string, bucket string, endpoint string) oss.StorageInterface {
sp, _ := googlecloud.New(&googlecloud.Config{
AccessID: clientId,
AccessKey: clientSecret,
Bucket: bucket,
Endpoint: endpoint,
func NewGoogleCloudStorageProvider(clientSecret string, bucket string, endpoint string) oss.StorageInterface {
sp, err := googlecloud.New(&googlecloud.Config{
ServiceAccountJson: clientSecret,
Bucket: bucket,
Endpoint: endpoint,
})
if err != nil {
panic(err)
}
return sp
}

View File

@@ -33,7 +33,7 @@ func GetStorageProvider(providerType string, clientId string, clientSecret strin
case "Qiniu Cloud Kodo":
return NewQiniuCloudKodoStorageProvider(clientId, clientSecret, region, bucket, endpoint)
case "Google Cloud Storage":
return NewGoogleCloudStorageProvider(clientId, clientSecret, bucket, endpoint)
return NewGoogleCloudStorageProvider(clientSecret, bucket, endpoint)
}
return nil

View File

@@ -45,6 +45,19 @@ func ParseInt(s string) int {
return i
}
func ParseIntWithError(s string) (int, error) {
if s == "" {
return 0, fmt.Errorf("ParseIntWithError() error, empty string")
}
i, err := strconv.Atoi(s)
if err != nil {
return 0, err
}
return i, nil
}
func ParseFloat(s string) float64 {
f, err := strconv.ParseFloat(s, 64)
if err != nil {

View File

@@ -13,7 +13,7 @@
// limitations under the License.
import React from "react";
import {Button, Card, Col, ConfigProvider, Input, List, Popover, Radio, Result, Row, Select, Space, Switch, Upload} from "antd";
import {Button, Card, Col, ConfigProvider, Input, InputNumber, List, Popover, Radio, Result, Row, Select, Space, Switch, Upload} from "antd";
import {CopyOutlined, LinkOutlined, UploadOutlined} from "@ant-design/icons";
import * as ApplicationBackend from "./backend/ApplicationBackend";
import * as CertBackend from "./backend/CertBackend";
@@ -199,7 +199,7 @@ class ApplicationEditPage extends React.Component {
}
parseApplicationField(key, value) {
if (["expireInHours", "refreshExpireInHours", "offset"].includes(key)) {
if (["offset"].includes(key)) {
value = Setting.myParseInt(value);
}
return value;
@@ -394,8 +394,8 @@ class ApplicationEditPage extends React.Component {
{Setting.getLabel(i18next.t("application:Token expire"), i18next.t("application:Token expire - Tooltip"))} :
</Col>
<Col span={22} >
<Input style={{width: "150px"}} value={this.state.application.expireInHours} suffix="Hours" onChange={e => {
this.updateApplicationField("expireInHours", e.target.value);
<InputNumber style={{width: "150px"}} value={this.state.application.expireInHours} min={1} step={1} precision={0} addonAfter="Hours" onChange={value => {
this.updateApplicationField("expireInHours", value);
}} />
</Col>
</Row>
@@ -404,8 +404,28 @@ class ApplicationEditPage extends React.Component {
{Setting.getLabel(i18next.t("application:Refresh token expire"), i18next.t("application:Refresh token expire - Tooltip"))} :
</Col>
<Col span={22} >
<Input style={{width: "150px"}} value={this.state.application.refreshExpireInHours} suffix="Hours" onChange={e => {
this.updateApplicationField("refreshExpireInHours", e.target.value);
<InputNumber style={{width: "150px"}} value={this.state.application.refreshExpireInHours} min={1} step={1} precision={0} addonAfter="Hours" onChange={value => {
this.updateApplicationField("refreshExpireInHours", value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("application:Failed signin limit"), i18next.t("application:Failed signin limit - Tooltip"))} :
</Col>
<Col span={22} >
<InputNumber style={{width: "150px"}} value={this.state.application.failedSigninLimit} min={1} step={1} precision={0} addonAfter="Times" onChange={value => {
this.updateApplicationField("failedSigninLimit", value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("application:Failed signin frozen time"), i18next.t("application:Failed signin frozen time - Tooltip"))} :
</Col>
<Col span={22} >
<InputNumber style={{width: "150px"}} value={this.state.application.failedSigninfrozenTime} min={1} step={1} precision={0} addonAfter="Minutes" onChange={value => {
this.updateApplicationField("failedSigninfrozenTime", value);
}} />
</Col>
</Row>

View File

@@ -303,7 +303,7 @@ class PermissionEditPage extends React.Component {
{Setting.getLabel(i18next.t("role:Sub roles"), i18next.t("role:Sub roles - Tooltip"))} :
</Col>
<Col span={22} >
<Select disabled={!this.hasRoleDefinition(this.state.model)} virtual={false} mode="multiple" style={{width: "100%"}} value={this.state.permission.roles}
<Select disabled={!this.hasRoleDefinition(this.state.model)} placeholder={this.hasRoleDefinition(this.state.model) ? "" : "This field is disabled because the model is empty or it doesn't support RBAC (in another word, doesn't contain [role_definition])"} virtual={false} mode="multiple" style={{width: "100%"}} value={this.state.permission.roles}
onChange={(value => {this.updatePermissionField("roles", value);})}
options={[
Setting.getOption(i18next.t("organization:All"), "*"),
@@ -323,7 +323,7 @@ class PermissionEditPage extends React.Component {
})}
options={[
Setting.getOption(i18next.t("organization:All"), "*"),
...this.state.permission.domains.map((domain) => Setting.getOption(domain, domain)),
...this.state.permission.domains.filter(domain => domain !== "*").map((domain) => Setting.getOption(domain, domain)),
]}
/>
</Col>

View File

@@ -44,7 +44,7 @@ class PermissionListPage extends BaseListPage {
submitter: this.props.account.name,
approver: "",
approveTime: "",
state: "Pending",
state: Setting.isLocalAdminUser(this.props.account) ? "Approved" : "Pending",
};
}

View File

@@ -197,6 +197,12 @@ class ProviderEditPage extends React.Component {
} else {
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip"));
}
case "Storage":
if (provider.type === "Google Cloud Storage") {
return Setting.getLabel(i18next.t("provider:Service account JSON"), i18next.t("provider:Service account JSON - Tooltip"));
} else {
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip"));
}
case "Email":
if (provider.type === "Azure ACS") {
return Setting.getLabel(i18next.t("provider:Secret key"), i18next.t("provider:Secret key - Tooltip"));
@@ -305,6 +311,9 @@ class ProviderEditPage extends React.Component {
} else if (provider.type === "Infoflow") {
text = i18next.t("provider:Agent ID");
tooltip = i18next.t("provider:Agent ID - Tooltip");
} else if (provider.type === "AzureADB2C") {
text = i18next.t("provider:User flow");
tooltip = i18next.t("provider:User flow - Tooltip");
}
} else if (provider.category === "SMS") {
if (provider.type === "Twilio SMS" || provider.type === "Azure ACS") {
@@ -521,6 +530,13 @@ class ProviderEditPage extends React.Component {
this.updateProviderField("scopes", "openid profile email");
this.updateProviderField("customTokenUrl", "https://door.casdoor.com/api/login/oauth/access_token");
this.updateProviderField("customUserInfoUrl", "https://door.casdoor.com/api/userinfo");
} else if (value === "Custom HTTP SMS") {
this.updateProviderField("endpoint", "https://example.com/send-custom-http-sms");
this.updateProviderField("method", "GET");
this.updateProviderField("title", "code");
} else if (value === "Custom HTTP Email") {
this.updateProviderField("endpoint", "https://example.com/send-custom-http-email");
this.updateProviderField("method", "POST");
} else if (value === "Custom HTTP") {
this.updateProviderField("method", "GET");
this.updateProviderField("title", "");
@@ -668,9 +684,11 @@ class ProviderEditPage extends React.Component {
(this.state.provider.category === "Captcha" && this.state.provider.type === "Default") ||
(this.state.provider.category === "Web3") ||
(this.state.provider.category === "Storage" && this.state.provider.type === "Local File System") ||
(this.state.provider.category === "SMS" && this.state.provider.type === "Custom HTTP SMS") ||
(this.state.provider.category === "Notification" && (this.state.provider.type === "Google Chat" || this.state.provider.type === "Custom HTTP")) ? null : (
<React.Fragment>
{
(this.state.provider.category === "Storage" && this.state.provider.type === "Google Cloud Storage") ||
(this.state.provider.category === "Email" && this.state.provider.type === "Azure ACS") ||
(this.state.provider.category === "Notification" && (this.state.provider.type === "Line" || this.state.provider.type === "Telegram" || this.state.provider.type === "Bark" || this.state.provider.type === "Discord" || this.state.provider.type === "Slack" || this.state.provider.type === "Pushbullet" || this.state.provider.type === "Pushover" || this.state.provider.type === "Lark" || this.state.provider.type === "Microsoft Teams")) ? null : (
<Row style={{marginTop: "20px"}} >
@@ -743,7 +761,7 @@ class ProviderEditPage extends React.Component {
)
}
{
this.state.provider.type !== "ADFS" && this.state.provider.type !== "AzureAD" && this.state.provider.type !== "Casdoor" && this.state.provider.type !== "Okta" ? null : (
this.state.provider.type !== "ADFS" && this.state.provider.type !== "AzureAD" && this.state.provider.type !== "AzureADB2C" && this.state.provider.type !== "Casdoor" && this.state.provider.type !== "Okta" ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} :
@@ -756,7 +774,7 @@ class ProviderEditPage extends React.Component {
</Row>
)
}
{this.state.provider.category === "Storage" ? (
{this.state.provider.category === "Storage" || ["Custom HTTP SMS", "Custom HTTP Email"].includes(this.state.provider.type) ? (
<div>
{["Local File System"].includes(this.state.provider.type) ? null : (
<Row style={{marginTop: "20px"}} >
@@ -770,7 +788,7 @@ class ProviderEditPage extends React.Component {
</Col>
</Row>
)}
{["Local File System", "MinIO", "Tencent Cloud COS", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : (
{["Custom HTTP SMS", "Local File System", "MinIO", "Tencent Cloud COS", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("provider:Endpoint (Intranet)"), i18next.t("provider:Region endpoint for Intranet"))} :
@@ -782,7 +800,7 @@ class ProviderEditPage extends React.Component {
</Col>
</Row>
)}
{["Local File System"].includes(this.state.provider.type) ? null : (
{["Custom HTTP SMS", "Local File System"].includes(this.state.provider.type) ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("provider:Bucket"), i18next.t("provider:Bucket - Tooltip"))} :
@@ -794,17 +812,19 @@ class ProviderEditPage extends React.Component {
</Col>
</Row>
)}
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("provider:Path prefix"), i18next.t("provider:Path prefix - Tooltip"))} :
</Col>
<Col span={22} >
<Input value={this.state.provider.pathPrefix} onChange={e => {
this.updateProviderField("pathPrefix", e.target.value);
}} />
</Col>
</Row>
{["MinIO", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : (
{["Custom HTTP SMS"].includes(this.state.provider.type) ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("provider:Path prefix"), i18next.t("provider:Path prefix - Tooltip"))} :
</Col>
<Col span={22} >
<Input value={this.state.provider.pathPrefix} onChange={e => {
this.updateProviderField("pathPrefix", e.target.value);
}} />
</Col>
</Row>
)}
{["Custom HTTP SMS", "MinIO", "Google Cloud Storage", "Qiniu Cloud Kodo"].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"))} :
@@ -974,7 +994,7 @@ class ProviderEditPage extends React.Component {
</React.Fragment>
) : this.state.provider.category === "SMS" ? (
<React.Fragment>
{["Twilio SMS", "Amazon SNS", "Azure ACS", "Msg91 SMS", "Infobip SMS"].includes(this.state.provider.type) ?
{["Custom HTTP SMS", "Twilio SMS", "Amazon SNS", "Azure ACS", "Msg91 SMS", "Infobip SMS"].includes(this.state.provider.type) ?
null :
(<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
@@ -988,7 +1008,7 @@ class ProviderEditPage extends React.Component {
</Row>
)
}
{["Infobip SMS"].includes(this.state.provider.type) ?
{["Custom HTTP SMS", "Infobip SMS"].includes(this.state.provider.type) ?
null :
(<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
@@ -1002,6 +1022,39 @@ class ProviderEditPage extends React.Component {
</Row>
)
}
{
!["Custom HTTP SMS", "Custom HTTP Email"].includes(this.state.provider.type) ? null : (
<React.Fragment>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("general:Method"), i18next.t("provider:Method - Tooltip"))} :
</Col>
<Col span={22} >
<Select virtual={false} style={{width: "100%"}} value={this.state.provider.method} onChange={value => {
this.updateProviderField("method", value);
}}>
{
[
{id: "GET", name: "GET"},
{id: "POST", name: "POST"},
].map((method, index) => <Option key={index} value={method.id}>{method.name}</Option>)
}
</Select>
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Parameter"), i18next.t("provider:Parameter - Tooltip"))} :
</Col>
<Col span={22} >
<Input value={this.state.provider.title} onChange={e => {
this.updateProviderField("title", e.target.value);
}} />
</Col>
</Row>
</React.Fragment>
)
}
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:SMS Test"), i18next.t("provider:SMS Test - Tooltip"))} :
@@ -1026,7 +1079,7 @@ class ProviderEditPage extends React.Component {
</Col>
<Col span={2} >
<Button style={{marginLeft: "10px", marginBottom: "5px"}} type="primary"
disabled={!Setting.isValidPhone(this.state.provider.receiver)}
disabled={!Setting.isValidPhone(this.state.provider.receiver) && (this.state.provider.type !== "Custom HTTP SMS" || this.state.provider.endpoint === "")}
onClick={() => ProviderEditTestSms.sendTestSms(this.state.provider, "+" + Setting.getCountryCode(this.state.provider.content) + this.state.provider.receiver)} >
{i18next.t("provider:Send Testing SMS")}
</Button>
@@ -1155,7 +1208,7 @@ class ProviderEditPage extends React.Component {
(this.state.provider.type === "Alipay") ? (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Root Cert"), i18next.t("general:Root Cert - Tooltip"))} :
{Setting.getLabel(i18next.t("general:Root cert"), i18next.t("general:Root cert - Tooltip"))} :
</Col>
<Col span={22} >
<Select virtual={false} style={{width: "100%"}} value={this.state.provider.metadata} onChange={(value => {this.updateProviderField("metadata", value);})}>

View File

@@ -143,6 +143,10 @@ export const OtherProviderInfo = {
logo: `${StaticBaseUrl}/img/social_msg91.ico`,
url: "https://control.msg91.com/app/",
},
"Custom HTTP SMS": {
logo: `${StaticBaseUrl}/img/social_default.png`,
url: "https://casdoor.org/docs/provider/sms/overview",
},
"Mock SMS": {
logo: `${StaticBaseUrl}/img/social_default.png`,
url: "",
@@ -165,6 +169,10 @@ export const OtherProviderInfo = {
logo: `${StaticBaseUrl}/img/social_azure.png`,
url: "https://learn.microsoft.com/zh-cn/azure/communication-services",
},
"Custom HTTP Email": {
logo: `${StaticBaseUrl}/img/social_default.png`,
url: "https://casdoor.org/docs/provider/email/overview",
},
},
Storage: {
"Local File System": {
@@ -916,7 +924,8 @@ export function getProviderTypeOptions(category) {
{id: "Casdoor", name: "Casdoor"},
{id: "Infoflow", name: "Infoflow"},
{id: "Apple", name: "Apple"},
{id: "AzureAD", name: "AzureAD"},
{id: "AzureAD", name: "Azure AD"},
{id: "AzureADB2C", name: "Azure AD B2C"},
{id: "Slack", name: "Slack"},
{id: "Steam", name: "Steam"},
{id: "Bilibili", name: "Bilibili"},
@@ -981,6 +990,7 @@ export function getProviderTypeOptions(category) {
{id: "SUBMAIL", name: "SUBMAIL"},
{id: "Mailtrap", name: "Mailtrap"},
{id: "Azure ACS", name: "Azure ACS"},
{id: "Custom HTTP Email", name: "Custom HTTP Email"},
]
);
} else if (category === "SMS") {
@@ -989,6 +999,8 @@ export function getProviderTypeOptions(category) {
{id: "Aliyun SMS", name: "Alibaba Cloud SMS"},
{id: "Amazon SNS", name: "Amazon SNS"},
{id: "Azure ACS", name: "Azure ACS"},
{id: "Custom HTTP SMS", name: "Custom HTTP SMS"},
{id: "Mock SMS", name: "Mock SMS"},
{id: "Infobip SMS", name: "Infobip SMS"},
{id: "Tencent Cloud SMS", name: "Tencent Cloud SMS"},
{id: "Baidu Cloud SMS", name: "Baidu Cloud SMS"},

View File

@@ -280,12 +280,12 @@ class SubscriptionEditPage extends React.Component {
this.updateSubscriptionField("state", value);
})}
options={[
{value: "Pending", name: i18next.t("permission:Pending")},
{value: "Active", name: i18next.t("permission:Active")},
{value: "Upcoming", name: i18next.t("permission:Upcoming")},
{value: "Expired", name: i18next.t("permission:Expired")},
{value: "Error", name: i18next.t("permission:Error")},
{value: "Suspended", name: i18next.t("permission:Suspended")},
{value: "Pending", name: i18next.t("subscription:Pending")},
{value: "Active", name: i18next.t("subscription:Active")},
{value: "Upcoming", name: i18next.t("subscription:Upcoming")},
{value: "Expired", name: i18next.t("subscription:Expired")},
{value: "Error", name: i18next.t("subscription:Error")},
{value: "Suspended", name: i18next.t("subscription:Suspended")},
].map((item) => Setting.getOption(item.name, item.value))}
/>
</Col>

View File

@@ -201,17 +201,17 @@ class SubscriptionListPage extends BaseListPage {
render: (text, record, index) => {
switch (text) {
case "Pending":
return Setting.getTag("processing", i18next.t("permission:Pending"), <ExclamationCircleOutlined />);
return Setting.getTag("processing", i18next.t("subscription:Pending"), <ExclamationCircleOutlined />);
case "Active":
return Setting.getTag("success", i18next.t("permission:Active"), <SyncOutlined spin />);
return Setting.getTag("success", i18next.t("subscription:Active"), <SyncOutlined spin />);
case "Upcoming":
return Setting.getTag("warning", i18next.t("permission:Upcoming"), <ClockCircleOutlined />);
return Setting.getTag("warning", i18next.t("subscription:Upcoming"), <ClockCircleOutlined />);
case "Expired":
return Setting.getTag("warning", i18next.t("permission:Expired"), <ClockCircleOutlined />);
return Setting.getTag("warning", i18next.t("subscription:Expired"), <ClockCircleOutlined />);
case "Error":
return Setting.getTag("error", i18next.t("permission:Error"), <CloseCircleOutlined />);
return Setting.getTag("error", i18next.t("subscription:Error"), <CloseCircleOutlined />);
case "Suspended":
return Setting.getTag("default", i18next.t("permission:Suspended"), <MinusCircleOutlined />);
return Setting.getTag("default", i18next.t("subscription:Suspended"), <MinusCircleOutlined />);
default:
return null;
}

View File

@@ -374,12 +374,9 @@ class UserEditPage extends React.Component {
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Avatar"), i18next.t("general:Avatar - Tooltip"))} :
</Col>
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("general:Preview")}:
</Col>
<Col>
{this.renderImage(this.state.user.avatar, i18next.t("user:Upload a photo"), i18next.t("user:Set new profile picture"), "avatar", false)}
</Col>
{
this.renderImage(this.state.user.avatar, i18next.t("user:Upload a photo"), i18next.t("user:Set new profile picture"), "avatar", false)
}
</Row>
);
} else if (accountItem.name === "User type") {
@@ -550,9 +547,6 @@ class UserEditPage extends React.Component {
</Col>
<Col span={22} >
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("general:Preview")}:
</Col>
{
[
{name: "ID card front", value: "idCardFront"},
@@ -975,7 +969,7 @@ class UserEditPage extends React.Component {
renderImage(imgUrl, title, set, tag, disabled) {
return (
<Col span={4} style={{textAlign: "center", margin: "auto"}} key={tag}>
<Col span={4} style={{textAlign: "center", margin: "auto", marginLeft: "20px"}} key={tag}>
{
imgUrl ?
<div style={{marginBottom: "10px"}}>
@@ -986,7 +980,7 @@ class UserEditPage extends React.Component {
:
<Col style={{height: "78%", border: "1px dotted grey", borderRadius: 3, marginBottom: "10px"}}>
<div style={{fontSize: 30, margin: 10}}>+</div>
<div style={{verticalAlign: "middle", marginBottom: 10}}>{`Upload ${title}...`}</div>
<div style={{verticalAlign: "middle", marginBottom: 10}}>{`(${i18next.t("general:empty")})`}</div>
</Col>
}
<CropperDivModal disabled={disabled} tag={tag} setTitle={set} buttonText={`${title}...`} title={title} user={this.state.user} organization={this.state.organizations.find(organization => organization.name === this.state.organizationName)} />

View File

@@ -325,6 +325,10 @@ class UserListPage extends BaseListPage {
sorter: true,
...this.getColumnSearchProps("tag"),
render: (text, record, index) => {
if (this.state.organization?.tags?.length === 0) {
return text;
}
const tagMap = {};
this.state.organization?.tags?.map((tag, index) => {
const tokens = tag.split("|");

View File

@@ -0,0 +1,32 @@
// Copyright 2023 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 {createButton} from "react-social-login-buttons";
import {StaticBaseUrl} from "../Setting";
function Icon({width = 24, height = 24, color}) {
return <img src={`${StaticBaseUrl}/buttons/azuread.svg`} alt="Sign in with Azure AD B2C" style={{width: 24, height: 24}} />;
}
const config = {
text: "Sign in with Azure AD B2C",
icon: Icon,
iconFormat: name => `fa fa-${name}`,
style: {background: "#ffffff", color: "#000000"},
activeStyle: {background: "#ededee"},
};
const AzureADB2CLoginButton = createButton(config);
export default AzureADB2CLoginButton;

View File

@@ -16,11 +16,11 @@ import {createButton} from "react-social-login-buttons";
import {StaticBaseUrl} from "../Setting";
function Icon({width = 24, height = 24, color}) {
return <img src={`${StaticBaseUrl}/buttons/azuread.svg`} alt="Sign in with AzureAD" style={{width: 24, height: 24}} />;
return <img src={`${StaticBaseUrl}/buttons/azuread.svg`} alt="Sign in with Azure AD" style={{width: 24, height: 24}} />;
}
const config = {
text: "Sign in with AzureAD",
text: "Sign in with Azure AD",
icon: Icon,
iconFormat: name => `fa fa-${name}`,
style: {background: "#ffffff", color: "#000000"},

View File

@@ -337,7 +337,7 @@ class LoginPage extends React.Component {
const casParams = Util.getCasParameters();
values["type"] = this.state.type;
AuthBackend.loginCas(values, casParams).then((res) => {
if (res.status === "ok") {
const loginHandler = (res) => {
let msg = "Logged in successfully. ";
if (casParams.service === "") {
// If service was not specified, Casdoor must display a message notifying the client that it has successfully initiated a single sign-on session.
@@ -351,6 +351,28 @@ class LoginPage extends React.Component {
newUrl.searchParams.append("ticket", st);
window.location.href = newUrl.toString();
}
};
if (res.status === "ok") {
if (res.data === NextMfa) {
this.setState({
getVerifyTotp: () => {
return (
<MfaAuthVerifyForm
mfaProps={res.data2}
formValues={values}
authParams={casParams}
application={this.getApplicationObj()}
onFail={() => {
Setting.showMessage("error", i18next.t("mfa:Verification failed"));
}}
onSuccess={(res) => loginHandler(res)}
/>);
},
});
} else {
loginHandler(res);
}
} else {
Setting.showMessage("error", `${i18next.t("application:Failed to sign in")}: ${res.msg}`);
}
@@ -361,7 +383,7 @@ class LoginPage extends React.Component {
this.populateOauthValues(values);
AuthBackend.login(values, oAuthParams)
.then((res) => {
const callback = (res) => {
const loginHandler = (res) => {
const responseType = values["type"];
if (responseType === "login") {
@@ -396,12 +418,12 @@ class LoginPage extends React.Component {
<MfaAuthVerifyForm
mfaProps={res.data2}
formValues={values}
oAuthParams={oAuthParams}
authParams={oAuthParams}
application={this.getApplicationObj()}
onFail={() => {
Setting.showMessage("error", i18next.t("mfa:Verification failed"));
}}
onSuccess={(res) => callback(res)}
onSuccess={(res) => loginHandler(res)}
/>);
},
});
@@ -414,7 +436,7 @@ class LoginPage extends React.Component {
const sub = res.data2;
Setting.goToLink(`/buy-plan/${sub.owner}/${sub.pricing}/result?subscription=${sub.name}`);
} else {
callback(res);
loginHandler(res);
}
} else {
Setting.showMessage("error", `${i18next.t("application:Failed to sign in")}: ${res.msg}`);

View File

@@ -100,6 +100,10 @@ const authInfo = {
scope: "user.read",
endpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
},
AzureADB2C: {
scope: "openid",
endpoint: "https://tenant.b2clogin.com/tenant.onmicrosoft.com/userflow/oauth2/v2.0/authorize",
},
Slack: {
scope: "users:read",
endpoint: "https://slack.com/oauth/authorize",
@@ -406,6 +410,8 @@ export function getAuthUrl(application, provider, method) {
|| provider.type === "Twitch" || provider.type === "Typetalk" || provider.type === "Uber" || provider.type === "VK" || provider.type === "Wepay"
|| provider.type === "Xero" || provider.type === "Yahoo" || provider.type === "Yammer" || provider.type === "Yandex" || provider.type === "Zoom") {
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&scope=${scope}&response_type=code&state=${state}`;
} else if (provider.type === "AzureADB2C") {
return `https://${provider.domain}.b2clogin.com/${provider.domain}.onmicrosoft.com/${provider.appId}/oauth2/v2.0/authorize?client_id=${provider.clientId}&nonce=defaultNonce&redirect_uri=${encodeURIComponent(redirectUri)}&scope=${scope}&response_type=code&state=${state}&prompt=login`;
} else if (provider.type === "DingTalk") {
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&scope=${scope}&response_type=code&prompt=consent&state=${state}`;
} else if (provider.type === "WeChat") {

View File

@@ -35,6 +35,7 @@ import AlipayLoginButton from "./AlipayLoginButton";
import InfoflowLoginButton from "./InfoflowLoginButton";
import AppleLoginButton from "./AppleLoginButton";
import AzureADLoginButton from "./AzureADLoginButton";
import AzureADB2CLoginButton from "./AzureADB2CLoginButton";
import SlackLoginButton from "./SlackLoginButton";
import SteamLoginButton from "./SteamLoginButton";
import BilibiliLoginButton from "./BilibiliLoginButton";
@@ -85,6 +86,8 @@ function getSigninButton(provider) {
return <AppleLoginButton text={text} align={"center"} />;
} else if (provider.type === "AzureAD") {
return <AzureADLoginButton text={text} align={"center"} />;
} else if (provider.type === "AzureADB2C") {
return <AzureADB2CLoginButton text={text} align={"center"} />;
} else if (provider.type === "Slack") {
return <SlackLoginButton text={text} align={"center"} />;
} else if (provider.type === "Steam") {

View File

@@ -24,7 +24,7 @@ import MfaVerifyTotpForm from "./MfaVerifyTotpForm";
export const NextMfa = "NextMfa";
export const RequiredMfa = "RequiredMfa";
export function MfaAuthVerifyForm({formValues, oAuthParams, mfaProps, application, onSuccess, onFail}) {
export function MfaAuthVerifyForm({formValues, authParams, mfaProps, application, onSuccess, onFail}) {
formValues.password = "";
formValues.username = "";
const [loading, setLoading] = useState(false);
@@ -34,7 +34,8 @@ export function MfaAuthVerifyForm({formValues, oAuthParams, mfaProps, applicatio
const verify = ({passcode}) => {
setLoading(true);
const values = {...formValues, passcode, mfaType};
AuthBackend.login(values, oAuthParams).then((res) => {
const loginFunction = formValues.type === "cas" ? AuthBackend.loginCas : AuthBackend.login;
loginFunction(values, authParams).then((res) => {
if (res.status === "ok") {
onSuccess(res);
} else {
@@ -49,7 +50,9 @@ export function MfaAuthVerifyForm({formValues, oAuthParams, mfaProps, applicatio
const recover = () => {
setLoading(true);
AuthBackend.login({...formValues, recoveryCode}, oAuthParams).then(res => {
const values = {...formValues, recoveryCode};
const loginFunction = formValues.type === "cas" ? AuthBackend.loginCas : AuthBackend.login;
loginFunction(values, authParams).then((res) => {
if (res.status === "ok") {
onSuccess(res);
} else {

View File

@@ -153,11 +153,12 @@ export function sendCode(captchaType, captchaToken, clientSecret, method, countr
});
}
export function verifyCaptcha(captchaType, captchaToken, clientSecret) {
export function verifyCaptcha(owner, name, captchaType, captchaToken, clientSecret) {
const formData = new FormData();
formData.append("captchaType", captchaType);
formData.append("captchaToken", captchaToken);
formData.append("clientSecret", clientSecret);
formData.append("applicationId", `${owner}/${name}`);
return fetch(`${Setting.ServerUrl}/api/verify-captcha`, {
method: "POST",
credentials: "include",

View File

@@ -50,7 +50,7 @@ export const CaptchaPreview = (props) => {
};
const onOk = (captchaType, captchaToken, clientSecret) => {
UserBackend.verifyCaptcha(captchaType, captchaToken, clientSecret).then(() => {
UserBackend.verifyCaptcha(owner, name, captchaType, captchaToken, clientSecret).then(() => {
setVisible(false);
});
};

View File

@@ -12,7 +12,9 @@
"Policies": "Policies",
"Policies - Tooltip": "Casbin policy rules",
"Rule type": "Rule type",
"Sync policies successfully": "Sync policies successfully"
"Sync policies successfully": "Sync policies successfully",
"Use same DB": "Use same DB",
"Use same DB - Tooltip": "Use same DB - Tooltip"
},
"application": {
"Always": "Always",
@@ -30,6 +32,8 @@
"Edit Application": "Edit Application",
"Enable Email linking": "Enable Email linking",
"Enable Email linking - Tooltip": "When using 3rd-party providers to log in, if there is a user in the organization with the same Email, the 3rd-party login method will be automatically associated with that user",
"Enable SAML C14N10": "Enable SAML C14N10",
"Enable SAML C14N10 - Tooltip": "Enable SAML C14N10 - Tooltip",
"Enable SAML compression": "Enable SAML compression",
"Enable SAML compression - Tooltip": "Whether to compress SAML response messages when Casdoor is used as SAML idp",
"Enable WebAuthn signin": "Enable WebAuthn signin",
@@ -42,6 +46,10 @@
"Enable signin session - Tooltip": "Whether Casdoor maintains a session after logging into Casdoor from the application",
"Enable signup": "Enable signup",
"Enable signup - Tooltip": "Whether to allow users to register a new account",
"Failed signin frozen time": "Failed signin frozen time",
"Failed signin frozen time - Tooltip": "Failed signin frozen time - Tooltip",
"Failed signin limit": "Failed signin limit",
"Failed signin limit - Tooltip": "Failed signin limit - Tooltip",
"Failed to sign in": "Failed to sign in",
"File uploaded successfully": "File uploaded successfully",
"First, last": "First, last",
@@ -200,6 +208,8 @@
"Default application - Tooltip": "Default application for users registered directly from the organization page",
"Default avatar": "Default avatar",
"Default avatar - Tooltip": "Default avatar used when newly registered users do not set an avatar image",
"Default password": "Default password",
"Default password - Tooltip": "Default password - Tooltip",
"Delete": "Delete",
"Description": "Description",
"Description - Tooltip": "Detailed description information for reference, Casdoor itself will not use it",
@@ -218,8 +228,10 @@
"Failed to connect to server": "Failed to connect to server",
"Failed to delete": "Failed to delete",
"Failed to enable": "Failed to enable",
"Failed to get TermsOfUse URL": "Failed to get TermsOfUse URL",
"Failed to remove": "Failed to remove",
"Failed to save": "Failed to save",
"Failed to sync": "Failed to sync",
"Failed to verify": "Failed to verify",
"Favicon": "Favicon",
"Favicon - Tooltip": "Favicon icon URL used in all Casdoor pages of the organization",
@@ -251,6 +263,8 @@
"MFA items - Tooltip": "MFA items - Tooltip",
"Master password": "Master password",
"Master password - Tooltip": "Can be used to log in to all users under this organization, making it convenient for administrators to log in as this user to solve technical issues",
"Master verification code": "Master verification code",
"Master verification code - Tooltip": "Master verification code - Tooltip",
"Menu": "Menu",
"Method": "Method",
"Model": "Model",
@@ -272,6 +286,8 @@
"Password salt - Tooltip": "Random parameter used for password encryption",
"Password type": "Password type",
"Password type - Tooltip": "Storage format of passwords in the database",
"Payment": "Payment",
"Payment - Tooltip": "Payment - Tooltip",
"Payments": "Payments",
"Permissions": "Permissions",
"Permissions - Tooltip": "Permissions owned by this user",
@@ -283,6 +299,8 @@
"Plans - Tooltip": "Plans - Tooltip",
"Preview": "Preview",
"Preview - Tooltip": "Preview the configured effects",
"Pricing": "Pricing",
"Pricing - Tooltip": "Pricing - Tooltip",
"Pricings": "Pricings",
"Products": "Products",
"Provider": "Provider",
@@ -296,6 +314,10 @@
"Role - Tooltip": "Role - Tooltip",
"Roles": "Roles",
"Roles - Tooltip": "Roles that the user belongs to",
"Root cert": "Root cert",
"Root cert - Tooltip": "Root cert - Tooltip",
"SAML attributes": "SAML attributes",
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
"Save": "Save",
"Save & Exit": "Save & Exit",
"Session ID": "Session ID",
@@ -318,6 +340,7 @@
"Successfully removed": "Successfully removed",
"Successfully saved": "Successfully saved",
"Successfully sent": "Successfully sent",
"Successfully synced": "Successfully synced",
"Supported country codes": "Supported country codes",
"Supported country codes - Tooltip": "Country codes supported by the organization. These codes can be selected as a prefix when sending SMS verification codes",
"Sure to delete": "Sure to delete",
@@ -573,11 +596,13 @@
"plan": {
"Edit Plan": "Edit Plan",
"New Plan": "New Plan",
"Price per month": "Price per month",
"Price per month - Tooltip": "Price per month - Tooltip",
"Price per year": "Price per year",
"Price per year - Tooltip": "Price per year - Tooltip",
"per month": "per month"
"Period": "Period",
"Period - Tooltip": "Period - Tooltip",
"Price": "Price",
"Price - Tooltip": "Price - Tooltip",
"Related product": "Related product",
"per month": "per month",
"per year": "per year"
},
"pricing": {
"Copy pricing page URL": "Copy pricing page URL",
@@ -589,6 +614,7 @@
"Trial duration": "Trial duration",
"Trial duration - Tooltip": "Trial duration period",
"days trial available!": "days trial available!",
"paid-user do not have active subscription or pending subscription, please select a plan to buy": "paid-user do not have active subscription or pending subscription, please select a plan to buy",
"pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser"
},
"product": {
@@ -600,17 +626,16 @@
"Detail - Tooltip": "Detail of product",
"Dummy": "Dummy",
"Edit Product": "Edit Product",
"I have completed the payment": "I have completed the payment",
"Image": "Image",
"Image - Tooltip": "Image of product",
"New Product": "New Product",
"Pay": "Pay",
"PayPal": "PayPal",
"Payment cancelled": "Payment cancelled",
"Payment failed": "Payment failed",
"Payment providers": "Payment providers",
"Payment providers - Tooltip": "Providers of payment services",
"Placing order...": "Placing order...",
"Please provide your username in the remark": "Please provide your username in the remark",
"Please scan the QR code to pay": "Please scan the QR code to pay",
"Price": "Price",
"Price - Tooltip": "Price of product",
"Quantity": "Quantity",
@@ -672,8 +697,8 @@
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copy",
"DB Test": "DB Test",
"DB Test - Tooltip": "DB Test - Tooltip",
"DB test": "DB test",
"DB test - Tooltip": "DB test - Tooltip",
"Disable SSL": "Disable SSL",
"Disable SSL - Tooltip": "Whether to disable SSL protocol when communicating with STMP server",
"Domain": "Domain",
@@ -700,6 +725,10 @@
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
"Key ID": "Key ID",
"Key ID - Tooltip": "Key ID - Tooltip",
"Key text": "Key text",
"Key text - Tooltip": "Key text - Tooltip",
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
"Metadata": "Metadata",
"Metadata - Tooltip": "SAML metadata",
@@ -754,6 +783,10 @@
"Sender Id - Tooltip": "Sender Id - Tooltip",
"Sender number": "Sender number",
"Sender number - Tooltip": "Sender number - Tooltip",
"Service ID identifier": "Service ID identifier",
"Service ID identifier - Tooltip": "Service ID identifier - Tooltip",
"Service account JSON": "Service account JSON",
"Service account JSON - Tooltip": "Service account JSON - Tooltip",
"Sign Name": "Sign Name",
"Sign Name - Tooltip": "Name of the signature to be used",
"Sign request": "Sign request",
@@ -764,12 +797,15 @@
"Signup HTML": "Signup HTML",
"Signup HTML - Edit": "Signup HTML - Edit",
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
"Signup group": "Signup group",
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Team ID": "Team ID",
"Team ID - Tooltip": "Team ID - Tooltip",
"Template code": "Template code",
"Template code - Tooltip": "Template code",
"Test Email": "Test Email",
@@ -780,6 +816,8 @@
"Token URL - Tooltip": "Token URL",
"Type": "Type",
"Type - Tooltip": "Select a type",
"User flow": "User flow",
"User flow - Tooltip": "User flow - Tooltip",
"User mapping": "User mapping",
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URL",
@@ -801,6 +839,8 @@
"New Role": "New Role",
"Sub domains": "Sub domains",
"Sub domains - Tooltip": "Domains included in the current role",
"Sub groups": "Sub groups",
"Sub groups - Tooltip": "Sub groups - Tooltip",
"Sub roles": "Sub roles",
"Sub roles - Tooltip": "Roles included in the current role",
"Sub users": "Sub users",
@@ -812,6 +852,9 @@
"Confirm": "Confirm",
"Decline": "Decline",
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",
"Please confirm your password!": "Please confirm your password!",
@@ -830,6 +873,11 @@
"Please select your country/region!": "Please select your country/region!",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
"Text 2": "Text 2",
"Text 3": "Text 3",
"Text 4": "Text 4",
"Text 5": "Text 5",
"The input is not invoice Tax ID!": "The input is not invoice Tax ID!",
"The input is not invoice title!": "The input is not invoice title!",
"The input is not valid Email!": "The input is not valid Email!",
@@ -841,14 +889,19 @@
"sign in now": "sign in now"
},
"subscription": {
"Duration": "Duration",
"Duration - Tooltip": "Subscription duration",
"Active": "Active",
"Edit Subscription": "Edit Subscription",
"End date": "End date",
"End date - Tooltip": "End date",
"End time": "End time",
"End time - Tooltip": "End time - Tooltip",
"Error": "Error",
"Expired": "Expired",
"New Subscription": "New Subscription",
"Start date": "Start date",
"Start date - Tooltip": "Start date"
"Pending": "Pending",
"Period": "Period",
"Start time": "Start time",
"Start time - Tooltip": "Start time - Tooltip",
"Suspended": "Suspended",
"Upcoming": "Upcoming"
},
"syncer": {
"Affiliation table": "Affiliation table",
@@ -872,6 +925,8 @@
"Is read-only": "Is read-only",
"Is read-only - Tooltip": "Is read-only - Tooltip",
"New Syncer": "New Syncer",
"SSL mode": "SSL mode",
"SSL mode - Tooltip": "SSL mode - Tooltip",
"Sync interval": "Sync interval",
"Sync interval - Tooltip": "Unit in seconds",
"Table": "Table",
@@ -974,6 +1029,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1011,6 +1068,7 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -12,7 +12,9 @@
"Policies": "Richtlinien",
"Policies - Tooltip": "Casbin Richtlinienregeln",
"Rule type": "Rule type",
"Sync policies successfully": "Richtlinien synchronisiert"
"Sync policies successfully": "Richtlinien synchronisiert",
"Use same DB": "Use same DB",
"Use same DB - Tooltip": "Use same DB - Tooltip"
},
"application": {
"Always": "Immer",
@@ -30,6 +32,8 @@
"Edit Application": "Bearbeitungsanwendung",
"Enable Email linking": "E-Mail-Verknüpfung aktivieren",
"Enable Email linking - Tooltip": "Bei der Verwendung von Drittanbietern zur Anmeldung wird, wenn es in der Organisation einen Benutzer mit der gleichen E-Mail gibt, automatisch die Drittanbieter-Anmelde-Methode mit diesem Benutzer verbunden",
"Enable SAML C14N10": "Enable SAML C14N10",
"Enable SAML C14N10 - Tooltip": "Enable SAML C14N10 - Tooltip",
"Enable SAML compression": "Aktivieren Sie SAML-Komprimierung",
"Enable SAML compression - Tooltip": "Ob SAML-Antwortnachrichten komprimiert werden sollen, wenn Casdoor als SAML-IdP verwendet wird",
"Enable WebAuthn signin": "Anmeldung mit WebAuthn aktivieren",
@@ -42,6 +46,10 @@
"Enable signin session - Tooltip": "Ob Casdoor eine Sitzung aufrechterhält, nachdem man sich von der Anwendung aus bei Casdoor angemeldet hat",
"Enable signup": "Registrierung aktivieren",
"Enable signup - Tooltip": "Ob Benutzern erlaubt werden soll, ein neues Konto zu registrieren",
"Failed signin frozen time": "Failed signin frozen time",
"Failed signin frozen time - Tooltip": "Failed signin frozen time - Tooltip",
"Failed signin limit": "Failed signin limit",
"Failed signin limit - Tooltip": "Failed signin limit - Tooltip",
"Failed to sign in": "Fehler bei der Anmeldung",
"File uploaded successfully": "Datei erfolgreich hochgeladen",
"First, last": "First, last",
@@ -200,6 +208,8 @@
"Default application - Tooltip": "Standard-Anwendung für Benutzer, die direkt von der Organisationsseite registriert wurden",
"Default avatar": "Standard-Avatar",
"Default avatar - Tooltip": "Standard-Avatar, der verwendet wird, wenn neu registrierte Benutzer kein Avatar-Bild festlegen",
"Default password": "Default password",
"Default password - Tooltip": "Default password - Tooltip",
"Delete": "Löschen",
"Description": "Beschreibung",
"Description - Tooltip": "Detaillierte Beschreibungsinformationen zur Referenz, Casdoor selbst wird es nicht verwenden",
@@ -218,8 +228,10 @@
"Failed to connect to server": "Die Verbindung zum Server konnte nicht hergestellt werden",
"Failed to delete": "Konnte nicht gelöscht werden",
"Failed to enable": "Failed to enable",
"Failed to get TermsOfUse URL": "Failed to get TermsOfUse URL",
"Failed to remove": "Failed to remove",
"Failed to save": "Konnte nicht gespeichert werden",
"Failed to sync": "Failed to sync",
"Failed to verify": "Failed to verify",
"Favicon": "Favicon",
"Favicon - Tooltip": "Favicon-URL, die auf allen Casdoor-Seiten der Organisation verwendet wird",
@@ -251,6 +263,8 @@
"MFA items - Tooltip": "MFA items - Tooltip",
"Master password": "Hauptpasswort",
"Master password - Tooltip": "Kann zum Einloggen aller Benutzer unter dieser Organisation verwendet werden, was es Administratoren bequem macht, sich als dieser Benutzer einzuloggen, um technische Probleme zu lösen",
"Master verification code": "Master verification code",
"Master verification code - Tooltip": "Master verification code - Tooltip",
"Menu": "Menü",
"Method": "Methode",
"Model": "Modell",
@@ -272,6 +286,8 @@
"Password salt - Tooltip": "Zufälliger Parameter, der für die Verschlüsselung von Passwörtern verwendet wird",
"Password type": "Passworttyp",
"Password type - Tooltip": "Speicherformat von Passwörtern in der Datenbank",
"Payment": "Payment",
"Payment - Tooltip": "Payment - Tooltip",
"Payments": "Zahlungen",
"Permissions": "Rechte",
"Permissions - Tooltip": "Berechtigungen, die diesem Benutzer gehören",
@@ -283,6 +299,8 @@
"Plans - Tooltip": "Plans - Tooltip",
"Preview": "Vorschau",
"Preview - Tooltip": "Vorschau der konfigurierten Effekte",
"Pricing": "Pricing",
"Pricing - Tooltip": "Pricing - Tooltip",
"Pricings": "Preise",
"Products": "Produkte",
"Provider": "Anbieter",
@@ -296,6 +314,10 @@
"Role - Tooltip": "Role - Tooltip",
"Roles": "Rollen",
"Roles - Tooltip": "Rollen, denen der Benutzer angehört",
"Root cert": "Root cert",
"Root cert - Tooltip": "Root cert - Tooltip",
"SAML attributes": "SAML attributes",
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
"Save": "Speichern",
"Save & Exit": "Speichern und verlassen",
"Session ID": "Session-ID",
@@ -318,6 +340,7 @@
"Successfully removed": "Successfully removed",
"Successfully saved": "Erfolgreich gespeichert",
"Successfully sent": "Successfully sent",
"Successfully synced": "Successfully synced",
"Supported country codes": "Unterstützte Ländercodes",
"Supported country codes - Tooltip": "Ländercodes, die von der Organisation unterstützt werden. Diese Codes können als Präfix ausgewählt werden, wenn SMS-Verifizierungscodes gesendet werden",
"Sure to delete": "Sicher zu löschen",
@@ -573,11 +596,13 @@
"plan": {
"Edit Plan": "Edit Plan",
"New Plan": "New Plan",
"Price per month": "Price per month",
"Price per month - Tooltip": "Price per month - Tooltip",
"Price per year": "Price per year",
"Price per year - Tooltip": "Price per year - Tooltip",
"per month": "pro Monat"
"Period": "Period",
"Period - Tooltip": "Period - Tooltip",
"Price": "Price",
"Price - Tooltip": "Price - Tooltip",
"Related product": "Related product",
"per month": "pro Monat",
"per year": "per year"
},
"pricing": {
"Copy pricing page URL": "Preisseite URL kopieren",
@@ -589,6 +614,7 @@
"Trial duration": "Testphase Dauer",
"Trial duration - Tooltip": "Dauer der Testphase",
"days trial available!": "Tage Testphase verfügbar!",
"paid-user do not have active subscription or pending subscription, please select a plan to buy": "paid-user do not have active subscription or pending subscription, please select a plan to buy",
"pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "Preisseite URL erfolgreich in die Zwischenablage kopiert. Bitte fügen Sie sie in ein Inkognito-Fenster oder einen anderen Browser ein."
},
"product": {
@@ -600,17 +626,16 @@
"Detail - Tooltip": "Detail des Produkts",
"Dummy": "Dummy",
"Edit Product": "Produkt bearbeiten",
"I have completed the payment": "Ich habe die Zahlung abgeschlossen",
"Image": "Bild",
"Image - Tooltip": "Bild des Produkts",
"New Product": "Neues Produkt",
"Pay": "Zahlen",
"PayPal": "PayPal",
"Payment cancelled": "Payment cancelled",
"Payment failed": "Payment failed",
"Payment providers": "Zahlungsprovider",
"Payment providers - Tooltip": "Provider von Zahlungsdiensten",
"Placing order...": "Bestellung aufgeben...",
"Please provide your username in the remark": "Bitte geben Sie Ihren Benutzernamen in der Anmerkung an",
"Please scan the QR code to pay": "Bitte scannen Sie den QR-Code, um zu bezahlen",
"Price": "Preis",
"Price - Tooltip": "Preis des Produkts",
"Quantity": "Menge",
@@ -672,8 +697,8 @@
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Kopieren",
"DB Test": "DB Test",
"DB Test - Tooltip": "DB Test - Tooltip",
"DB test": "DB test",
"DB test - Tooltip": "DB test - Tooltip",
"Disable SSL": "SSL deaktivieren",
"Disable SSL - Tooltip": "Ob die Deaktivierung des SSL-Protokolls bei der Kommunikation mit dem STMP-Server erfolgen soll",
"Domain": "Domäne",
@@ -700,6 +725,10 @@
"Internal": "Internal",
"Issuer URL": "Issuer-URL",
"Issuer URL - Tooltip": "Emittenten-URL",
"Key ID": "Key ID",
"Key ID - Tooltip": "Key ID - Tooltip",
"Key text": "Key text",
"Key text - Tooltip": "Key text - Tooltip",
"Link copied to clipboard successfully": "Link wurde erfolgreich in die Zwischenablage kopiert",
"Metadata": "Metadaten",
"Metadata - Tooltip": "SAML-Metadaten",
@@ -754,6 +783,10 @@
"Sender Id - Tooltip": "Sender Id - Tooltip",
"Sender number": "Sender number",
"Sender number - Tooltip": "Sender number - Tooltip",
"Service ID identifier": "Service ID identifier",
"Service ID identifier - Tooltip": "Service ID identifier - Tooltip",
"Service account JSON": "Service account JSON",
"Service account JSON - Tooltip": "Service account JSON - Tooltip",
"Sign Name": "Signatur Namen",
"Sign Name - Tooltip": "Name der Signatur, die verwendet werden soll",
"Sign request": "Unterschriftsanforderung",
@@ -764,12 +797,15 @@
"Signup HTML": "Registrierungs-HTML",
"Signup HTML - Edit": "Registrierung HTML - Bearbeiten",
"Signup HTML - Tooltip": "Benutzerdefiniertes HTML zur Ersetzung des Standard-Registrierungs-Seitenstils",
"Signup group": "Signup group",
"Silent": "Silent",
"Site key": "Site-Key",
"Site key - Tooltip": "Seitenschlüssel",
"Sliding Validation": "Sliding Validation",
"Sub type": "Untertyp",
"Sub type - Tooltip": "Unterart",
"Team ID": "Team ID",
"Team ID - Tooltip": "Team ID - Tooltip",
"Template code": "Template-Code",
"Template code - Tooltip": "Template-Code",
"Test Email": "Test E-Mail",
@@ -780,6 +816,8 @@
"Token URL - Tooltip": "Token-URL",
"Type": "Typ",
"Type - Tooltip": "Wählen Sie einen Typ aus",
"User flow": "User flow",
"User flow - Tooltip": "User flow - Tooltip",
"User mapping": "User mapping",
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo-URL",
@@ -801,6 +839,8 @@
"New Role": "Neue Rolle",
"Sub domains": "Subdomains",
"Sub domains - Tooltip": "In der aktuellen Rolle enthaltene Domains",
"Sub groups": "Sub groups",
"Sub groups - Tooltip": "Sub groups - Tooltip",
"Sub roles": "Unterrollen",
"Sub roles - Tooltip": "Rollen, die in der aktuellen Rolle enthalten sind",
"Sub users": "Unterbenutzer",
@@ -812,6 +852,9 @@
"Confirm": "Bestätigen",
"Decline": "Abnahme",
"Have account?": "Haben Sie ein Konto?",
"Label": "Label",
"Label HTML": "Label HTML",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Bitte akzeptieren Sie die Vereinbarung!",
"Please click the below button to sign in": "Bitte klicken Sie auf den untenstehenden Button, um sich anzumelden",
"Please confirm your password!": "Bitte bestätige dein Passwort!",
@@ -830,6 +873,11 @@
"Please select your country/region!": "Bitte wählen Sie Ihr Land/Ihre Region aus!",
"Terms of Use": "Nutzungsbedingungen",
"Terms of Use - Tooltip": "Nutzungsbedingungen, die Benutzer während der Registrierung lesen und akzeptieren müssen",
"Text 1": "Text 1",
"Text 2": "Text 2",
"Text 3": "Text 3",
"Text 4": "Text 4",
"Text 5": "Text 5",
"The input is not invoice Tax ID!": "Die Eingabe ist keine Rechnungssteuer-ID!",
"The input is not invoice title!": "Der Eingabewert ist nicht die Rechnungsbezeichnung!",
"The input is not valid Email!": "Die Eingabe ist keine gültige E-Mail-Adresse!",
@@ -841,14 +889,19 @@
"sign in now": "Jetzt anmelden"
},
"subscription": {
"Duration": "Laufzeit",
"Duration - Tooltip": "Laufzeit des Abonnements",
"Active": "Active",
"Edit Subscription": "Edit Subscription",
"End date": "Enddatum",
"End date - Tooltip": "Enddatum",
"End time": "End time",
"End time - Tooltip": "End time - Tooltip",
"Error": "Error",
"Expired": "Expired",
"New Subscription": "New Subscription",
"Start date": "Startdatum",
"Start date - Tooltip": "Startdatum"
"Pending": "Pending",
"Period": "Period",
"Start time": "Start time",
"Start time - Tooltip": "Start time - Tooltip",
"Suspended": "Suspended",
"Upcoming": "Upcoming"
},
"syncer": {
"Affiliation table": "Zuordnungstabelle",
@@ -872,6 +925,8 @@
"Is read-only": "Is read-only",
"Is read-only - Tooltip": "Is read-only - Tooltip",
"New Syncer": "Neuer Syncer",
"SSL mode": "SSL mode",
"SSL mode - Tooltip": "SSL mode - Tooltip",
"Sync interval": "Synchronisierungsintervall",
"Sync interval - Tooltip": "Einheit in Sekunden",
"Table": "Tabelle",
@@ -974,6 +1029,8 @@
"Managed accounts": "Verwaltete Konten",
"Modify password...": "Passwort ändern...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "Neue E-Mail",
"New Password": "Neues Passwort",
"New User": "Neuer Benutzer",
@@ -1011,6 +1068,7 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Lade ein Foto hoch",
"Value": "Value",
"Values": "Werte",
"Verification code sent": "Bestätigungscode gesendet",
"WebAuthn credentials": "WebAuthn-Anmeldeinformationen",

View File

@@ -12,7 +12,9 @@
"Policies": "Policies",
"Policies - Tooltip": "Casbin policy rules",
"Rule type": "Rule type",
"Sync policies successfully": "Sync policies successfully"
"Sync policies successfully": "Sync policies successfully",
"Use same DB": "Use same DB",
"Use same DB - Tooltip": "Use the same DB as Casdoor"
},
"application": {
"Always": "Always",
@@ -30,6 +32,8 @@
"Edit Application": "Edit Application",
"Enable Email linking": "Enable Email linking",
"Enable Email linking - Tooltip": "When using 3rd-party providers to log in, if there is a user in the organization with the same Email, the 3rd-party login method will be automatically associated with that user",
"Enable SAML C14N10": "Enable SAML C14N10",
"Enable SAML C14N10 - Tooltip": "Use C14N10 instead of C14N11 in SAML",
"Enable SAML compression": "Enable SAML compression",
"Enable SAML compression - Tooltip": "Whether to compress SAML response messages when Casdoor is used as SAML idp",
"Enable WebAuthn signin": "Enable WebAuthn signin",
@@ -42,6 +46,10 @@
"Enable signin session - Tooltip": "Whether Casdoor maintains a session after logging into Casdoor from the application",
"Enable signup": "Enable signup",
"Enable signup - Tooltip": "Whether to allow users to register a new account",
"Failed signin frozen time": "Failed signin frozen time",
"Failed signin frozen time - Tooltip": "Failed signin frozen time - Tooltip",
"Failed signin limit": "Failed signin limit",
"Failed signin limit - Tooltip": "Failed signin limit - Tooltip",
"Failed to sign in": "Failed to sign in",
"File uploaded successfully": "File uploaded successfully",
"First, last": "First, last",
@@ -200,6 +208,8 @@
"Default application - Tooltip": "Default application for users registered directly from the organization page",
"Default avatar": "Default avatar",
"Default avatar - Tooltip": "Default avatar used when newly registered users do not set an avatar image",
"Default password": "Default password",
"Default password - Tooltip": "When adding new user, if the user's password is not specified, the default password will be used as the user's password",
"Delete": "Delete",
"Description": "Description",
"Description - Tooltip": "Detailed description information for reference, Casdoor itself will not use it",
@@ -218,8 +228,10 @@
"Failed to connect to server": "Failed to connect to server",
"Failed to delete": "Failed to delete",
"Failed to enable": "Failed to enable",
"Failed to get TermsOfUse URL": "Failed to get TermsOfUse URL",
"Failed to remove": "Failed to remove",
"Failed to save": "Failed to save",
"Failed to sync": "Failed to sync",
"Failed to verify": "Failed to verify",
"Favicon": "Favicon",
"Favicon - Tooltip": "Favicon icon URL used in all Casdoor pages of the organization",
@@ -251,6 +263,8 @@
"MFA items - Tooltip": "MFA items - Tooltip",
"Master password": "Master password",
"Master password - Tooltip": "Can be used to log in to all users under this organization, making it convenient for administrators to log in as this user to solve technical issues",
"Master verification code": "Master verification code",
"Master verification code - Tooltip": "When the master verification code is set, all email and SMS verification codes sent under this organization will use this fixed code. It's mainly used for automated testing and CI purposes and is generally not used in normal environments",
"Menu": "Menu",
"Method": "Method",
"Model": "Model",
@@ -272,6 +286,8 @@
"Password salt - Tooltip": "Random parameter used for password encryption",
"Password type": "Password type",
"Password type - Tooltip": "Storage format of passwords in the database",
"Payment": "Payment",
"Payment - Tooltip": "Payment - Tooltip",
"Payments": "Payments",
"Permissions": "Permissions",
"Permissions - Tooltip": "Permissions owned by this user",
@@ -283,6 +299,8 @@
"Plans - Tooltip": "Plans - Tooltip",
"Preview": "Preview",
"Preview - Tooltip": "Preview the configured effects",
"Pricing": "Pricing",
"Pricing - Tooltip": "Pricing - Tooltip",
"Pricings": "Pricings",
"Products": "Products",
"Provider": "Provider",
@@ -296,6 +314,10 @@
"Role - Tooltip": "Role - Tooltip",
"Roles": "Roles",
"Roles - Tooltip": "Roles that the user belongs to",
"Root cert": "Root cert",
"Root cert - Tooltip": "Root cert - Tooltip",
"SAML attributes": "SAML attributes",
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
"Save": "Save",
"Save & Exit": "Save & Exit",
"Session ID": "Session ID",
@@ -318,6 +340,7 @@
"Successfully removed": "Successfully removed",
"Successfully saved": "Successfully saved",
"Successfully sent": "Successfully sent",
"Successfully synced": "Successfully synced",
"Supported country codes": "Supported country codes",
"Supported country codes - Tooltip": "Country codes supported by the organization. These codes can be selected as a prefix when sending SMS verification codes",
"Sure to delete": "Sure to delete",
@@ -573,11 +596,13 @@
"plan": {
"Edit Plan": "Edit Plan",
"New Plan": "New Plan",
"Price per month": "Price per month",
"Price per month - Tooltip": "Price per month - Tooltip",
"Price per year": "Price per year",
"Price per year - Tooltip": "Price per year - Tooltip",
"per month": "per month"
"Period": "Period",
"Period - Tooltip": "Period for the plan",
"Price": "Price",
"Price - Tooltip": "Price needs to pay to subscribe the plan",
"Related product": "Related product",
"per month": "per month",
"per year": "per year"
},
"pricing": {
"Copy pricing page URL": "Copy pricing page URL",
@@ -589,6 +614,7 @@
"Trial duration": "Trial duration",
"Trial duration - Tooltip": "Trial duration period",
"days trial available!": "days trial available!",
"paid-user do not have active subscription or pending subscription, please select a plan to buy": "paid-user do not have active subscription or pending subscription, please select a plan to buy",
"pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser"
},
"product": {
@@ -600,17 +626,16 @@
"Detail - Tooltip": "Detail of product",
"Dummy": "Dummy",
"Edit Product": "Edit Product",
"I have completed the payment": "I have completed the payment",
"Image": "Image",
"Image - Tooltip": "Image of product",
"New Product": "New Product",
"Pay": "Pay",
"PayPal": "PayPal",
"Payment cancelled": "Payment cancelled",
"Payment failed": "Payment failed",
"Payment providers": "Payment providers",
"Payment providers - Tooltip": "Providers of payment services",
"Placing order...": "Placing order...",
"Please provide your username in the remark": "Please provide your username in the remark",
"Please scan the QR code to pay": "Please scan the QR code to pay",
"Price": "Price",
"Price - Tooltip": "Price of product",
"Quantity": "Quantity",
@@ -672,8 +697,8 @@
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copy",
"DB Test": "DB Test",
"DB Test - Tooltip": "DB Test - Tooltip",
"DB test": "DB test",
"DB test - Tooltip": "Test the connectivity to the database",
"Disable SSL": "Disable SSL",
"Disable SSL - Tooltip": "Whether to disable SSL protocol when communicating with STMP server",
"Domain": "Domain",
@@ -700,6 +725,10 @@
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
"Key ID": "Key ID",
"Key ID - Tooltip": "Key ID",
"Key text": "Key text",
"Key text - Tooltip": "Key text",
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
"Metadata": "Metadata",
"Metadata - Tooltip": "SAML metadata",
@@ -754,6 +783,10 @@
"Sender Id - Tooltip": "Sender Id - Tooltip",
"Sender number": "Sender number",
"Sender number - Tooltip": "Sender number - Tooltip",
"Service ID identifier": "Service ID identifier",
"Service ID identifier - Tooltip": "Service ID identifier",
"Service account JSON": "Service account JSON",
"Service account JSON - Tooltip": "The JSON file content for the service account",
"Sign Name": "Sign Name",
"Sign Name - Tooltip": "Name of the signature to be used",
"Sign request": "Sign request",
@@ -764,12 +797,15 @@
"Signup HTML": "Signup HTML",
"Signup HTML - Edit": "Signup HTML - Edit",
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
"Signup group": "Signup group",
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Team ID": "Team ID",
"Team ID - Tooltip": "Team ID",
"Template code": "Template code",
"Template code - Tooltip": "Template code",
"Test Email": "Test Email",
@@ -780,6 +816,8 @@
"Token URL - Tooltip": "Token URL",
"Type": "Type",
"Type - Tooltip": "Select a type",
"User flow": "User flow",
"User flow - Tooltip": "User flow",
"User mapping": "User mapping",
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URL",
@@ -801,6 +839,8 @@
"New Role": "New Role",
"Sub domains": "Sub domains",
"Sub domains - Tooltip": "Domains included in the current role",
"Sub groups": "Sub groups",
"Sub groups - Tooltip": "Groups included in the current role",
"Sub roles": "Sub roles",
"Sub roles - Tooltip": "Roles included in the current role",
"Sub users": "Sub users",
@@ -812,6 +852,9 @@
"Confirm": "Confirm",
"Decline": "Decline",
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",
"Please confirm your password!": "Please confirm your password!",
@@ -830,6 +873,11 @@
"Please select your country/region!": "Please select your country/region!",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
"Text 2": "Text 2",
"Text 3": "Text 3",
"Text 4": "Text 4",
"Text 5": "Text 5",
"The input is not invoice Tax ID!": "The input is not invoice Tax ID!",
"The input is not invoice title!": "The input is not invoice title!",
"The input is not valid Email!": "The input is not valid Email!",
@@ -841,14 +889,19 @@
"sign in now": "sign in now"
},
"subscription": {
"Duration": "Duration",
"Duration - Tooltip": "Subscription duration",
"Active": "Active",
"Edit Subscription": "Edit Subscription",
"End date": "End date",
"End date - Tooltip": "End date",
"End time": "End time",
"End time - Tooltip": "End time of the subscription",
"Error": "Error",
"Expired": "Expired",
"New Subscription": "New Subscription",
"Start date": "Start date",
"Start date - Tooltip": "Start date"
"Pending": "Pending",
"Period": "Period",
"Start time": "Start time",
"Start time - Tooltip": "Start time of the subscription",
"Suspended": "Suspended",
"Upcoming": "Upcoming"
},
"syncer": {
"Affiliation table": "Affiliation table",
@@ -872,6 +925,8 @@
"Is read-only": "Is read-only",
"Is read-only - Tooltip": "Is read-only - Tooltip",
"New Syncer": "New Syncer",
"SSL mode": "SSL mode",
"SSL mode - Tooltip": "The SSL mode used when connecting to the database",
"Sync interval": "Sync interval",
"Sync interval - Tooltip": "Unit in seconds",
"Table": "Table",
@@ -974,6 +1029,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1011,6 +1068,7 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -12,7 +12,9 @@
"Policies": "Políticas",
"Policies - Tooltip": "Reglas de política de Casbin",
"Rule type": "Rule type",
"Sync policies successfully": "Sincronizar políticas correctamente"
"Sync policies successfully": "Sincronizar políticas correctamente",
"Use same DB": "Use same DB",
"Use same DB - Tooltip": "Use same DB - Tooltip"
},
"application": {
"Always": "siempre",
@@ -30,6 +32,8 @@
"Edit Application": "Editar solicitud",
"Enable Email linking": "Habilitar enlace de correo electrónico",
"Enable Email linking - Tooltip": "Cuando se utilizan proveedores externos de inicio de sesión, si hay un usuario en la organización con el mismo correo electrónico, el método de inicio de sesión externo se asociará automáticamente con ese usuario",
"Enable SAML C14N10": "Enable SAML C14N10",
"Enable SAML C14N10 - Tooltip": "Enable SAML C14N10 - Tooltip",
"Enable SAML compression": "Activar la compresión SAML",
"Enable SAML compression - Tooltip": "Si comprimir o no los mensajes de respuesta SAML cuando se utiliza Casdoor como proveedor de identidad SAML",
"Enable WebAuthn signin": "Permite iniciar sesión con WebAuthn",
@@ -42,6 +46,10 @@
"Enable signin session - Tooltip": "Si Casdoor mantiene una sesión después de iniciar sesión en Casdoor desde la aplicación",
"Enable signup": "Habilitar registro",
"Enable signup - Tooltip": "Ya sea permitir que los usuarios registren una nueva cuenta",
"Failed signin frozen time": "Failed signin frozen time",
"Failed signin frozen time - Tooltip": "Failed signin frozen time - Tooltip",
"Failed signin limit": "Failed signin limit",
"Failed signin limit - Tooltip": "Failed signin limit - Tooltip",
"Failed to sign in": "Error al iniciar sesión",
"File uploaded successfully": "Archivo subido exitosamente",
"First, last": "First, last",
@@ -200,6 +208,8 @@
"Default application - Tooltip": "Aplicación predeterminada para usuarios registrados directamente desde la página de la organización",
"Default avatar": "Avatar predeterminado",
"Default avatar - Tooltip": "Avatar predeterminado utilizado cuando los usuarios recién registrados no establecen una imagen de avatar",
"Default password": "Default password",
"Default password - Tooltip": "Default password - Tooltip",
"Delete": "Eliminar",
"Description": "Descripción",
"Description - Tooltip": "Información detallada de descripción para referencia, Casdoor en sí no la utilizará",
@@ -218,8 +228,10 @@
"Failed to connect to server": "No se pudo conectar al servidor",
"Failed to delete": "No se pudo eliminar",
"Failed to enable": "Failed to enable",
"Failed to get TermsOfUse URL": "Failed to get TermsOfUse URL",
"Failed to remove": "Failed to remove",
"Failed to save": "No se pudo guardar",
"Failed to sync": "Failed to sync",
"Failed to verify": "Failed to verify",
"Favicon": "Favicon (ícono de favoritos)",
"Favicon - Tooltip": "URL del icono Favicon utilizado en todas las páginas de Casdoor de la organización",
@@ -251,6 +263,8 @@
"MFA items - Tooltip": "MFA items - Tooltip",
"Master password": "Contraseña maestra",
"Master password - Tooltip": "Se puede usar para iniciar sesión en todos los usuarios de esta organización, lo que hace conveniente que los administradores inicien sesión como este usuario para resolver problemas técnicos",
"Master verification code": "Master verification code",
"Master verification code - Tooltip": "Master verification code - Tooltip",
"Menu": "Menú",
"Method": "Método",
"Model": "Modelo",
@@ -272,6 +286,8 @@
"Password salt - Tooltip": "Parámetro aleatorio utilizado para la encriptación de contraseñas",
"Password type": "Tipo de contraseña",
"Password type - Tooltip": "Formato de almacenamiento de contraseñas en la base de datos",
"Payment": "Payment",
"Payment - Tooltip": "Payment - Tooltip",
"Payments": "Pagos",
"Permissions": "Permisos",
"Permissions - Tooltip": "Permisos propiedad de este usuario",
@@ -283,6 +299,8 @@
"Plans - Tooltip": "Plans - Tooltip",
"Preview": "Avance",
"Preview - Tooltip": "Vista previa de los efectos configurados",
"Pricing": "Pricing",
"Pricing - Tooltip": "Pricing - Tooltip",
"Pricings": "Precios",
"Products": "Productos",
"Provider": "Proveedor",
@@ -296,6 +314,10 @@
"Role - Tooltip": "Role - Tooltip",
"Roles": "Roles",
"Roles - Tooltip": "Roles a los que pertenece el usuario",
"Root cert": "Root cert",
"Root cert - Tooltip": "Root cert - Tooltip",
"SAML attributes": "SAML attributes",
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
"Save": "Guardar",
"Save & Exit": "Guardar y salir",
"Session ID": "ID de sesión",
@@ -318,6 +340,7 @@
"Successfully removed": "Successfully removed",
"Successfully saved": "Guardado exitosamente",
"Successfully sent": "Successfully sent",
"Successfully synced": "Successfully synced",
"Supported country codes": "Códigos de país admitidos",
"Supported country codes - Tooltip": "Códigos de país compatibles con la organización. Estos códigos se pueden seleccionar como prefijo al enviar códigos de verificación SMS",
"Sure to delete": "Seguro que eliminar",
@@ -573,11 +596,13 @@
"plan": {
"Edit Plan": "Edit Plan",
"New Plan": "New Plan",
"Price per month": "Price per month",
"Price per month - Tooltip": "Price per month - Tooltip",
"Price per year": "Price per year",
"Price per year - Tooltip": "Price per year - Tooltip",
"per month": "por mes"
"Period": "Period",
"Period - Tooltip": "Period - Tooltip",
"Price": "Price",
"Price - Tooltip": "Price - Tooltip",
"Related product": "Related product",
"per month": "por mes",
"per year": "per year"
},
"pricing": {
"Copy pricing page URL": "Copiar URL de la página de precios",
@@ -589,6 +614,7 @@
"Trial duration": "Duración del período de prueba",
"Trial duration - Tooltip": "Duración del período de prueba",
"days trial available!": "días de prueba disponibles",
"paid-user do not have active subscription or pending subscription, please select a plan to buy": "paid-user do not have active subscription or pending subscription, please select a plan to buy",
"pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "URL de la página de precios copiada correctamente al portapapeles, péguela en una ventana de incógnito u otro navegador"
},
"product": {
@@ -600,17 +626,16 @@
"Detail - Tooltip": "Detalle del producto",
"Dummy": "Dummy",
"Edit Product": "Editar Producto",
"I have completed the payment": "He completado el pago",
"Image": "Imagen",
"Image - Tooltip": "Imagen del producto",
"New Product": "Nuevo producto",
"Pay": "Pagar",
"PayPal": "PayPal",
"Payment cancelled": "Payment cancelled",
"Payment failed": "Payment failed",
"Payment providers": "Proveedores de pago",
"Payment providers - Tooltip": "Proveedores de servicios de pago",
"Placing order...": "Haciendo un pedido...",
"Please provide your username in the remark": "Por favor proporcione su nombre de usuario en el comentario",
"Please scan the QR code to pay": "Por favor, escanee el código QR para pagar",
"Price": "Precio",
"Price - Tooltip": "Precio del producto",
"Quantity": "Cantidad",
@@ -672,8 +697,8 @@
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copiar",
"DB Test": "DB Test",
"DB Test - Tooltip": "DB Test - Tooltip",
"DB test": "DB test",
"DB test - Tooltip": "DB test - Tooltip",
"Disable SSL": "Desactivar SSL",
"Disable SSL - Tooltip": "¿Hay que desactivar el protocolo SSL al comunicarse con el servidor STMP?",
"Domain": "Dominio",
@@ -700,6 +725,10 @@
"Internal": "Internal",
"Issuer URL": "URL del emisor",
"Issuer URL - Tooltip": "URL del emisor",
"Key ID": "Key ID",
"Key ID - Tooltip": "Key ID - Tooltip",
"Key text": "Key text",
"Key text - Tooltip": "Key text - Tooltip",
"Link copied to clipboard successfully": "Enlace copiado al portapapeles satisfactoriamente",
"Metadata": "Metadatos",
"Metadata - Tooltip": "Metadatos SAML",
@@ -754,6 +783,10 @@
"Sender Id - Tooltip": "Sender Id - Tooltip",
"Sender number": "Sender number",
"Sender number - Tooltip": "Sender number - Tooltip",
"Service ID identifier": "Service ID identifier",
"Service ID identifier - Tooltip": "Service ID identifier - Tooltip",
"Service account JSON": "Service account JSON",
"Service account JSON - Tooltip": "Service account JSON - Tooltip",
"Sign Name": "Firma de Nombre",
"Sign Name - Tooltip": "Nombre de la firma a ser utilizada",
"Sign request": "Solicitud de firma",
@@ -764,12 +797,15 @@
"Signup HTML": "Registro HTML",
"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",
"Silent": "Silent",
"Site key": "Clave del sitio",
"Site key - Tooltip": "Clave del sitio",
"Sliding Validation": "Sliding Validation",
"Sub type": "Subtipo",
"Sub type - Tooltip": "Subtipo",
"Team ID": "Team ID",
"Team ID - Tooltip": "Team ID - Tooltip",
"Template code": "Código de plantilla",
"Template code - Tooltip": "Código de plantilla",
"Test Email": "Correo de prueba",
@@ -780,6 +816,8 @@
"Token URL - Tooltip": "URL de token",
"Type": "Tipo",
"Type - Tooltip": "Seleccionar un tipo",
"User flow": "User flow",
"User flow - Tooltip": "User flow - Tooltip",
"User mapping": "User mapping",
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "URL de información del usuario",
@@ -801,6 +839,8 @@
"New Role": "Nuevo rol",
"Sub domains": "Subdominios",
"Sub domains - Tooltip": "Dominios incluidos en el rol actual",
"Sub groups": "Sub groups",
"Sub groups - Tooltip": "Sub groups - Tooltip",
"Sub roles": "Roles secundarios",
"Sub roles - Tooltip": "Roles incluidos en el rol actual",
"Sub users": "Subusuarios",
@@ -812,6 +852,9 @@
"Confirm": "Confirmar",
"Decline": "Declive",
"Have account?": "¿Tiene una cuenta?",
"Label": "Label",
"Label HTML": "Label HTML",
"Placeholder": "Placeholder",
"Please accept the agreement!": "¡Por favor, acepta el acuerdo!",
"Please click the below button to sign in": "Por favor, haga clic en el botón de abajo para iniciar sesión",
"Please confirm your password!": "¡Por favor confirma tu contraseña!",
@@ -830,6 +873,11 @@
"Please select your country/region!": "¡Por favor seleccione su país/región!",
"Terms of Use": "Términos de uso",
"Terms of Use - Tooltip": "Términos de uso que los usuarios necesitan leer y aceptar durante el registro",
"Text 1": "Text 1",
"Text 2": "Text 2",
"Text 3": "Text 3",
"Text 4": "Text 4",
"Text 5": "Text 5",
"The input is not invoice Tax ID!": "¡La entrada no es el ID fiscal de la factura!",
"The input is not invoice title!": "¡El entrada no es el título de la factura!",
"The input is not valid Email!": "¡La entrada no es un correo electrónico válido!",
@@ -841,14 +889,19 @@
"sign in now": "Inicie sesión ahora"
},
"subscription": {
"Duration": "Duración",
"Duration - Tooltip": "Duración de la suscripción",
"Active": "Active",
"Edit Subscription": "Edit Subscription",
"End date": "Fecha de finalización",
"End date - Tooltip": "Fecha de finalización",
"End time": "End time",
"End time - Tooltip": "End time - Tooltip",
"Error": "Error",
"Expired": "Expired",
"New Subscription": "New Subscription",
"Start date": "Fecha de inicio",
"Start date - Tooltip": "Fecha de inicio"
"Pending": "Pending",
"Period": "Period",
"Start time": "Start time",
"Start time - Tooltip": "Start time - Tooltip",
"Suspended": "Suspended",
"Upcoming": "Upcoming"
},
"syncer": {
"Affiliation table": "Tabla de afiliación",
@@ -872,6 +925,8 @@
"Is read-only": "Is read-only",
"Is read-only - Tooltip": "Is read-only - Tooltip",
"New Syncer": "Nuevo Syncer",
"SSL mode": "SSL mode",
"SSL mode - Tooltip": "SSL mode - Tooltip",
"Sync interval": "Intervalo de sincronización",
"Sync interval - Tooltip": "Unidad en segundos",
"Table": "Mesa",
@@ -974,6 +1029,8 @@
"Managed accounts": "Cuentas gestionadas",
"Modify password...": "Modificar contraseña...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "Nuevo correo electrónico",
"New Password": "Nueva contraseña",
"New User": "Nuevo Usuario",
@@ -1011,6 +1068,7 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Subir una foto",
"Value": "Value",
"Values": "Valores",
"Verification code sent": "Código de verificación enviado",
"WebAuthn credentials": "Credenciales de WebAuthn",

View File

@@ -12,7 +12,9 @@
"Policies": "Policies",
"Policies - Tooltip": "Casbin policy rules",
"Rule type": "Rule type",
"Sync policies successfully": "Sync policies successfully"
"Sync policies successfully": "Sync policies successfully",
"Use same DB": "Use same DB",
"Use same DB - Tooltip": "Use same DB - Tooltip"
},
"application": {
"Always": "Always",
@@ -30,6 +32,8 @@
"Edit Application": "Edit Application",
"Enable Email linking": "Enable Email linking",
"Enable Email linking - Tooltip": "When using 3rd-party providers to log in, if there is a user in the organization with the same Email, the 3rd-party login method will be automatically associated with that user",
"Enable SAML C14N10": "Enable SAML C14N10",
"Enable SAML C14N10 - Tooltip": "Enable SAML C14N10 - Tooltip",
"Enable SAML compression": "Enable SAML compression",
"Enable SAML compression - Tooltip": "Whether to compress SAML response messages when Casdoor is used as SAML idp",
"Enable WebAuthn signin": "Enable WebAuthn signin",
@@ -42,6 +46,10 @@
"Enable signin session - Tooltip": "Whether Casdoor maintains a session after logging into Casdoor from the application",
"Enable signup": "Enable signup",
"Enable signup - Tooltip": "Whether to allow users to register a new account",
"Failed signin frozen time": "Failed signin frozen time",
"Failed signin frozen time - Tooltip": "Failed signin frozen time - Tooltip",
"Failed signin limit": "Failed signin limit",
"Failed signin limit - Tooltip": "Failed signin limit - Tooltip",
"Failed to sign in": "Failed to sign in",
"File uploaded successfully": "File uploaded successfully",
"First, last": "First, last",
@@ -200,6 +208,8 @@
"Default application - Tooltip": "Default application for users registered directly from the organization page",
"Default avatar": "Default avatar",
"Default avatar - Tooltip": "Default avatar used when newly registered users do not set an avatar image",
"Default password": "Default password",
"Default password - Tooltip": "Default password - Tooltip",
"Delete": "Delete",
"Description": "Description",
"Description - Tooltip": "Detailed description information for reference, Casdoor itself will not use it",
@@ -218,8 +228,10 @@
"Failed to connect to server": "Failed to connect to server",
"Failed to delete": "Failed to delete",
"Failed to enable": "Failed to enable",
"Failed to get TermsOfUse URL": "Failed to get TermsOfUse URL",
"Failed to remove": "Failed to remove",
"Failed to save": "Failed to save",
"Failed to sync": "Failed to sync",
"Failed to verify": "Failed to verify",
"Favicon": "Favicon",
"Favicon - Tooltip": "Favicon icon URL used in all Casdoor pages of the organization",
@@ -251,6 +263,8 @@
"MFA items - Tooltip": "MFA items - Tooltip",
"Master password": "Master password",
"Master password - Tooltip": "Can be used to log in to all users under this organization, making it convenient for administrators to log in as this user to solve technical issues",
"Master verification code": "Master verification code",
"Master verification code - Tooltip": "Master verification code - Tooltip",
"Menu": "Menu",
"Method": "Method",
"Model": "Model",
@@ -272,6 +286,8 @@
"Password salt - Tooltip": "Random parameter used for password encryption",
"Password type": "Password type",
"Password type - Tooltip": "Storage format of passwords in the database",
"Payment": "Payment",
"Payment - Tooltip": "Payment - Tooltip",
"Payments": "Payments",
"Permissions": "Permissions",
"Permissions - Tooltip": "Permissions owned by this user",
@@ -283,6 +299,8 @@
"Plans - Tooltip": "Plans - Tooltip",
"Preview": "Preview",
"Preview - Tooltip": "Preview the configured effects",
"Pricing": "Pricing",
"Pricing - Tooltip": "Pricing - Tooltip",
"Pricings": "Pricings",
"Products": "Products",
"Provider": "Provider",
@@ -296,6 +314,10 @@
"Role - Tooltip": "Role - Tooltip",
"Roles": "Roles",
"Roles - Tooltip": "Roles that the user belongs to",
"Root cert": "Root cert",
"Root cert - Tooltip": "Root cert - Tooltip",
"SAML attributes": "SAML attributes",
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
"Save": "Save",
"Save & Exit": "Save & Exit",
"Session ID": "Session ID",
@@ -318,6 +340,7 @@
"Successfully removed": "Successfully removed",
"Successfully saved": "Successfully saved",
"Successfully sent": "Successfully sent",
"Successfully synced": "Successfully synced",
"Supported country codes": "Supported country codes",
"Supported country codes - Tooltip": "Country codes supported by the organization. These codes can be selected as a prefix when sending SMS verification codes",
"Sure to delete": "Sure to delete",
@@ -573,11 +596,13 @@
"plan": {
"Edit Plan": "Edit Plan",
"New Plan": "New Plan",
"Price per month": "Price per month",
"Price per month - Tooltip": "Price per month - Tooltip",
"Price per year": "Price per year",
"Price per year - Tooltip": "Price per year - Tooltip",
"per month": "per month"
"Period": "Period",
"Period - Tooltip": "Period - Tooltip",
"Price": "Price",
"Price - Tooltip": "Price - Tooltip",
"Related product": "Related product",
"per month": "per month",
"per year": "per year"
},
"pricing": {
"Copy pricing page URL": "Copy pricing page URL",
@@ -589,6 +614,7 @@
"Trial duration": "Trial duration",
"Trial duration - Tooltip": "Trial duration period",
"days trial available!": "days trial available!",
"paid-user do not have active subscription or pending subscription, please select a plan to buy": "paid-user do not have active subscription or pending subscription, please select a plan to buy",
"pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser"
},
"product": {
@@ -600,17 +626,16 @@
"Detail - Tooltip": "Detail of product",
"Dummy": "Dummy",
"Edit Product": "Edit Product",
"I have completed the payment": "I have completed the payment",
"Image": "Image",
"Image - Tooltip": "Image of product",
"New Product": "New Product",
"Pay": "Pay",
"PayPal": "PayPal",
"Payment cancelled": "Payment cancelled",
"Payment failed": "Payment failed",
"Payment providers": "Payment providers",
"Payment providers - Tooltip": "Providers of payment services",
"Placing order...": "Placing order...",
"Please provide your username in the remark": "Please provide your username in the remark",
"Please scan the QR code to pay": "Please scan the QR code to pay",
"Price": "Price",
"Price - Tooltip": "Price of product",
"Quantity": "Quantity",
@@ -672,8 +697,8 @@
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copy",
"DB Test": "DB Test",
"DB Test - Tooltip": "DB Test - Tooltip",
"DB test": "DB test",
"DB test - Tooltip": "DB test - Tooltip",
"Disable SSL": "Disable SSL",
"Disable SSL - Tooltip": "Whether to disable SSL protocol when communicating with STMP server",
"Domain": "Domain",
@@ -700,6 +725,10 @@
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
"Key ID": "Key ID",
"Key ID - Tooltip": "Key ID - Tooltip",
"Key text": "Key text",
"Key text - Tooltip": "Key text - Tooltip",
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
"Metadata": "Metadata",
"Metadata - Tooltip": "SAML metadata",
@@ -754,6 +783,10 @@
"Sender Id - Tooltip": "Sender Id - Tooltip",
"Sender number": "Sender number",
"Sender number - Tooltip": "Sender number - Tooltip",
"Service ID identifier": "Service ID identifier",
"Service ID identifier - Tooltip": "Service ID identifier - Tooltip",
"Service account JSON": "Service account JSON",
"Service account JSON - Tooltip": "Service account JSON - Tooltip",
"Sign Name": "Sign Name",
"Sign Name - Tooltip": "Name of the signature to be used",
"Sign request": "Sign request",
@@ -764,12 +797,15 @@
"Signup HTML": "Signup HTML",
"Signup HTML - Edit": "Signup HTML - Edit",
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
"Signup group": "Signup group",
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Team ID": "Team ID",
"Team ID - Tooltip": "Team ID - Tooltip",
"Template code": "Template code",
"Template code - Tooltip": "Template code",
"Test Email": "Test Email",
@@ -780,6 +816,8 @@
"Token URL - Tooltip": "Token URL",
"Type": "Type",
"Type - Tooltip": "Select a type",
"User flow": "User flow",
"User flow - Tooltip": "User flow - Tooltip",
"User mapping": "User mapping",
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URL",
@@ -801,6 +839,8 @@
"New Role": "New Role",
"Sub domains": "Sub domains",
"Sub domains - Tooltip": "Domains included in the current role",
"Sub groups": "Sub groups",
"Sub groups - Tooltip": "Sub groups - Tooltip",
"Sub roles": "Sub roles",
"Sub roles - Tooltip": "Roles included in the current role",
"Sub users": "Sub users",
@@ -812,6 +852,9 @@
"Confirm": "Confirm",
"Decline": "Decline",
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",
"Please confirm your password!": "Please confirm your password!",
@@ -830,6 +873,11 @@
"Please select your country/region!": "Please select your country/region!",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
"Text 2": "Text 2",
"Text 3": "Text 3",
"Text 4": "Text 4",
"Text 5": "Text 5",
"The input is not invoice Tax ID!": "The input is not invoice Tax ID!",
"The input is not invoice title!": "The input is not invoice title!",
"The input is not valid Email!": "The input is not valid Email!",
@@ -841,14 +889,19 @@
"sign in now": "sign in now"
},
"subscription": {
"Duration": "Duration",
"Duration - Tooltip": "Subscription duration",
"Active": "Active",
"Edit Subscription": "Edit Subscription",
"End date": "End date",
"End date - Tooltip": "End date",
"End time": "End time",
"End time - Tooltip": "End time - Tooltip",
"Error": "Error",
"Expired": "Expired",
"New Subscription": "New Subscription",
"Start date": "Start date",
"Start date - Tooltip": "Start date"
"Pending": "Pending",
"Period": "Period",
"Start time": "Start time",
"Start time - Tooltip": "Start time - Tooltip",
"Suspended": "Suspended",
"Upcoming": "Upcoming"
},
"syncer": {
"Affiliation table": "Affiliation table",
@@ -872,6 +925,8 @@
"Is read-only": "Is read-only",
"Is read-only - Tooltip": "Is read-only - Tooltip",
"New Syncer": "New Syncer",
"SSL mode": "SSL mode",
"SSL mode - Tooltip": "SSL mode - Tooltip",
"Sync interval": "Sync interval",
"Sync interval - Tooltip": "Unit in seconds",
"Table": "Table",
@@ -974,6 +1029,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1011,6 +1068,7 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -12,7 +12,9 @@
"Policies": "Policies",
"Policies - Tooltip": "Casbin policy rules",
"Rule type": "Rule type",
"Sync policies successfully": "Sync policies successfully"
"Sync policies successfully": "Sync policies successfully",
"Use same DB": "Use same DB",
"Use same DB - Tooltip": "Use same DB - Tooltip"
},
"application": {
"Always": "Always",
@@ -30,6 +32,8 @@
"Edit Application": "Edit Application",
"Enable Email linking": "Enable Email linking",
"Enable Email linking - Tooltip": "When using 3rd-party providers to log in, if there is a user in the organization with the same Email, the 3rd-party login method will be automatically associated with that user",
"Enable SAML C14N10": "Enable SAML C14N10",
"Enable SAML C14N10 - Tooltip": "Enable SAML C14N10 - Tooltip",
"Enable SAML compression": "Enable SAML compression",
"Enable SAML compression - Tooltip": "Whether to compress SAML response messages when Casdoor is used as SAML idp",
"Enable WebAuthn signin": "Enable WebAuthn signin",
@@ -42,6 +46,10 @@
"Enable signin session - Tooltip": "Whether Casdoor maintains a session after logging into Casdoor from the application",
"Enable signup": "Enable signup",
"Enable signup - Tooltip": "Whether to allow users to register a new account",
"Failed signin frozen time": "Failed signin frozen time",
"Failed signin frozen time - Tooltip": "Failed signin frozen time - Tooltip",
"Failed signin limit": "Failed signin limit",
"Failed signin limit - Tooltip": "Failed signin limit - Tooltip",
"Failed to sign in": "Failed to sign in",
"File uploaded successfully": "File uploaded successfully",
"First, last": "First, last",
@@ -200,6 +208,8 @@
"Default application - Tooltip": "Default application for users registered directly from the organization page",
"Default avatar": "Default avatar",
"Default avatar - Tooltip": "Default avatar used when newly registered users do not set an avatar image",
"Default password": "Default password",
"Default password - Tooltip": "Default password - Tooltip",
"Delete": "Delete",
"Description": "Description",
"Description - Tooltip": "Detailed description information for reference, Casdoor itself will not use it",
@@ -218,8 +228,10 @@
"Failed to connect to server": "Failed to connect to server",
"Failed to delete": "Failed to delete",
"Failed to enable": "Failed to enable",
"Failed to get TermsOfUse URL": "Failed to get TermsOfUse URL",
"Failed to remove": "Failed to remove",
"Failed to save": "Failed to save",
"Failed to sync": "Failed to sync",
"Failed to verify": "Failed to verify",
"Favicon": "Favicon",
"Favicon - Tooltip": "Favicon icon URL used in all Casdoor pages of the organization",
@@ -251,6 +263,8 @@
"MFA items - Tooltip": "MFA items - Tooltip",
"Master password": "Master password",
"Master password - Tooltip": "Can be used to log in to all users under this organization, making it convenient for administrators to log in as this user to solve technical issues",
"Master verification code": "Master verification code",
"Master verification code - Tooltip": "Master verification code - Tooltip",
"Menu": "Menu",
"Method": "Method",
"Model": "Model",
@@ -272,6 +286,8 @@
"Password salt - Tooltip": "Random parameter used for password encryption",
"Password type": "Password type",
"Password type - Tooltip": "Storage format of passwords in the database",
"Payment": "Payment",
"Payment - Tooltip": "Payment - Tooltip",
"Payments": "Payments",
"Permissions": "Permissions",
"Permissions - Tooltip": "Permissions owned by this user",
@@ -283,6 +299,8 @@
"Plans - Tooltip": "Plans - Tooltip",
"Preview": "Preview",
"Preview - Tooltip": "Preview the configured effects",
"Pricing": "Pricing",
"Pricing - Tooltip": "Pricing - Tooltip",
"Pricings": "Pricings",
"Products": "Products",
"Provider": "Provider",
@@ -296,6 +314,10 @@
"Role - Tooltip": "Role - Tooltip",
"Roles": "Roles",
"Roles - Tooltip": "Roles that the user belongs to",
"Root cert": "Root cert",
"Root cert - Tooltip": "Root cert - Tooltip",
"SAML attributes": "SAML attributes",
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
"Save": "Save",
"Save & Exit": "Save & Exit",
"Session ID": "Session ID",
@@ -318,6 +340,7 @@
"Successfully removed": "Successfully removed",
"Successfully saved": "Successfully saved",
"Successfully sent": "Successfully sent",
"Successfully synced": "Successfully synced",
"Supported country codes": "Supported country codes",
"Supported country codes - Tooltip": "Country codes supported by the organization. These codes can be selected as a prefix when sending SMS verification codes",
"Sure to delete": "Sure to delete",
@@ -573,11 +596,13 @@
"plan": {
"Edit Plan": "Edit Plan",
"New Plan": "New Plan",
"Price per month": "Price per month",
"Price per month - Tooltip": "Price per month - Tooltip",
"Price per year": "Price per year",
"Price per year - Tooltip": "Price per year - Tooltip",
"per month": "per month"
"Period": "Period",
"Period - Tooltip": "Period - Tooltip",
"Price": "Price",
"Price - Tooltip": "Price - Tooltip",
"Related product": "Related product",
"per month": "per month",
"per year": "per year"
},
"pricing": {
"Copy pricing page URL": "Copy pricing page URL",
@@ -589,6 +614,7 @@
"Trial duration": "Trial duration",
"Trial duration - Tooltip": "Trial duration period",
"days trial available!": "days trial available!",
"paid-user do not have active subscription or pending subscription, please select a plan to buy": "paid-user do not have active subscription or pending subscription, please select a plan to buy",
"pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser"
},
"product": {
@@ -600,17 +626,16 @@
"Detail - Tooltip": "Detail of product",
"Dummy": "Dummy",
"Edit Product": "Edit Product",
"I have completed the payment": "I have completed the payment",
"Image": "Image",
"Image - Tooltip": "Image of product",
"New Product": "New Product",
"Pay": "Pay",
"PayPal": "PayPal",
"Payment cancelled": "Payment cancelled",
"Payment failed": "Payment failed",
"Payment providers": "Payment providers",
"Payment providers - Tooltip": "Providers of payment services",
"Placing order...": "Placing order...",
"Please provide your username in the remark": "Please provide your username in the remark",
"Please scan the QR code to pay": "Please scan the QR code to pay",
"Price": "Price",
"Price - Tooltip": "Price of product",
"Quantity": "Quantity",
@@ -672,8 +697,8 @@
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copy",
"DB Test": "DB Test",
"DB Test - Tooltip": "DB Test - Tooltip",
"DB test": "DB test",
"DB test - Tooltip": "DB test - Tooltip",
"Disable SSL": "Disable SSL",
"Disable SSL - Tooltip": "Whether to disable SSL protocol when communicating with STMP server",
"Domain": "Domain",
@@ -700,6 +725,10 @@
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
"Key ID": "Key ID",
"Key ID - Tooltip": "Key ID - Tooltip",
"Key text": "Key text",
"Key text - Tooltip": "Key text - Tooltip",
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
"Metadata": "Metadata",
"Metadata - Tooltip": "SAML metadata",
@@ -754,6 +783,10 @@
"Sender Id - Tooltip": "Sender Id - Tooltip",
"Sender number": "Sender number",
"Sender number - Tooltip": "Sender number - Tooltip",
"Service ID identifier": "Service ID identifier",
"Service ID identifier - Tooltip": "Service ID identifier - Tooltip",
"Service account JSON": "Service account JSON",
"Service account JSON - Tooltip": "Service account JSON - Tooltip",
"Sign Name": "Sign Name",
"Sign Name - Tooltip": "Name of the signature to be used",
"Sign request": "Sign request",
@@ -764,12 +797,15 @@
"Signup HTML": "Signup HTML",
"Signup HTML - Edit": "Signup HTML - Edit",
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
"Signup group": "Signup group",
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Team ID": "Team ID",
"Team ID - Tooltip": "Team ID - Tooltip",
"Template code": "Template code",
"Template code - Tooltip": "Template code",
"Test Email": "Test Email",
@@ -780,6 +816,8 @@
"Token URL - Tooltip": "Token URL",
"Type": "Type",
"Type - Tooltip": "Select a type",
"User flow": "User flow",
"User flow - Tooltip": "User flow - Tooltip",
"User mapping": "User mapping",
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URL",
@@ -801,6 +839,8 @@
"New Role": "New Role",
"Sub domains": "Sub domains",
"Sub domains - Tooltip": "Domains included in the current role",
"Sub groups": "Sub groups",
"Sub groups - Tooltip": "Sub groups - Tooltip",
"Sub roles": "Sub roles",
"Sub roles - Tooltip": "Roles included in the current role",
"Sub users": "Sub users",
@@ -812,6 +852,9 @@
"Confirm": "Confirm",
"Decline": "Decline",
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",
"Please confirm your password!": "Please confirm your password!",
@@ -830,6 +873,11 @@
"Please select your country/region!": "Please select your country/region!",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
"Text 2": "Text 2",
"Text 3": "Text 3",
"Text 4": "Text 4",
"Text 5": "Text 5",
"The input is not invoice Tax ID!": "The input is not invoice Tax ID!",
"The input is not invoice title!": "The input is not invoice title!",
"The input is not valid Email!": "The input is not valid Email!",
@@ -841,14 +889,19 @@
"sign in now": "sign in now"
},
"subscription": {
"Duration": "Duration",
"Duration - Tooltip": "Subscription duration",
"Active": "Active",
"Edit Subscription": "Edit Subscription",
"End date": "End date",
"End date - Tooltip": "End date",
"End time": "End time",
"End time - Tooltip": "End time - Tooltip",
"Error": "Error",
"Expired": "Expired",
"New Subscription": "New Subscription",
"Start date": "Start date",
"Start date - Tooltip": "Start date"
"Pending": "Pending",
"Period": "Period",
"Start time": "Start time",
"Start time - Tooltip": "Start time - Tooltip",
"Suspended": "Suspended",
"Upcoming": "Upcoming"
},
"syncer": {
"Affiliation table": "Affiliation table",
@@ -872,6 +925,8 @@
"Is read-only": "Is read-only",
"Is read-only - Tooltip": "Is read-only - Tooltip",
"New Syncer": "New Syncer",
"SSL mode": "SSL mode",
"SSL mode - Tooltip": "SSL mode - Tooltip",
"Sync interval": "Sync interval",
"Sync interval - Tooltip": "Unit in seconds",
"Table": "Table",
@@ -974,6 +1029,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1011,6 +1068,7 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -12,7 +12,9 @@
"Policies": "Règles",
"Policies - Tooltip": "Règles de Casbin",
"Rule type": "Type de règle",
"Sync policies successfully": "Synchronisation des règles réussie"
"Sync policies successfully": "Synchronisation des règles réussie",
"Use same DB": "Use same DB",
"Use same DB - Tooltip": "Use same DB - Tooltip"
},
"application": {
"Always": "Toujours",
@@ -30,6 +32,8 @@
"Edit Application": "Modifier l'application",
"Enable Email linking": "Autoriser à lier l'e-mail",
"Enable Email linking - Tooltip": "Lorsqu'un fournisseur tiers est utilisé pour se connecter, si un compte existe dans l'organisation avec la même adresse e-mail, la méthode de connexion tierce sera automatiquement associée à ce compte",
"Enable SAML C14N10": "Enable SAML C14N10",
"Enable SAML C14N10 - Tooltip": "Enable SAML C14N10 - Tooltip",
"Enable SAML compression": "Activer la compression SAML",
"Enable SAML compression - Tooltip": "Compresser ou non les messages de réponse SAML lorsque Casdoor est utilisé en tant que fournisseur d'identité SAML",
"Enable WebAuthn signin": "Autoriser la connexion via WebAuthn",
@@ -42,6 +46,10 @@
"Enable signin session - Tooltip": "Conserver une session après la connexion à Casdoor à partir de l'application",
"Enable signup": "Activer l'inscription",
"Enable signup - Tooltip": "Autoriser la création de nouveaux comptes",
"Failed signin frozen time": "Failed signin frozen time",
"Failed signin frozen time - Tooltip": "Failed signin frozen time - Tooltip",
"Failed signin limit": "Failed signin limit",
"Failed signin limit - Tooltip": "Failed signin limit - Tooltip",
"Failed to sign in": "Échec de la connexion",
"File uploaded successfully": "Fichier téléchargé avec succès",
"First, last": "Prénom, nom",
@@ -200,6 +208,8 @@
"Default application - Tooltip": "Application par défaut pour les comptes enregistrés directement depuis la page de l'organisation",
"Default avatar": "Avatar par défaut",
"Default avatar - Tooltip": "Avatar par défaut utilisé lorsque des comptes nouvellement enregistrés ne définissent pas d'image d'avatar",
"Default password": "Default password",
"Default password - Tooltip": "Default password - Tooltip",
"Delete": "Supprimer",
"Description": "Description",
"Description - Tooltip": "Description détaillée pour référence, Casdoor ne l'utilisera pas en soi",
@@ -218,8 +228,10 @@
"Failed to connect to server": "Échec de la connexion au serveur",
"Failed to delete": "Échec de la suppression",
"Failed to enable": "Échec de l'activation",
"Failed to get TermsOfUse URL": "Failed to get TermsOfUse URL",
"Failed to remove": "Échec de la suppression",
"Failed to save": "Échec de sauvegarde",
"Failed to sync": "Failed to sync",
"Failed to verify": "Échec de la vérification",
"Favicon": "Icône du site",
"Favicon - Tooltip": "L'URL de l'icône « favicon » utilisée dans toutes les pages Casdoor de l'organisation",
@@ -251,6 +263,8 @@
"MFA items - Tooltip": "Types d'authentification multifacteur - Infobulle",
"Master password": "Mot de passe passe-partout",
"Master password - Tooltip": "Mot de passe qui peut être utilisé pour se connecter à tous les comptes sous cette organisation, ce qui facilite la connexion des administrateurs et administratrices en tant que ce compte pour résoudre les problèmes techniques",
"Master verification code": "Master verification code",
"Master verification code - Tooltip": "Master verification code - Tooltip",
"Menu": "Menu",
"Method": "Méthode",
"Model": "Modèle",
@@ -272,6 +286,8 @@
"Password salt - Tooltip": "Paramètre aléatoire utilisé pour le chiffrement des mots de passe",
"Password type": "Type de mot de passe",
"Password type - Tooltip": "Format de stockage des mots de passe dans la base de données",
"Payment": "Payment",
"Payment - Tooltip": "Payment - Tooltip",
"Payments": "Paiements",
"Permissions": "Permissions",
"Permissions - Tooltip": "Permissions détenues par ce compte",
@@ -283,6 +299,8 @@
"Plans - Tooltip": "Offres - Infobulle",
"Preview": "Aperçu",
"Preview - Tooltip": "Prévisualisation des effets configurés",
"Pricing": "Pricing",
"Pricing - Tooltip": "Pricing - Tooltip",
"Pricings": "Tarifs",
"Products": "Produits",
"Provider": "Fournisseur",
@@ -296,6 +314,10 @@
"Role - Tooltip": "Rôle - Infobulle",
"Roles": "Rôles",
"Roles - Tooltip": "Les rôles auxquels le compte appartient",
"Root cert": "Root cert",
"Root cert - Tooltip": "Root cert - Tooltip",
"SAML attributes": "SAML attributes",
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
"Save": "Enregistrer",
"Save & Exit": "Enregistrer et quitter",
"Session ID": "Identifiant de session",
@@ -318,6 +340,7 @@
"Successfully removed": "Retiré avec succès",
"Successfully saved": "Enregistré avec succès",
"Successfully sent": "Envoyé avec succès",
"Successfully synced": "Successfully synced",
"Supported country codes": "Indicatifs téléphoniques acceptés",
"Supported country codes - Tooltip": "Indicatifs téléphoniques internationaux acceptés par l'organisation. Ces indicatifs peuvent être sélectionnés comme préfixe lors de l'envoi de codes de vérification par SMS",
"Sure to delete": "Certain⋅e de supprimer",
@@ -573,11 +596,13 @@
"plan": {
"Edit Plan": "Modifier l'offre",
"New Plan": "Nouvelle offre",
"Price per month": "Prix par mois",
"Price per month - Tooltip": "Prix par mois - Infobulle",
"Price per year": "Prix annuel",
"Price per year - Tooltip": "Prix annuel - Infobulle",
"per month": "par mois"
"Period": "Period",
"Period - Tooltip": "Period - Tooltip",
"Price": "Price",
"Price - Tooltip": "Price - Tooltip",
"Related product": "Related product",
"per month": "par mois",
"per year": "per year"
},
"pricing": {
"Copy pricing page URL": "Copier l'URL de la page tarifs",
@@ -589,6 +614,7 @@
"Trial duration": "Durée de l'essai",
"Trial duration - Tooltip": "Durée de la période d'essai",
"days trial available!": "jours d'essai disponibles !",
"paid-user do not have active subscription or pending subscription, please select a plan to buy": "paid-user do not have active subscription or pending subscription, please select a plan to buy",
"pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "URL de la page tarifs copiée avec succès dans le presse-papiers, veuillez la coller dans une fenêtre de navigation privée ou un autre navigateur"
},
"product": {
@@ -600,17 +626,16 @@
"Detail - Tooltip": "Détail du produit",
"Dummy": "Exemple",
"Edit Product": "Modifier le produit",
"I have completed the payment": "J'ai effectué le paiement",
"Image": "Image",
"Image - Tooltip": "Image du produit",
"New Product": "Nouveau produit",
"Pay": "Payer",
"PayPal": "PayPal",
"Payment cancelled": "Payment cancelled",
"Payment failed": "Payment failed",
"Payment providers": "Fournisseurs de paiement",
"Payment providers - Tooltip": "Fournisseurs de services de paiement",
"Placing order...": "Passer une commande...",
"Please provide your username in the remark": "Veuillez indiquer votre identifiant dans la remarque",
"Please scan the QR code to pay": "Veuillez scanner le code QR pour effectuer le paiement",
"Price": "Prix",
"Price - Tooltip": "Prix du produit",
"Quantity": "Quantité",
@@ -672,8 +697,8 @@
"Content": "Contenu",
"Content - Tooltip": "Contenu - Infobulle",
"Copy": "Copie",
"DB Test": "Test de la BD",
"DB Test - Tooltip": "Test de la BD - Infobulle",
"DB test": "DB test",
"DB test - Tooltip": "DB test - Tooltip",
"Disable SSL": "Désactiver SSL",
"Disable SSL - Tooltip": "Désactiver le protocole SSL lors de la communication avec le serveur STMP",
"Domain": "Domaine",
@@ -700,6 +725,10 @@
"Internal": "Interne",
"Issuer URL": "URL de l'émetteur",
"Issuer URL - Tooltip": "URL de l'émetteur",
"Key ID": "Key ID",
"Key ID - Tooltip": "Key ID - Tooltip",
"Key text": "Key text",
"Key text - Tooltip": "Key text - Tooltip",
"Link copied to clipboard successfully": "Lien copié avec succès dans le presse-papiers",
"Metadata": "Métadonnées",
"Metadata - Tooltip": "Métadonnées SAML",
@@ -754,6 +783,10 @@
"Sender Id - Tooltip": "ID de l'expéditeur - Infobulle",
"Sender number": "Numéro de l'expéditeur",
"Sender number - Tooltip": "Numéro de l'expéditeur - Infobulle",
"Service ID identifier": "Service ID identifier",
"Service ID identifier - Tooltip": "Service ID identifier - Tooltip",
"Service account JSON": "Service account JSON",
"Service account JSON - Tooltip": "Service account JSON - Tooltip",
"Sign Name": "Nom de signature",
"Sign Name - Tooltip": "Nom de la signature à utiliser",
"Sign request": "Demande de signature",
@@ -764,12 +797,15 @@
"Signup HTML": "HTML de la page d'inscription",
"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",
"Silent": "Silencieux",
"Site key": "Clé de site",
"Site key - Tooltip": "Clé de site",
"Sliding Validation": "Validation glissante",
"Sub type": "Sous-type",
"Sub type - Tooltip": "Sous-type",
"Team ID": "Team ID",
"Team ID - Tooltip": "Team ID - Tooltip",
"Template code": "Code modèle",
"Template code - Tooltip": "Code de modèle",
"Test Email": "E-mail de test",
@@ -780,6 +816,8 @@
"Token URL - Tooltip": "URL de jeton",
"Type": "Type de texte",
"Type - Tooltip": "Sélectionnez un type",
"User flow": "User flow",
"User flow - Tooltip": "User flow - Tooltip",
"User mapping": "Association de compte",
"User mapping - Tooltip": "Mapping utilisateur - Infobulle",
"UserInfo URL": "URL d'informations utilisateur",
@@ -801,6 +839,8 @@
"New Role": "Nouveau rôle",
"Sub domains": "Domaines",
"Sub domains - Tooltip": "Domaines pour lesquels s'appliquent le rôle ou la permission",
"Sub groups": "Sub groups",
"Sub groups - Tooltip": "Sub groups - Tooltip",
"Sub roles": "Rôles",
"Sub roles - Tooltip": "Rôles pour lesquels s'appliquent le rôle ou la permission",
"Sub users": "Comptes",
@@ -812,6 +852,9 @@
"Confirm": "Confirmer",
"Decline": "Décliner",
"Have account?": "Avez-vous un compte ?",
"Label": "Label",
"Label HTML": "Label HTML",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Veuillez accepter l'accord !",
"Please click the below button to sign in": "Veuillez cliquer sur le bouton ci-dessous pour vous connecter",
"Please confirm your password!": "Veuillez confirmer votre mot de passe !",
@@ -830,6 +873,11 @@
"Please select your country/region!": "Veuillez sélectionner votre pays/région !",
"Terms of Use": "Conditions d'utilisation",
"Terms of Use - Tooltip": "Conditions d'utilisation qui doivent être lus acceptés lors de l'enregistrement du compte",
"Text 1": "Text 1",
"Text 2": "Text 2",
"Text 3": "Text 3",
"Text 4": "Text 4",
"Text 5": "Text 5",
"The input is not invoice Tax ID!": "L'entrée n'est pas l'identifiant fiscal de la facture !",
"The input is not invoice title!": "L'entrée n'est pas un nom ou une dénomination sociale !",
"The input is not valid Email!": "L'entrée n'est pas une adresse e-mail valide !",
@@ -841,14 +889,19 @@
"sign in now": "Connectez-vous maintenant"
},
"subscription": {
"Duration": "Durée",
"Duration - Tooltip": "Durée de l'abonnement",
"Active": "Active",
"Edit Subscription": "Modifier labonnement",
"End date": "Date de fin",
"End date - Tooltip": "Date de fin",
"End time": "End time",
"End time - Tooltip": "End time - Tooltip",
"Error": "Error",
"Expired": "Expired",
"New Subscription": "Nouvel abonnement",
"Start date": "Date de début",
"Start date - Tooltip": "Date de début"
"Pending": "Pending",
"Period": "Period",
"Start time": "Start time",
"Start time - Tooltip": "Start time - Tooltip",
"Suspended": "Suspended",
"Upcoming": "Upcoming"
},
"syncer": {
"Affiliation table": "Table d'affiliation",
@@ -872,6 +925,8 @@
"Is read-only": "Est en lecture seule",
"Is read-only - Tooltip": "En lecture seule - Infobulle",
"New Syncer": "Nouveau synchroniseur",
"SSL mode": "SSL mode",
"SSL mode - Tooltip": "SSL mode - Tooltip",
"Sync interval": "Intervalle de synchronisation",
"Sync interval - Tooltip": "Unité en secondes",
"Table": "Tableau",
@@ -974,6 +1029,8 @@
"Managed accounts": "Comptes gérés",
"Modify password...": "Modifier le mot de passe...",
"Multi-factor authentication": "Authentification multifacteur",
"Name": "Name",
"Name format": "Name format",
"New Email": "Nouvelle adresse e-mail",
"New Password": "Nouveau mot de passe",
"New User": "Nouveau compte",
@@ -1011,6 +1068,7 @@
"Upload ID card front picture": "Télécharger une photo de l'endroit de la pièce d'identité",
"Upload ID card with person picture": "Télécharger une photo la pièce d'identité avec une personne",
"Upload a photo": "Télécharger une photo",
"Value": "Value",
"Values": "Valeurs",
"Verification code sent": "Code de vérification envoyé",
"WebAuthn credentials": "Identifiants WebAuthn",

View File

@@ -12,7 +12,9 @@
"Policies": "Policies",
"Policies - Tooltip": "Casbin policy rules",
"Rule type": "Rule type",
"Sync policies successfully": "Sync policies successfully"
"Sync policies successfully": "Sync policies successfully",
"Use same DB": "Use same DB",
"Use same DB - Tooltip": "Use same DB - Tooltip"
},
"application": {
"Always": "Always",
@@ -30,6 +32,8 @@
"Edit Application": "Edit Application",
"Enable Email linking": "Enable Email linking",
"Enable Email linking - Tooltip": "When using 3rd-party providers to log in, if there is a user in the organization with the same Email, the 3rd-party login method will be automatically associated with that user",
"Enable SAML C14N10": "Enable SAML C14N10",
"Enable SAML C14N10 - Tooltip": "Enable SAML C14N10 - Tooltip",
"Enable SAML compression": "Enable SAML compression",
"Enable SAML compression - Tooltip": "Whether to compress SAML response messages when Casdoor is used as SAML idp",
"Enable WebAuthn signin": "Enable WebAuthn signin",
@@ -42,6 +46,10 @@
"Enable signin session - Tooltip": "Whether Casdoor maintains a session after logging into Casdoor from the application",
"Enable signup": "Enable signup",
"Enable signup - Tooltip": "Whether to allow users to register a new account",
"Failed signin frozen time": "Failed signin frozen time",
"Failed signin frozen time - Tooltip": "Failed signin frozen time - Tooltip",
"Failed signin limit": "Failed signin limit",
"Failed signin limit - Tooltip": "Failed signin limit - Tooltip",
"Failed to sign in": "Failed to sign in",
"File uploaded successfully": "File uploaded successfully",
"First, last": "First, last",
@@ -200,6 +208,8 @@
"Default application - Tooltip": "Default application for users registered directly from the organization page",
"Default avatar": "Default avatar",
"Default avatar - Tooltip": "Default avatar used when newly registered users do not set an avatar image",
"Default password": "Default password",
"Default password - Tooltip": "Default password - Tooltip",
"Delete": "Delete",
"Description": "Description",
"Description - Tooltip": "Detailed description information for reference, Casdoor itself will not use it",
@@ -218,8 +228,10 @@
"Failed to connect to server": "Failed to connect to server",
"Failed to delete": "Failed to delete",
"Failed to enable": "Failed to enable",
"Failed to get TermsOfUse URL": "Failed to get TermsOfUse URL",
"Failed to remove": "Failed to remove",
"Failed to save": "Failed to save",
"Failed to sync": "Failed to sync",
"Failed to verify": "Failed to verify",
"Favicon": "Favicon",
"Favicon - Tooltip": "Favicon icon URL used in all Casdoor pages of the organization",
@@ -251,6 +263,8 @@
"MFA items - Tooltip": "MFA items - Tooltip",
"Master password": "Master password",
"Master password - Tooltip": "Can be used to log in to all users under this organization, making it convenient for administrators to log in as this user to solve technical issues",
"Master verification code": "Master verification code",
"Master verification code - Tooltip": "Master verification code - Tooltip",
"Menu": "Menu",
"Method": "Method",
"Model": "Model",
@@ -272,6 +286,8 @@
"Password salt - Tooltip": "Random parameter used for password encryption",
"Password type": "Password type",
"Password type - Tooltip": "Storage format of passwords in the database",
"Payment": "Payment",
"Payment - Tooltip": "Payment - Tooltip",
"Payments": "Payments",
"Permissions": "Permissions",
"Permissions - Tooltip": "Permissions owned by this user",
@@ -283,6 +299,8 @@
"Plans - Tooltip": "Plans - Tooltip",
"Preview": "Preview",
"Preview - Tooltip": "Preview the configured effects",
"Pricing": "Pricing",
"Pricing - Tooltip": "Pricing - Tooltip",
"Pricings": "Pricings",
"Products": "Products",
"Provider": "Provider",
@@ -296,6 +314,10 @@
"Role - Tooltip": "Role - Tooltip",
"Roles": "Roles",
"Roles - Tooltip": "Roles that the user belongs to",
"Root cert": "Root cert",
"Root cert - Tooltip": "Root cert - Tooltip",
"SAML attributes": "SAML attributes",
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
"Save": "Save",
"Save & Exit": "Save & Exit",
"Session ID": "Session ID",
@@ -318,6 +340,7 @@
"Successfully removed": "Successfully removed",
"Successfully saved": "Successfully saved",
"Successfully sent": "Successfully sent",
"Successfully synced": "Successfully synced",
"Supported country codes": "Supported country codes",
"Supported country codes - Tooltip": "Country codes supported by the organization. These codes can be selected as a prefix when sending SMS verification codes",
"Sure to delete": "Sure to delete",
@@ -573,11 +596,13 @@
"plan": {
"Edit Plan": "Edit Plan",
"New Plan": "New Plan",
"Price per month": "Price per month",
"Price per month - Tooltip": "Price per month - Tooltip",
"Price per year": "Price per year",
"Price per year - Tooltip": "Price per year - Tooltip",
"per month": "per month"
"Period": "Period",
"Period - Tooltip": "Period - Tooltip",
"Price": "Price",
"Price - Tooltip": "Price - Tooltip",
"Related product": "Related product",
"per month": "per month",
"per year": "per year"
},
"pricing": {
"Copy pricing page URL": "Copy pricing page URL",
@@ -589,6 +614,7 @@
"Trial duration": "Trial duration",
"Trial duration - Tooltip": "Trial duration period",
"days trial available!": "days trial available!",
"paid-user do not have active subscription or pending subscription, please select a plan to buy": "paid-user do not have active subscription or pending subscription, please select a plan to buy",
"pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser"
},
"product": {
@@ -600,17 +626,16 @@
"Detail - Tooltip": "Detail of product",
"Dummy": "Dummy",
"Edit Product": "Edit Product",
"I have completed the payment": "I have completed the payment",
"Image": "Image",
"Image - Tooltip": "Image of product",
"New Product": "New Product",
"Pay": "Pay",
"PayPal": "PayPal",
"Payment cancelled": "Payment cancelled",
"Payment failed": "Payment failed",
"Payment providers": "Payment providers",
"Payment providers - Tooltip": "Providers of payment services",
"Placing order...": "Placing order...",
"Please provide your username in the remark": "Please provide your username in the remark",
"Please scan the QR code to pay": "Please scan the QR code to pay",
"Price": "Price",
"Price - Tooltip": "Price of product",
"Quantity": "Quantity",
@@ -672,8 +697,8 @@
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Copy",
"DB Test": "DB Test",
"DB Test - Tooltip": "DB Test - Tooltip",
"DB test": "DB test",
"DB test - Tooltip": "DB test - Tooltip",
"Disable SSL": "Disable SSL",
"Disable SSL - Tooltip": "Whether to disable SSL protocol when communicating with STMP server",
"Domain": "Domain",
@@ -700,6 +725,10 @@
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
"Key ID": "Key ID",
"Key ID - Tooltip": "Key ID - Tooltip",
"Key text": "Key text",
"Key text - Tooltip": "Key text - Tooltip",
"Link copied to clipboard successfully": "Link copied to clipboard successfully",
"Metadata": "Metadata",
"Metadata - Tooltip": "SAML metadata",
@@ -754,6 +783,10 @@
"Sender Id - Tooltip": "Sender Id - Tooltip",
"Sender number": "Sender number",
"Sender number - Tooltip": "Sender number - Tooltip",
"Service ID identifier": "Service ID identifier",
"Service ID identifier - Tooltip": "Service ID identifier - Tooltip",
"Service account JSON": "Service account JSON",
"Service account JSON - Tooltip": "Service account JSON - Tooltip",
"Sign Name": "Sign Name",
"Sign Name - Tooltip": "Name of the signature to be used",
"Sign request": "Sign request",
@@ -764,12 +797,15 @@
"Signup HTML": "Signup HTML",
"Signup HTML - Edit": "Signup HTML - Edit",
"Signup HTML - Tooltip": "Custom HTML for replacing the default signup page style",
"Signup group": "Signup group",
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Team ID": "Team ID",
"Team ID - Tooltip": "Team ID - Tooltip",
"Template code": "Template code",
"Template code - Tooltip": "Template code",
"Test Email": "Test Email",
@@ -780,6 +816,8 @@
"Token URL - Tooltip": "Token URL",
"Type": "Type",
"Type - Tooltip": "Select a type",
"User flow": "User flow",
"User flow - Tooltip": "User flow - Tooltip",
"User mapping": "User mapping",
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URL",
@@ -801,6 +839,8 @@
"New Role": "New Role",
"Sub domains": "Sub domains",
"Sub domains - Tooltip": "Domains included in the current role",
"Sub groups": "Sub groups",
"Sub groups - Tooltip": "Sub groups - Tooltip",
"Sub roles": "Sub roles",
"Sub roles - Tooltip": "Roles included in the current role",
"Sub users": "Sub users",
@@ -812,6 +852,9 @@
"Confirm": "Confirm",
"Decline": "Decline",
"Have account?": "Have account?",
"Label": "Label",
"Label HTML": "Label HTML",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Please accept the agreement!",
"Please click the below button to sign in": "Please click the below button to sign in",
"Please confirm your password!": "Please confirm your password!",
@@ -830,6 +873,11 @@
"Please select your country/region!": "Please select your country/region!",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
"Text 2": "Text 2",
"Text 3": "Text 3",
"Text 4": "Text 4",
"Text 5": "Text 5",
"The input is not invoice Tax ID!": "The input is not invoice Tax ID!",
"The input is not invoice title!": "The input is not invoice title!",
"The input is not valid Email!": "The input is not valid Email!",
@@ -841,14 +889,19 @@
"sign in now": "sign in now"
},
"subscription": {
"Duration": "Duration",
"Duration - Tooltip": "Subscription duration",
"Active": "Active",
"Edit Subscription": "Edit Subscription",
"End date": "End date",
"End date - Tooltip": "End date",
"End time": "End time",
"End time - Tooltip": "End time - Tooltip",
"Error": "Error",
"Expired": "Expired",
"New Subscription": "New Subscription",
"Start date": "Start date",
"Start date - Tooltip": "Start date"
"Pending": "Pending",
"Period": "Period",
"Start time": "Start time",
"Start time - Tooltip": "Start time - Tooltip",
"Suspended": "Suspended",
"Upcoming": "Upcoming"
},
"syncer": {
"Affiliation table": "Affiliation table",
@@ -872,6 +925,8 @@
"Is read-only": "Is read-only",
"Is read-only - Tooltip": "Is read-only - Tooltip",
"New Syncer": "New Syncer",
"SSL mode": "SSL mode",
"SSL mode - Tooltip": "SSL mode - Tooltip",
"Sync interval": "Sync interval",
"Sync interval - Tooltip": "Unit in seconds",
"Table": "Table",
@@ -974,6 +1029,8 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1011,6 +1068,7 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -12,7 +12,9 @@
"Policies": "Kebijakan",
"Policies - Tooltip": "Kebijakan aturan Casbin",
"Rule type": "Rule type",
"Sync policies successfully": "Sinkronisasi kebijakan berhasil dilakukan"
"Sync policies successfully": "Sinkronisasi kebijakan berhasil dilakukan",
"Use same DB": "Use same DB",
"Use same DB - Tooltip": "Use same DB - Tooltip"
},
"application": {
"Always": "Selalu",
@@ -30,6 +32,8 @@
"Edit Application": "Mengedit aplikasi",
"Enable Email linking": "Aktifkan pengaitan email",
"Enable Email linking - Tooltip": "Ketika menggunakan penyedia layanan pihak ketiga untuk masuk, jika ada pengguna di organisasi dengan email yang sama, metode login pihak ketiga akan secara otomatis terhubung dengan pengguna tersebut",
"Enable SAML C14N10": "Enable SAML C14N10",
"Enable SAML C14N10 - Tooltip": "Enable SAML C14N10 - Tooltip",
"Enable SAML compression": "Aktifkan kompresi SAML",
"Enable SAML compression - Tooltip": "Apakah pesan respons SAML harus dikompres saat Casdoor digunakan sebagai SAML idp?",
"Enable WebAuthn signin": "Aktifkan masuk WebAuthn",
@@ -42,6 +46,10 @@
"Enable signin session - Tooltip": "Apakah Casdoor mempertahankan sesi setelah login ke Casdoor dari aplikasi",
"Enable signup": "Aktifkan pendaftaran",
"Enable signup - Tooltip": "Apakah akan mengizinkan pengguna untuk mendaftar akun baru",
"Failed signin frozen time": "Failed signin frozen time",
"Failed signin frozen time - Tooltip": "Failed signin frozen time - Tooltip",
"Failed signin limit": "Failed signin limit",
"Failed signin limit - Tooltip": "Failed signin limit - Tooltip",
"Failed to sign in": "Gagal masuk",
"File uploaded successfully": "Berkas telah diunggah dengan sukses",
"First, last": "First, last",
@@ -200,6 +208,8 @@
"Default application - Tooltip": "Aplikasi default untuk pengguna yang terdaftar langsung dari halaman organisasi",
"Default avatar": "Avatar default",
"Default avatar - Tooltip": "Avatar default yang digunakan ketika pengguna yang baru terdaftar tidak mengatur gambar avatar",
"Default password": "Default password",
"Default password - Tooltip": "Default password - Tooltip",
"Delete": "Hapus",
"Description": "Deskripsi",
"Description - Tooltip": "Informasi deskripsi terperinci untuk referensi, Casdoor itu sendiri tidak akan menggunakannya",
@@ -218,8 +228,10 @@
"Failed to connect to server": "Gagal terhubung ke server",
"Failed to delete": "Gagal menghapus",
"Failed to enable": "Failed to enable",
"Failed to get TermsOfUse URL": "Failed to get TermsOfUse URL",
"Failed to remove": "Failed to remove",
"Failed to save": "Gagal menyimpan",
"Failed to sync": "Failed to sync",
"Failed to verify": "Failed to verify",
"Favicon": "Favicon",
"Favicon - Tooltip": "URL ikon Favicon yang digunakan di semua halaman Casdoor organisasi",
@@ -251,6 +263,8 @@
"MFA items - Tooltip": "MFA items - Tooltip",
"Master password": "Kata sandi utama",
"Master password - Tooltip": "Dapat digunakan untuk masuk ke semua pengguna di bawah organisasi ini, sehingga memudahkan administrator untuk masuk sebagai pengguna ini untuk menyelesaikan masalah teknis",
"Master verification code": "Master verification code",
"Master verification code - Tooltip": "Master verification code - Tooltip",
"Menu": "Daftar makanan",
"Method": "Metode",
"Model": "Model",
@@ -272,6 +286,8 @@
"Password salt - Tooltip": "Parameter acak yang digunakan untuk enkripsi kata sandi",
"Password type": "Jenis kata sandi",
"Password type - Tooltip": "Format penyimpanan kata sandi di database",
"Payment": "Payment",
"Payment - Tooltip": "Payment - Tooltip",
"Payments": "Pembayaran-pembayaran",
"Permissions": "Izin-izin",
"Permissions - Tooltip": "Izin dimiliki oleh pengguna ini",
@@ -283,6 +299,8 @@
"Plans - Tooltip": "Plans - Tooltip",
"Preview": "Tinjauan",
"Preview - Tooltip": "Mengawali pratinjau efek yang sudah dikonfigurasi",
"Pricing": "Pricing",
"Pricing - Tooltip": "Pricing - Tooltip",
"Pricings": "Harga",
"Products": "Produk",
"Provider": "Penyedia",
@@ -296,6 +314,10 @@
"Role - Tooltip": "Role - Tooltip",
"Roles": "Peran-peran",
"Roles - Tooltip": "Peran-peran yang diikuti oleh pengguna",
"Root cert": "Root cert",
"Root cert - Tooltip": "Root cert - Tooltip",
"SAML attributes": "SAML attributes",
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
"Save": "Menyimpan",
"Save & Exit": "Simpan & Keluar",
"Session ID": "ID sesi",
@@ -318,6 +340,7 @@
"Successfully removed": "Successfully removed",
"Successfully saved": "Berhasil disimpan",
"Successfully sent": "Successfully sent",
"Successfully synced": "Successfully synced",
"Supported country codes": "Kode negara yang didukung",
"Supported country codes - Tooltip": "Kode negara yang didukung oleh organisasi. Kode-kode ini dapat dipilih sebagai awalan saat mengirim kode verifikasi SMS",
"Sure to delete": "Pasti untuk menghapus",
@@ -573,11 +596,13 @@
"plan": {
"Edit Plan": "Edit Plan",
"New Plan": "New Plan",
"Price per month": "Price per month",
"Price per month - Tooltip": "Price per month - Tooltip",
"Price per year": "Price per year",
"Price per year - Tooltip": "Price per year - Tooltip",
"per month": "per bulan"
"Period": "Period",
"Period - Tooltip": "Period - Tooltip",
"Price": "Price",
"Price - Tooltip": "Price - Tooltip",
"Related product": "Related product",
"per month": "per bulan",
"per year": "per year"
},
"pricing": {
"Copy pricing page URL": "Salin URL halaman harga",
@@ -589,6 +614,7 @@
"Trial duration": "Durasi percobaan",
"Trial duration - Tooltip": "Durasi periode percobaan",
"days trial available!": "hari percobaan tersedia!",
"paid-user do not have active subscription or pending subscription, please select a plan to buy": "paid-user do not have active subscription or pending subscription, please select a plan to buy",
"pricing page URL copied to clipboard successfully, please paste it into the incognito window or another browser": "URL halaman harga berhasil disalin ke clipboard, silakan tempelkan ke dalam jendela mode penyamaran atau browser lainnya"
},
"product": {
@@ -600,17 +626,16 @@
"Detail - Tooltip": "Detail produk",
"Dummy": "Dummy",
"Edit Product": "Edit Produk",
"I have completed the payment": "Saya telah menyelesaikan pembayaran",
"Image": "Gambar",
"Image - Tooltip": "Gambar produk",
"New Product": "Produk Baru",
"Pay": "Bayar",
"PayPal": "Paypal",
"Payment cancelled": "Payment cancelled",
"Payment failed": "Payment failed",
"Payment providers": "Penyedia pembayaran",
"Payment providers - Tooltip": "Penyedia layanan pembayaran",
"Placing order...": "Menempatkan pesanan...",
"Please provide your username in the remark": "Tolong berikan nama pengguna Anda dalam komentar",
"Please scan the QR code to pay": "Silakan pemindaian kode QR untuk pembayaran",
"Price": "Harga",
"Price - Tooltip": "Harga produk",
"Quantity": "Kuantitas",
@@ -672,8 +697,8 @@
"Content": "Content",
"Content - Tooltip": "Content - Tooltip",
"Copy": "Salin",
"DB Test": "DB Test",
"DB Test - Tooltip": "DB Test - Tooltip",
"DB test": "DB test",
"DB test - Tooltip": "DB test - Tooltip",
"Disable SSL": "Menonaktifkan SSL",
"Disable SSL - Tooltip": "Apakah perlu menonaktifkan protokol SSL saat berkomunikasi dengan server STMP?",
"Domain": "Domain",
@@ -700,6 +725,10 @@
"Internal": "Internal",
"Issuer URL": "URL penerbit",
"Issuer URL - Tooltip": "URL Penerbit",
"Key ID": "Key ID",
"Key ID - Tooltip": "Key ID - Tooltip",
"Key text": "Key text",
"Key text - Tooltip": "Key text - Tooltip",
"Link copied to clipboard successfully": "Tautan berhasil disalin ke papan klip",
"Metadata": "Metadata: data yang menjelaskan atau memberikan informasi tentang data atau informasi digital lainnya, seperti informasi mengenai sumber data, format, waktu pembuatan, penulis, dan informasi lainnya yang dapat membantu dalam pengelolaan dan pemrosesan data",
"Metadata - Tooltip": "Metadata SAML",
@@ -754,6 +783,10 @@
"Sender Id - Tooltip": "Sender Id - Tooltip",
"Sender number": "Sender number",
"Sender number - Tooltip": "Sender number - Tooltip",
"Service ID identifier": "Service ID identifier",
"Service ID identifier - Tooltip": "Service ID identifier - Tooltip",
"Service account JSON": "Service account JSON",
"Service account JSON - Tooltip": "Service account JSON - Tooltip",
"Sign Name": "Tanda Tangan",
"Sign Name - Tooltip": "Nama tanda tangan yang akan digunakan",
"Sign request": "Permintaan tanda tangan",
@@ -764,12 +797,15 @@
"Signup HTML": "Pendaftaran HTML",
"Signup HTML - Edit": "Pendaftaran HTML - Sunting",
"Signup HTML - Tooltip": "HTML khusus untuk mengganti gaya halaman pendaftaran bawaan",
"Signup group": "Signup group",
"Silent": "Silent",
"Site key": "Kunci situs",
"Site key - Tooltip": "Kunci situs atau kunci halaman web",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub jenis",
"Sub type - Tooltip": "Sub jenis",
"Team ID": "Team ID",
"Team ID - Tooltip": "Team ID - Tooltip",
"Template code": "Kode template",
"Template code - Tooltip": "Kode template",
"Test Email": "Email Uji Coba",
@@ -780,6 +816,8 @@
"Token URL - Tooltip": "Token URL: URL Token",
"Type": "Jenis",
"Type - Tooltip": "Pilih tipe",
"User flow": "User flow",
"User flow - Tooltip": "User flow - Tooltip",
"User mapping": "User mapping",
"User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "URL UserInfo",
@@ -801,6 +839,8 @@
"New Role": "Peran Baru",
"Sub domains": "Sub domain-sub domain",
"Sub domains - Tooltip": "Domain yang termasuk dalam peran saat ini",
"Sub groups": "Sub groups",
"Sub groups - Tooltip": "Sub groups - Tooltip",
"Sub roles": "Peran tambahan",
"Sub roles - Tooltip": "Terjemahkan ke bahasa Indonesia: Peran yang termasuk dalam peran saat ini",
"Sub users": "Pengguna sub",
@@ -812,6 +852,9 @@
"Confirm": "Konfirmasi",
"Decline": "Menurun",
"Have account?": "Punya akun?",
"Label": "Label",
"Label HTML": "Label HTML",
"Placeholder": "Placeholder",
"Please accept the agreement!": "Tolong terima perjanjian ini!",
"Please click the below button to sign in": "Silakan klik tombol di bawah ini untuk masuk",
"Please confirm your password!": "Tolong konfirmasi kata sandi Anda!",
@@ -830,6 +873,11 @@
"Please select your country/region!": "Silakan pilih negara/region Anda!",
"Terms of Use": "Syarat Penggunaan",
"Terms of Use - Tooltip": "Syarat penggunaan yang harus dibaca dan disetujui oleh pengguna selama proses registrasi",
"Text 1": "Text 1",
"Text 2": "Text 2",
"Text 3": "Text 3",
"Text 4": "Text 4",
"Text 5": "Text 5",
"The input is not invoice Tax ID!": "Input ini bukan Tax ID faktur!",
"The input is not invoice title!": "Masukan bukan judul faktur!",
"The input is not valid Email!": "Input yang dimasukkan bukan sesuai dengan format Email yang valid!",
@@ -841,14 +889,19 @@
"sign in now": "Masuk sekarang"
},
"subscription": {
"Duration": "Durasi",
"Duration - Tooltip": "Durasi langganan",
"Active": "Active",
"Edit Subscription": "Edit Subscription",
"End date": "Tanggal Berakhir",
"End date - Tooltip": "Tanggal Berakhir",
"End time": "End time",
"End time - Tooltip": "End time - Tooltip",
"Error": "Error",
"Expired": "Expired",
"New Subscription": "New Subscription",
"Start date": "Tanggal Mulai",
"Start date - Tooltip": "Tanggal Mulai"
"Pending": "Pending",
"Period": "Period",
"Start time": "Start time",
"Start time - Tooltip": "Start time - Tooltip",
"Suspended": "Suspended",
"Upcoming": "Upcoming"
},
"syncer": {
"Affiliation table": "Tabel afiliasi",
@@ -872,6 +925,8 @@
"Is read-only": "Is read-only",
"Is read-only - Tooltip": "Is read-only - Tooltip",
"New Syncer": "Sinkronisasi Baru",
"SSL mode": "SSL mode",
"SSL mode - Tooltip": "SSL mode - Tooltip",
"Sync interval": "Interval sinkronisasi",
"Sync interval - Tooltip": "Satuan dalam detik",
"Table": "Tabel",
@@ -974,6 +1029,8 @@
"Managed accounts": "Akun yang dikelola",
"Modify password...": "Mengubah kata sandi...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "Email baru",
"New Password": "Kata Sandi Baru",
"New User": "Pengguna Baru",
@@ -1011,6 +1068,7 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Unggah foto",
"Value": "Value",
"Values": "Nilai-nilai",
"Verification code sent": "Kode verifikasi telah dikirim",
"WebAuthn credentials": "Kredensial WebAuthn",

Some files were not shown because too many files have changed in this diff Show More