forked from casdoor/casdoor
Compare commits
145 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5530253d38 | ||
|
|
4cef6c5f3f | ||
|
|
7e6929b900 | ||
|
|
46ae1a9580 | ||
|
|
37e22f3e2c | ||
|
|
68cde65d84 | ||
|
|
1c7f5fdfe4 | ||
|
|
1a5be46325 | ||
|
|
f7bafb28d6 | ||
|
|
6f815aefdf | ||
|
|
eb49f29529 | ||
|
|
5ad4e6aac0 | ||
|
|
3c28a2202d | ||
|
|
0a9a9117e5 | ||
|
|
f3ee1f83fe | ||
|
|
171af2901c | ||
|
|
2ded293e10 | ||
|
|
a1c6d6c6cf | ||
|
|
bf42176708 | ||
|
|
23a45c1d33 | ||
|
|
6894ca407e | ||
|
|
d288ecf6ed | ||
|
|
0a04174ec8 | ||
|
|
3feb723abf | ||
|
|
ff8b8fb631 | ||
|
|
df38c0dd62 | ||
|
|
93e87e009e | ||
|
|
f0a4ccbc3c | ||
|
|
f17c8622f7 | ||
|
|
09698b0714 | ||
|
|
1d913677a0 | ||
|
|
f3b00fb431 | ||
|
|
c95a427635 | ||
|
|
778be62bae | ||
|
|
5574c6ad0d | ||
|
|
36db852a32 | ||
|
|
8ee8767882 | ||
|
|
af5a9c805d | ||
|
|
f8e5fedf8b | ||
|
|
962a4970f4 | ||
|
|
d239b3f0cb | ||
|
|
0df467ce5e | ||
|
|
3d5356a1f0 | ||
|
|
1824762e00 | ||
|
|
a533212d8a | ||
|
|
53e1813dc8 | ||
|
|
ba95c7ffb0 | ||
|
|
10105de418 | ||
|
|
9582163bdd | ||
|
|
cc7408e976 | ||
|
|
d67d714105 | ||
|
|
0aab27f154 | ||
|
|
212090325b | ||
|
|
b24e43c736 | ||
|
|
1728bf01ac | ||
|
|
86a7a87c57 | ||
|
|
61c8e08eb0 | ||
|
|
caccd75edb | ||
|
|
7b2666d23e | ||
|
|
b7b6d2377a | ||
|
|
d43ee2d48f | ||
|
|
242c75d9dc | ||
|
|
6571ad88a2 | ||
|
|
bb33c8ea31 | ||
|
|
48f5531332 | ||
|
|
3e5114e42d | ||
|
|
03082db9f2 | ||
|
|
a2363e55e7 | ||
|
|
dde4e41e24 | ||
|
|
c3eea4d895 | ||
|
|
4ff28cacbe | ||
|
|
e8ed9ca9e3 | ||
|
|
8f8b7e5215 | ||
|
|
099e6437a9 | ||
|
|
fdbb0d52da | ||
|
|
9c89705a19 | ||
|
|
18451a874e | ||
|
|
99dae68c53 | ||
|
|
7e2c2bfc64 | ||
|
|
4ae6675198 | ||
|
|
8c37533b92 | ||
|
|
3e77bd30a0 | ||
|
|
55257d6190 | ||
|
|
b9046bec01 | ||
|
|
40d4e3a1a9 | ||
|
|
60bfc8891a | ||
|
|
126879533b | ||
|
|
469b6036fd | ||
|
|
6c750867b0 | ||
|
|
625b3e2c63 | ||
|
|
28dff8083a | ||
|
|
02c4bddb5f | ||
|
|
df65fb3525 | ||
|
|
d3bbf954f8 | ||
|
|
f3755d925c | ||
|
|
ca819e7e83 | ||
|
|
d619e91d9e | ||
|
|
5079c37818 | ||
|
|
d5f29d716a | ||
|
|
00b278a00f | ||
|
|
d883db907b | ||
|
|
8e7efe5c23 | ||
|
|
bf75508d95 | ||
|
|
986b94cc90 | ||
|
|
890f528556 | ||
|
|
b46e779235 | ||
|
|
5c80948a06 | ||
|
|
1467199159 | ||
|
|
64c2b8f0c2 | ||
|
|
8f7ea7f0a0 | ||
|
|
2ab85c0c44 | ||
|
|
bf67be2af6 | ||
|
|
bc94735a8d | ||
|
|
89c6ef5aae | ||
|
|
21da9f5ff2 | ||
|
|
3b11e778e7 | ||
|
|
ad240a373f | ||
|
|
01000f7022 | ||
|
|
f93aeb5350 | ||
|
|
8fa681f883 | ||
|
|
3b16406442 | ||
|
|
fbc16ef124 | ||
|
|
f26f56e88b | ||
|
|
9cb633c9e2 | ||
|
|
d0d059d42f | ||
|
|
c184dc7f3a | ||
|
|
2fa0890c11 | ||
|
|
a0e2be7ba8 | ||
|
|
09b389b1f7 | ||
|
|
a23033758f | ||
|
|
f7bc822087 | ||
|
|
e533ff1ee1 | ||
|
|
9f187f690e | ||
|
|
fe5aa1f214 | ||
|
|
eda742a848 | ||
|
|
83df077a02 | ||
|
|
ad6080e763 | ||
|
|
c179324de4 | ||
|
|
645716e485 | ||
|
|
955e73ddd1 | ||
|
|
2493ae9cfe | ||
|
|
b5c80513fb | ||
|
|
0653353be1 | ||
|
|
d6778fb4e6 | ||
|
|
fee7773839 |
33
.github/workflows/build.yml
vendored
33
.github/workflows/build.yml
vendored
@@ -1,6 +1,10 @@
|
||||
name: Build
|
||||
|
||||
on: [ push, pull_request ]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -20,7 +24,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '^1.16.5'
|
||||
go-version: '1.23'
|
||||
cache-dependency-path: ./go.mod
|
||||
- name: Tests
|
||||
run: |
|
||||
@@ -49,7 +53,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '^1.16.5'
|
||||
go-version: '1.23'
|
||||
cache-dependency-path: ./go.mod
|
||||
- run: go version
|
||||
- name: Build
|
||||
@@ -65,7 +69,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '^1.16.5'
|
||||
go-version: '1.23'
|
||||
cache: false
|
||||
|
||||
# gen a dummy config file
|
||||
@@ -94,11 +98,28 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '^1.16.5'
|
||||
go-version: '1.23'
|
||||
cache-dependency-path: ./go.mod
|
||||
- name: start backend
|
||||
run: nohup go run ./main.go &
|
||||
run: nohup go run ./main.go > /tmp/backend.log 2>&1 &
|
||||
working-directory: ./
|
||||
- name: Wait for backend to be ready
|
||||
run: |
|
||||
echo "Waiting for backend server to start on port 8000..."
|
||||
for i in {1..60}; do
|
||||
if curl -s http://localhost:8000 > /dev/null 2>&1; then
|
||||
echo "Backend is ready!"
|
||||
break
|
||||
fi
|
||||
if [ $i -eq 60 ]; then
|
||||
echo "Backend failed to start within 60 seconds"
|
||||
echo "Backend logs:"
|
||||
cat /tmp/backend.log || echo "No backend logs available"
|
||||
exit 1
|
||||
fi
|
||||
echo "Waiting... ($i/60)"
|
||||
sleep 1
|
||||
done
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,6 +5,7 @@
|
||||
*.so
|
||||
*.dylib
|
||||
*.swp
|
||||
server_*
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
@@ -4,7 +4,7 @@ COPY ./web .
|
||||
RUN yarn install --frozen-lockfile --network-timeout 1000000 && NODE_OPTIONS="--max-old-space-size=4096" yarn run build
|
||||
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:1.21.13 AS BACK
|
||||
FROM --platform=$BUILDPLATFORM golang:1.23.12 AS BACK
|
||||
WORKDIR /go/src/casdoor
|
||||
COPY . .
|
||||
RUN ./build.sh
|
||||
|
||||
@@ -46,6 +46,8 @@ p, *, *, POST, /api/login, *, *
|
||||
p, *, *, GET, /api/get-app-login, *, *
|
||||
p, *, *, POST, /api/logout, *, *
|
||||
p, *, *, GET, /api/logout, *, *
|
||||
p, *, *, POST, /api/sso-logout, *, *
|
||||
p, *, *, GET, /api/sso-logout, *, *
|
||||
p, *, *, POST, /api/callback, *, *
|
||||
p, *, *, POST, /api/device-auth, *, *
|
||||
p, *, *, GET, /api/get-account, *, *
|
||||
@@ -61,6 +63,7 @@ p, *, *, GET, /api/get-application, *, *
|
||||
p, *, *, GET, /api/get-organization-applications, *, *
|
||||
p, *, *, GET, /api/get-user, *, *
|
||||
p, *, *, GET, /api/get-user-application, *, *
|
||||
p, *, *, POST, /api/upload-users, *, *
|
||||
p, *, *, GET, /api/get-resources, *, *
|
||||
p, *, *, GET, /api/get-records, *, *
|
||||
p, *, *, GET, /api/get-product, *, *
|
||||
@@ -80,6 +83,9 @@ p, *, *, POST, /api/upload-resource, *, *
|
||||
p, *, *, GET, /.well-known/openid-configuration, *, *
|
||||
p, *, *, GET, /.well-known/webfinger, *, *
|
||||
p, *, *, *, /.well-known/jwks, *, *
|
||||
p, *, *, GET, /.well-known/:application/openid-configuration, *, *
|
||||
p, *, *, GET, /.well-known/:application/webfinger, *, *
|
||||
p, *, *, *, /.well-known/:application/jwks, *, *
|
||||
p, *, *, GET, /api/get-saml-login, *, *
|
||||
p, *, *, POST, /api/acs, *, *
|
||||
p, *, *, GET, /api/saml/metadata, *, *
|
||||
@@ -143,6 +149,10 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
|
||||
return false
|
||||
}
|
||||
|
||||
if user.IsGlobalAdmin() {
|
||||
return true
|
||||
}
|
||||
|
||||
if user.IsAdmin && (subOwner == objOwner || (objOwner == "admin")) {
|
||||
return true
|
||||
}
|
||||
@@ -153,12 +163,19 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if !res {
|
||||
res, err = object.CheckApiPermission(util.GetId(subOwner, subName), objOwner, urlPath, method)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
|
||||
if method == "POST" {
|
||||
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/callback" || urlPath == "/api/send-verification-code" || urlPath == "/api/send-email" || urlPath == "/api/verify-captcha" || urlPath == "/api/verify-code" || urlPath == "/api/check-user-password" || strings.HasPrefix(urlPath, "/api/mfa/") || urlPath == "/api/webhook" || urlPath == "/api/get-qrcode" || urlPath == "/api/refresh-engines" {
|
||||
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/sso-logout" || urlPath == "/api/signup" || urlPath == "/api/callback" || urlPath == "/api/send-verification-code" || urlPath == "/api/send-email" || urlPath == "/api/verify-captcha" || urlPath == "/api/verify-code" || urlPath == "/api/check-user-password" || strings.HasPrefix(urlPath, "/api/mfa/") || urlPath == "/api/webhook" || urlPath == "/api/get-qrcode" || urlPath == "/api/refresh-engines" {
|
||||
return true
|
||||
} else if urlPath == "/api/update-user" {
|
||||
// Allow ordinary users to update their own information
|
||||
|
||||
@@ -197,7 +197,7 @@ func (c *ApiController) Signup() {
|
||||
|
||||
userType := "normal-user"
|
||||
if authForm.Plan != "" && authForm.Pricing != "" {
|
||||
err = object.CheckPricingAndPlan(authForm.Organization, authForm.Pricing, authForm.Plan)
|
||||
err = object.CheckPricingAndPlan(authForm.Organization, authForm.Pricing, authForm.Plan, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -218,7 +218,7 @@ func (c *ApiController) Signup() {
|
||||
Tag: authForm.Tag,
|
||||
Education: authForm.Education,
|
||||
Avatar: organization.DefaultAvatar,
|
||||
Email: authForm.Email,
|
||||
Email: strings.ToLower(authForm.Email),
|
||||
Phone: authForm.Phone,
|
||||
CountryCode: authForm.CountryCode,
|
||||
Address: []string{},
|
||||
@@ -235,6 +235,8 @@ func (c *ApiController) Signup() {
|
||||
Invitation: invitationName,
|
||||
InvitationCode: authForm.InvitationCode,
|
||||
EmailVerified: userEmailVerified,
|
||||
RegisterType: "Application Signup",
|
||||
RegisterSource: fmt.Sprintf("%s/%s", authForm.Organization, application.Name),
|
||||
}
|
||||
|
||||
if len(organization.Tags) > 0 {
|
||||
@@ -288,6 +290,8 @@ func (c *ApiController) Signup() {
|
||||
|
||||
if user.Type == "normal-user" {
|
||||
c.SetSessionUsername(user.GetId())
|
||||
} else if user.Type == "paid-user" {
|
||||
c.SetSession("paidUsername", user.GetId())
|
||||
}
|
||||
|
||||
if authForm.Email != "" {
|
||||
@@ -326,9 +330,9 @@ func (c *ApiController) Signup() {
|
||||
// @router /logout [post]
|
||||
func (c *ApiController) Logout() {
|
||||
// https://openid.net/specs/openid-connect-rpinitiated-1_0-final.html
|
||||
accessToken := c.Input().Get("id_token_hint")
|
||||
redirectUri := c.Input().Get("post_logout_redirect_uri")
|
||||
state := c.Input().Get("state")
|
||||
accessToken := c.GetString("id_token_hint")
|
||||
redirectUri := c.GetString("post_logout_redirect_uri")
|
||||
state := c.GetString("state")
|
||||
|
||||
user := c.GetSessionUsername()
|
||||
|
||||
@@ -341,8 +345,12 @@ func (c *ApiController) Logout() {
|
||||
|
||||
c.ClearUserSession()
|
||||
c.ClearTokenSession()
|
||||
owner, username := util.GetOwnerAndNameFromId(user)
|
||||
_, err := object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
|
||||
owner, username, err := util.GetOwnerAndNameFromIdWithError(user)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -389,7 +397,11 @@ func (c *ApiController) Logout() {
|
||||
c.ClearUserSession()
|
||||
c.ClearTokenSession()
|
||||
// TODO https://github.com/casdoor/casdoor/pull/1494#discussion_r1095675265
|
||||
owner, username := util.GetOwnerAndNameFromId(user)
|
||||
owner, username, err := util.GetOwnerAndNameFromIdWithError(user)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
|
||||
if err != nil {
|
||||
@@ -421,6 +433,62 @@ func (c *ApiController) Logout() {
|
||||
}
|
||||
}
|
||||
|
||||
// SsoLogout
|
||||
// @Title SsoLogout
|
||||
// @Tag Login API
|
||||
// @Description logout the current user from all applications
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /sso-logout [get,post]
|
||||
func (c *ApiController) SsoLogout() {
|
||||
user := c.GetSessionUsername()
|
||||
|
||||
if user == "" {
|
||||
c.ResponseOk()
|
||||
return
|
||||
}
|
||||
|
||||
c.ClearUserSession()
|
||||
c.ClearTokenSession()
|
||||
owner, username, err := util.GetOwnerAndNameFromIdWithError(user)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, err = object.ExpireTokenByUser(owner, username)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
sessions, err := object.GetUserSessions(owner, username)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var sessionIds []string
|
||||
for _, session := range sessions {
|
||||
sessionIds = append(sessionIds, session.SessionId...)
|
||||
}
|
||||
object.DeleteBeegoSession(sessionIds)
|
||||
|
||||
_, err = object.DeleteAllUserSessions(owner, username)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
util.LogInfo(c.Ctx, "API: [%s] logged out from all applications", user)
|
||||
|
||||
c.ResponseOk()
|
||||
}
|
||||
|
||||
// GetAccount
|
||||
// @Title GetAccount
|
||||
// @Tag Account API
|
||||
|
||||
@@ -237,7 +237,7 @@ func (c *ApiController) UpdateApplication() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application))
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application, c.IsGlobalAdmin(), c.GetAcceptLanguage()))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego"
|
||||
"github.com/casdoor/casdoor/captcha"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/form"
|
||||
@@ -61,6 +62,11 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
return
|
||||
}
|
||||
|
||||
if user.IsDeleted {
|
||||
c.ResponseError(c.T("check:The user has been deleted and cannot be used to sign in, please contact the administrator"))
|
||||
return
|
||||
}
|
||||
|
||||
userId := user.GetId()
|
||||
|
||||
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
|
||||
@@ -131,6 +137,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:paid-user %s does not have active or pending subscription and the application: %s does not have default pricing"), user.Name, application.Name))
|
||||
return
|
||||
} else {
|
||||
c.SetSession("paidUsername", user.GetId())
|
||||
// let the paid-user select plan
|
||||
c.ResponseOk("SelectPlan", pricing)
|
||||
return
|
||||
@@ -157,7 +164,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
c.ResponseError(c.T("auth:Challenge method should be S256"))
|
||||
return
|
||||
}
|
||||
code, err := object.GetOAuthCode(userId, clientId, form.Provider, responseType, redirectUri, scope, state, nonce, codeChallenge, c.Ctx.Request.Host, c.GetAcceptLanguage())
|
||||
code, err := object.GetOAuthCode(userId, clientId, form.Provider, form.SigninMethod, responseType, redirectUri, scope, state, nonce, codeChallenge, c.Ctx.Request.Host, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error(), nil)
|
||||
return
|
||||
@@ -244,12 +251,32 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
c.setExpireForSession()
|
||||
}
|
||||
|
||||
if application.EnableExclusiveSignin {
|
||||
sessions, err := object.GetUserAppSessions(user.Owner, user.Name, application.Name)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
for _, session := range sessions {
|
||||
for _, sid := range session.SessionId {
|
||||
err := beego.GlobalSessions.GetProvider().SessionDestroy(sid)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error(), nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if resp.Status == "ok" {
|
||||
_, err = object.AddSession(&object.Session{
|
||||
Owner: user.Owner,
|
||||
Name: user.Name,
|
||||
Application: application.Name,
|
||||
SessionId: []string{c.Ctx.Input.CruSession.SessionID()},
|
||||
|
||||
ExclusiveSignin: true,
|
||||
})
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error(), nil)
|
||||
@@ -688,6 +715,7 @@ func (c *ApiController) Login() {
|
||||
}
|
||||
if provider == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The provider: %s does not exist"), authForm.Provider))
|
||||
return
|
||||
}
|
||||
|
||||
providerItem := application.GetProviderItem(provider.Name)
|
||||
@@ -719,7 +747,8 @@ func (c *ApiController) Login() {
|
||||
|
||||
setHttpClient(idProvider, provider.Type)
|
||||
|
||||
if authForm.State != conf.GetConfigString("authState") && authForm.State != application.Name {
|
||||
stateApplicationName := strings.Split(authForm.State, "-org-")[0]
|
||||
if authForm.State != conf.GetConfigString("authState") && stateApplicationName != application.Name {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:State expected: %s, but got: %s"), conf.GetConfigString("authState"), authForm.State))
|
||||
return
|
||||
}
|
||||
@@ -775,7 +804,7 @@ func (c *ApiController) Login() {
|
||||
if user != nil && !user.IsDeleted {
|
||||
// Sign in via OAuth (want to sign up but already have account)
|
||||
// sync info from 3rd-party if possible
|
||||
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo)
|
||||
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo, provider.UserMapping)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -788,7 +817,7 @@ func (c *ApiController) Login() {
|
||||
resp = c.HandleLoggedIn(application, user, &authForm)
|
||||
|
||||
c.Ctx.Input.SetParam("recordUserId", user.GetId())
|
||||
} else if provider.Category == "OAuth" || provider.Category == "Web3" {
|
||||
} else if provider.Category == "OAuth" || provider.Category == "Web3" || provider.Category == "SAML" {
|
||||
// Sign up via OAuth
|
||||
if application.EnableLinkWithEmail {
|
||||
if userInfo.Email != "" {
|
||||
@@ -810,14 +839,26 @@ func (c *ApiController) Login() {
|
||||
}
|
||||
}
|
||||
|
||||
if user == nil || user.IsDeleted {
|
||||
// Try to find existing user by username (case-insensitive)
|
||||
// This allows OAuth providers (e.g., Wecom) to automatically associate with
|
||||
// existing users when usernames match, particularly useful for enterprise
|
||||
// scenarios where signup is disabled and users already exist in Casdoor
|
||||
if user == nil && userInfo.Username != "" {
|
||||
user, err = object.GetUserByFields(application.Organization, userInfo.Username)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
if !application.EnableSignUp {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support"), provider.Type, userInfo.Username, userInfo.DisplayName))
|
||||
return
|
||||
}
|
||||
|
||||
if !providerItem.CanSignUp {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up"), provider.Type, userInfo.Username, userInfo.DisplayName, provider.Type))
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up"), provider.Type, userInfo.Username, userInfo.DisplayName, provider.Type))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -886,6 +927,12 @@ func (c *ApiController) Login() {
|
||||
IsDeleted: false,
|
||||
SignupApplication: application.Name,
|
||||
Properties: properties,
|
||||
RegisterType: "Application Signup",
|
||||
RegisterSource: fmt.Sprintf("%s/%s", application.Organization, application.Name),
|
||||
}
|
||||
|
||||
if providerItem.SignupGroup != "" {
|
||||
user.Groups = []string{providerItem.SignupGroup}
|
||||
}
|
||||
|
||||
var affected bool
|
||||
@@ -899,19 +946,10 @@ func (c *ApiController) Login() {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:Failed to create user, user information is invalid: %s"), util.StructToJson(user)))
|
||||
return
|
||||
}
|
||||
|
||||
if providerItem.SignupGroup != "" {
|
||||
user.Groups = []string{providerItem.SignupGroup}
|
||||
_, err = object.UpdateUser(user.GetId(), user, []string{"groups"}, false)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sync info from 3rd-party if possible
|
||||
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo)
|
||||
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo, provider.UserMapping)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -959,7 +997,7 @@ func (c *ApiController) Login() {
|
||||
}
|
||||
|
||||
// sync info from 3rd-party if possible
|
||||
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo)
|
||||
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo, provider.UserMapping)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -1185,6 +1223,11 @@ func (c *ApiController) HandleOfficialAccountEvent() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if provider == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The provider: %s does not exist"), providerId))
|
||||
return
|
||||
}
|
||||
|
||||
if data.Ticket == "" {
|
||||
c.ResponseError("empty ticket")
|
||||
return
|
||||
@@ -1240,6 +1283,11 @@ func (c *ApiController) GetQRCode() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if provider == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The provider: %s does not exist"), providerId))
|
||||
return
|
||||
}
|
||||
|
||||
code, ticket, err := idp.GetWechatOfficialAccountQRCode(provider.ClientId2, provider.ClientSecret2, providerId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
||||
@@ -122,6 +122,26 @@ func (c *ApiController) GetSessionUsername() string {
|
||||
return user.(string)
|
||||
}
|
||||
|
||||
// GetPaidUsername ...
|
||||
func (c *ApiController) GetPaidUsername() string {
|
||||
// check if user session expired
|
||||
sessionData := c.GetSessionData()
|
||||
|
||||
if sessionData != nil &&
|
||||
sessionData.ExpireTime != 0 &&
|
||||
sessionData.ExpireTime < time.Now().Unix() {
|
||||
c.ClearUserSession()
|
||||
return ""
|
||||
}
|
||||
|
||||
user := c.GetSession("paidUsername")
|
||||
if user == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return user.(string)
|
||||
}
|
||||
|
||||
func (c *ApiController) GetSessionToken() string {
|
||||
accessToken := c.GetSession("accessToken")
|
||||
if accessToken == nil {
|
||||
|
||||
@@ -119,7 +119,11 @@ func (c *ApiController) Enforce() {
|
||||
|
||||
permissions := []*object.Permission{}
|
||||
if modelId != "" {
|
||||
owner, modelName := util.GetOwnerAndNameFromId(modelId)
|
||||
owner, modelName, err := util.GetOwnerAndNameFromIdWithError(modelId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
permissions, err = object.GetPermissionsByModel(owner, modelName)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -255,7 +259,11 @@ func (c *ApiController) BatchEnforce() {
|
||||
|
||||
permissions := []*object.Permission{}
|
||||
if modelId != "" {
|
||||
owner, modelName := util.GetOwnerAndNameFromId(modelId)
|
||||
owner, modelName, err := util.GetOwnerAndNameFromIdWithError(modelId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
permissions, err = object.GetPermissionsByModel(owner, modelName)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -38,6 +39,46 @@ var (
|
||||
cliVersionMutex sync.RWMutex
|
||||
)
|
||||
|
||||
// cleanOldMEIFolders cleans up old _MEIXXX folders from the Casdoor temp directory
|
||||
// that are older than 24 hours. These folders are created by PyInstaller when
|
||||
// executing casbin-python-cli and can accumulate over time.
|
||||
func cleanOldMEIFolders() {
|
||||
tempDir := "temp"
|
||||
cutoffTime := time.Now().Add(-24 * time.Hour)
|
||||
|
||||
entries, err := os.ReadDir(tempDir)
|
||||
if err != nil {
|
||||
// Log error but don't fail - cleanup is best-effort
|
||||
// This is expected if temp directory doesn't exist yet
|
||||
return
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
// Check if the entry is a directory and matches the _MEI pattern
|
||||
if !entry.IsDir() || !strings.HasPrefix(entry.Name(), "_MEI") {
|
||||
continue
|
||||
}
|
||||
|
||||
dirPath := filepath.Join(tempDir, entry.Name())
|
||||
info, err := entry.Info()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if the folder is older than 24 hours
|
||||
if info.ModTime().Before(cutoffTime) {
|
||||
// Try to remove the directory
|
||||
err = os.RemoveAll(dirPath)
|
||||
if err != nil {
|
||||
// Log but continue with other folders
|
||||
fmt.Printf("failed to remove old MEI folder %s: %v\n", dirPath, err)
|
||||
} else {
|
||||
fmt.Printf("removed old MEI folder: %s\n", dirPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getCLIVersion
|
||||
// @Title getCLIVersion
|
||||
// @Description Get CLI version with cache mechanism
|
||||
@@ -66,6 +107,9 @@ func getCLIVersion(language string) (string, error) {
|
||||
}
|
||||
cliVersionMutex.RUnlock()
|
||||
|
||||
// Clean up old _MEI folders before running the command
|
||||
cleanOldMEIFolders()
|
||||
|
||||
cmd := exec.Command(binaryName, "--version")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
@@ -152,6 +196,19 @@ func (c *ApiController) RunCasbinCommand() {
|
||||
return
|
||||
}
|
||||
|
||||
// Generate cache key for this command
|
||||
cacheKey, err := generateCacheKey(language, args)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Check if result is cached
|
||||
if cachedOutput, found := getCachedCommandResult(cacheKey); found {
|
||||
c.ResponseOk(cachedOutput)
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) > 0 && args[0] == "--version" {
|
||||
version, err := getCLIVersion(language)
|
||||
if err != nil {
|
||||
@@ -173,6 +230,10 @@ func (c *ApiController) RunCasbinCommand() {
|
||||
return
|
||||
}
|
||||
|
||||
// Clean up old _MEI folders before running the command
|
||||
// This is especially important for Python CLI which creates these folders
|
||||
cleanOldMEIFolders()
|
||||
|
||||
command := exec.Command(binaryName, processedArgs...)
|
||||
outputBytes, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
@@ -188,6 +249,10 @@ func (c *ApiController) RunCasbinCommand() {
|
||||
|
||||
output := string(outputBytes)
|
||||
output = strings.TrimSuffix(output, "\n")
|
||||
|
||||
// Store result in cache
|
||||
setCachedCommandResult(cacheKey, output)
|
||||
|
||||
c.ResponseOk(output)
|
||||
}
|
||||
|
||||
|
||||
100
controllers/casbin_cli_api_cache.go
Normal file
100
controllers/casbin_cli_api_cache.go
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CommandCacheEntry struct {
|
||||
Output string
|
||||
CachedTime time.Time
|
||||
}
|
||||
|
||||
var (
|
||||
commandCache = make(map[string]*CommandCacheEntry)
|
||||
commandCacheMutex sync.RWMutex
|
||||
cacheTTL = 5 * time.Minute
|
||||
cleanupInProgress = false
|
||||
cleanupMutex sync.Mutex
|
||||
)
|
||||
|
||||
// generateCacheKey creates a unique cache key based on language and arguments
|
||||
func generateCacheKey(language string, args []string) (string, error) {
|
||||
argsJSON, err := json.Marshal(args)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal args: %v", err)
|
||||
}
|
||||
data := fmt.Sprintf("%s:%s", language, string(argsJSON))
|
||||
hash := sha256.Sum256([]byte(data))
|
||||
return hex.EncodeToString(hash[:]), nil
|
||||
}
|
||||
|
||||
// cleanExpiredCacheEntries removes expired entries from the cache
|
||||
func cleanExpiredCacheEntries() {
|
||||
commandCacheMutex.Lock()
|
||||
defer commandCacheMutex.Unlock()
|
||||
|
||||
for key, entry := range commandCache {
|
||||
if time.Since(entry.CachedTime) >= cacheTTL {
|
||||
delete(commandCache, key)
|
||||
}
|
||||
}
|
||||
|
||||
cleanupMutex.Lock()
|
||||
cleanupInProgress = false
|
||||
cleanupMutex.Unlock()
|
||||
}
|
||||
|
||||
// getCachedCommandResult retrieves cached command result if available and not expired
|
||||
func getCachedCommandResult(cacheKey string) (string, bool) {
|
||||
commandCacheMutex.RLock()
|
||||
defer commandCacheMutex.RUnlock()
|
||||
|
||||
if entry, exists := commandCache[cacheKey]; exists {
|
||||
if time.Since(entry.CachedTime) < cacheTTL {
|
||||
return entry.Output, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// setCachedCommandResult stores command result in cache and performs periodic cleanup
|
||||
func setCachedCommandResult(cacheKey string, output string) {
|
||||
commandCacheMutex.Lock()
|
||||
commandCache[cacheKey] = &CommandCacheEntry{
|
||||
Output: output,
|
||||
CachedTime: time.Now(),
|
||||
}
|
||||
shouldCleanup := len(commandCache)%100 == 0
|
||||
commandCacheMutex.Unlock()
|
||||
|
||||
// Periodically clean expired entries (every 100 cache sets)
|
||||
if shouldCleanup {
|
||||
cleanupMutex.Lock()
|
||||
if !cleanupInProgress {
|
||||
cleanupInProgress = true
|
||||
cleanupMutex.Unlock()
|
||||
go cleanExpiredCacheEntries()
|
||||
} else {
|
||||
cleanupMutex.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ const (
|
||||
goCliRepo = "https://api.github.com/repos/casbin/casbin-go-cli/releases/latest"
|
||||
rustCliRepo = "https://api.github.com/repos/casbin-rs/casbin-rust-cli/releases/latest"
|
||||
pythonCliRepo = "https://api.github.com/repos/casbin/casbin-python-cli/releases/latest"
|
||||
dotnetCliRepo = "https://api.github.com/repos/casbin-net/casbin-dotnet-cli/releases/latest"
|
||||
downloadFolder = "bin"
|
||||
)
|
||||
|
||||
@@ -45,6 +46,7 @@ func getBinaryNames() map[string]string {
|
||||
java = "java"
|
||||
rust = "rust"
|
||||
python = "python"
|
||||
dotnet = "dotnet"
|
||||
)
|
||||
|
||||
arch := runtime.GOARCH
|
||||
@@ -65,6 +67,7 @@ func getBinaryNames() map[string]string {
|
||||
java: "casbin-java-cli.jar",
|
||||
rust: fmt.Sprintf("casbin-rust-cli-%s-pc-windows-gnu", archNames.rustArch),
|
||||
python: fmt.Sprintf("casbin-python-cli-windows-%s.exe", archNames.goArch),
|
||||
dotnet: fmt.Sprintf("casbin-dotnet-cli-windows-%s.exe", archNames.goArch),
|
||||
}
|
||||
case "darwin":
|
||||
return map[string]string{
|
||||
@@ -72,6 +75,7 @@ func getBinaryNames() map[string]string {
|
||||
java: "casbin-java-cli.jar",
|
||||
rust: fmt.Sprintf("casbin-rust-cli-%s-apple-darwin", archNames.rustArch),
|
||||
python: fmt.Sprintf("casbin-python-cli-darwin-%s", archNames.goArch),
|
||||
dotnet: fmt.Sprintf("casbin-dotnet-cli-darwin-%s", archNames.goArch),
|
||||
}
|
||||
case "linux":
|
||||
return map[string]string{
|
||||
@@ -79,6 +83,7 @@ func getBinaryNames() map[string]string {
|
||||
java: "casbin-java-cli.jar",
|
||||
rust: fmt.Sprintf("casbin-rust-cli-%s-unknown-linux-gnu", archNames.rustArch),
|
||||
python: fmt.Sprintf("casbin-python-cli-linux-%s", archNames.goArch),
|
||||
dotnet: fmt.Sprintf("casbin-dotnet-cli-linux-%s", archNames.goArch),
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
@@ -108,6 +113,11 @@ func getFinalBinaryName(lang string) string {
|
||||
return "casbin-python-cli.exe"
|
||||
}
|
||||
return "casbin-python-cli"
|
||||
case "dotnet":
|
||||
if runtime.GOOS == "windows" {
|
||||
return "casbin-dotnet-cli.exe"
|
||||
}
|
||||
return "casbin-dotnet-cli"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
@@ -347,6 +357,7 @@ func downloadCLI() error {
|
||||
"go": goCliRepo,
|
||||
"rust": rustCliRepo,
|
||||
"python": pythonCliRepo,
|
||||
"dotnet": dotnetCliRepo,
|
||||
}
|
||||
|
||||
for lang, repo := range repos {
|
||||
|
||||
@@ -83,6 +83,10 @@ func (c *ApiController) GetEnforcer() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if enforcer == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("general:The enforcer: %s does not exist"), id))
|
||||
return
|
||||
}
|
||||
|
||||
if loadModelCfg == "true" && enforcer.Model != "" {
|
||||
err := enforcer.LoadModelCfg()
|
||||
|
||||
175
controllers/form.go
Normal file
175
controllers/form.go
Normal file
@@ -0,0 +1,175 @@
|
||||
// Copyright 2025 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetGlobalForms
|
||||
// @Title GetGlobalForms
|
||||
// @Tag Form API
|
||||
// @Description get global forms
|
||||
// @Success 200 {array} object.Form The Response object
|
||||
// @router /get-global-forms [get]
|
||||
func (c *ApiController) GetGlobalForms() {
|
||||
forms, err := object.GetGlobalForms()
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(object.GetMaskedForms(forms, true))
|
||||
}
|
||||
|
||||
// GetForms
|
||||
// @Title GetForms
|
||||
// @Tag Form API
|
||||
// @Description get forms
|
||||
// @Param owner query string true "The owner of form"
|
||||
// @Success 200 {array} object.Form The Response object
|
||||
// @router /get-forms [get]
|
||||
func (c *ApiController) GetForms() {
|
||||
owner := c.Input().Get("owner")
|
||||
limit := c.Input().Get("pageSize")
|
||||
page := c.Input().Get("p")
|
||||
field := c.Input().Get("field")
|
||||
value := c.Input().Get("value")
|
||||
sortField := c.Input().Get("sortField")
|
||||
sortOrder := c.Input().Get("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
forms, err := object.GetForms(owner)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(object.GetMaskedForms(forms, true))
|
||||
} else {
|
||||
limit := util.ParseInt(limit)
|
||||
count, err := object.GetFormCount(owner, field, value)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
forms, err := object.GetPaginationForms(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
c.ResponseOk(forms, paginator.Nums())
|
||||
}
|
||||
}
|
||||
|
||||
// GetForm
|
||||
// @Title GetForm
|
||||
// @Tag Form API
|
||||
// @Description get form
|
||||
// @Param id query string true "The id (owner/name) of form"
|
||||
// @Success 200 {object} object.Form The Response object
|
||||
// @router /get-form [get]
|
||||
func (c *ApiController) GetForm() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
form, err := object.GetForm(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(object.GetMaskedForm(form, true))
|
||||
}
|
||||
|
||||
// UpdateForm
|
||||
// @Title UpdateForm
|
||||
// @Tag Form API
|
||||
// @Description update form
|
||||
// @Param id query string true "The id (owner/name) of the form"
|
||||
// @Param body body object.Form true "The details of the form"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-form [post]
|
||||
func (c *ApiController) UpdateForm() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
var form object.Form
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
success, err := object.UpdateForm(id, &form)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(success)
|
||||
}
|
||||
|
||||
// AddForm
|
||||
// @Title AddForm
|
||||
// @Tag Form API
|
||||
// @Description add form
|
||||
// @Param body body object.Form true "The details of the form"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /add-form [post]
|
||||
func (c *ApiController) AddForm() {
|
||||
var form object.Form
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
success, err := object.AddForm(&form)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(success)
|
||||
}
|
||||
|
||||
// DeleteForm
|
||||
// @Title DeleteForm
|
||||
// @Tag Form API
|
||||
// @Description delete form
|
||||
// @Param body body object.Form true "The details of the form"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /delete-form [post]
|
||||
func (c *ApiController) DeleteForm() {
|
||||
var form object.Form
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
success, err := object.DeleteForm(&form)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(success)
|
||||
}
|
||||
@@ -24,7 +24,11 @@ import (
|
||||
|
||||
func (c *ApiController) UploadGroups() {
|
||||
userId := c.GetSessionUsername()
|
||||
owner, user := util.GetOwnerAndNameFromId(userId)
|
||||
owner, user, err := util.GetOwnerAndNameFromIdWithError(userId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
file, header, err := c.Ctx.Request.FormFile("file")
|
||||
if err != nil {
|
||||
|
||||
@@ -16,6 +16,8 @@ package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
@@ -100,6 +102,10 @@ func (c *ApiController) GetInvitationCodeInfo() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if application == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("general:The application: %s does not exist"), applicationId))
|
||||
return
|
||||
}
|
||||
|
||||
invitation, msg := object.GetInvitationByCode(code, application.Organization, c.GetAcceptLanguage())
|
||||
if msg != "" {
|
||||
@@ -188,3 +194,77 @@ func (c *ApiController) VerifyInvitation() {
|
||||
|
||||
c.ResponseOk(payment, attachInfo)
|
||||
}
|
||||
|
||||
// SendInvitation
|
||||
// @Title VerifyInvitation
|
||||
// @Tag Invitation API
|
||||
// @Description verify invitation
|
||||
// @Param id query string true "The id ( owner/name ) of the invitation"
|
||||
// @Param body body []string true "The details of the invitation"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /send-invitation [post]
|
||||
func (c *ApiController) SendInvitation() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
var destinations []string
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &destinations)
|
||||
|
||||
if !c.IsAdmin() {
|
||||
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||
return
|
||||
}
|
||||
|
||||
invitation, err := object.GetInvitation(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if invitation == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("invitation:Invitation %s does not exist"), id))
|
||||
return
|
||||
}
|
||||
|
||||
organization, err := object.GetOrganization(fmt.Sprintf("admin/%s", invitation.Owner))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if organization == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("general:The organization: %s does not exist"), invitation.Owner))
|
||||
return
|
||||
}
|
||||
|
||||
application, err := object.GetApplicationByOrganizationName(invitation.Owner)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if application == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("general:The organization: %s should have one application at least"), invitation.Owner))
|
||||
return
|
||||
}
|
||||
|
||||
provider, err := application.GetEmailProvider("Invitation")
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if provider == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("verification:please add an Email provider to the \"Providers\" list for the application: %s"), invitation.Owner))
|
||||
return
|
||||
}
|
||||
|
||||
content := provider.Metadata
|
||||
|
||||
content = strings.ReplaceAll(content, "%code", invitation.Code)
|
||||
content = strings.ReplaceAll(content, "%link", invitation.GetInvitationLink(c.Ctx.Request.Host, application.Name))
|
||||
|
||||
err = object.SendEmail(provider, provider.Title, content, destinations, organization.DisplayName)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk()
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
@@ -47,12 +48,20 @@ type LdapSyncResp struct {
|
||||
func (c *ApiController) GetLdapUsers() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
_, ldapId := util.GetOwnerAndNameFromId(id)
|
||||
_, ldapId, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
ldapServer, err := object.GetLdap(ldapId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if ldapServer == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("general:The LDAP: %s does not exist"), ldapId))
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := ldapServer.GetLdapConn()
|
||||
if err != nil {
|
||||
@@ -125,7 +134,11 @@ func (c *ApiController) GetLdap() {
|
||||
return
|
||||
}
|
||||
|
||||
_, name := util.GetOwnerAndNameFromId(id)
|
||||
_, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
ldap, err := object.GetLdap(name)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -255,9 +268,13 @@ func (c *ApiController) DeleteLdap() {
|
||||
func (c *ApiController) SyncLdapUsers() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
owner, ldapId := util.GetOwnerAndNameFromId(id)
|
||||
owner, ldapId, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
var users []object.LdapUser
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &users)
|
||||
err = json.Unmarshal(c.Ctx.Input.RequestBody, &users)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
||||
@@ -124,6 +124,28 @@ func (c *ApiController) MfaSetupVerify() {
|
||||
return
|
||||
}
|
||||
config.Secret = dest
|
||||
} else if mfaType == object.RadiusType {
|
||||
if dest == "" {
|
||||
c.ResponseError("RADIUS username is missing")
|
||||
return
|
||||
}
|
||||
config.Secret = dest
|
||||
if secret == "" {
|
||||
c.ResponseError("RADIUS provider is missing")
|
||||
return
|
||||
}
|
||||
config.URL = secret
|
||||
} else if mfaType == object.PushType {
|
||||
if dest == "" {
|
||||
c.ResponseError("push notification receiver is missing")
|
||||
return
|
||||
}
|
||||
config.Secret = dest
|
||||
if secret == "" {
|
||||
c.ResponseError("push notification provider is missing")
|
||||
return
|
||||
}
|
||||
config.URL = secret
|
||||
}
|
||||
|
||||
mfaUtil := object.GetMfaUtil(mfaType, config)
|
||||
@@ -200,6 +222,28 @@ func (c *ApiController) MfaSetupEnable() {
|
||||
}
|
||||
user.CountryCode = countryCode
|
||||
}
|
||||
} else if mfaType == object.RadiusType {
|
||||
if dest == "" {
|
||||
c.ResponseError("RADIUS username is missing")
|
||||
return
|
||||
}
|
||||
config.Secret = dest
|
||||
if secret == "" {
|
||||
c.ResponseError("RADIUS provider is missing")
|
||||
return
|
||||
}
|
||||
config.URL = secret
|
||||
} else if mfaType == object.PushType {
|
||||
if dest == "" {
|
||||
c.ResponseError("push notification receiver is missing")
|
||||
return
|
||||
}
|
||||
config.Secret = dest
|
||||
if secret == "" {
|
||||
c.ResponseError("push notification provider is missing")
|
||||
return
|
||||
}
|
||||
config.URL = secret
|
||||
}
|
||||
|
||||
if recoveryCodes == "" {
|
||||
|
||||
@@ -28,7 +28,21 @@ import (
|
||||
// @router /.well-known/openid-configuration [get]
|
||||
func (c *RootController) GetOidcDiscovery() {
|
||||
host := c.Ctx.Request.Host
|
||||
c.Data["json"] = object.GetOidcDiscovery(host)
|
||||
c.Data["json"] = object.GetOidcDiscovery(host, "")
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetOidcDiscoveryByApplication
|
||||
// @Title GetOidcDiscoveryByApplication
|
||||
// @Tag OIDC API
|
||||
// @Description Get Oidc Discovery for specific application
|
||||
// @Param application path string true "application name"
|
||||
// @Success 200 {object} object.OidcDiscovery
|
||||
// @router /.well-known/:application/openid-configuration [get]
|
||||
func (c *RootController) GetOidcDiscoveryByApplication() {
|
||||
application := c.Ctx.Input.Param(":application")
|
||||
host := c.Ctx.Request.Host
|
||||
c.Data["json"] = object.GetOidcDiscovery(host, application)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
@@ -38,7 +52,24 @@ func (c *RootController) GetOidcDiscovery() {
|
||||
// @Success 200 {object} jose.JSONWebKey
|
||||
// @router /.well-known/jwks [get]
|
||||
func (c *RootController) GetJwks() {
|
||||
jwks, err := object.GetJsonWebKeySet()
|
||||
jwks, err := object.GetJsonWebKeySet("")
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
c.Data["json"] = jwks
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetJwksByApplication
|
||||
// @Title GetJwksByApplication
|
||||
// @Tag OIDC API
|
||||
// @Param application path string true "application name"
|
||||
// @Success 200 {object} jose.JSONWebKey
|
||||
// @router /.well-known/:application/jwks [get]
|
||||
func (c *RootController) GetJwksByApplication() {
|
||||
application := c.Ctx.Input.Param(":application")
|
||||
jwks, err := object.GetJsonWebKeySet(application)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -64,7 +95,37 @@ func (c *RootController) GetWebFinger() {
|
||||
}
|
||||
}
|
||||
|
||||
webfinger, err := object.GetWebFinger(resource, rels, host)
|
||||
webfinger, err := object.GetWebFinger(resource, rels, host, "")
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = webfinger
|
||||
c.Ctx.Output.ContentType("application/jrd+json")
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetWebFingerByApplication
|
||||
// @Title GetWebFingerByApplication
|
||||
// @Tag OIDC API
|
||||
// @Param application path string true "application name"
|
||||
// @Param resource query string true "resource"
|
||||
// @Success 200 {object} object.WebFinger
|
||||
// @router /.well-known/:application/webfinger [get]
|
||||
func (c *RootController) GetWebFingerByApplication() {
|
||||
application := c.Ctx.Input.Param(":application")
|
||||
resource := c.Input().Get("resource")
|
||||
rels := []string{}
|
||||
host := c.Ctx.Request.Host
|
||||
|
||||
for key, value := range c.Input() {
|
||||
if strings.HasPrefix(key, "rel") {
|
||||
rels = append(rels, value...)
|
||||
}
|
||||
}
|
||||
|
||||
webfinger, err := object.GetWebFinger(resource, rels, host, application)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
||||
@@ -24,7 +24,11 @@ import (
|
||||
|
||||
func (c *ApiController) UploadPermissions() {
|
||||
userId := c.GetSessionUsername()
|
||||
owner, user := util.GetOwnerAndNameFromId(userId)
|
||||
owner, user, err := util.GetOwnerAndNameFromIdWithError(userId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
file, header, err := c.Ctx.Request.FormFile("file")
|
||||
if err != nil {
|
||||
|
||||
@@ -180,13 +180,21 @@ func (c *ApiController) BuyProduct() {
|
||||
pricingName := c.Input().Get("pricingName")
|
||||
planName := c.Input().Get("planName")
|
||||
paidUserName := c.Input().Get("userName")
|
||||
owner, _ := util.GetOwnerAndNameFromId(id)
|
||||
userId := util.GetId(owner, paidUserName)
|
||||
if paidUserName != "" && paidUserName != c.GetSessionUsername() && !c.IsAdmin() {
|
||||
c.ResponseError(c.T("general:Only admin user can specify user"))
|
||||
owner, _, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if paidUserName == "" {
|
||||
var userId string
|
||||
if paidUserName != "" {
|
||||
userId = util.GetId(owner, paidUserName)
|
||||
if userId != c.GetSessionUsername() && !c.IsAdmin() && userId != c.GetPaidUsername() {
|
||||
c.ResponseError(c.T("general:Only admin user can specify user"))
|
||||
return
|
||||
}
|
||||
|
||||
c.SetSession("paidUsername", "")
|
||||
} else {
|
||||
userId = c.GetSessionUsername()
|
||||
}
|
||||
if userId == "" {
|
||||
|
||||
@@ -16,6 +16,7 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
// GetPrometheusInfo
|
||||
@@ -37,3 +38,17 @@ func (c *ApiController) GetPrometheusInfo() {
|
||||
|
||||
c.ResponseOk(prometheusInfo)
|
||||
}
|
||||
|
||||
// GetMetrics
|
||||
// @Title GetMetrics
|
||||
// @Tag System API
|
||||
// @Description get Prometheus metrics
|
||||
// @Success 200 {string} Prometheus metrics in text format
|
||||
// @router /metrics [get]
|
||||
func (c *ApiController) GetMetrics() {
|
||||
_, ok := c.RequireAdmin()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
promhttp.Handler().ServeHTTP(c.Ctx.ResponseWriter, c.Ctx.Request)
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ func (c *ApiController) UploadResource() {
|
||||
}
|
||||
|
||||
applicationObj.TermsOfUse = fileUrl
|
||||
_, err = object.UpdateApplication(applicationId, applicationObj)
|
||||
_, err = object.UpdateApplication(applicationId, applicationObj, true, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
||||
@@ -24,7 +24,11 @@ import (
|
||||
|
||||
func (c *ApiController) UploadRoles() {
|
||||
userId := c.GetSessionUsername()
|
||||
owner, user := util.GetOwnerAndNameFromId(userId)
|
||||
owner, user, err := util.GetOwnerAndNameFromIdWithError(userId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
file, header, err := c.Ctx.Request.FormFile("file")
|
||||
if err != nil {
|
||||
|
||||
@@ -59,8 +59,10 @@ func (c *ApiController) HandleSamlRedirect() {
|
||||
|
||||
relayState := c.Input().Get("RelayState")
|
||||
samlRequest := c.Input().Get("SAMLRequest")
|
||||
username := c.Input().Get("username")
|
||||
loginHint := c.Input().Get("login_hint")
|
||||
|
||||
targetURL := object.GetSamlRedirectAddress(owner, application, relayState, samlRequest, host)
|
||||
targetURL := object.GetSamlRedirectAddress(owner, application, relayState, samlRequest, host, username, loginHint)
|
||||
|
||||
c.Redirect(targetURL, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ func (c *ApiController) SendEmail() {
|
||||
content = strings.Replace(content, string(matchContent), "", -1)
|
||||
|
||||
for _, receiver := range emailForm.Receivers {
|
||||
err = object.SendEmail(provider, emailForm.Title, content, receiver, emailForm.Sender)
|
||||
err = object.SendEmail(provider, emailForm.Title, content, []string{receiver}, emailForm.Sender)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
||||
@@ -68,7 +68,7 @@ func (c *ApiController) GetSessions() {
|
||||
// @Title GetSingleSession
|
||||
// @Tag Session API
|
||||
// @Description Get session for one user in one application.
|
||||
// @Param id query string true "The id(organization/application/user) of session"
|
||||
// @Param sessionPkId query string true "The id(organization/user/application) of session"
|
||||
// @Success 200 {array} string The Response object
|
||||
// @router /get-session [get]
|
||||
func (c *ApiController) GetSingleSession() {
|
||||
@@ -87,7 +87,7 @@ func (c *ApiController) GetSingleSession() {
|
||||
// @Title UpdateSession
|
||||
// @Tag Session API
|
||||
// @Description Update session for one user in one application.
|
||||
// @Param id query string true "The id(organization/application/user) of session"
|
||||
// @Param id query string true "The id(organization/user/application) of session"
|
||||
// @Success 200 {array} string The Response object
|
||||
// @router /update-session [post]
|
||||
func (c *ApiController) UpdateSession() {
|
||||
@@ -106,7 +106,7 @@ func (c *ApiController) UpdateSession() {
|
||||
// @Title AddSession
|
||||
// @Tag Session API
|
||||
// @Description Add session for one user in one application. If there are other existing sessions, join the session into the list.
|
||||
// @Param id query string true "The id(organization/application/user) of session"
|
||||
// @Param id query string true "The id(organization/user/application) of session"
|
||||
// @Param sessionId query string true "sessionId to be added"
|
||||
// @Success 200 {array} string The Response object
|
||||
// @router /add-session [post]
|
||||
@@ -126,7 +126,7 @@ func (c *ApiController) AddSession() {
|
||||
// @Title DeleteSession
|
||||
// @Tag Session API
|
||||
// @Description Delete session for one user in one application.
|
||||
// @Param id query string true "The id(organization/application/user) of session"
|
||||
// @Param id query string true "The id(organization/user/application) of session"
|
||||
// @Success 200 {array} string The Response object
|
||||
// @router /delete-session [post]
|
||||
func (c *ApiController) DeleteSession() {
|
||||
@@ -145,7 +145,7 @@ func (c *ApiController) DeleteSession() {
|
||||
// @Title IsSessionDuplicated
|
||||
// @Tag Session API
|
||||
// @Description Check if there are other different sessions for one user in one application.
|
||||
// @Param id query string true "The id(organization/application/user) of session"
|
||||
// @Param sessionPkId query string true "The id(organization/user/application) of session"
|
||||
// @Param sessionId query string true "sessionId to be checked"
|
||||
// @Success 200 {array} string The Response object
|
||||
// @router /is-session-duplicated [get]
|
||||
|
||||
@@ -16,6 +16,7 @@ package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
@@ -103,7 +104,7 @@ func (c *ApiController) UpdateSyncer() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateSyncer(id, &syncer))
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateSyncer(id, &syncer, c.IsGlobalAdmin(), c.GetAcceptLanguage()))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
@@ -159,6 +160,10 @@ func (c *ApiController) RunSyncer() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if syncer == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("general:The syncer: %s does not exist"), id))
|
||||
return
|
||||
}
|
||||
|
||||
err = object.RunSyncer(syncer)
|
||||
if err != nil {
|
||||
@@ -177,7 +182,7 @@ func (c *ApiController) TestSyncerDb() {
|
||||
return
|
||||
}
|
||||
|
||||
err = object.TestSyncerDb(syncer)
|
||||
err = object.TestSyncer(syncer)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
||||
@@ -105,7 +105,7 @@ func (c *ApiController) UpdateToken() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateToken(id, &token))
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateToken(id, &token, c.IsGlobalAdmin()))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,26 @@ func (c *ApiController) GetTransactions() {
|
||||
sortOrder := c.Input().Get("sortOrder")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
transactions, err := object.GetTransactions(owner)
|
||||
var transactions []*object.Transaction
|
||||
var err error
|
||||
|
||||
if c.IsAdmin() {
|
||||
// If field is "user", filter by that user even for admins
|
||||
if field == "user" && value != "" {
|
||||
transactions, err = object.GetUserTransactions(owner, value)
|
||||
} else {
|
||||
transactions, err = object.GetTransactions(owner)
|
||||
}
|
||||
} else {
|
||||
user := c.GetSessionUsername()
|
||||
_, userName, userErr := util.GetOwnerAndNameFromIdWithError(user)
|
||||
if userErr != nil {
|
||||
c.ResponseError(userErr.Error())
|
||||
return
|
||||
}
|
||||
transactions, err = object.GetUserTransactions(owner, userName)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -48,6 +67,19 @@ func (c *ApiController) GetTransactions() {
|
||||
c.ResponseOk(transactions)
|
||||
} else {
|
||||
limit := util.ParseInt(limit)
|
||||
|
||||
// Apply user filter for non-admin users
|
||||
if !c.IsAdmin() {
|
||||
user := c.GetSessionUsername()
|
||||
_, userName, userErr := util.GetOwnerAndNameFromIdWithError(user)
|
||||
if userErr != nil {
|
||||
c.ResponseError(userErr.Error())
|
||||
return
|
||||
}
|
||||
field = "user"
|
||||
value = userName
|
||||
}
|
||||
|
||||
count, err := object.GetTransactionCount(owner, field, value)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -65,28 +97,6 @@ func (c *ApiController) GetTransactions() {
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserTransactions
|
||||
// @Title GetUserTransaction
|
||||
// @Tag Transaction API
|
||||
// @Description get transactions for a user
|
||||
// @Param owner query string true "The owner of transactions"
|
||||
// @Param organization query string true "The organization of the user"
|
||||
// @Param user query string true "The username of the user"
|
||||
// @Success 200 {array} object.Transaction The Response object
|
||||
// @router /get-user-transactions [get]
|
||||
func (c *ApiController) GetUserTransactions() {
|
||||
owner := c.Input().Get("owner")
|
||||
user := c.Input().Get("user")
|
||||
|
||||
transactions, err := object.GetUserTransactions(owner, user)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(transactions)
|
||||
}
|
||||
|
||||
// GetTransaction
|
||||
// @Title GetTransaction
|
||||
// @Tag Transaction API
|
||||
@@ -124,7 +134,7 @@ func (c *ApiController) UpdateTransaction() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateTransaction(id, &transaction))
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateTransaction(id, &transaction, c.GetAcceptLanguage()))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
@@ -143,7 +153,7 @@ func (c *ApiController) AddTransaction() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddTransaction(&transaction))
|
||||
c.Data["json"] = wrapActionResponse(object.AddTransaction(&transaction, c.GetAcceptLanguage()))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
@@ -162,6 +172,6 @@ func (c *ApiController) DeleteTransaction() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.DeleteTransaction(&transaction))
|
||||
c.Data["json"] = wrapActionResponse(object.DeleteTransaction(&transaction, c.GetAcceptLanguage()))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
@@ -252,12 +252,16 @@ func (c *ApiController) GetUser() {
|
||||
// @Title UpdateUser
|
||||
// @Tag User API
|
||||
// @Description update user
|
||||
// @Param id query string true "The id ( owner/name ) of the user"
|
||||
// @Param id query string false "The id ( owner/name ) of the user"
|
||||
// @Param userId query string false "The userId (UUID) of the user"
|
||||
// @Param owner query string false "The owner of the user (required when using userId)"
|
||||
// @Param body body object.User true "The details of the user"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-user [post]
|
||||
func (c *ApiController) UpdateUser() {
|
||||
id := c.Input().Get("id")
|
||||
userId := c.Input().Get("userId")
|
||||
owner := c.Input().Get("owner")
|
||||
columnsStr := c.Input().Get("columns")
|
||||
|
||||
var user object.User
|
||||
@@ -267,17 +271,38 @@ func (c *ApiController) UpdateUser() {
|
||||
return
|
||||
}
|
||||
|
||||
if id == "" {
|
||||
if id == "" && userId == "" {
|
||||
id = c.GetSessionUsername()
|
||||
if id == "" {
|
||||
c.ResponseError(c.T("general:Missing parameter"))
|
||||
return
|
||||
}
|
||||
}
|
||||
oldUser, err := object.GetUser(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
||||
var userFromUserId *object.User
|
||||
if userId != "" && owner != "" {
|
||||
userFromUserId, err = object.GetUserByUserId(owner, userId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if userFromUserId == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
|
||||
return
|
||||
}
|
||||
|
||||
id = util.GetId(userFromUserId.Owner, userFromUserId.Name)
|
||||
}
|
||||
|
||||
var oldUser *object.User
|
||||
if userId != "" {
|
||||
oldUser = userFromUserId
|
||||
} else {
|
||||
oldUser, err = object.GetUser(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if oldUser == nil {
|
||||
@@ -367,6 +392,17 @@ func (c *ApiController) AddUser() {
|
||||
return
|
||||
}
|
||||
|
||||
// Set RegisterSource based on the current user if not already set
|
||||
if user.RegisterType == "" {
|
||||
user.RegisterType = "Add User"
|
||||
}
|
||||
if user.RegisterSource == "" {
|
||||
currentUser := c.getCurrentUser()
|
||||
if currentUser != nil {
|
||||
user.RegisterSource = currentUser.GetId()
|
||||
}
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddUser(&user, c.GetAcceptLanguage()))
|
||||
c.ServeJSON()
|
||||
}
|
||||
@@ -464,11 +500,6 @@ func (c *ApiController) SetPassword() {
|
||||
// return
|
||||
// }
|
||||
|
||||
if strings.Contains(newPassword, " ") {
|
||||
c.ResponseError(c.T("user:New password cannot contain blank space."))
|
||||
return
|
||||
}
|
||||
|
||||
userId := util.GetId(userOwner, userName)
|
||||
|
||||
user, err := object.GetUser(userId)
|
||||
@@ -481,6 +512,41 @@ func (c *ApiController) SetPassword() {
|
||||
return
|
||||
}
|
||||
|
||||
// Get organization to check for password obfuscation settings
|
||||
organization, err := object.GetOrganizationByUser(user)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if organization == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:the organization: %s is not found"), user.Owner))
|
||||
return
|
||||
}
|
||||
|
||||
// Deobfuscate passwords if organization has password obfuscator configured
|
||||
// Note: Deobfuscation is optional - if it fails, we treat the password as plain text
|
||||
// This allows SDKs and raw HTTP API calls to work without obfuscation support
|
||||
if organization.PasswordObfuscatorType != "" && organization.PasswordObfuscatorType != "Plain" {
|
||||
if oldPassword != "" {
|
||||
deobfuscatedOldPassword, deobfuscateErr := util.GetUnobfuscatedPassword(organization.PasswordObfuscatorType, organization.PasswordObfuscatorKey, oldPassword)
|
||||
if deobfuscateErr == nil {
|
||||
oldPassword = deobfuscatedOldPassword
|
||||
}
|
||||
}
|
||||
|
||||
if newPassword != "" {
|
||||
deobfuscatedNewPassword, deobfuscateErr := util.GetUnobfuscatedPassword(organization.PasswordObfuscatorType, organization.PasswordObfuscatorKey, newPassword)
|
||||
if deobfuscateErr == nil {
|
||||
newPassword = deobfuscatedNewPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(newPassword, " ") {
|
||||
c.ResponseError(c.T("user:New password cannot contain blank space."))
|
||||
return
|
||||
}
|
||||
|
||||
requestUserId := c.GetSessionUsername()
|
||||
if requestUserId == "" && code == "" {
|
||||
c.ResponseError(c.T("general:Please login first"), "Please login first")
|
||||
@@ -524,30 +590,28 @@ func (c *ApiController) SetPassword() {
|
||||
}
|
||||
}
|
||||
} else if code == "" {
|
||||
if user.Ldap == "" {
|
||||
err = object.CheckPassword(targetUser, oldPassword, c.GetAcceptLanguage())
|
||||
} else {
|
||||
err = object.CheckLdapUserPassword(targetUser, oldPassword, c.GetAcceptLanguage())
|
||||
}
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
if targetUser.Password != "" || user.Ldap != "" {
|
||||
if user.Ldap == "" {
|
||||
err = object.CheckPassword(targetUser, oldPassword, c.GetAcceptLanguage())
|
||||
} else {
|
||||
err = object.CheckLdapUserPassword(targetUser, oldPassword, c.GetAcceptLanguage())
|
||||
}
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg := object.CheckPasswordComplexity(targetUser, newPassword)
|
||||
msg := object.CheckPasswordComplexity(targetUser, newPassword, c.GetAcceptLanguage())
|
||||
if msg != "" {
|
||||
c.ResponseError(msg)
|
||||
return
|
||||
}
|
||||
|
||||
organization, err := object.GetOrganizationByUser(targetUser)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if organization == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:the organization: %s is not found"), targetUser.Owner))
|
||||
// Check if the new password is the same as the current password
|
||||
if !object.CheckPasswordNotSameAsCurrent(targetUser, newPassword, organization) {
|
||||
c.ResponseError(c.T("user:The new password must be different from your current password"))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -40,8 +40,23 @@ func saveFile(path string, file *multipart.File) (err error) {
|
||||
}
|
||||
|
||||
func (c *ApiController) UploadUsers() {
|
||||
if !c.IsAdmin() {
|
||||
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||
return
|
||||
}
|
||||
|
||||
userObj := c.getCurrentUser()
|
||||
if userObj == nil {
|
||||
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||
return
|
||||
}
|
||||
|
||||
userId := c.GetSessionUsername()
|
||||
owner, user := util.GetOwnerAndNameFromId(userId)
|
||||
owner, user, err := util.GetOwnerAndNameFromIdWithError(userId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
file, header, err := c.Ctx.Request.FormFile("file")
|
||||
if err != nil {
|
||||
@@ -58,7 +73,7 @@ func (c *ApiController) UploadUsers() {
|
||||
return
|
||||
}
|
||||
|
||||
affected, err := object.UploadUsers(owner, path)
|
||||
affected, err := object.UploadUsers(owner, path, userObj, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
||||
@@ -44,7 +44,11 @@ const (
|
||||
// @Success 200 {array} object.Verification The Response object
|
||||
// @router /get-payments [get]
|
||||
func (c *ApiController) GetVerifications() {
|
||||
owner := c.Input().Get("owner")
|
||||
organization, ok := c.RequireAdmin()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
limit := c.Input().Get("pageSize")
|
||||
page := c.Input().Get("p")
|
||||
field := c.Input().Get("field")
|
||||
@@ -52,8 +56,15 @@ func (c *ApiController) GetVerifications() {
|
||||
sortField := c.Input().Get("sortField")
|
||||
sortOrder := c.Input().Get("sortOrder")
|
||||
|
||||
owner := c.Input().Get("owner")
|
||||
// For global admin with organizationName parameter, use it to filter
|
||||
// For org admin, use their organization
|
||||
if c.IsGlobalAdmin() && owner != "" {
|
||||
organization = owner
|
||||
}
|
||||
|
||||
if limit == "" || page == "" {
|
||||
payments, err := object.GetVerifications(owner)
|
||||
payments, err := object.GetVerifications(organization)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -62,14 +73,14 @@ func (c *ApiController) GetVerifications() {
|
||||
c.ResponseOk(payments)
|
||||
} else {
|
||||
limit := util.ParseInt(limit)
|
||||
count, err := object.GetVerificationCount(owner, field, value)
|
||||
count, err := object.GetVerificationCount(organization, field, value)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
payments, err := object.GetPaginationVerifications(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
payments, err := object.GetPaginationVerifications(organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -258,7 +269,7 @@ func (c *ApiController) SendVerificationCode() {
|
||||
return
|
||||
}
|
||||
|
||||
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, clientIp, vform.Dest, vform.Method, c.Ctx.Request.Host, application.Name)
|
||||
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, clientIp, vform.Dest, vform.Method, c.Ctx.Request.Host, application.Name, application)
|
||||
case object.VerifyTypePhone:
|
||||
if vform.Method == LoginVerification || vform.Method == ForgetVerification {
|
||||
if user != nil && util.GetMaskedPhone(user.Phone) == vform.Dest {
|
||||
@@ -304,7 +315,7 @@ func (c *ApiController) SendVerificationCode() {
|
||||
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), vform.CountryCode))
|
||||
return
|
||||
} else {
|
||||
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, clientIp, phone)
|
||||
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, clientIp, phone, application)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,9 +446,15 @@ func (c *ApiController) ResetEmailOrPhone() {
|
||||
|
||||
switch destType {
|
||||
case object.VerifyTypeEmail:
|
||||
id := user.GetId()
|
||||
user.Email = dest
|
||||
user.EmailVerified = true
|
||||
_, err = object.UpdateUser(user.GetId(), user, []string{"email", "email_verified"}, false)
|
||||
columns := []string{"email", "email_verified"}
|
||||
if organization.UseEmailAsUsername {
|
||||
user.Name = user.Email
|
||||
columns = append(columns, "name")
|
||||
}
|
||||
_, err = object.UpdateUser(id, user, columns, false)
|
||||
case object.VerifyTypePhone:
|
||||
user.Phone = dest
|
||||
_, err = object.SetUserField(user, "phone", user.Phone)
|
||||
@@ -449,6 +466,9 @@ func (c *ApiController) ResetEmailOrPhone() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if organization.UseEmailAsUsername {
|
||||
c.SetSessionUsername(user.GetId())
|
||||
}
|
||||
|
||||
err = object.DisableVerificationCode(checkDest)
|
||||
if err != nil {
|
||||
|
||||
@@ -105,7 +105,7 @@ func (c *ApiController) UpdateWebhook() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateWebhook(id, &webhook))
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateWebhook(id, &webhook, c.IsGlobalAdmin(), c.GetAcceptLanguage()))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
|
||||
@@ -96,15 +96,17 @@ func NewAzureACSEmailProvider(accessKey string, endpoint string) *AzureACSEmailP
|
||||
}
|
||||
}
|
||||
|
||||
func newEmail(fromAddress string, toAddress string, subject string, content string) *Email {
|
||||
func newEmail(fromAddress string, toAddress []string, subject string, content string) *Email {
|
||||
var to []EmailAddress
|
||||
for _, addr := range toAddress {
|
||||
to = append(to, EmailAddress{
|
||||
DisplayName: addr,
|
||||
Address: addr,
|
||||
})
|
||||
}
|
||||
return &Email{
|
||||
Recipients: Recipients{
|
||||
To: []EmailAddress{
|
||||
{
|
||||
DisplayName: toAddress,
|
||||
Address: toAddress,
|
||||
},
|
||||
},
|
||||
To: to,
|
||||
},
|
||||
SenderAddress: fromAddress,
|
||||
Content: Content{
|
||||
@@ -116,7 +118,7 @@ func newEmail(fromAddress string, toAddress string, subject string, content stri
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AzureACSEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
|
||||
func (a *AzureACSEmailProvider) Send(fromAddress string, fromName string, toAddress []string, subject string, content string) error {
|
||||
email := newEmail(fromAddress, toAddress, subject, content)
|
||||
|
||||
postBody, err := json.Marshal(email)
|
||||
|
||||
@@ -48,21 +48,26 @@ func NewHttpEmailProvider(endpoint string, method string, httpHeaders map[string
|
||||
return client
|
||||
}
|
||||
|
||||
func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
|
||||
func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress []string, subject string, content string) error {
|
||||
var req *http.Request
|
||||
var err error
|
||||
|
||||
fromAddressField := "fromAddress"
|
||||
fromNameField := "fromName"
|
||||
toAddressField := "toAddress"
|
||||
toAddressesField := "toAddresses"
|
||||
subjectField := "subject"
|
||||
contentField := "content"
|
||||
|
||||
for k, v := range c.bodyMapping {
|
||||
switch k {
|
||||
case "fromAddress":
|
||||
fromAddressField = v
|
||||
case "fromName":
|
||||
fromNameField = v
|
||||
case "toAddress":
|
||||
toAddressField = v
|
||||
case "toAddresses":
|
||||
toAddressesField = v
|
||||
case "subject":
|
||||
subjectField = v
|
||||
case "content":
|
||||
@@ -72,8 +77,8 @@ func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress
|
||||
|
||||
if c.method == "POST" || c.method == "PUT" || c.method == "DELETE" {
|
||||
bodyMap := make(map[string]string)
|
||||
bodyMap[fromAddressField] = fromAddress
|
||||
bodyMap[fromNameField] = fromName
|
||||
bodyMap[toAddressField] = toAddress
|
||||
bodyMap[subjectField] = subject
|
||||
bodyMap[contentField] = content
|
||||
|
||||
@@ -89,6 +94,13 @@ func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress
|
||||
for k, v := range bodyMap {
|
||||
formValues.Add(k, v)
|
||||
}
|
||||
if len(toAddress) == 1 {
|
||||
formValues.Add(toAddressField, toAddress[0])
|
||||
} else {
|
||||
for _, addr := range toAddress {
|
||||
formValues.Add(toAddressesField, addr)
|
||||
}
|
||||
}
|
||||
req, err = http.NewRequest(c.method, c.endpoint, strings.NewReader(formValues.Encode()))
|
||||
}
|
||||
|
||||
@@ -104,8 +116,15 @@ func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress
|
||||
}
|
||||
|
||||
q := req.URL.Query()
|
||||
q.Add(fromAddressField, fromAddress)
|
||||
q.Add(fromNameField, fromName)
|
||||
q.Add(toAddressField, toAddress)
|
||||
if len(toAddress) == 1 {
|
||||
q.Add(toAddressField, toAddress[0])
|
||||
} else {
|
||||
for _, addr := range toAddress {
|
||||
q.Add(toAddressesField, addr)
|
||||
}
|
||||
}
|
||||
q.Add(subjectField, subject)
|
||||
q.Add(contentField, content)
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
package email
|
||||
|
||||
type EmailProvider interface {
|
||||
Send(fromAddress string, fromName, toAddress string, subject string, content string) error
|
||||
Send(fromAddress string, fromName string, toAddress []string, subject string, content string) error
|
||||
}
|
||||
|
||||
func GetEmailProvider(typ string, clientId string, clientSecret string, host string, port int, disableSsl bool, endpoint string, method string, httpHeaders map[string]string, bodyMapping map[string]string, contentType string) EmailProvider {
|
||||
func GetEmailProvider(typ string, clientId string, clientSecret string, host string, port int, disableSsl bool, endpoint string, method string, httpHeaders map[string]string, bodyMapping map[string]string, contentType string, enableProxy bool) EmailProvider {
|
||||
if typ == "Azure ACS" {
|
||||
return NewAzureACSEmailProvider(clientSecret, host)
|
||||
} else if typ == "Custom HTTP Email" {
|
||||
@@ -26,6 +26,6 @@ func GetEmailProvider(typ string, clientId string, clientSecret string, host str
|
||||
} else if typ == "SendGrid" {
|
||||
return NewSendgridEmailProvider(clientSecret, host, endpoint)
|
||||
} else {
|
||||
return NewSmtpEmailProvider(clientId, clientSecret, host, port, typ, disableSsl)
|
||||
return NewSmtpEmailProvider(clientId, clientSecret, host, port, typ, disableSsl, enableProxy)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,13 +41,24 @@ func NewSendgridEmailProvider(apiKey string, host string, endpoint string) *Send
|
||||
return &SendgridEmailProvider{ApiKey: apiKey, Host: host, Endpoint: endpoint}
|
||||
}
|
||||
|
||||
func (s *SendgridEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
|
||||
client := s.initSendgridClient()
|
||||
|
||||
func (s *SendgridEmailProvider) Send(fromAddress string, fromName string, toAddresses []string, subject string, content string) error {
|
||||
from := mail.NewEmail(fromName, fromAddress)
|
||||
to := mail.NewEmail("", toAddress)
|
||||
message := mail.NewSingleEmail(from, subject, to, "", content)
|
||||
message := mail.NewV3Mail()
|
||||
message.SetFrom(from)
|
||||
message.AddContent(mail.NewContent("text/html", content))
|
||||
|
||||
personalization := mail.NewPersonalization()
|
||||
|
||||
for _, toAddress := range toAddresses {
|
||||
to := mail.NewEmail(toAddress, toAddress)
|
||||
personalization.AddTos(to)
|
||||
}
|
||||
|
||||
personalization.Subject = subject
|
||||
|
||||
message.AddPersonalizations(personalization)
|
||||
|
||||
client := s.initSendgridClient()
|
||||
resp, err := client.Send(message)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -16,7 +16,6 @@ package email
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"strings"
|
||||
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/gomail/v2"
|
||||
@@ -26,7 +25,7 @@ type SmtpEmailProvider struct {
|
||||
Dialer *gomail.Dialer
|
||||
}
|
||||
|
||||
func NewSmtpEmailProvider(userName string, password string, host string, port int, typ string, disableSsl bool) *SmtpEmailProvider {
|
||||
func NewSmtpEmailProvider(userName string, password string, host string, port int, typ string, disableSsl bool, enableProxy bool) *SmtpEmailProvider {
|
||||
dialer := gomail.NewDialer(host, port, userName, password)
|
||||
if typ == "SUBMAIL" {
|
||||
dialer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
@@ -34,7 +33,7 @@ func NewSmtpEmailProvider(userName string, password string, host string, port in
|
||||
|
||||
dialer.SSL = !disableSsl
|
||||
|
||||
if strings.HasSuffix(host, ".amazonaws.com") {
|
||||
if enableProxy {
|
||||
socks5Proxy := conf.GetConfigString("socks5Proxy")
|
||||
if socks5Proxy != "" {
|
||||
dialer.SetSocks5Proxy(socks5Proxy)
|
||||
@@ -44,11 +43,15 @@ func NewSmtpEmailProvider(userName string, password string, host string, port in
|
||||
return &SmtpEmailProvider{Dialer: dialer}
|
||||
}
|
||||
|
||||
func (s *SmtpEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
|
||||
func (s *SmtpEmailProvider) Send(fromAddress string, fromName string, toAddresses []string, subject string, content string) error {
|
||||
message := gomail.NewMessage()
|
||||
|
||||
message.SetAddressHeader("From", fromAddress, fromName)
|
||||
message.SetHeader("To", toAddress)
|
||||
var addresses []string
|
||||
for _, address := range toAddresses {
|
||||
addresses = append(addresses, message.FormatAddress(address, ""))
|
||||
}
|
||||
message.SetHeader("To", addresses...)
|
||||
message.SetHeader("Subject", subject)
|
||||
message.SetBody("text/html", content)
|
||||
|
||||
|
||||
34
go.mod
34
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/casdoor/casdoor
|
||||
|
||||
go 1.21
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
github.com/Masterminds/squirrel v1.5.3
|
||||
@@ -29,7 +29,8 @@ require (
|
||||
github.com/go-git/go-git/v5 v5.13.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-pay/gopay v1.5.115
|
||||
github.com/go-pay/util v0.0.4
|
||||
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.10.2
|
||||
@@ -41,7 +42,7 @@ require (
|
||||
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
|
||||
github.com/markbates/goth v1.79.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/nyaruka/phonenumbers v1.1.5
|
||||
github.com/nyaruka/phonenumbers v1.2.2
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/prometheus/client_golang v1.11.1
|
||||
github.com/prometheus/client_model v0.4.0
|
||||
@@ -59,13 +60,13 @@ require (
|
||||
github.com/xorm-io/builder v0.3.13
|
||||
github.com/xorm-io/core v0.7.4
|
||||
github.com/xorm-io/xorm v1.1.6
|
||||
golang.org/x/crypto v0.32.0
|
||||
golang.org/x/net v0.34.0
|
||||
golang.org/x/crypto v0.39.0
|
||||
golang.org/x/net v0.40.0
|
||||
golang.org/x/oauth2 v0.17.0
|
||||
golang.org/x/text v0.21.0
|
||||
golang.org/x/text v0.26.0
|
||||
google.golang.org/api v0.150.0
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68
|
||||
layeh.com/radius v0.0.0-20231213012653-1006025d24f8
|
||||
maunium.net/go/mautrix v0.16.0
|
||||
modernc.org/sqlite v1.18.2
|
||||
)
|
||||
@@ -128,10 +129,15 @@ require (
|
||||
github.com/go-git/go-billy/v5 v5.6.0 // indirect
|
||||
github.com/go-lark/lark v1.9.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-pay/crypto v0.0.1 // indirect
|
||||
github.com/go-pay/errgroup v0.0.3 // indirect
|
||||
github.com/go-pay/smap v0.0.2 // indirect
|
||||
github.com/go-pay/xlog v0.0.3 // indirect
|
||||
github.com/go-pay/xtime v0.0.2 // indirect
|
||||
github.com/go-webauthn/x v0.1.9 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
@@ -188,7 +194,7 @@ require (
|
||||
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
|
||||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||
github.com/slack-go/slack v0.12.3 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
@@ -217,18 +223,18 @@ require (
|
||||
go.uber.org/zap v1.19.1 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
|
||||
golang.org/x/mod v0.19.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.23.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
|
||||
google.golang.org/grpc v1.59.0 // indirect
|
||||
google.golang.org/protobuf v1.32.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
|
||||
63
go.sum
63
go.sum
@@ -384,8 +384,20 @@ github.com/go-mysql-org/go-mysql v1.7.0 h1:qE5FTRb3ZeTQmlk3pjE+/m2ravGxxRDrVDTyD
|
||||
github.com/go-mysql-org/go-mysql v1.7.0/go.mod h1:9cRWLtuXNKhamUPMkrDVzBhaomGvqLRLtBiyjvjc4pk=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-pay/gopay v1.5.72 h1:3zm64xMBhJBa8rXbm//q5UiGgOa4WO5XYEnU394N2Zw=
|
||||
github.com/go-pay/gopay v1.5.72/go.mod h1:0qOGIJuFW7PKDOjmecwKyW0mgsVImgwB9yPJj0ilpn8=
|
||||
github.com/go-pay/crypto v0.0.1 h1:B6InT8CLfSLc6nGRVx9VMJRBBazFMjr293+jl0lLXUY=
|
||||
github.com/go-pay/crypto v0.0.1/go.mod h1:41oEIvHMKbNcYlWUlRWtsnC6+ASgh7u29z0gJXe5bes=
|
||||
github.com/go-pay/errgroup v0.0.3 h1:DB4s8e8oWYDyETKQ1y1riMJ7y29zE1uIsMCSjEOFSbU=
|
||||
github.com/go-pay/errgroup v0.0.3/go.mod h1:0+4b8mvFMS71MIzsaC+gVvB4x37I93lRb2dqrwuU8x8=
|
||||
github.com/go-pay/gopay v1.5.115 h1:8WjWftPChKCiVt5Qz2xLqXeUdidsR+y9/R2S/7Q9szc=
|
||||
github.com/go-pay/gopay v1.5.115/go.mod h1:p48xvWeepPolZuakAjCeucWynWwW7msoXsqahcoJpKE=
|
||||
github.com/go-pay/smap v0.0.2 h1:kKflYor5T5FgZltPFBMTFfjJvqYMHr5VnIFSEyhVTcA=
|
||||
github.com/go-pay/smap v0.0.2/go.mod h1:HW9oAo0okuyDYsbpbj5fJFxnNj/BZorRGFw26SxrNWw=
|
||||
github.com/go-pay/util v0.0.4 h1:TuwSU9o3Qd7m9v1PbzFuIA/8uO9FJnA6P7neG/NwPyk=
|
||||
github.com/go-pay/util v0.0.4/go.mod h1:Tsdhs8Ib9J9b4+NKNO1PHh5hWHhlg98PthsX0ckq6PM=
|
||||
github.com/go-pay/xlog v0.0.3 h1:avyMhCL/JgBHreoGx/am/kHxfs1udDOAeVqbmzP/Yes=
|
||||
github.com/go-pay/xlog v0.0.3/go.mod h1:mH47xbobrdsSHWsmFtSF5agWbMHFP+tK0ZbVCk5OAEw=
|
||||
github.com/go-pay/xtime v0.0.2 h1:7YR4/iuELsEHpJ6LUO0SVK80hQxDO9MLCfuVYIiTCRM=
|
||||
github.com/go-pay/xtime v0.0.2/go.mod h1:W1yRbJaSt4CSBcdAtLBQ8xajiN/Pl5hquGczUcUE9xE=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
@@ -416,8 +428,8 @@ github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptG
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
@@ -728,8 +740,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/nyaruka/phonenumbers v1.1.5 h1:vYy2DI+z5hdaemqVzXYJ4CVyK92IG484CirEY+40GTo=
|
||||
github.com/nyaruka/phonenumbers v1.1.5/go.mod h1:yShPJHDSH3aTKzCbXyVxNpbl2kA+F+Ne5Pun/MvFRos=
|
||||
github.com/nyaruka/phonenumbers v1.2.2 h1:OwVjf7Y4uHoK9VJUrA8ebR0ha2yc6sEYbfrwkq0asCY=
|
||||
github.com/nyaruka/phonenumbers v1.2.2/go.mod h1:wzk2qq7qwsaBKrfbkWKdgHYOOH+QFTesSpIq53ELw8M=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||
@@ -868,8 +880,9 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
|
||||
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
|
||||
github.com/slack-go/slack v0.12.3 h1:92/dfFU8Q5XP6Wp5rr5/T5JHLM5c5Smtn53fhToAP88=
|
||||
@@ -1023,7 +1036,6 @@ golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
@@ -1037,7 +1049,6 @@ golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
@@ -1049,8 +1060,9 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -1096,8 +1108,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.0.0-20171115151908-9dfe39835686/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1159,8 +1171,9 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1186,8 +1199,9 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1272,8 +1286,9 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -1290,8 +1305,9 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1310,8 +1326,9 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1378,8 +1395,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1487,8 +1504,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
@@ -1536,8 +1553,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68 h1:2NDro2Jzkrqfngy/sA5GVnChs7fx8EzcQKFi/lI2cfg=
|
||||
layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68/go.mod h1:pFWM9De99EY9TPVyHIyA56QmoRViVck/x41WFkUlc9A=
|
||||
layeh.com/radius v0.0.0-20231213012653-1006025d24f8 h1:orYXpi6BJZdvgytfHH4ybOe4wHnLbbS71Cmd8mWdZjs=
|
||||
layeh.com/radius v0.0.0-20231213012653-1006025d24f8/go.mod h1:QRf+8aRqXc019kHkpcs/CTgyWXFzf+bxlsyuo2nAl1o=
|
||||
lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU=
|
||||
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||
maunium.net/go/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8=
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "فشل تسجيل الدخول: %s",
|
||||
"Invalid token": "الرمز غير صالح",
|
||||
"State expected: %s, but got: %s": "كان من المتوقع الحالة: %s، لكن حصلنا على: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "الحساب الخاص بالمزود: %s واسم المستخدم: %s (%s) غير موجود ولا يُسمح بالتسجيل كحساب جديد عبر %%s، يرجى استخدام طريقة أخرى للتسجيل",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "الحساب الخاص بالمزود: %s واسم المستخدم: %s (%s) غير موجود ولا يُسمح بالتسجيل كحساب جديد عبر %s، يرجى استخدام طريقة أخرى للتسجيل",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "الحساب الخاص بالمزود: %s واسم المستخدم: %s (%s) غير موجود ولا يُسمح بالتسجيل كحساب جديد، يرجى الاتصال بدعم تكنولوجيا المعلومات",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "الحساب الخاص بالمزود: %s واسم المستخدم: %s (%s) مرتبط بالفعل بحساب آخر: %s (%s)",
|
||||
"The application: %s does not exist": "التطبيق: %s غير موجود",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "التطبيق: %s قد عطّل تسجيل دخول المستخدمين",
|
||||
"The group: %s does not exist": "المجموعة: %s غير موجودة",
|
||||
"The login method: login with LDAP is not enabled for the application": "طريقة تسجيل الدخول: تسجيل الدخول باستخدام LDAP غير مفعّلة لهذا التطبيق",
|
||||
"The login method: login with SMS is not enabled for the application": "طريقة تسجيل الدخول: تسجيل الدخول باستخدام الرسائل النصية غير مفعّلة لهذا التطبيق",
|
||||
"The login method: login with email is not enabled for the application": "طريقة تسجيل الدخول: تسجيل الدخول باستخدام البريد الإلكتروني غير مفعّلة لهذا التطبيق",
|
||||
"The login method: login with face is not enabled for the application": "طريقة تسجيل الدخول: تسجيل الدخول باستخدام الوجه غير مفعّلة لهذا التطبيق",
|
||||
"The login method: login with password is not enabled for the application": "طريقة تسجيل الدخول: تسجيل الدخول باستخدام كلمة المرور غير مفعّلة لهذا التطبيق",
|
||||
"The organization: %s does not exist": "المنظمة: %s غير موجودة",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "المنظمة: %s قد عطّلت تسجيل دخول المستخدمين",
|
||||
"The plan: %s does not exist": "الخطة: %s غير موجودة",
|
||||
"The pricing: %s does not exist": "التسعير: %s غير موجود",
|
||||
"The pricing: %s does not have plan: %s": "التسعير: %s لا يحتوي على الخطة: %s",
|
||||
"The provider: %s does not exist": "المزود: %s غير موجود",
|
||||
"The provider: %s is not enabled for the application": "المزود: %s غير مفعّل لهذا التطبيق",
|
||||
"Unauthorized operation": "عملية غير مصرح بها",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "يرجى التسجيل باستخدام اسم المستخدم المطابق لرمز الدعوة",
|
||||
"Session outdated, please login again": "الجلسة منتهية الصلاحية، يرجى تسجيل الدخول مرة أخرى",
|
||||
"The invitation code has already been used": "رمز الدعوة تم استخدامه بالفعل",
|
||||
"The password must contain at least one special character": "يجب أن تحتوي كلمة المرور على حرف خاص واحد على الأقل",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "يجب أن تحتوي كلمة المرور على حرف كبير واحد على الأقل وحرف صغير ورقم",
|
||||
"The password must have at least 6 characters": "يجب أن تحتوي كلمة المرور على 6 أحرف على الأقل",
|
||||
"The password must have at least 8 characters": "يجب أن تحتوي كلمة المرور على 8 أحرف على الأقل",
|
||||
"The password must not contain any repeated characters": "يجب ألا تحتوي كلمة المرور على أي أحرف متكررة",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "تم حذف المستخدم ولا يمكن استخدامه لتسجيل الدخول، يرجى الاتصال بالمسؤول",
|
||||
"The user is forbidden to sign in, please contact the administrator": "المستخدم ممنوع من تسجيل الدخول، يرجى الاتصال بالمسؤول",
|
||||
"The user: %s doesn't exist in LDAP server": "المستخدم: %s غير موجود في خادم LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "اسم المستخدم يمكن أن يحتوي فقط على أحرف وأرقام، شرطات سفلية أو علوية، لا يمكن أن تحتوي على شرطات متتالية، ولا يمكن أن يبدأ أو ينتهي بشرطة.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "هذه العملية غير مسموح بها في وضع العرض التوضيحي",
|
||||
"this operation requires administrator to perform": "هذه العملية تتطلب مسؤولاً لتنفيذها"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "الدعوة %s غير موجودة"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "خادم LDAP موجود"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "تم تمكين MFA للبريد الإلكتروني لكن البريد الإلكتروني فارغ",
|
||||
"MFA phone is enabled but phone number is empty": "تم تمكين MFA للهاتف لكن رقم الهاتف فارغ",
|
||||
"New password cannot contain blank space.": "كلمة المرور الجديدة لا يمكن أن تحتوي على مسافات.",
|
||||
"The new password must be different from your current password": "يجب أن تكون كلمة المرور الجديدة مختلفة عن كلمة المرور الحالية",
|
||||
"the user's owner and name should not be empty": "مالك المستخدم واسمه لا يجب أن يكونا فارغين"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "المستخدم غير موجود، يرجى التسجيل أولاً"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "لم يتم العثور على بيانات اعتماد لهذا المستخدم",
|
||||
"Please call WebAuthnSigninBegin first": "يرجى استدعاء WebAuthnSigninBegin أولاً"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,12 @@
|
||||
"Failed to login in: %s": "Giriş uğursuz oldu: %s",
|
||||
"Invalid token": "Etibarsız token",
|
||||
"State expected: %s, but got: %s": "Gözlənilən vəziyyət: %s, lakin alınan: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Provayder üçün hesab: %s və istifadəçi adı: %s (%s) mövcud deyil və %%s vasitəsilə yeni hesab olaraq qeydiyyatdan keçməyə icazə verilmir, xahiş edirik qeydiyyat üçün başqa üsul istifadə edin",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Provayder üçün hesab: %s və istifadəçi adı: %s (%s) mövcud deyil və %s vasitəsilə yeni hesab olaraq qeydiyyatdan keçməyə icazə verilmir, xahiş edirik qeydiyyat üçün başqa üsul istifadə edin",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Provayder üçün hesab: %s və istifadəçi adı: %s (%s) mövcud deyil və yeni hesab olaraq qeydiyyatdan keçməyə icazə verilmir, xahiş edirik IT dəstəyinizlə əlaqə saxlayın",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Provayder üçün hesab: %s və istifadəçi adı: %s (%s) artıq başqa hesabla əlaqələndirilmişdir: %s (%s)",
|
||||
"The application: %s does not exist": "Tətbiq: %s mövcud deyil",
|
||||
"The application: %s has disabled users to signin": "Tətbiq: %s istifadəçilərin girişini söndürmüşdür",
|
||||
"The group: %s does not exist": "Qrup: %s mövcud deyil",
|
||||
"The login method: login with LDAP is not enabled for the application": "Giriş metodu: LDAP ilə giriş bu tətbiq üçün aktiv deyil",
|
||||
"The login method: login with SMS is not enabled for the application": "Giriş metodu: SMS ilə giriş bu tətbiq üçün aktiv deyil",
|
||||
"The login method: login with email is not enabled for the application": "Giriş metodu: email ilə giriş bu tətbiq üçün aktiv deyil",
|
||||
@@ -24,6 +25,9 @@
|
||||
"The login method: login with password is not enabled for the application": "Giriş metodu: şifrə ilə giriş bu tətbiq üçün aktiv deyil",
|
||||
"The organization: %s does not exist": "Təşkilat: %s mövcud deyil",
|
||||
"The organization: %s has disabled users to signin": "Təşkilat: %s istifadəçilərin girişini söndürmüşdür",
|
||||
"The plan: %s does not exist": "Plan: %s mövcud deyil",
|
||||
"The pricing: %s does not exist": "Qiymətləndirmə: %s mövcud deyil",
|
||||
"The pricing: %s does not have plan: %s": "Qiymətləndirmə: %s planı yoxdur: %s",
|
||||
"The provider: %s does not exist": "Provayder: %s mövcud deyil",
|
||||
"The provider: %s is not enabled for the application": "Provayder: %s bu tətbiq üçün aktiv deyil",
|
||||
"Unauthorized operation": "İcazəsiz əməliyyat",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Xahiş edirik dəvət koduna uyğun istifadəçi adı istifadə edərək qeydiyyatdan keçin",
|
||||
"Session outdated, please login again": "Sessiyanın vaxtı keçib, xahiş edirik yenidən daxil olun",
|
||||
"The invitation code has already been used": "Dəvət kodu artıq istifadə edilib",
|
||||
"The password must contain at least one special character": "Parol ən azı bir xüsusi simvol ehtiva etməlidir",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Parol ən azı bir böyük hərf, bir kiçik hərf və bir rəqəm ehtiva etməlidir",
|
||||
"The password must have at least 6 characters": "Parol ən azı 6 simvoldan ibarət olmalıdır",
|
||||
"The password must have at least 8 characters": "Parol ən azı 8 simvoldan ibarət olmalıdır",
|
||||
"The password must not contain any repeated characters": "Parol təkrarlanan simvollar ehtiva etməməlidir",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "İstifadəçi silinib və daxil olmaq üçün istifadə edilə bilməz, zəhmət olmasa administratorla əlaqə saxlayın",
|
||||
"The user is forbidden to sign in, please contact the administrator": "İstifadəçinin girişi qadağandır, xahiş edirik administratorla əlaqə saxlayın",
|
||||
"The user: %s doesn't exist in LDAP server": "İstifadəçi: %s LDAP serverində mövcud deyil",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "İstifadəçi adı yalnız hərf-rəqəm simvolları, alt xətt və ya defis ehtiva edə bilər, ardıcıl defis və ya alt xətt ola bilməz və defis və ya alt xəttlə başlaya və ya bitə bilməz.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "bu əməliyyat demo rejimində icazə verilmir",
|
||||
"this operation requires administrator to perform": "bu əməliyyat administrator tərəfindən yerinə yetirilməsini tələb edir"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Dəvət %s mövcud deyil"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP serveri mövcuddur"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA email aktiv edilib, lakin email boşdur",
|
||||
"MFA phone is enabled but phone number is empty": "MFA telefon aktiv edilib, lakin telefon nömrəsi boşdur",
|
||||
"New password cannot contain blank space.": "Yeni şifrə boş yer ehtiva edə bilməz.",
|
||||
"The new password must be different from your current password": "Yeni şifrə cari şifrənizdən fərqli olmalıdır",
|
||||
"the user's owner and name should not be empty": "istifadəçinin sahibi və adı boş olmamalıdır"
|
||||
},
|
||||
"util": {
|
||||
@@ -190,4 +204,4 @@
|
||||
"Found no credentials for this user": "Bu istifadəçi üçün heç bir etimadnamə tapılmadı",
|
||||
"Please call WebAuthnSigninBegin first": "Xahiş edirik əvvəlcə WebAuthnSigninBegin çağırın"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Nepodařilo se přihlásit: %s",
|
||||
"Invalid token": "Neplatný token",
|
||||
"State expected: %s, but got: %s": "Očekávaný stav: %s, ale získán: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) neexistuje a není povoleno se registrovat jako nový účet přes %%s, prosím použijte jiný způsob registrace",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) neexistuje a není povoleno se registrovat jako nový účet přes %s, prosím použijte jiný způsob registrace",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) neexistuje a není povoleno se registrovat jako nový účet, prosím kontaktujte svou IT podporu",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) je již propojen s jiným účtem: %s (%s)",
|
||||
"The application: %s does not exist": "Aplikace: %s neexistuje",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Aplikace: %s zakázala přihlašování uživatelů",
|
||||
"The group: %s does not exist": "Skupina: %s neexistuje",
|
||||
"The login method: login with LDAP is not enabled for the application": "Přihlašovací metoda: přihlášení pomocí LDAP není pro aplikaci povolena",
|
||||
"The login method: login with SMS is not enabled for the application": "Přihlašovací metoda: přihlášení pomocí SMS není pro aplikaci povolena",
|
||||
"The login method: login with email is not enabled for the application": "Přihlašovací metoda: přihlášení pomocí e-mailu není pro aplikaci povolena",
|
||||
"The login method: login with face is not enabled for the application": "Přihlašovací metoda: přihlášení pomocí obličeje není pro aplikaci povolena",
|
||||
"The login method: login with password is not enabled for the application": "Metoda přihlášení: přihlášení pomocí hesla není pro aplikaci povolena",
|
||||
"The organization: %s does not exist": "Organizace: %s neexistuje",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Organizace: %s zakázala přihlašování uživatelů",
|
||||
"The plan: %s does not exist": "Plán: %s neexistuje",
|
||||
"The pricing: %s does not exist": "Ceník: %s neexistuje",
|
||||
"The pricing: %s does not have plan: %s": "Ceník: %s nemá plán: %s",
|
||||
"The provider: %s does not exist": "Poskytovatel: %s neexistuje",
|
||||
"The provider: %s is not enabled for the application": "Poskytovatel: %s není pro aplikaci povolen",
|
||||
"Unauthorized operation": "Neoprávněná operace",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Prosím registrujte se pomocí uživatelského jména odpovídajícího pozvánkovému kódu",
|
||||
"Session outdated, please login again": "Relace je zastaralá, prosím přihlaste se znovu",
|
||||
"The invitation code has already been used": "Pozvánkový kód již byl použit",
|
||||
"The password must contain at least one special character": "Heslo musí obsahovat alespoň jeden speciální znak",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Heslo musí obsahovat alespoň jedno velké písmeno, jedno malé písmeno a jednu číslici",
|
||||
"The password must have at least 6 characters": "Heslo musí mít alespoň 6 znaků",
|
||||
"The password must have at least 8 characters": "Heslo musí mít alespoň 8 znaků",
|
||||
"The password must not contain any repeated characters": "Heslo nesmí obsahovat opakující se znaky",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Uživatel byl odstraněn a nelze jej použít k přihlášení, kontaktujte prosím správce",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Uživatel má zakázáno se přihlásit, prosím kontaktujte administrátora",
|
||||
"The user: %s doesn't exist in LDAP server": "Uživatel: %s neexistuje na LDAP serveru",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Uživatelské jméno může obsahovat pouze alfanumerické znaky, podtržítka nebo pomlčky, nemůže mít po sobě jdoucí pomlčky nebo podtržítka a nemůže začínat nebo končit pomlčkou nebo podtržítkem.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "tato operace není povolena v demo režimu",
|
||||
"this operation requires administrator to perform": "tato operace vyžaduje administrátora k provedení"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Pozvánka %s neexistuje"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Ldap server existuje"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA e-mail je povolen, ale e-mail je prázdný",
|
||||
"MFA phone is enabled but phone number is empty": "MFA telefon je povolen, ale telefonní číslo je prázdné",
|
||||
"New password cannot contain blank space.": "Nové heslo nemůže obsahovat prázdné místo.",
|
||||
"The new password must be different from your current password": "Nové heslo musí být odlišné od vašeho současného hesla",
|
||||
"the user's owner and name should not be empty": "vlastník a jméno uživatele by neměly být prázdné"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "uživatel neexistuje, prosím nejprve se zaregistrujte"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Pro tohoto uživatele nebyly nalezeny žádné přihlašovací údaje",
|
||||
"Please call WebAuthnSigninBegin first": "Prosím, nejprve zavolejte WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Konnte nicht anmelden: %s",
|
||||
"Invalid token": "Ungültiges Token",
|
||||
"State expected: %s, but got: %s": "Erwarteter Zustand: %s, aber erhalten: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Das Konto für den Anbieter: %s und Benutzernamen: %s (%s) existiert nicht und darf nicht über %%s als neues Konto erstellt werden. Bitte nutzen Sie einen anderen Weg, um sich anzumelden",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Das Konto für den Anbieter: %s und Benutzernamen: %s (%s) existiert nicht und darf nicht über %s als neues Konto erstellt werden. Bitte nutzen Sie einen anderen Weg, um sich anzumelden",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Das Konto für den Anbieter %s und Benutzernamen %s (%s) existiert nicht und es ist nicht erlaubt, ein neues Konto anzumelden. Bitte wenden Sie sich an Ihren IT-Support",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Das Konto für den Anbieter %s und Benutzernamen %s (%s) ist bereits mit einem anderen Konto verknüpft: %s (%s)",
|
||||
"The application: %s does not exist": "Die Anwendung: %s existiert nicht",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Die Anwendung: %s hat die Anmeldung von Benutzern deaktiviert",
|
||||
"The group: %s does not exist": "Die Gruppe: %s existiert nicht",
|
||||
"The login method: login with LDAP is not enabled for the application": "Die Anmeldemethode: Anmeldung mit LDAP ist für die Anwendung nicht aktiviert",
|
||||
"The login method: login with SMS is not enabled for the application": "Die Anmeldemethode: Anmeldung per SMS ist für die Anwendung nicht aktiviert",
|
||||
"The login method: login with email is not enabled for the application": "Die Anmeldemethode: Anmeldung per E-Mail ist für die Anwendung nicht aktiviert",
|
||||
"The login method: login with face is not enabled for the application": "Die Anmeldemethode: Anmeldung per Gesicht ist für die Anwendung nicht aktiviert",
|
||||
"The login method: login with password is not enabled for the application": "Die Anmeldeart \"Anmeldung mit Passwort\" ist für die Anwendung nicht aktiviert",
|
||||
"The organization: %s does not exist": "Die Organisation: %s existiert nicht",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Die Organisation: %s hat die Anmeldung von Benutzern deaktiviert",
|
||||
"The plan: %s does not exist": "Der Plan: %s existiert nicht",
|
||||
"The pricing: %s does not exist": "Die Preisgestaltung: %s existiert nicht",
|
||||
"The pricing: %s does not have plan: %s": "Die Preisgestaltung: %s hat keinen Plan: %s",
|
||||
"The provider: %s does not exist": "Der Anbieter: %s existiert nicht",
|
||||
"The provider: %s is not enabled for the application": "Der Anbieter: %s ist nicht für die Anwendung aktiviert",
|
||||
"Unauthorized operation": "Nicht autorisierte Operation",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Bitte registrieren Sie sich mit dem Benutzernamen, der zum Einladungscode gehört",
|
||||
"Session outdated, please login again": "Sitzung abgelaufen, bitte erneut anmelden",
|
||||
"The invitation code has already been used": "Der Einladungscode wurde bereits verwendet",
|
||||
"The password must contain at least one special character": "Das Passwort muss mindestens ein Sonderzeichen enthalten",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Das Passwort muss mindestens einen Großbuchstaben, einen Kleinbuchstaben und eine Ziffer enthalten",
|
||||
"The password must have at least 6 characters": "Das Passwort muss mindestens 6 Zeichen haben",
|
||||
"The password must have at least 8 characters": "Das Passwort muss mindestens 8 Zeichen haben",
|
||||
"The password must not contain any repeated characters": "Das Passwort darf keine wiederholten Zeichen enthalten",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Der Benutzer wurde gelöscht und kann nicht zur Anmeldung verwendet werden. Bitte wenden Sie sich an den Administrator",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Dem Benutzer ist der Zugang verboten, bitte kontaktieren Sie den Administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "Der Benutzer: %s existiert nicht im LDAP-Server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Der Benutzername darf nur alphanumerische Zeichen, Unterstriche oder Bindestriche enthalten, keine aufeinanderfolgenden Bindestriche oder Unterstriche haben und darf nicht mit einem Bindestrich oder Unterstrich beginnen oder enden.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "Dieser Vorgang ist im Demo-Modus nicht erlaubt",
|
||||
"this operation requires administrator to perform": "Dieser Vorgang erfordert einen Administrator zur Ausführung"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Einladung %s existiert nicht"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Es gibt einen LDAP-Server"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA-E-Mail ist aktiviert, aber E-Mail ist leer",
|
||||
"MFA phone is enabled but phone number is empty": "MFA-Telefon ist aktiviert, aber Telefonnummer ist leer",
|
||||
"New password cannot contain blank space.": "Das neue Passwort darf keine Leerzeichen enthalten.",
|
||||
"The new password must be different from your current password": "Das neue Passwort muss sich von Ihrem aktuellen Passwort unterscheiden",
|
||||
"the user's owner and name should not be empty": "Eigentümer und Name des Benutzers dürfen nicht leer sein"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "Der Benutzer existiert nicht, bitte zuerst anmelden"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Für diesen Benutzer wurden keine Anmeldeinformationen gefunden",
|
||||
"Please call WebAuthnSigninBegin first": "Bitte rufen Sie zuerst WebAuthnSigninBegin auf"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,12 @@
|
||||
"Failed to login in: %s": "Failed to login in: %s",
|
||||
"Invalid token": "Invalid token",
|
||||
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
|
||||
"The application: %s does not exist": "The application: %s does not exist",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The group: %s does not exist": "The group: %s does not exist",
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
@@ -24,6 +25,9 @@
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The plan: %s does not exist": "The plan: %s does not exist",
|
||||
"The pricing: %s does not exist": "The pricing: %s does not exist",
|
||||
"The pricing: %s does not have plan: %s": "The pricing: %s does not have plan: %s",
|
||||
"The provider: %s does not exist": "The provider: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
|
||||
"Session outdated, please login again": "Session outdated, please login again",
|
||||
"The invitation code has already been used": "The invitation code has already been used",
|
||||
"The password must contain at least one special character": "The password must contain at least one special character",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "The password must contain at least one uppercase letter, one lowercase letter and one digit",
|
||||
"The password must have at least 6 characters": "The password must have at least 6 characters",
|
||||
"The password must have at least 8 characters": "The password must have at least 8 characters",
|
||||
"The password must not contain any repeated characters": "The password must not contain any repeated characters",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "The user has been deleted and cannot be used to sign in, please contact the administrator",
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
|
||||
"this operation requires administrator to perform": "this operation requires administrator to perform"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Invitation %s does not exist"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Ldap server exist"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
|
||||
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
|
||||
"New password cannot contain blank space.": "New password cannot contain blank space.",
|
||||
"The new password must be different from your current password": "The new password must be different from your current password",
|
||||
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
|
||||
},
|
||||
"util": {
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "No se ha podido iniciar sesión en: %s",
|
||||
"Invalid token": "Token inválido",
|
||||
"State expected: %s, but got: %s": "Estado esperado: %s, pero se obtuvo: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "La cuenta para el proveedor: %s y nombre de usuario: %s (%s) no existe y no está permitido registrarse como una cuenta nueva a través de %%s, por favor use otro método para registrarse",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "La cuenta para el proveedor: %s y nombre de usuario: %s (%s) no existe y no está permitido registrarse como una cuenta nueva a través de %s, por favor use otro método para registrarse",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "La cuenta para el proveedor: %s y el nombre de usuario: %s (%s) no existe y no se permite registrarse como una nueva cuenta, por favor contacte a su soporte de TI",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "La cuenta para proveedor: %s y nombre de usuario: %s (%s) ya está vinculada a otra cuenta: %s (%s)",
|
||||
"The application: %s does not exist": "La aplicación: %s no existe",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "La aplicación: %s ha desactivado el inicio de sesión de usuarios",
|
||||
"The group: %s does not exist": "El grupo: %s no existe",
|
||||
"The login method: login with LDAP is not enabled for the application": "El método de inicio de sesión: inicio de sesión con LDAP no está habilitado para la aplicación",
|
||||
"The login method: login with SMS is not enabled for the application": "El método de inicio de sesión: inicio de sesión con SMS no está habilitado para la aplicación",
|
||||
"The login method: login with email is not enabled for the application": "El método de inicio de sesión: inicio de sesión con correo electrónico no está habilitado para la aplicación",
|
||||
"The login method: login with face is not enabled for the application": "El método de inicio de sesión: inicio de sesión con reconocimiento facial no está habilitado para la aplicación",
|
||||
"The login method: login with password is not enabled for the application": "El método de inicio de sesión: inicio de sesión con contraseña no está habilitado para la aplicación",
|
||||
"The organization: %s does not exist": "La organización: %s no existe",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "La organización: %s ha desactivado el inicio de sesión de usuarios",
|
||||
"The plan: %s does not exist": "El plan: %s no existe",
|
||||
"The pricing: %s does not exist": "El precio: %s no existe",
|
||||
"The pricing: %s does not have plan: %s": "El precio: %s no tiene el plan: %s",
|
||||
"The provider: %s does not exist": "El proveedor: %s no existe",
|
||||
"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",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Regístrese usando el nombre de usuario correspondiente al código de invitación",
|
||||
"Session outdated, please login again": "Sesión expirada, por favor vuelva a iniciar sesión",
|
||||
"The invitation code has already been used": "El código de invitación ya ha sido utilizado",
|
||||
"The password must contain at least one special character": "La contraseña debe contener al menos un carácter especial",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "La contraseña debe contener al menos una letra mayúscula, una letra minúscula y un dígito",
|
||||
"The password must have at least 6 characters": "La contraseña debe tener al menos 6 caracteres",
|
||||
"The password must have at least 8 characters": "La contraseña debe tener al menos 8 caracteres",
|
||||
"The password must not contain any repeated characters": "La contraseña no debe contener caracteres repetidos",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "El usuario ha sido eliminado y no se puede usar para iniciar sesión, póngase en contacto con el administrador",
|
||||
"The user is forbidden to sign in, please contact the administrator": "El usuario no está autorizado a iniciar sesión, por favor contacte al administrador",
|
||||
"The user: %s doesn't exist in LDAP server": "El usuario: %s no existe en el servidor LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "El nombre de usuario solo puede contener caracteres alfanuméricos, guiones bajos o guiones, no puede tener guiones o subrayados consecutivos, y no puede comenzar ni terminar con un guión o subrayado.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "esta operación no está permitida en modo de demostración",
|
||||
"this operation requires administrator to perform": "esta operación requiere que el administrador la realice"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "La invitación %s no existe"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "El servidor LDAP existe"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "El correo electrónico MFA está habilitado pero el correo está vacío",
|
||||
"MFA phone is enabled but phone number is empty": "El teléfono MFA está habilitado pero el número de teléfono está vacío",
|
||||
"New password cannot contain blank space.": "La nueva contraseña no puede contener espacios en blanco.",
|
||||
"The new password must be different from your current password": "La nueva contraseña debe ser diferente de su contraseña actual",
|
||||
"the user's owner and name should not be empty": "el propietario y el nombre del usuario no deben estar vacíos"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "El usuario no existe, por favor regístrese primero"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "No se encontraron credenciales para este usuario",
|
||||
"Please call WebAuthnSigninBegin first": "Por favor, llama primero a WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "عدم موفقیت در ورود: %s",
|
||||
"Invalid token": "توکن نامعتبر",
|
||||
"State expected: %s, but got: %s": "وضعیت مورد انتظار: %s، اما دریافت شد: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "حساب برای ارائهدهنده: %s و نام کاربری: %s (%s) وجود ندارد و مجاز به ثبتنام بهعنوان حساب جدید از طریق %%s نیست، لطفاً از روش دیگری برای ثبتنام استفاده کنید",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "حساب برای ارائهدهنده: %s و نام کاربری: %s (%s) وجود ندارد و مجاز به ثبتنام بهعنوان حساب جدید از طریق %s نیست، لطفاً از روش دیگری برای ثبتنام استفاده کنید",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "حساب برای ارائهدهنده: %s و نام کاربری: %s (%s) وجود ندارد و مجاز به ثبتنام بهعنوان حساب جدید نیست، لطفاً با پشتیبانی IT خود تماس بگیرید",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "حساب برای ارائهدهنده: %s و نام کاربری: %s (%s) در حال حاضر به حساب دیگری مرتبط است: %s (%s)",
|
||||
"The application: %s does not exist": "برنامه: %s وجود ندارد",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "برنامه: %s ورود کاربران را غیرفعال کرده است",
|
||||
"The group: %s does not exist": "گروه: %s وجود ندارد",
|
||||
"The login method: login with LDAP is not enabled for the application": "روش ورود: ورود با LDAP برای برنامه فعال نیست",
|
||||
"The login method: login with SMS is not enabled for the application": "روش ورود: ورود با پیامک برای برنامه فعال نیست",
|
||||
"The login method: login with email is not enabled for the application": "روش ورود: ورود با ایمیل برای برنامه فعال نیست",
|
||||
"The login method: login with face is not enabled for the application": "روش ورود: ورود با چهره برای برنامه فعال نیست",
|
||||
"The login method: login with password is not enabled for the application": "روش ورود: ورود با رمز عبور برای برنامه فعال نیست",
|
||||
"The organization: %s does not exist": "سازمان: %s وجود ندارد",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "سازمان: %s ورود کاربران را غیرفعال کرده است",
|
||||
"The plan: %s does not exist": "طرح: %s وجود ندارد",
|
||||
"The pricing: %s does not exist": "قیمتگذاری: %s وجود ندارد",
|
||||
"The pricing: %s does not have plan: %s": "قیمتگذاری: %s طرح ندارد: %s",
|
||||
"The provider: %s does not exist": "ارائهکننده: %s وجود ندارد",
|
||||
"The provider: %s is not enabled for the application": "ارائهدهنده: %s برای برنامه فعال نیست",
|
||||
"Unauthorized operation": "عملیات غیرمجاز",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "لطفاً با استفاده از نام کاربری مربوط به کد دعوت ثبتنام کنید",
|
||||
"Session outdated, please login again": "جلسه منقضی شده است، لطفاً دوباره وارد شوید",
|
||||
"The invitation code has already been used": "کد دعوت قبلاً استفاده شده است",
|
||||
"The password must contain at least one special character": "رمز عبور باید حداقل یک کاراکتر خاص داشته باشد",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "رمز عبور باید حداقل یک حرف بزرگ، یک حرف کوچک و یک رقم داشته باشد",
|
||||
"The password must have at least 6 characters": "رمز عبور باید حداقل 6 کاراکتر داشته باشد",
|
||||
"The password must have at least 8 characters": "رمز عبور باید حداقل 8 کاراکتر داشته باشد",
|
||||
"The password must not contain any repeated characters": "رمز عبور نباید شامل کاراکترهای تکراری باشد",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "کاربر حذف شده است و نمی توان از آن برای ورود استفاده کرد، لطفا با مدیر تماس بگیرید",
|
||||
"The user is forbidden to sign in, please contact the administrator": "ورود کاربر ممنوع است، لطفاً با مدیر تماس بگیرید",
|
||||
"The user: %s doesn't exist in LDAP server": "کاربر: %s در سرور LDAP وجود ندارد",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "نام کاربری فقط میتواند حاوی کاراکترهای الفبایی عددی، زیرخط یا خط تیره باشد، نمیتواند خط تیره یا زیرخط متوالی داشته باشد، و نمیتواند با خط تیره یا زیرخط شروع یا پایان یابد.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "این عملیات در حالت دمو مجاز نیست",
|
||||
"this operation requires administrator to perform": "این عملیات نیاز به مدیر برای انجام دارد"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "دعوتنامه %s وجود ندارد"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "سرور LDAP وجود دارد"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "ایمیل MFA فعال است اما ایمیل خالی است",
|
||||
"MFA phone is enabled but phone number is empty": "تلفن MFA فعال است اما شماره تلفن خالی است",
|
||||
"New password cannot contain blank space.": "رمز عبور جدید نمیتواند حاوی فاصله خالی باشد.",
|
||||
"The new password must be different from your current password": "رمز عبور جدید باید با رمز عبور فعلی شما متفاوت باشد",
|
||||
"the user's owner and name should not be empty": "مالک و نام کاربر نباید خالی باشند"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "کاربر وجود ندارد، لطفاً ابتدا ثبتنام کنید"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "اطلاعات ورود برای این کاربر یافت نشد",
|
||||
"Please call WebAuthnSigninBegin first": "لطفاً ابتدا WebAuthnSigninBegin را فراخوانی کنید"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Sisäänkirjautuminen epäonnistui: %s",
|
||||
"Invalid token": "Virheellinen token",
|
||||
"State expected: %s, but got: %s": "Odotettiin tilaa: %s, mutta saatiin: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Tiliä providerille: %s ja käyttäjälle: %s (%s) ei ole olemassa, eikä sitä voi rekisteröidä uutena tilinä kautta %%s, käytä toista tapaa rekisteröityä",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Tiliä providerille: %s ja käyttäjälle: %s (%s) ei ole olemassa, eikä sitä voi rekisteröidä uutena tilinä kautta %s, käytä toista tapaa rekisteröityä",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Tiliä providerille: %s ja käyttäjälle: %s (%s) ei ole olemassa, eikä sitä voi rekisteröidä uutena tilinä, ota yhteyttä IT-tukeen",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Tili providerille: %s ja käyttäjälle: %s (%s) on jo linkitetty toiseen tiliin: %s (%s)",
|
||||
"The application: %s does not exist": "Sovellus: %s ei ole olemassa",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Sovellus: %s on estänyt käyttäjien kirjautumisen",
|
||||
"The group: %s does not exist": "Ryhmä: %s ei ole olemassa",
|
||||
"The login method: login with LDAP is not enabled for the application": "Kirjautumistapa: kirjautuminen LDAP:n kautta ei ole käytössä sovelluksessa",
|
||||
"The login method: login with SMS is not enabled for the application": "Kirjautumistapa: kirjautuminen SMS:n kautta ei ole käytössä sovelluksessa",
|
||||
"The login method: login with email is not enabled for the application": "Kirjautumistapa: kirjautuminen sähköpostin kautta ei ole käytössä sovelluksessa",
|
||||
"The login method: login with face is not enabled for the application": "Kirjautumistapa: kirjautuminen kasvotunnistuksella ei ole käytössä sovelluksessa",
|
||||
"The login method: login with password is not enabled for the application": "Kirjautumistapa: kirjautuminen salasanalla ei ole käytössä sovelluksessa",
|
||||
"The organization: %s does not exist": "Organisaatio: %s ei ole olemassa",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Organisaatio: %s on estänyt käyttäjien kirjautumisen",
|
||||
"The plan: %s does not exist": "Suunnitelma: %s ei ole olemassa",
|
||||
"The pricing: %s does not exist": "Hinnoittelu: %s ei ole olemassa",
|
||||
"The pricing: %s does not have plan: %s": "Hinnoittelu: %s ei sisällä suunnitelmaa: %s",
|
||||
"The provider: %s does not exist": "Provider: %s ei ole olemassa",
|
||||
"The provider: %s is not enabled for the application": "Provider: %s ei ole käytössä sovelluksessa",
|
||||
"Unauthorized operation": "Luvaton toiminto",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Rekisteröidy käyttämällä kutsukoodiin vastaavaa käyttäjänimeä",
|
||||
"Session outdated, please login again": "Istunto vanhentunut, kirjaudu uudelleen",
|
||||
"The invitation code has already been used": "Kutsukoodi on jo käytetty",
|
||||
"The password must contain at least one special character": "Salasanan on sisällettävä vähintään yksi erikoismerkki",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Salasanan on sisällettävä vähintään yksi iso kirjain, yksi pieni kirjain ja yksi numero",
|
||||
"The password must have at least 6 characters": "Salasanassa on oltava vähintään 6 merkkiä",
|
||||
"The password must have at least 8 characters": "Salasanassa on oltava vähintään 8 merkkiä",
|
||||
"The password must not contain any repeated characters": "Salasana ei saa sisältää toistuvia merkkejä",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Käyttäjä on poistettu eikä sitä voi käyttää kirjautumiseen, ota yhteyttä järjestelmänvalvojaan",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Käyttäjän kirjautuminen on estetty, ota yhteyttä ylläpitäjään",
|
||||
"The user: %s doesn't exist in LDAP server": "Käyttäjä: %s ei ole olemassa LDAP-palvelimessa",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Käyttäjänimi voi sisältää vain alfanumeerisia merkkejä, alaviivoja tai tavuviivoja, ei voi sisältää peräkkäisiä tavuviivoja tai alaviivoja, eikä voi alkaa tai loppua tavuviivalla tai alaviivalla.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "tämä toiminto ei ole sallittu demo-tilassa",
|
||||
"this operation requires administrator to perform": "tämä toiminto vaatii ylläpitäjän suorittamista"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Kutsua %s ei ole olemassa"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP-palvelin on olemassa"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA-sähköposti on käytössä, mutta sähköposti on tyhjä",
|
||||
"MFA phone is enabled but phone number is empty": "MFA-puhelin on käytössä, mutta puhelinnumero on tyhjä",
|
||||
"New password cannot contain blank space.": "Uusi salasana ei voi sisältää välilyöntejä.",
|
||||
"The new password must be different from your current password": "Uuden salasanan on oltava erilainen kuin nykyinen salasana",
|
||||
"the user's owner and name should not be empty": "käyttäjän omistaja ja nimi eivät saa olla tyhjiä"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "käyttäjää ei ole olemassa, rekisteröidy ensin"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Tälle käyttäjälle ei löytynyt kirjautumistietoja",
|
||||
"Please call WebAuthnSigninBegin first": "Kutsu ensin WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Échec de la connexion : %s",
|
||||
"Invalid token": "Jeton invalide",
|
||||
"State expected: %s, but got: %s": "État attendu : %s, mais obtenu : %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Le compte pour le fournisseur : %s et le nom d'utilisateur : %s (%s) n'existe pas et n'est pas autorisé à s'inscrire en tant que nouveau compte via %%s, veuillez utiliser une autre méthode pour vous inscrire",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Le compte pour le fournisseur : %s et le nom d'utilisateur : %s (%s) n'existe pas et n'est pas autorisé à s'inscrire en tant que nouveau compte via %s, veuillez utiliser une autre méthode pour vous inscrire",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Le compte pour le fournisseur : %s et le nom d'utilisateur : %s (%s) n'existe pas et n'est pas autorisé à s'inscrire comme nouveau compte, veuillez contacter votre support informatique",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Le compte du fournisseur : %s et le nom d'utilisateur : %s (%s) sont déjà liés à un autre compte : %s (%s)",
|
||||
"The application: %s does not exist": "L'application : %s n'existe pas",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "L'application: %s a désactivé la connexion des utilisateurs",
|
||||
"The group: %s does not exist": "Le groupe : %s n'existe pas",
|
||||
"The login method: login with LDAP is not enabled for the application": "La méthode de connexion : connexion LDAP n'est pas activée pour l'application",
|
||||
"The login method: login with SMS is not enabled for the application": "La méthode de connexion : connexion par SMS n'est pas activée pour l'application",
|
||||
"The login method: login with email is not enabled for the application": "La méthode de connexion : connexion par e-mail n'est pas activée pour l'application",
|
||||
"The login method: login with face is not enabled for the application": "La méthode de connexion : connexion par visage n'est pas activée pour l'application",
|
||||
"The login method: login with password is not enabled for the application": "La méthode de connexion : connexion avec mot de passe n'est pas activée pour l'application",
|
||||
"The organization: %s does not exist": "L'organisation : %s n'existe pas",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "L'organisation: %s a désactivé la connexion des utilisateurs",
|
||||
"The plan: %s does not exist": "Le plan : %s n'existe pas",
|
||||
"The pricing: %s does not exist": "Le tarif : %s n'existe pas",
|
||||
"The pricing: %s does not have plan: %s": "Le tarif : %s n'a pas de plan : %s",
|
||||
"The provider: %s does not exist": "Le fournisseur : %s n'existe pas",
|
||||
"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",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Veuillez vous inscrire avec le nom d'utilisateur correspondant au code d'invitation",
|
||||
"Session outdated, please login again": "Session expirée, veuillez vous connecter à nouveau",
|
||||
"The invitation code has already been used": "Le code d'invitation a déjà été utilisé",
|
||||
"The password must contain at least one special character": "Le mot de passe doit contenir au moins un caractère spécial",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Le mot de passe doit contenir au moins une lettre majuscule, une lettre minuscule et un chiffre",
|
||||
"The password must have at least 6 characters": "Le mot de passe doit contenir au moins 6 caractères",
|
||||
"The password must have at least 8 characters": "Le mot de passe doit contenir au moins 8 caractères",
|
||||
"The password must not contain any repeated characters": "Le mot de passe ne doit pas contenir de caractères répétés",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "L'utilisateur a été supprimé et ne peut pas être utilisé pour se connecter, veuillez contacter l'administrateur",
|
||||
"The user is forbidden to sign in, please contact the administrator": "L'utilisateur est interdit de se connecter, veuillez contacter l'administrateur",
|
||||
"The user: %s doesn't exist in LDAP server": "L'utilisateur : %s n'existe pas sur le serveur LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Le nom d'utilisateur ne peut contenir que des caractères alphanumériques, des traits soulignés ou des tirets, ne peut pas avoir de tirets ou de traits soulignés consécutifs et ne peut pas commencer ou se terminer par un tiret ou un trait souligné.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "cette opération n'est pas autorisée en mode démo",
|
||||
"this operation requires administrator to perform": "cette opération nécessite un administrateur pour être effectuée"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "L'invitation %s n'existe pas"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Le serveur LDAP existe"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "L'authentification MFA par e-mail est activée mais l'e-mail est vide",
|
||||
"MFA phone is enabled but phone number is empty": "L'authentification MFA par téléphone est activée mais le numéro de téléphone est vide",
|
||||
"New password cannot contain blank space.": "Le nouveau mot de passe ne peut pas contenir d'espace.",
|
||||
"The new password must be different from your current password": "Le nouveau mot de passe doit être différent de votre mot de passe actuel",
|
||||
"the user's owner and name should not be empty": "le propriétaire et le nom de l'utilisateur ne doivent pas être vides"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "L'utilisateur n'existe pas, veuillez vous inscrire d'abord"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Aucune information d'identification trouvée pour cet utilisateur",
|
||||
"Please call WebAuthnSigninBegin first": "Veuillez d'abord appeler WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "כניסה נכשלה: %s",
|
||||
"Invalid token": "אסימון שגוי",
|
||||
"State expected: %s, but got: %s": "מצב צפוי: %s, אך התקבל: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "החשבון עבור ספק: %s ושם משתמש: %s (%s) אינו קיים ואינו מאופשר להרשמה כחשבון חדש דרך %%s, אנא השתמש בדרך אחרת להרשמה",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "החשבון עבור ספק: %s ושם משתמש: %s (%s) אינו קיים ואינו מאופשר להרשמה כחשבון חדש דרך %s, אנא השתמש בדרך אחרת להרשמה",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "החשבון עבור ספק: %s ושם משתמש: %s (%s) אינו קיים ואינו מאופשר להרשמה כחשבון חדש, אנא צור קשר עם התמיכה הטכנית",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "החשבון עבור ספק: %s ושם משתמש: %s (%s) כבר מקושר לחשבון אחר: %s (%s)",
|
||||
"The application: %s does not exist": "האפליקציה: %s אינה קיימת",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "האפליקציה: %s השביתה כניסת משתמשים",
|
||||
"The group: %s does not exist": "הקבוצה: %s לא קיימת",
|
||||
"The login method: login with LDAP is not enabled for the application": "שיטת הכניסה: כניסה עם LDAP אינה מאופשרת לאפליקציה",
|
||||
"The login method: login with SMS is not enabled for the application": "שיטת הכניסה: כניסה עם SMS אינה מאופשרת לאפליקציה",
|
||||
"The login method: login with email is not enabled for the application": "שיטת הכניסה: כניסה עם אימייל אינה מאופשרת לאפליקציה",
|
||||
"The login method: login with face is not enabled for the application": "שיטת הכניסה: כניסה עם פנים אינה מאופשרת לאפליקציה",
|
||||
"The login method: login with password is not enabled for the application": "שיטת הכניסה: כניסה עם סיסמה אינה מאופשרת לאפליקציה",
|
||||
"The organization: %s does not exist": "הארגון: %s אינו קיים",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "הארגון: %s השבית כניסת משתמשים",
|
||||
"The plan: %s does not exist": "התוכנית: %s לא קיימת",
|
||||
"The pricing: %s does not exist": "התמחור: %s לא קיים",
|
||||
"The pricing: %s does not have plan: %s": "התמחור: %s אין לו תוכנית: %s",
|
||||
"The provider: %s does not exist": "הספק: %s אינו קיים",
|
||||
"The provider: %s is not enabled for the application": "הספק: %s אינו מאופשר לאפליקציה",
|
||||
"Unauthorized operation": "פעולה לא מורשית",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "אנא הרשם באמצעות שם המשתמש התואם לקוד ההזמנה",
|
||||
"Session outdated, please login again": "הסשן פג תוקף, אנא התחבר שוב",
|
||||
"The invitation code has already been used": "קוד ההזמנה כבר נוצל",
|
||||
"The password must contain at least one special character": "הסיסמה חייבת להכיל לפחות תו מיוחד אחד",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "הסיסמה חייבת להכיל לפחות אות גדולה אחת, אות קטנה אחת וספרה אחת",
|
||||
"The password must have at least 6 characters": "הסיסמה חייבת להכיל לפחות 6 תווים",
|
||||
"The password must have at least 8 characters": "הסיסמה חייבת להכיל לפחות 8 תווים",
|
||||
"The password must not contain any repeated characters": "הסיסמה אינה יכולה להכיל תווים חוזרים",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "המשתמש נמחק ולא ניתן להשתמש בו לכניסה, אנא צור קשר עם המנהל",
|
||||
"The user is forbidden to sign in, please contact the administrator": "המשתמש אסור להיכנס, אנא צור קשר עם המנהל",
|
||||
"The user: %s doesn't exist in LDAP server": "המשתמש: %s אינו קיים בשרת ה-LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "שם המשתמש יכול להכיל רק תווים אלפאנומריים, קווים תחתונים או מקפים, לא יכול להכיל מקפים או קווים תחתונים רצופים, ולא יכול להתחיל או להסתיים עם מקף או קו תחתון.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "פעולה זו אינה מותרת במצב הדגמה",
|
||||
"this operation requires administrator to perform": "פעולה זו דורשת מנהל לביצוע"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "ההזמנה %s אינה קיימת"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "שרת LDAP קיים"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA דוא\"ל מופעל אך הדוא\"ל ריק",
|
||||
"MFA phone is enabled but phone number is empty": "MFA טלפון מופעל אך מספר הטלפון ריק",
|
||||
"New password cannot contain blank space.": "הסיסמה החדשה אינה יכולה להכיל רווחים.",
|
||||
"The new password must be different from your current password": "הסיסמה החדשה חייבת להיות שונה מהסיסמה הנוכחית שלך",
|
||||
"the user's owner and name should not be empty": "הבעלים והשם של המשתמש אינם יכולים להיות ריקים"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "המשתמש אינו קיים, אנא הרשם תחילה"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "לא נמצאו אישורים עבור משתמש זה",
|
||||
"Please call WebAuthnSigninBegin first": "אנא קרא ל-WebAuthnSigninBegin תחילה"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Gagal masuk: %s",
|
||||
"Invalid token": "Token tidak valid",
|
||||
"State expected: %s, but got: %s": "Diharapkan: %s, tapi diperoleh: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Akun untuk penyedia: %s dan nama pengguna: %s (%s) tidak ada dan tidak diizinkan untuk mendaftar sebagai akun baru melalui %%s, silakan gunakan cara lain untuk mendaftar",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Akun untuk penyedia: %s dan nama pengguna: %s (%s) tidak ada dan tidak diizinkan untuk mendaftar sebagai akun baru melalui %s, silakan gunakan cara lain untuk mendaftar",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Akun untuk penyedia: %s dan nama pengguna: %s (%s) tidak ada dan tidak diizinkan untuk mendaftar sebagai akun baru, silakan hubungi dukungan IT Anda",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Akun untuk penyedia: %s dan username: %s (%s) sudah terhubung dengan akun lain: %s (%s)",
|
||||
"The application: %s does not exist": "Aplikasi: %s tidak ada",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Aplikasi: %s telah menonaktifkan pengguna untuk masuk",
|
||||
"The group: %s does not exist": "Grup: %s tidak ada",
|
||||
"The login method: login with LDAP is not enabled for the application": "Metode masuk: masuk dengan LDAP tidak diaktifkan untuk aplikasi ini",
|
||||
"The login method: login with SMS is not enabled for the application": "Metode masuk: masuk dengan SMS tidak diaktifkan untuk aplikasi ini",
|
||||
"The login method: login with email is not enabled for the application": "Metode masuk: masuk dengan email tidak diaktifkan untuk aplikasi ini",
|
||||
"The login method: login with face is not enabled for the application": "Metode masuk: masuk dengan wajah tidak diaktifkan untuk aplikasi ini",
|
||||
"The login method: login with password is not enabled for the application": "Metode login: login dengan sandi tidak diaktifkan untuk aplikasi tersebut",
|
||||
"The organization: %s does not exist": "Organisasi: %s tidak ada",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Organisasi: %s telah menonaktifkan pengguna untuk masuk",
|
||||
"The plan: %s does not exist": "Rencana: %s tidak ada",
|
||||
"The pricing: %s does not exist": "Harga: %s tidak ada",
|
||||
"The pricing: %s does not have plan: %s": "Harga: %s tidak memiliki rencana: %s",
|
||||
"The provider: %s does not exist": "Penyedia: %s tidak ada",
|
||||
"The provider: %s is not enabled for the application": "Penyedia: %s tidak diaktifkan untuk aplikasi ini",
|
||||
"Unauthorized operation": "Operasi tidak sah",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Silakan daftar menggunakan nama pengguna yang sesuai dengan kode undangan",
|
||||
"Session outdated, please login again": "Sesi kadaluwarsa, silakan masuk lagi",
|
||||
"The invitation code has already been used": "Kode undangan sudah digunakan",
|
||||
"The password must contain at least one special character": "Kata sandi harus berisi setidaknya satu karakter khusus",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Kata sandi harus berisi setidaknya satu huruf besar, satu huruf kecil dan satu angka",
|
||||
"The password must have at least 6 characters": "Kata sandi harus memiliki setidaknya 6 karakter",
|
||||
"The password must have at least 8 characters": "Kata sandi harus memiliki setidaknya 8 karakter",
|
||||
"The password must not contain any repeated characters": "Kata sandi tidak boleh berisi karakter yang berulang",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Pengguna telah dihapus dan tidak dapat digunakan untuk masuk, silakan hubungi administrator",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Pengguna dilarang masuk, silakan hubungi administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "Pengguna: %s tidak ada di server LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Nama pengguna hanya bisa menggunakan karakter alfanumerik, garis bawah atau tanda hubung, tidak boleh memiliki dua tanda hubung atau garis bawah berurutan, dan tidak boleh diawali atau diakhiri dengan tanda hubung atau garis bawah.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "operasi ini tidak diizinkan dalam mode demo",
|
||||
"this operation requires administrator to perform": "operasi ini memerlukan administrator untuk melakukannya"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Undangan %s tidak ada"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Server ldap ada"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "Email MFA diaktifkan tetapi email kosong",
|
||||
"MFA phone is enabled but phone number is empty": "Telepon MFA diaktifkan tetapi nomor telepon kosong",
|
||||
"New password cannot contain blank space.": "Sandi baru tidak boleh mengandung spasi kosong.",
|
||||
"The new password must be different from your current password": "Kata sandi baru harus berbeda dari kata sandi Anda saat ini",
|
||||
"the user's owner and name should not be empty": "pemilik dan nama pengguna tidak boleh kosong"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "Pengguna tidak ada, silakan daftar terlebih dahulu"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Tidak ditemukan kredensial untuk pengguna ini",
|
||||
"Please call WebAuthnSigninBegin first": "Harap panggil WebAuthnSigninBegin terlebih dahulu"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Login fallito: %s",
|
||||
"Invalid token": "Token non valido",
|
||||
"State expected: %s, but got: %s": "Stato atteso: %s, ricevuto: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Account per provider: %s e utente: %s (%s) non esiste, registrazione tramite %%s non consentita",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Account per provider: %s e utente: %s (%s) non esiste, registrazione tramite %s non consentita",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Account per provider: %s e utente: %s (%s) non esiste, registrazione non consentita: contatta l'assistenza IT",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Account per provider: %s e utente: %s (%s) già collegato a un altro account: %s (%s)",
|
||||
"The application: %s does not exist": "L'app: %s non esiste",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "L'applicazione: %s ha disabilitato l'accesso degli utenti",
|
||||
"The group: %s does not exist": "Il gruppo: %s non esiste",
|
||||
"The login method: login with LDAP is not enabled for the application": "Metodo di accesso: login con LDAP non abilitato per l'applicazione",
|
||||
"The login method: login with SMS is not enabled for the application": "Metodo di accesso: login con SMS non abilitato per l'applicazione",
|
||||
"The login method: login with email is not enabled for the application": "Metodo di accesso: login con email non abilitato per l'applicazione",
|
||||
"The login method: login with face is not enabled for the application": "Metodo di accesso: login con riconoscimento facciale non abilitato per l'applicazione",
|
||||
"The login method: login with password is not enabled for the application": "Login con password non abilitato per questa app",
|
||||
"The organization: %s does not exist": "L'organizzazione: %s non esiste",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "L'organizzazione: %s ha disabilitato l'accesso degli utenti",
|
||||
"The plan: %s does not exist": "Il piano: %s non esiste",
|
||||
"The pricing: %s does not exist": "Il prezzo: %s non esiste",
|
||||
"The pricing: %s does not have plan: %s": "Il prezzo: %s non ha il piano: %s",
|
||||
"The provider: %s does not exist": "Il provider: %s non esiste",
|
||||
"The provider: %s is not enabled for the application": "Il provider: %s non è abilitato per l'app",
|
||||
"Unauthorized operation": "Operazione non autorizzata",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Registrati con il nome utente corrispondente al codice di invito",
|
||||
"Session outdated, please login again": "Sessione scaduta, rieffettua il login",
|
||||
"The invitation code has already been used": "Il codice di invito è già stato utilizzato",
|
||||
"The password must contain at least one special character": "La password deve contenere almeno un carattere speciale",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "La password deve contenere almeno una lettera maiuscola, una lettera minuscola e una cifra",
|
||||
"The password must have at least 6 characters": "La password deve avere almeno 6 caratteri",
|
||||
"The password must have at least 8 characters": "La password deve avere almeno 8 caratteri",
|
||||
"The password must not contain any repeated characters": "La password non deve contenere caratteri ripetuti",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "L'utente è stato eliminato e non può essere utilizzato per accedere, contattare l'amministratore",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Utente bloccato, contatta l'amministratore",
|
||||
"The user: %s doesn't exist in LDAP server": "L'utente: %s non esiste nel server LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Username solo caratteri alfanumerici, underscore o trattini. Non può iniziare/finire con trattino o underscore.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "questa operazione non è consentita in modalità demo",
|
||||
"this operation requires administrator to perform": "questa operazione richiede un amministratore"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "L'invito %s non esiste"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Server LDAP esistente"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "L'email MFA è abilitata ma l'email è vuota",
|
||||
"MFA phone is enabled but phone number is empty": "Il telefono MFA è abilitato ma il numero di telefono è vuoto",
|
||||
"New password cannot contain blank space.": "Nuova password non può contenere spazi",
|
||||
"The new password must be different from your current password": "La nuova password deve essere diversa dalla password attuale",
|
||||
"the user's owner and name should not be empty": "il proprietario e il nome dell'utente non devono essere vuoti"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "Utente inesistente, registrati prima"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Nessuna credenziale trovata per questo utente",
|
||||
"Please call WebAuthnSigninBegin first": "Chiamare prima WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "ログインできませんでした:%s",
|
||||
"Invalid token": "無効なトークン",
|
||||
"State expected: %s, but got: %s": "期待される状態: %s、実際には:%s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "プロバイダーのアカウント:%s とユーザー名:%s(%s)が存在せず、新しいアカウントを %%s 経由でサインアップすることはできません。他の方法でサインアップしてください",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "プロバイダーのアカウント:%s とユーザー名:%s(%s)が存在せず、新しいアカウントを %s 経由でサインアップすることはできません。他の方法でサインアップしてください",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "プロバイダー名:%sとユーザー名:%s(%s)のアカウントは存在しません。新しいアカウントとしてサインアップすることはできません。 ITサポートに連絡してください",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "プロバイダのアカウント:%s とユーザー名:%s (%s) は既に別のアカウント:%s (%s) にリンクされています",
|
||||
"The application: %s does not exist": "アプリケーション: %sは存在しません",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "アプリケーション: %s はユーザーのサインインを無効にしました",
|
||||
"The group: %s does not exist": "グループ: %sは存在しません",
|
||||
"The login method: login with LDAP is not enabled for the application": "このアプリケーションでは LDAP ログインは有効になっていません",
|
||||
"The login method: login with SMS is not enabled for the application": "このアプリケーションでは SMS ログインは有効になっていません",
|
||||
"The login method: login with email is not enabled for the application": "このアプリケーションではメールログインは有効になっていません",
|
||||
"The login method: login with face is not enabled for the application": "このアプリケーションでは顔認証ログインは有効になっていません",
|
||||
"The login method: login with password is not enabled for the application": "ログイン方法:パスワードでのログインはアプリケーションで有効になっていません",
|
||||
"The organization: %s does not exist": "組織「%s」は存在しません",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "組織: %s はユーザーのサインインを無効にしました",
|
||||
"The plan: %s does not exist": "プラン: %sは存在しません",
|
||||
"The pricing: %s does not exist": "料金: %sは存在しません",
|
||||
"The pricing: %s does not have plan: %s": "料金: %sにはプラン%sがありません",
|
||||
"The provider: %s does not exist": "プロバイダ「%s」は存在しません",
|
||||
"The provider: %s is not enabled for the application": "プロバイダー:%sはアプリケーションでは有効化されていません",
|
||||
"Unauthorized operation": "不正操作",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "招待コードに対応するユーザー名で登録してください",
|
||||
"Session outdated, please login again": "セッションが期限切れになりました。再度ログインしてください",
|
||||
"The invitation code has already been used": "この招待コードは既に使用されています",
|
||||
"The password must contain at least one special character": "パスワードには少なくとも1つの特殊文字が必要です",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "パスワードには少なくとも1つの大文字、1つの小文字、1つの数字が必要です",
|
||||
"The password must have at least 6 characters": "パスワードは少なくとも6文字必要です",
|
||||
"The password must have at least 8 characters": "パスワードは少なくとも8文字必要です",
|
||||
"The password must not contain any repeated characters": "パスワードに繰り返し文字を含めることはできません",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "ユーザーは削除されており、サインインに使用できません。管理者にお問い合わせください",
|
||||
"The user is forbidden to sign in, please contact the administrator": "ユーザーはサインインできません。管理者に連絡してください",
|
||||
"The user: %s doesn't exist in LDAP server": "ユーザー「%s」は LDAP サーバーに存在しません",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "ユーザー名には英数字、アンダースコア、ハイフンしか含めることができません。連続したハイフンまたはアンダースコアは不可であり、ハイフンまたはアンダースコアで始まるまたは終わることもできません。",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "この操作はデモモードでは許可されていません",
|
||||
"this operation requires administrator to perform": "この操作は管理者権限が必要です"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "招待 %s は存在しません"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAPサーバーは存在します"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA メールが有効になっていますが、メールアドレスが空です",
|
||||
"MFA phone is enabled but phone number is empty": "MFA 電話番号が有効になっていますが、電話番号が空です",
|
||||
"New password cannot contain blank space.": "新しいパスワードにはスペースを含めることはできません。",
|
||||
"The new password must be different from your current password": "新しいパスワードは現在のパスワードと異なる必要があります",
|
||||
"the user's owner and name should not be empty": "ユーザーのオーナーと名前は空にできません"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "ユーザーは存在しません。まず登録してください"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "このユーザーの認証情報が見つかりませんでした",
|
||||
"Please call WebAuthnSigninBegin first": "最初にWebAuthnSigninBeginを呼び出してください"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Inloggen mislukt: %s",
|
||||
"Invalid token": "Ongeldige token",
|
||||
"State expected: %s, but got: %s": "Verwachte state: %s, maar kreeg: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Account voor provider: %s en gebruikersnaam: %s (%s) bestaat niet en mag niet registreren via %%s, gebruik een andere methode",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Account voor provider: %s en gebruikersnaam: %s (%s) bestaat niet en mag niet registreren via %s, gebruik een andere methode",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Account voor provider: %s en gebruikersnaam: %s (%s) bestaat niet en mag niet registreren, contacteer IT-support",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Account voor provider: %s en gebruikersnaam: %s (%s) is al gelinkt aan ander account: %s (%s)",
|
||||
"The application: %s does not exist": "Applicatie: %s bestaat niet",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Қолданба: %s пайдаланушылардың кіруін өшірді",
|
||||
"The group: %s does not exist": "Топ: %s жоқ",
|
||||
"The login method: login with LDAP is not enabled for the application": "Inloggen via LDAP is niet ingeschakeld voor deze applicatie",
|
||||
"The login method: login with SMS is not enabled for the application": "Inloggen via SMS is niet ingeschakeld voor deze applicatie",
|
||||
"The login method: login with email is not enabled for the application": "Inloggen via e-mail is niet ingeschakeld voor deze applicatie",
|
||||
"The login method: login with face is not enabled for the application": "Inloggen via gezichtsherkenning is niet ingeschakeld voor deze applicatie",
|
||||
"The login method: login with password is not enabled for the application": "Inloggen via wachtwoord is niet ingeschakeld voor deze applicatie",
|
||||
"The organization: %s does not exist": "Organisatie: %s bestaat niet",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Ұйым: %s пайдаланушылардың кіруін өшірді",
|
||||
"The plan: %s does not exist": "Жоспар: %s жоқ",
|
||||
"The pricing: %s does not exist": "Баға: %s жоқ",
|
||||
"The pricing: %s does not have plan: %s": "Баға: %s жоспары жоқ: %s",
|
||||
"The provider: %s does not exist": "Provider: %s bestaat niet",
|
||||
"The provider: %s is not enabled for the application": "Provider: %s is niet ingeschakeld voor de applicatie",
|
||||
"Unauthorized operation": "Ongeautoriseerde handeling",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Registreer met de gebruikersnaam die hoort bij de uitnodigingscode",
|
||||
"Session outdated, please login again": "Sessie verlopen, gelieve opnieuw in te loggen",
|
||||
"The invitation code has already been used": "Uitnodigingscode is al gebruikt",
|
||||
"The password must contain at least one special character": "Құпия сөз кемінде бір арнайы таңбаны қамтуы керек",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Құпия сөз кемінде бір бас әріпті, бір кіші әріпті және бір санды қамтуы керек",
|
||||
"The password must have at least 6 characters": "Құпия сөз кемінде 6 таңбадан тұруы керек",
|
||||
"The password must have at least 8 characters": "Құпия сөз кемінде 8 таңбадан тұруы керек",
|
||||
"The password must not contain any repeated characters": "Құпия сөз қайталанатын таңбаларды қамтымауы керек",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Пайдаланушы жойылған және кіру үшін пайдалануға болмайды, әкімшіге хабарласыңыз",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Gebruiker mag niet inloggen, contacteer beheerder",
|
||||
"The user: %s doesn't exist in LDAP server": "Gebruiker: %s bestaat niet in LDAP-server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Gebruikersnaam mag alleen alfanumerieke tekens, underscores of koppeltekens bevatten, geen opeenvolgende koppeltekens/underscores, en mag niet beginnen of eindigen met koppelteken of underscore.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "deze handeling is niet toegestaan in demo-modus",
|
||||
"this operation requires administrator to perform": "deze handeling vereist beheerder"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Шақыру %s жоқ"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP-server bestaat al"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA-e-mail is ingeschakeld maar e-mailadres is leeg",
|
||||
"MFA phone is enabled but phone number is empty": "MFA-telefoon is ingeschakeld maar telefoonnummer is leeg",
|
||||
"New password cannot contain blank space.": "Nieuw wachtwoord mag geen spaties bevatten.",
|
||||
"The new password must be different from your current password": "Жаңа құпия сөз ағымдағы құпия сөзіңізден өзгеше болуы керек",
|
||||
"the user's owner and name should not be empty": "eigenaar en naam van gebruiker mogen niet leeg zijn"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "gebruiker bestaat niet, registreer eerst"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Бұл пайдаланушы үшін тіркелгі деректері табылмады",
|
||||
"Please call WebAuthnSigninBegin first": "Roep eerst WebAuthnSigninBegin aan"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "로그인에 실패했습니다.: %s",
|
||||
"Invalid token": "유효하지 않은 토큰",
|
||||
"State expected: %s, but got: %s": "예상한 상태: %s, 실제 상태: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "제공자 계정: %s와 사용자 이름: %s (%s)은(는) 존재하지 않으며 %%s를 통해 새 계정으로 가입하는 것이 허용되지 않습니다. 다른 방법으로 가입하십시오",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "제공자 계정: %s와 사용자 이름: %s (%s)은(는) 존재하지 않으며 %s를 통해 새 계정으로 가입하는 것이 허용되지 않습니다. 다른 방법으로 가입하십시오",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "공급자 계정 %s과 사용자 이름 %s (%s)는 존재하지 않으며 새 계정으로 등록할 수 없습니다. IT 지원팀에 문의하십시오",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "공급자 계정 %s과 사용자 이름 %s(%s)는 이미 다른 계정 %s(%s)에 연결되어 있습니다",
|
||||
"The application: %s does not exist": "해당 애플리케이션(%s)이 존재하지 않습니다",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "애플리케이션: %s이(가) 사용자 로그인을 비활성화했습니다",
|
||||
"The group: %s does not exist": "그룹: %s이(가) 존재하지 않습니다",
|
||||
"The login method: login with LDAP is not enabled for the application": "LDAP를 이용한 로그인 방식이 이 애플리케이션에 활성화되어 있지 않습니다",
|
||||
"The login method: login with SMS is not enabled for the application": "SMS를 이용한 로그인 방식이 이 애플리케이션에 활성화되어 있지 않습니다",
|
||||
"The login method: login with email is not enabled for the application": "이메일을 이용한 로그인 방식이 이 애플리케이션에 활성화되어 있지 않습니다",
|
||||
"The login method: login with face is not enabled for the application": "얼굴 인식을 이용한 로그인 방식이 이 애플리케이션에 활성화되어 있지 않습니다",
|
||||
"The login method: login with password is not enabled for the application": "어플리케이션에서는 암호를 사용한 로그인 방법이 활성화되어 있지 않습니다",
|
||||
"The organization: %s does not exist": "조직 %s이(가) 존재하지 않습니다",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "조직: %s이(가) 사용자 로그인을 비활성화했습니다",
|
||||
"The plan: %s does not exist": "플랜: %s이(가) 존재하지 않습니다",
|
||||
"The pricing: %s does not exist": "가격: %s이(가) 존재하지 않습니다",
|
||||
"The pricing: %s does not have plan: %s": "가격: %s에는 플랜 %s이(가) 없습니다",
|
||||
"The provider: %s does not exist": "제공자 %s이(가) 존재하지 않습니다",
|
||||
"The provider: %s is not enabled for the application": "제공자 %s은(는) 응용 프로그램에서 활성화되어 있지 않습니다",
|
||||
"Unauthorized operation": "무단 조작",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "초대 코드에 해당하는 사용자 이름으로 가입해 주세요",
|
||||
"Session outdated, please login again": "세션이 만료되었습니다. 다시 로그인해주세요",
|
||||
"The invitation code has already been used": "초대 코드는 이미 사용되었습니다",
|
||||
"The password must contain at least one special character": "비밀번호에는 하나 이상의 특수 문자가 포함되어야 합니다",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "비밀번호에는 하나 이상의 대문자, 소문자 및 숫자가 포함되어야 합니다",
|
||||
"The password must have at least 6 characters": "비밀번호는 최소 6자 이상이어야 합니다",
|
||||
"The password must have at least 8 characters": "비밀번호는 최소 8자 이상이어야 합니다",
|
||||
"The password must not contain any repeated characters": "비밀번호에는 반복되는 문자가 포함될 수 없습니다",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "사용자가 삭제되어 로그인에 사용할 수 없습니다. 관리자에게 문의하세요",
|
||||
"The user is forbidden to sign in, please contact the administrator": "사용자는 로그인이 금지되어 있습니다. 관리자에게 문의하십시오",
|
||||
"The user: %s doesn't exist in LDAP server": "LDAP 서버에 사용자 %s이(가) 존재하지 않습니다",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "사용자 이름은 알파벳, 숫자, 밑줄 또는 하이픈만 포함할 수 있으며, 연속된 하이픈 또는 밑줄을 가질 수 없으며, 하이픈 또는 밑줄로 시작하거나 끝날 수 없습니다.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "이 작업은 데모 모드에서 허용되지 않습니다",
|
||||
"this operation requires administrator to perform": "이 작업은 관리자 권한이 필요합니다"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "초대 %s이(가) 존재하지 않습니다"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP 서버가 존재합니다"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA 이메일이 활성화되었지만 이메일이 비어 있습니다",
|
||||
"MFA phone is enabled but phone number is empty": "MFA 전화번호가 활성화되었지만 전화번호가 비어 있습니다",
|
||||
"New password cannot contain blank space.": "새 비밀번호에는 공백이 포함될 수 없습니다.",
|
||||
"The new password must be different from your current password": "새 비밀번호는 현재 비밀번호와 달라야 합니다",
|
||||
"the user's owner and name should not be empty": "사용자의 소유자와 이름은 비워둘 수 없습니다"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "사용자가 존재하지 않습니다. 먼저 회원 가입 해주세요"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "이 사용자에 대한 자격 증명을 찾을 수 없습니다",
|
||||
"Please call WebAuthnSigninBegin first": "WebAuthnSigninBegin을 먼저 호출해주세요"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Gagal log masuk: %s",
|
||||
"Invalid token": "Token tidak sah",
|
||||
"State expected: %s, but got: %s": "Jangkaan keadaan: %s, tetapi dapat: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Akaun untuk pembekal: %s dan nama pengguna: %s (%s) tidak wujud dan tidak dibenarkan daftar melalui %%s, sila guna cara lain",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Akaun untuk pembekal: %s dan nama pengguna: %s (%s) tidak wujud dan tidak dibenarkan daftar melalui %s, sila guna cara lain",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Akaun untuk pembekal: %s dan nama pengguna: %s (%s) tidak wujud dan tidak dibenarkan daftar, sila hubungi sokongan IT",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Akaun untuk pembekal: %s dan nama pengguna: %s (%s) sudah dipautkan kepada akaun lain: %s (%s)",
|
||||
"The application: %s does not exist": "Aplikasi: %s tidak wujud",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Aplikasi: %s telah melumpuhkan pengguna untuk log masuk",
|
||||
"The group: %s does not exist": "Kumpulan: %s tidak wujud",
|
||||
"The login method: login with LDAP is not enabled for the application": "Kaedah log masuk LDAP tidak dibenarkan untuk aplikasi ini",
|
||||
"The login method: login with SMS is not enabled for the application": "Kaedah log masuk SMS tidak dibenarkan untuk aplikasi ini",
|
||||
"The login method: login with email is not enabled for the application": "Kaedah log masuk emel tidak dibenarkan untuk aplikasi ini",
|
||||
"The login method: login with face is not enabled for the application": "Kaedah log masuk muka tidak dibenarkan untuk aplikasi ini",
|
||||
"The login method: login with password is not enabled for the application": "Kaedah log masuk kata laluan tidak dibenarkan untuk aplikasi ini",
|
||||
"The organization: %s does not exist": "Organisasi: %s tidak wujud",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Organisasi: %s telah melumpuhkan pengguna untuk log masuk",
|
||||
"The plan: %s does not exist": "Pelan: %s tidak wujud",
|
||||
"The pricing: %s does not exist": "Harga: %s tidak wujud",
|
||||
"The pricing: %s does not have plan: %s": "Harga: %s tidak mempunyai pelan: %s",
|
||||
"The provider: %s does not exist": "Pembekal: %s tidak wujud",
|
||||
"The provider: %s is not enabled for the application": "Pembekal: %s tidak dibenarkan untuk aplikasi ini",
|
||||
"Unauthorized operation": "Operasi tidak dibenarkan",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Sila daftar dengan nama pengguna yang sepadan dengan kod jemputan",
|
||||
"Session outdated, please login again": "Sesi tamat, sila log masuk semula",
|
||||
"The invitation code has already been used": "Kod jemputan sudah digunakan",
|
||||
"The password must contain at least one special character": "Kata laluan mesti mengandungi sekurang-kurangnya satu aksara khas",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Kata laluan mesti mengandungi sekurang-kurangnya satu huruf besar, satu huruf kecil dan satu digit",
|
||||
"The password must have at least 6 characters": "Kata laluan mesti mempunyai sekurang-kurangnya 6 aksara",
|
||||
"The password must have at least 8 characters": "Kata laluan mesti mempunyai sekurang-kurangnya 8 aksara",
|
||||
"The password must not contain any repeated characters": "Kata laluan tidak boleh mengandungi aksara berulang",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Pengguna telah dipadamkan dan tidak boleh digunakan untuk log masuk, sila hubungi pentadbir",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Pengguna dilarang log masuk, sila hubungi pentadbir",
|
||||
"The user: %s doesn't exist in LDAP server": "Pengguna: %s tidak wujud dalam pelayan LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Nama pengguna hanya boleh mengandungi alfanumerik, garis bawah atau sengkang, tidak boleh ada sengkang atau garis bawah berturutan, dan tidak boleh bermula atau berakhir dengan sengkang atau garis bawah.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "operasi ini tidak dibenarkan dalam mod demo",
|
||||
"this operation requires administrator to perform": "operasi ini perlukan pentadbir untuk jalankan"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Jemputan %s tidak wujud"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Pelayan LDAP sudah wujud"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA emel dibenarkan tetapi emel kosong",
|
||||
"MFA phone is enabled but phone number is empty": "MFA telefon dibenarkan tetapi nombor telefon kosong",
|
||||
"New password cannot contain blank space.": "Kata laluan baharu tidak boleh ada ruang kosong.",
|
||||
"The new password must be different from your current password": "Kata laluan baru mesti berbeza daripada kata laluan semasa anda",
|
||||
"the user's owner and name should not be empty": "pemilik dan nama pengguna tidak boleh kosong"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "pengguna tidak wujud, sila daftar dahulu"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Tiada kelayakan dijumpai untuk pengguna ini",
|
||||
"Please call WebAuthnSigninBegin first": "Sila panggil WebAuthnSigninBegin dahulu"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Inloggen mislukt: %s",
|
||||
"Invalid token": "Ongeldige token",
|
||||
"State expected: %s, but got: %s": "Verwachtte state: %s, gekregen: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Gebruiker bestaat niet; aanmelden via %%s niet toegestaan, kies andere methode",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Gebruiker bestaat niet; aanmelden via %s niet toegestaan, kies andere methode",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Gebruiker bestaat niet; aanmelden niet toegestaan, neem contact op met IT",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Account al gekoppeld aan andere gebruiker: %s (%s)",
|
||||
"The application: %s does not exist": "Applicatie %s bestaat niet",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "De applicatie: %s heeft het aanmelden van gebruikers uitgeschakeld",
|
||||
"The group: %s does not exist": "De groep: %s bestaat niet",
|
||||
"The login method: login with LDAP is not enabled for the application": "LDAP-login uitgeschakeld voor deze app",
|
||||
"The login method: login with SMS is not enabled for the application": "SMS-login uitgeschakeld voor deze app",
|
||||
"The login method: login with email is not enabled for the application": "E-mail-login uitgeschakeld voor deze app",
|
||||
"The login method: login with face is not enabled for the application": "Face-login uitgeschakeld voor deze app",
|
||||
"The login method: login with password is not enabled for the application": "Wachtwoord-login uitgeschakeld voor deze app",
|
||||
"The organization: %s does not exist": "Organisatie %s bestaat niet",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "De organisatie: %s heeft het aanmelden van gebruikers uitgeschakeld",
|
||||
"The plan: %s does not exist": "Het plan: %s bestaat niet",
|
||||
"The pricing: %s does not exist": "De prijsstelling: %s bestaat niet",
|
||||
"The pricing: %s does not have plan: %s": "De prijsstelling: %s heeft geen plan: %s",
|
||||
"The provider: %s does not exist": "Provider %s bestaat niet",
|
||||
"The provider: %s is not enabled for the application": "Provider %s uitgeschakeld voor deze app",
|
||||
"Unauthorized operation": "Niet toegestane handeling",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Registreer met de gebruikersnaam die bij de code hoort",
|
||||
"Session outdated, please login again": "Sessie verlopen, log opnieuw in",
|
||||
"The invitation code has already been used": "Code al gebruikt",
|
||||
"The password must contain at least one special character": "Het wachtwoord moet minstens één speciaal teken bevatten",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Het wachtwoord moet minstens één hoofdletter, één kleine letter en één cijfer bevatten",
|
||||
"The password must have at least 6 characters": "Het wachtwoord moet minstens 6 tekens bevatten",
|
||||
"The password must have at least 8 characters": "Het wachtwoord moet minstens 8 tekens bevatten",
|
||||
"The password must not contain any repeated characters": "Het wachtwoord mag geen herhaalde tekens bevatten",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "De gebruiker is verwijderd en kan niet worden gebruikt om in te loggen, neem contact op met de beheerder",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Inloggen verboden, neem contact op met beheerder",
|
||||
"The user: %s doesn't exist in LDAP server": "Gebruiker %s ontbreekt in LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Gebruikersnaam: alleen letters, cijfers, _ of -; geen dubbele streepjes/underscores; mag niet beginnen/eindigen met streepje of underscore.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "Handeling niet toegestaan in demo-modus",
|
||||
"this operation requires administrator to perform": "Alleen beheerder kan deze handeling uitvoeren"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Uitnodiging %s bestaat niet"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP-server bestaat al"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA-e-mail ingeschakeld maar e-mailadres leeg",
|
||||
"MFA phone is enabled but phone number is empty": "MFA-telefoon ingeschakeld maar nummer leeg",
|
||||
"New password cannot contain blank space.": "Nieuw wachtwoord mag geen spaties bevatten",
|
||||
"The new password must be different from your current password": "Het nieuwe wachtwoord moet verschillen van uw huidige wachtwoord",
|
||||
"the user's owner and name should not be empty": "Eigenaar en naam van gebruiker mogen niet leeg zijn"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "Gebruiker bestaat niet; meld je eerst aan"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Geen inloggegevens gevonden voor deze gebruiker",
|
||||
"Please call WebAuthnSigninBegin first": "Roep eerst WebAuthnSigninBegin aan"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Logowanie nie powiodło się: %s",
|
||||
"Invalid token": "Nieprawidłowy token",
|
||||
"State expected: %s, but got: %s": "Oczekiwano stanu: %s, ale otrzymano: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Konto dla dostawcy: %s i nazwy użytkownika: %s (%s) nie istnieje i nie można się zarejestrować jako nowe konto przez %%s, użyj innej metody rejestracji",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Konto dla dostawcy: %s i nazwy użytkownika: %s (%s) nie istnieje i nie można się zarejestrować jako nowe konto przez %s, użyj innej metody rejestracji",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Konto dla dostawcy: %s i nazwy użytkownika: %s (%s) nie istnieje i nie można się zarejestrować jako nowe konto, skontaktuj się z pomocą IT",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Konto dla dostawcy: %s i nazwy użytkownika: %s (%s) jest już powiązane z innym kontem: %s (%s)",
|
||||
"The application: %s does not exist": "Aplikacja: %s nie istnieje",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Aplikacja: %s wyłączyła logowanie użytkowników",
|
||||
"The group: %s does not exist": "Grupa: %s nie istnieje",
|
||||
"The login method: login with LDAP is not enabled for the application": "Metoda logowania: logowanie przez LDAP nie jest włączone dla aplikacji",
|
||||
"The login method: login with SMS is not enabled for the application": "Metoda logowania: logowanie przez SMS nie jest włączona dla aplikacji",
|
||||
"The login method: login with email is not enabled for the application": "Metoda logowania: logowanie przez email nie jest włączona dla aplikacji",
|
||||
"The login method: login with face is not enabled for the application": "Metoda logowania: logowanie przez twarz nie jest włączona dla aplikacji",
|
||||
"The login method: login with password is not enabled for the application": "Metoda logowania: logowanie przez hasło nie jest włączone dla aplikacji",
|
||||
"The organization: %s does not exist": "Organizacja: %s nie istnieje",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Organizacja: %s wyłączyła logowanie użytkowników",
|
||||
"The plan: %s does not exist": "Plan: %s nie istnieje",
|
||||
"The pricing: %s does not exist": "Cennik: %s nie istnieje",
|
||||
"The pricing: %s does not have plan: %s": "Cennik: %s nie ma planu: %s",
|
||||
"The provider: %s does not exist": "Dostawca: %s nie istnieje",
|
||||
"The provider: %s is not enabled for the application": "Dostawca: %s nie jest włączony dla aplikacji",
|
||||
"Unauthorized operation": "Nieautoryzowana operacja",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Zarejestruj się używając nazwy użytkownika odpowiadającej kodowi zaproszenia",
|
||||
"Session outdated, please login again": "Sesja wygasła, zaloguj się ponownie",
|
||||
"The invitation code has already been used": "Kod zaproszenia został już wykorzystany",
|
||||
"The password must contain at least one special character": "Hasło musi zawierać co najmniej jeden znak specjalny",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Hasło musi zawierać co najmniej jedną wielką literę, jedną małą literę i jedną cyfrę",
|
||||
"The password must have at least 6 characters": "Hasło musi zawierać co najmniej 6 znaków",
|
||||
"The password must have at least 8 characters": "Hasło musi zawierać co najmniej 8 znaków",
|
||||
"The password must not contain any repeated characters": "Hasło nie może zawierać powtarzających się znaków",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Użytkownik został usunięty i nie może być używany do logowania, skontaktuj się z administratorem",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Użytkownikowi zabroniono logowania, skontaktuj się z administratorem",
|
||||
"The user: %s doesn't exist in LDAP server": "Użytkownik: %s nie istnieje w serwerze LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Nazwa użytkownika może zawierać tylko znaki alfanumeryczne, podkreślenia lub myślniki, nie może mieć kolejnych myślników lub podkreśleń i nie może zaczynać się ani kończyć myślnikiem lub podkreśleniem.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "ta operacja nie jest dozwolona w trybie demo",
|
||||
"this operation requires administrator to perform": "ta operacja wymaga administratora do wykonania"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Zaproszenie %s nie istnieje"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Serwer LDAP istnieje"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA email jest włączone, ale email jest pusty",
|
||||
"MFA phone is enabled but phone number is empty": "MFA telefon jest włączony, ale numer telefonu jest pusty",
|
||||
"New password cannot contain blank space.": "Nowe hasło nie może zawierać spacji.",
|
||||
"The new password must be different from your current password": "Nowe hasło musi różnić się od obecnego hasła",
|
||||
"the user's owner and name should not be empty": "właściciel i nazwa użytkownika nie powinny być puste"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "użytkownik nie istnieje, najpierw się zarejestruj"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Nie znaleziono danych uwierzytelniających dla tego użytkownika",
|
||||
"Please call WebAuthnSigninBegin first": "Najpierw wywołaj WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,60 +1,64 @@
|
||||
{
|
||||
"account": {
|
||||
"Failed to add user": "Falha ao adicionar usuário",
|
||||
"Get init score failed, error: %w": "Obter pontuação inicial falhou, erro: %w",
|
||||
"Please sign out first": "Por favor, saia da sessão primeiro",
|
||||
"The application does not allow to sign up new account": "O aplicativo não permite a criação de uma nova conta"
|
||||
"Get init score failed, error: %w": "Falha ao obter pontuação inicial, erro: %w",
|
||||
"Please sign out first": "Por favor, saia primeiro",
|
||||
"The application does not allow to sign up new account": "O aplicativo não permite a criação de novas contas"
|
||||
},
|
||||
"auth": {
|
||||
"Challenge method should be S256": "Método de desafio deve ser S256",
|
||||
"Challenge method should be S256": "O método de desafio deve ser S256",
|
||||
"DeviceCode Invalid": "Código de dispositivo inválido",
|
||||
"Failed to create user, user information is invalid: %s": "Falha ao criar usuário, informação do usuário inválida: %s",
|
||||
"Failed to login in: %s": "Falha ao entrar em: %s",
|
||||
"Failed to create user, user information is invalid: %s": "Falha ao criar usuário, as informações são inválidas: %s",
|
||||
"Failed to login in: %s": "Falha ao fazer login em: %s",
|
||||
"Invalid token": "Token inválido",
|
||||
"State expected: %s, but got: %s": "Estado esperado: %s, mas recebeu: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "A conta para o provedor: %s e nome de usuário: %s (%s) não existe e não é permitido inscrever-se como uma nova conta via %%s, por favor, use outra forma de se inscrever",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "A conta para o provedor: %s e nome de usuário: %s (%s) não existe e não é permitido inscrever-se como uma nova conta entre em contato com seu suporte de TI",
|
||||
"State expected: %s, but got: %s": "Estado esperado: %s, mas recebido: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "A conta do provedor: %s e nome de usuário: %s (%s) não existe e não é permitido criar nova conta via %s, por favor, use outra forma de cadastro",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "A conta do provedor: %s e nome de usuário: %s (%s) não existe e não é permitido criar nova conta, entre em contato com o suporte de TI",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "A conta do provedor: %s e nome de usuário: %s (%s) já está vinculada a outra conta: %s (%s)",
|
||||
"The application: %s does not exist": "O aplicativo: %s não existe",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The login method: login with LDAP is not enabled for the application": "O método de login: login com LDAP não está ativado para a aplicação",
|
||||
"The login method: login with SMS is not enabled for the application": "O método de login: login com SMS não está ativado para a aplicação",
|
||||
"The login method: login with email is not enabled for the application": "O método de login: login com e-mail não está ativado para a aplicação",
|
||||
"The login method: login with face is not enabled for the application": "O método de login: login com reconhecimento facial não está ativado para a aplicação",
|
||||
"The login method: login with password is not enabled for the application": "O método de login: login com senha não está habilitado para o aplicativo",
|
||||
"The application: %s has disabled users to signin": "O aplicativo: %s desativou o login de usuários",
|
||||
"The group: %s does not exist": "O grupo: %s não existe",
|
||||
"The login method: login with LDAP is not enabled for the application": "O método de login com LDAP não está habilitado para o aplicativo",
|
||||
"The login method: login with SMS is not enabled for the application": "O método de login com SMS não está habilitado para o aplicativo",
|
||||
"The login method: login with email is not enabled for the application": "O método de login com e-mail não está habilitado para o aplicativo",
|
||||
"The login method: login with face is not enabled for the application": "O método de login com reconhecimento facial não está habilitado para o aplicativo",
|
||||
"The login method: login with password is not enabled for the application": "O método de login com senha não está habilitado para o aplicativo",
|
||||
"The organization: %s does not exist": "A organização: %s não existe",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "A organização: %s desativou o login de usuários",
|
||||
"The plan: %s does not exist": "O plano: %s não existe",
|
||||
"The pricing: %s does not exist": "O preço: %s não existe",
|
||||
"The pricing: %s does not have plan: %s": "O preço: %s não tem o plano: %s",
|
||||
"The provider: %s does not exist": "O provedor: %s não existe",
|
||||
"The provider: %s is not enabled for the application": "O provedor: %s não está habilitado para o aplicativo",
|
||||
"Unauthorized operation": "Operação não autorizada",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Tipo de autenticação desconhecido (não é senha ou provedor), formulário = %s",
|
||||
"User's tag: %s is not listed in the application's tags": "A tag do usuário: %s não está listada nas tags da aplicação",
|
||||
"User's tag: %s is not listed in the application's tags": "A tag do usuário: %s não está listada nas tags do aplicativo",
|
||||
"UserCode Expired": "Código de usuário expirado",
|
||||
"UserCode Invalid": "Código de usuário inválido",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "usuário pago %s não possui assinatura ativa ou pendente e a aplicação: %s não possui preço padrão",
|
||||
"the application for user %s is not found": "a aplicação para o usuário %s não foi encontrada",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "O usuário pago %s não possui assinatura ativa ou pendente e o aplicativo: %s não possui preço padrão",
|
||||
"the application for user %s is not found": "o aplicativo para o usuário %s não foi encontrado",
|
||||
"the organization: %s is not found": "a organização: %s não foi encontrada"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "O serviço %s e %s não correspondem"
|
||||
},
|
||||
"check": {
|
||||
"%s does not meet the CIDR format requirements: %s": "%s não atende aos requisitos de formato CIDR: %s",
|
||||
"Affiliation cannot be blank": "A filiação não pode estar em branco",
|
||||
"CIDR for IP: %s should not be empty": "CIDR para IP: %s não deve estar vazio",
|
||||
"Default code does not match the code's matching rules": "O código padrão não corresponde às regras de correspondência do código",
|
||||
"%s does not meet the CIDR format requirements: %s": "%s não atende aos requisitos do formato CIDR: %s",
|
||||
"Affiliation cannot be blank": "A afiliação não pode estar em branco",
|
||||
"CIDR for IP: %s should not be empty": "O CIDR para o IP: %s não pode estar vazio",
|
||||
"Default code does not match the code's matching rules": "O código padrão não corresponde às regras de validação do código",
|
||||
"DisplayName cannot be blank": "O nome de exibição não pode estar em branco",
|
||||
"DisplayName is not valid real name": "O nome de exibição não é um nome real válido",
|
||||
"Email already exists": "O e-mail já existe",
|
||||
"Email cannot be empty": "O e-mail não pode estar vazio",
|
||||
"Email is invalid": "O e-mail é inválido",
|
||||
"Email is invalid": "E-mail inválido",
|
||||
"Empty username.": "Nome de usuário vazio.",
|
||||
"Face data does not exist, cannot log in": "Dados faciais não existem, não é possível fazer login",
|
||||
"Face data mismatch": "Incompatibilidade de dados faciais",
|
||||
"Failed to parse client IP: %s": "Falha ao analisar IP do cliente: %s",
|
||||
"Face data mismatch": "Dados faciais não correspondem",
|
||||
"Failed to parse client IP: %s": "Falha ao analisar o IP do cliente: %s",
|
||||
"FirstName cannot be blank": "O primeiro nome não pode estar em branco",
|
||||
"Invitation code cannot be blank": "O código de convite não pode estar em branco",
|
||||
"Invitation code exhausted": "Código de convite esgotado",
|
||||
"Invitation code exhausted": "O código de convite foi esgotado",
|
||||
"Invitation code is invalid": "Código de convite inválido",
|
||||
"Invitation code suspended": "Código de convite suspenso",
|
||||
"LDAP user name or password incorrect": "Nome de usuário ou senha LDAP incorretos",
|
||||
@@ -64,75 +68,84 @@
|
||||
"Password cannot be empty": "A senha não pode estar vazia",
|
||||
"Phone already exists": "O telefone já existe",
|
||||
"Phone cannot be empty": "O telefone não pode estar vazio",
|
||||
"Phone number is invalid": "O número de telefone é inválido",
|
||||
"Phone number is invalid": "Número de telefone inválido",
|
||||
"Please register using the email corresponding to the invitation code": "Por favor, registre-se usando o e-mail correspondente ao código de convite",
|
||||
"Please register using the phone corresponding to the invitation code": "Por favor, registre-se usando o telefone correspondente ao código de convite",
|
||||
"Please register using the username corresponding to the invitation code": "Por favor, registre-se usando o nome de usuário correspondente ao código de convite",
|
||||
"Session outdated, please login again": "Sessão expirada, faça login novamente",
|
||||
"The invitation code has already been used": "O código de convite já foi utilizado",
|
||||
"The password must contain at least one special character": "A senha deve conter pelo menos um caractere especial",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "A senha deve conter pelo menos uma letra maiúscula, uma letra minúscula e um dígito",
|
||||
"The password must have at least 6 characters": "A senha deve ter pelo menos 6 caracteres",
|
||||
"The password must have at least 8 characters": "A senha deve ter pelo menos 8 caracteres",
|
||||
"The password must not contain any repeated characters": "A senha não deve conter caracteres repetidos",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "O usuário foi excluído e não pode ser usado para fazer login, entre em contato com o administrador",
|
||||
"The user is forbidden to sign in, please contact the administrator": "O usuário está proibido de entrar, entre em contato com o administrador",
|
||||
"The user: %s doesn't exist in LDAP server": "O usuário: %s não existe no servidor LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "O nome de usuário pode conter apenas caracteres alfanuméricos, sublinhados ou hífens, não pode ter hífens ou sublinhados consecutivos e não pode começar ou terminar com hífen ou sublinhado.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "O valor \\\"%s\\\" para o campo de conta \\\"%s\\\" não corresponde à expressão regular do item de conta",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "O valor \\\"%s\\\" para o campo de registro \\\"%s\\\" não corresponde à expressão regular do item de registro da aplicação \\\"%s\\\"",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "O valor \\\"%s\\\" para o campo de conta \\\"%s\\\" não corresponde à expressão regular definida",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "O valor \\\"%s\\\" para o campo de registro \\\"%s\\\" não corresponde à expressão regular definida na aplicação \\\"%s\\\"",
|
||||
"Username already exists": "O nome de usuário já existe",
|
||||
"Username cannot be an email address": "O nome de usuário não pode ser um endereço de e-mail",
|
||||
"Username cannot contain white spaces": "O nome de usuário não pode conter espaços em branco",
|
||||
"Username cannot start with a digit": "O nome de usuário não pode começar com um dígito",
|
||||
"Username is too long (maximum is 255 characters).": "Nome de usuário é muito longo (máximo é 255 caracteres).",
|
||||
"Username must have at least 2 characters": "Nome de usuário deve ter pelo menos 2 caracteres",
|
||||
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "O nome de usuário suporta formato de e-mail. Além disso, o nome de usuário pode conter apenas caracteres alfanuméricos, sublinhados ou hífens, não pode ter hífens ou sublinhados consecutivos e não pode começar ou terminar com hífen ou sublinhado. Preste atenção também ao formato de e-mail.",
|
||||
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Você digitou a senha ou o código incorretos muitas vezes, aguarde %d minutos e tente novamente",
|
||||
"Your IP address: %s has been banned according to the configuration of: ": "Seu endereço IP: %s foi banido de acordo com a configuração de: ",
|
||||
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Sua senha expirou. Por favor, redefina sua senha clicando em \\\"Esqueci a senha\\\"",
|
||||
"Username cannot start with a digit": "O nome de usuário não pode começar com um número",
|
||||
"Username is too long (maximum is 255 characters).": "O nome de usuário é muito longo (máximo de 255 caracteres).",
|
||||
"Username must have at least 2 characters": "O nome de usuário deve ter pelo menos 2 caracteres",
|
||||
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "O nome de usuário suporta o formato de e-mail. Além disso, pode conter apenas caracteres alfanuméricos, sublinhados ou hífens, não pode ter hífens ou sublinhados consecutivos e não pode começar ou terminar com hífen ou sublinhado. Também preste atenção ao formato do e-mail.",
|
||||
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Você digitou a senha ou o código incorretos muitas vezes. Aguarde %d minutos e tente novamente",
|
||||
"Your IP address: %s has been banned according to the configuration of: ": "Seu endereço IP: %s foi bloqueado de acordo com a configuração de: ",
|
||||
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Sua senha expirou. Por favor, redefina-a clicando em \\\"Esqueci a senha\\\"",
|
||||
"Your region is not allow to signup by phone": "Sua região não permite cadastro por telefone",
|
||||
"password or code is incorrect": "senha ou código incorreto",
|
||||
"password or code is incorrect, you have %s remaining chances": "senha ou código está incorreto, você tem %s chances restantes",
|
||||
"unsupported password type: %s": "tipo de senha não suportado: %s"
|
||||
"password or code is incorrect": "Senha ou código incorreto",
|
||||
"password or code is incorrect, you have %s remaining chances": "Senha ou código incorreto, você tem %s tentativas restantes",
|
||||
"unsupported password type: %s": "Tipo de senha não suportado: %s"
|
||||
},
|
||||
"enforcer": {
|
||||
"the adapter: %s is not found": "o adaptador: %s não foi encontrado"
|
||||
"the adapter: %s is not found": "O adaptador: %s não foi encontrado"
|
||||
},
|
||||
"general": {
|
||||
"Failed to import groups": "Falha ao importar grupos",
|
||||
"Failed to import users": "Falha ao importar usuários",
|
||||
"Missing parameter": "Parâmetro faltante",
|
||||
"Only admin user can specify user": "Apenas usuário administrador pode especificar usuário",
|
||||
"Please login first": "Faça login primeiro",
|
||||
"The organization: %s should have one application at least": "A organização: %s deve ter pelo menos uma aplicação",
|
||||
"Missing parameter": "Parâmetro ausente",
|
||||
"Only admin user can specify user": "Apenas um administrador pode especificar um usuário",
|
||||
"Please login first": "Por favor, faça login primeiro",
|
||||
"The organization: %s should have one application at least": "A organização: %s deve ter pelo menos um aplicativo",
|
||||
"The user: %s doesn't exist": "O usuário: %s não existe",
|
||||
"Wrong userId": "ID de usuário incorreto",
|
||||
"don't support captchaProvider: ": "não suporta captchaProvider: ",
|
||||
"don't support captchaProvider: ": "captchaProvider não suportado: ",
|
||||
"this operation is not allowed in demo mode": "esta operação não é permitida no modo de demonstração",
|
||||
"this operation requires administrator to perform": "esta operação requer um administrador para executar"
|
||||
"this operation requires administrator to perform": "esta operação requer privilégios de administrador"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "O convite %s não existe"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Servidor LDAP existe"
|
||||
"Ldap server exist": "O servidor LDAP existe"
|
||||
},
|
||||
"link": {
|
||||
"Please link first": "Vincule primeiro",
|
||||
"This application has no providers": "Este aplicativo não tem provedores",
|
||||
"This application has no providers of type": "Este aplicativo não tem provedores do tipo",
|
||||
"Please link first": "Por favor, vincule primeiro",
|
||||
"This application has no providers": "Este aplicativo não possui provedores",
|
||||
"This application has no providers of type": "Este aplicativo não possui provedores do tipo especificado",
|
||||
"This provider can't be unlinked": "Este provedor não pode ser desvinculado",
|
||||
"You are not the global admin, you can't unlink other users": "Você não é o administrador global, não pode desvincular outros usuários",
|
||||
"You can't unlink yourself, you are not a member of any application": "Você não pode se desvincular, não é membro de nenhum aplicativo"
|
||||
"You can't unlink yourself, you are not a member of any application": "Você não pode se desvincular, pois não é membro de nenhum aplicativo"
|
||||
},
|
||||
"organization": {
|
||||
"Only admin can modify the %s.": "Apenas o administrador pode modificar o %s.",
|
||||
"The %s is immutable.": "O %s é imutável.",
|
||||
"Unknown modify rule %s.": "Regra de modificação %s desconhecida.",
|
||||
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "nte desativada. Observe que todos os usuários na organização 'built-in' são administradores globais no Casdoor. Consulte a documentação: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. Se ainda desejar criar um usuário para a organização 'built-in', acesse a página de configurações da organização e habilite a opção 'Possui consentimento de privilégios'."
|
||||
"Unknown modify rule %s.": "Regra de modificação desconhecida: %s.",
|
||||
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "A adição de novos usuários à organização 'built-in' está desativada. Observe que todos os usuários nessa organização são administradores globais no Casdoor. Consulte a documentação: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. Se ainda desejar criar um usuário, vá até a página de configurações da organização e habilite a opção 'Possui consentimento de privilégios'."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "A permissão: \\\"%s\\\" não existe"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Id do aplicativo inválido",
|
||||
"the provider: %s does not exist": "o provedor: %s não existe"
|
||||
"Invalid application id": "ID de aplicativo inválido",
|
||||
"the provider: %s does not exist": "O provedor: %s não existe"
|
||||
},
|
||||
"resource": {
|
||||
"User is nil for tag: avatar": "Usuário é nulo para tag: avatar",
|
||||
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Nome de usuário ou fullFilePath está vazio: username = %s, fullFilePath = %s"
|
||||
"User is nil for tag: avatar": "Usuário nulo para a tag: avatar",
|
||||
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Nome de usuário ou fullFilePath vazio: username = %s, fullFilePath = %s"
|
||||
},
|
||||
"saml": {
|
||||
"Application %s not found": "Aplicativo %s não encontrado"
|
||||
@@ -146,7 +159,7 @@
|
||||
"Invalid phone receivers: %s": "Destinatários de telefone inválidos: %s"
|
||||
},
|
||||
"storage": {
|
||||
"The objectKey: %s is not allowed": "O objectKey: %s não é permitido",
|
||||
"The objectKey: %s is not allowed": "A chave de objeto: %s não é permitida",
|
||||
"The provider type: %s is not supported": "O tipo de provedor: %s não é suportado"
|
||||
},
|
||||
"subscription": {
|
||||
@@ -154,40 +167,41 @@
|
||||
},
|
||||
"token": {
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s não é suportado neste aplicativo",
|
||||
"Invalid application or wrong clientSecret": "Aplicativo inválido ou clientSecret errado",
|
||||
"Invalid application or wrong clientSecret": "Aplicativo inválido ou clientSecret incorreto",
|
||||
"Invalid client_id": "client_id inválido",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "URI de redirecionamento: %s não existe na lista de URI de redirecionamento permitida",
|
||||
"Token not found, invalid accessToken": "Token não encontrado, token de acesso inválido"
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "O URI de redirecionamento: %s não existe na lista de URIs permitidos",
|
||||
"Token not found, invalid accessToken": "Token não encontrado, accessToken inválido"
|
||||
},
|
||||
"user": {
|
||||
"Display name cannot be empty": "Nome de exibição não pode ser vazio",
|
||||
"MFA email is enabled but email is empty": "MFA por e-mail está ativado, mas o e-mail está vazio",
|
||||
"MFA phone is enabled but phone number is empty": "MFA por telefone está ativado, mas o número de telefone está vazio",
|
||||
"New password cannot contain blank space.": "A nova senha não pode conter espaço em branco.",
|
||||
"the user's owner and name should not be empty": "o proprietário e o nome do usuário não devem estar vazios"
|
||||
"Display name cannot be empty": "O nome de exibição não pode estar vazio",
|
||||
"MFA email is enabled but email is empty": "MFA por e-mail está habilitado, mas o e-mail está vazio",
|
||||
"MFA phone is enabled but phone number is empty": "MFA por telefone está habilitado, mas o número de telefone está vazio",
|
||||
"New password cannot contain blank space.": "A nova senha não pode conter espaços em branco.",
|
||||
"The new password must be different from your current password": "A nova senha deve ser diferente da senha atual",
|
||||
"the user's owner and name should not be empty": "O proprietário e o nome do usuário não devem estar vazios"
|
||||
},
|
||||
"util": {
|
||||
"No application is found for userId: %s": "Nenhum aplicativo encontrado para userId: %s",
|
||||
"No provider for category: %s is found for application: %s": "Nenhum provedor para categoria: %s encontrado para aplicativo: %s",
|
||||
"No application is found for userId: %s": "Nenhum aplicativo encontrado para o userId: %s",
|
||||
"No provider for category: %s is found for application: %s": "Nenhum provedor da categoria: %s encontrado para o aplicativo: %s",
|
||||
"The provider: %s is not found": "O provedor: %s não foi encontrado"
|
||||
},
|
||||
"verification": {
|
||||
"Invalid captcha provider.": "Provedor de captcha inválido.",
|
||||
"Phone number is invalid in your region %s": "Número de telefone é inválido em sua região %s",
|
||||
"Phone number is invalid in your region %s": "Número de telefone inválido na sua região %s",
|
||||
"The verification code has already been used!": "O código de verificação já foi utilizado!",
|
||||
"The verification code has not been sent yet!": "O código de verificação ainda não foi enviado!",
|
||||
"Turing test failed.": "Teste de Turing falhou.",
|
||||
"Turing test failed.": "O teste de Turing falhou.",
|
||||
"Unable to get the email modify rule.": "Não foi possível obter a regra de modificação de e-mail.",
|
||||
"Unable to get the phone modify rule.": "Não foi possível obter a regra de modificação de telefone.",
|
||||
"Unknown type": "Tipo desconhecido",
|
||||
"Wrong verification code!": "Código de verificação incorreto!",
|
||||
"You should verify your code in %d min!": "Você deve verificar seu código em %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "por favor, adicione um provedor de SMS à lista \\\"Providers\\\" da aplicação: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "por favor, adicione um provedor de e-mail à lista \\\"Providers\\\" da aplicação: %s",
|
||||
"the user does not exist, please sign up first": "o usuário não existe, cadastre-se primeiro"
|
||||
"You should verify your code in %d min!": "Você deve verificar seu código em %d minuto(s)!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "Adicione um provedor de SMS à lista \\\"Providers\\\" do aplicativo: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "Adicione um provedor de e-mail à lista \\\"Providers\\\" do aplicativo: %s",
|
||||
"the user does not exist, please sign up first": "O usuário não existe, cadastre-se primeiro"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Please call WebAuthnSigninBegin first": "Por favor, chame WebAuthnSigninBegin primeiro"
|
||||
"Found no credentials for this user": "Nenhuma credencial encontrada para este usuário",
|
||||
"Please call WebAuthnSigninBegin first": "Por favor, inicie com WebAuthnSigninBegin primeiro"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Не удалось войти в систему: %s",
|
||||
"Invalid token": "Недействительный токен",
|
||||
"State expected: %s, but got: %s": "Ожидался статус: %s, но получен: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Аккаунт провайдера: %s и имя пользователя: %s (%s) не существует и не может быть зарегистрирован через %%s, пожалуйста, используйте другой способ регистрации",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Аккаунт провайдера: %s и имя пользователя: %s (%s) не существует и не может быть зарегистрирован через %s, пожалуйста, используйте другой способ регистрации",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Аккаунт для провайдера: %s и имя пользователя: %s (%s) не существует и не может быть зарегистрирован как новый аккаунт. Пожалуйста, обратитесь в службу поддержки IT",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Аккаунт поставщика: %s и имя пользователя: %s (%s) уже связаны с другим аккаунтом: %s (%s)",
|
||||
"The application: %s does not exist": "Приложение: %s не существует",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Приложение: %s отключило вход пользователей",
|
||||
"The group: %s does not exist": "Группа: %s не существует",
|
||||
"The login method: login with LDAP is not enabled for the application": "Метод входа через LDAP отключен для этого приложения",
|
||||
"The login method: login with SMS is not enabled for the application": "Метод входа через SMS отключен для этого приложения",
|
||||
"The login method: login with email is not enabled for the application": "Метод входа через электронную почту отключен для этого приложения",
|
||||
"The login method: login with face is not enabled for the application": "Метод входа через распознавание лица отключен для этого приложения",
|
||||
"The login method: login with password is not enabled for the application": "Метод входа: вход с паролем не включен для приложения",
|
||||
"The organization: %s does not exist": "Организация: %s не существует",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Организация: %s отключила вход пользователей",
|
||||
"The plan: %s does not exist": "План: %s не существует",
|
||||
"The pricing: %s does not exist": "Тариф: %s не существует",
|
||||
"The pricing: %s does not have plan: %s": "Тариф: %s не имеет план: %s",
|
||||
"The provider: %s does not exist": "Провайдер: %s не существует",
|
||||
"The provider: %s is not enabled for the application": "Провайдер: %s не включен для приложения",
|
||||
"Unauthorized operation": "Несанкционированная операция",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Пожалуйста, зарегистрируйтесь, используя имя пользователя, соответствующее коду приглашения",
|
||||
"Session outdated, please login again": "Сессия устарела, пожалуйста, войдите снова",
|
||||
"The invitation code has already been used": "Код приглашения уже использован",
|
||||
"The password must contain at least one special character": "Пароль должен содержать хотя бы один специальный символ",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Пароль должен содержать хотя бы одну заглавную букву, одну строчную букву и одну цифру",
|
||||
"The password must have at least 6 characters": "Пароль должен содержать не менее 6 символов",
|
||||
"The password must have at least 8 characters": "Пароль должен содержать не менее 8 символов",
|
||||
"The password must not contain any repeated characters": "Пароль не должен содержать повторяющихся символов",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Пользователь был удален и не может быть использован для входа, пожалуйста, свяжитесь с администратором",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Пользователю запрещен вход, пожалуйста, обратитесь к администратору",
|
||||
"The user: %s doesn't exist in LDAP server": "Пользователь: %s не существует на сервере LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Имя пользователя может состоять только из буквенно-цифровых символов, нижних подчеркиваний или дефисов, не может содержать последовательные дефисы или подчеркивания, а также не может начинаться или заканчиваться на дефис или подчеркивание.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "эта операция недоступна в демонстрационном режиме",
|
||||
"this operation requires administrator to perform": "эта операция требует прав администратора"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Приглашение %s не существует"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP-сервер существует"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA по электронной почте включен, но электронная почта не указана",
|
||||
"MFA phone is enabled but phone number is empty": "MFA по телефону включен, но номер телефона не указан",
|
||||
"New password cannot contain blank space.": "Новый пароль не может содержать пробелы.",
|
||||
"The new password must be different from your current password": "Новый пароль должен отличаться от текущего пароля",
|
||||
"the user's owner and name should not be empty": "владелец и имя пользователя не должны быть пустыми"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "Пользователь не существует, пожалуйста, сначала зарегистрируйтесь"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Учетные данные для этого пользователя не найдены",
|
||||
"Please call WebAuthnSigninBegin first": "Пожалуйста, сначала вызовите WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Prihlásenie zlyhalo: %s",
|
||||
"Invalid token": "Neplatný token",
|
||||
"State expected: %s, but got: %s": "Očakávaný stav: %s, ale dostali sme: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Účet pre poskytovateľa: %s a používateľské meno: %s (%s) neexistuje a nie je povolené zaregistrovať nový účet cez %%s, prosím použite iný spôsob registrácie",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Účet pre poskytovateľa: %s a používateľské meno: %s (%s) neexistuje a nie je povolené zaregistrovať nový účet cez %s, prosím použite iný spôsob registrácie",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Účet pre poskytovateľa: %s a používateľské meno: %s (%s) neexistuje a nie je povolené zaregistrovať nový účet, prosím kontaktujte vašu IT podporu",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Účet pre poskytovateľa: %s a používateľské meno: %s (%s) je už prepojený s iným účtom: %s (%s)",
|
||||
"The application: %s does not exist": "Aplikácia: %s neexistuje",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Aplikácia: %s zakázala prihlasovanie používateľov",
|
||||
"The group: %s does not exist": "Skupina: %s neexistuje",
|
||||
"The login method: login with LDAP is not enabled for the application": "Metóda prihlásenia: prihlásenie pomocou LDAP nie je pre aplikáciu povolená",
|
||||
"The login method: login with SMS is not enabled for the application": "Metóda prihlásenia: prihlásenie pomocou SMS nie je pre aplikáciu povolená",
|
||||
"The login method: login with email is not enabled for the application": "Metóda prihlásenia: prihlásenie pomocou e-mailu nie je pre aplikáciu povolená",
|
||||
"The login method: login with face is not enabled for the application": "Metóda prihlásenia: prihlásenie pomocou tváre nie je pre aplikáciu povolená",
|
||||
"The login method: login with password is not enabled for the application": "Metóda prihlásenia: prihlásenie pomocou hesla nie je pre aplikáciu povolená",
|
||||
"The organization: %s does not exist": "Organizácia: %s neexistuje",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Organizácia: %s zakázala prihlasovanie používateľov",
|
||||
"The plan: %s does not exist": "Plán: %s neexistuje",
|
||||
"The pricing: %s does not exist": "Cenník: %s neexistuje",
|
||||
"The pricing: %s does not have plan: %s": "Cenník: %s nemá plán: %s",
|
||||
"The provider: %s does not exist": "Poskytovatel: %s neexistuje",
|
||||
"The provider: %s is not enabled for the application": "Poskytovateľ: %s nie je pre aplikáciu povolený",
|
||||
"Unauthorized operation": "Neautorizovaná operácia",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Prosím, zaregistrujte sa pomocou používateľského mena zodpovedajúceho kódu pozvania",
|
||||
"Session outdated, please login again": "Relácia je zastaraná, prosím, prihláste sa znova",
|
||||
"The invitation code has already been used": "Kód pozvania už bol použitý",
|
||||
"The password must contain at least one special character": "Heslo musí obsahovať aspoň jeden špeciálny znak",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Heslo musí obsahovať aspoň jedno veľké písmeno, jedno malé písmeno a jednu číslicu",
|
||||
"The password must have at least 6 characters": "Heslo musí mať aspoň 6 znakov",
|
||||
"The password must have at least 8 characters": "Heslo musí mať aspoň 8 znakov",
|
||||
"The password must not contain any repeated characters": "Heslo nesmie obsahovať opakujúce sa znaky",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Používateľ bol odstránený a nie je možné ho použiť na prihlásenie, kontaktujte prosím správcu",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Používateľovi je zakázané prihlásenie, prosím, kontaktujte administrátora",
|
||||
"The user: %s doesn't exist in LDAP server": "Používateľ: %s neexistuje na LDAP serveri",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Používateľské meno môže obsahovať iba alfanumerické znaky, podtržníky alebo pomlčky, nemôže obsahovať po sebe idúce pomlčky alebo podtržníky a nemôže začínať alebo končiť pomlčkou alebo podtržníkom.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "táto operácia nie je povolená v demo režime",
|
||||
"this operation requires administrator to perform": "táto operácia vyžaduje vykonanie administrátorom"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Pozvánka %s neexistuje"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP server existuje"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA e-mail je zapnutý, ale e-mail je prázdny",
|
||||
"MFA phone is enabled but phone number is empty": "MFA telefón je zapnutý, ale telefónne číslo je prázdne",
|
||||
"New password cannot contain blank space.": "Nové heslo nemôže obsahovať medzery.",
|
||||
"The new password must be different from your current password": "Nové heslo sa musí líšiť od vášho aktuálneho hesla",
|
||||
"the user's owner and name should not be empty": "vlastník a meno používateľa nesmú byť prázdne"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "používateľ neexistuje, prosím, zaregistrujte sa najskôr"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Pre tohto používateľa sa nenašli žiadne prihlasovacie údaje",
|
||||
"Please call WebAuthnSigninBegin first": "Najskôr prosím zavolajte WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Misslyckades logga in: %s",
|
||||
"Invalid token": "Ogiltig token",
|
||||
"State expected: %s, but got: %s": "Förväntat tillstånd: %s, men fick: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Kontot för leverantör: %s och användarnamn: %s (%s) finns inte och det är inte tillåtet att registrera ett nytt konto via %%s, använd ett annat sätt att registrera dig",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Kontot för leverantör: %s och användarnamn: %s (%s) finns inte och det är inte tillåtet att registrera ett nytt konto via %s, använd ett annat sätt att registrera dig",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Kontot för leverantör: %s och användarnamn: %s (%s) finns inte och det är inte tillåtet att registrera ett nytt konto, kontakta din IT-support",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Kontot för leverantör: %s och användarnamn: %s (%s) är redan länkat till ett annat konto: %s (%s)",
|
||||
"The application: %s does not exist": "Applikationen: %s finns inte",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Applikationen: %s har inaktiverat användarinloggning",
|
||||
"The group: %s does not exist": "Gruppen: %s finns inte",
|
||||
"The login method: login with LDAP is not enabled for the application": "Inloggningsmetoden: inloggning med LDAP är inte aktiverad för applikationen",
|
||||
"The login method: login with SMS is not enabled for the application": "Inloggningsmetoden: inloggning med SMS är inte aktiverad för applikationen",
|
||||
"The login method: login with email is not enabled for the application": "Inloggningsmetoden: inloggning med e-post är inte aktiverad för applikationen",
|
||||
"The login method: login with face is not enabled for the application": "Inloggningsmetoden: inloggning med ansikte är inte aktiverad för applikationen",
|
||||
"The login method: login with password is not enabled for the application": "Inloggningsmetoden: inloggning med lösenord är inte aktiverad för applikationen",
|
||||
"The organization: %s does not exist": "Organisationen: %s finns inte",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Organisationen: %s har inaktiverat användarinloggning",
|
||||
"The plan: %s does not exist": "Planen: %s finns inte",
|
||||
"The pricing: %s does not exist": "Prissättningen: %s finns inte",
|
||||
"The pricing: %s does not have plan: %s": "Prissättningen: %s har inte plan: %s",
|
||||
"The provider: %s does not exist": "Leverantören: %s finns inte",
|
||||
"The provider: %s is not enabled for the application": "Leverantören: %s är inte aktiverad för applikationen",
|
||||
"Unauthorized operation": "Obehörig åtgärd",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Registrera dig med det användarnamn som motsvarar inbjudningskoden",
|
||||
"Session outdated, please login again": "Sessionen har gått ut, logga in igen",
|
||||
"The invitation code has already been used": "Inbjudningskoden har redan använts",
|
||||
"The password must contain at least one special character": "Lösenordet måste innehålla minst ett specialtecken",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Lösenordet måste innehålla minst en stor bokstav, en liten bokstav och en siffra",
|
||||
"The password must have at least 6 characters": "Lösenordet måste ha minst 6 tecken",
|
||||
"The password must have at least 8 characters": "Lösenordet måste ha minst 8 tecken",
|
||||
"The password must not contain any repeated characters": "Lösenordet får inte innehålla upprepade tecken",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Användaren har tagits bort och kan inte användas för att logga in, kontakta administratören",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Användaren är förbjuden att logga in, kontakta administratören",
|
||||
"The user: %s doesn't exist in LDAP server": "Användaren: %s finns inte i LDAP-servern",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Användarnamnet får endast innehålla alfanumeriska tecken, understreck eller bindestreck, får inte ha flera understreck eller bindestreck i följd, och får inte börja eller sluta med ett understreck eller bindestreck.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "denna åtgärd är inte tillåten i demoläge",
|
||||
"this operation requires administrator to perform": "denna åtgärd kräver administratör för att genomföras"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Inbjudan %s existerar inte"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP-servern finns redan"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA-e-post är aktiverat men e-post är tom",
|
||||
"MFA phone is enabled but phone number is empty": "MFA-telefon är aktiverat men telefonnummer är tomt",
|
||||
"New password cannot contain blank space.": "Nytt lösenord får inte innehålla mellanslag.",
|
||||
"The new password must be different from your current password": "Det nya lösenordet måste skilja sig från ditt nuvarande lösenord",
|
||||
"the user's owner and name should not be empty": "användarens ägare och namn får inte vara tomma"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "användaren finns inte, registrera dig först"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Inga autentiseringsuppgifter hittades för denna användare",
|
||||
"Please call WebAuthnSigninBegin first": "Anropa WebAuthnSigninBegin först"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Giriş yapılamadı: %s",
|
||||
"Invalid token": "Geçersiz token",
|
||||
"State expected: %s, but got: %s": "Beklenen durum: %s, fakat alınan: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Provider: %s ve kullanıcı adı: %s (%s) için hesap mevcut değil ve %%s ile yeni hesap açılmasına izin verilmiyor, lütfen başka yöntemle kaydolun",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Provider: %s ve kullanıcı adı: %s (%s) için hesap mevcut değil ve %s ile yeni hesap açılmasına izin verilmiyor, lütfen başka yöntemle kaydolun",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Provider: %s ve kullanıcı adı: %s (%s) için hesap mevcut değil ve yeni hesap açılmasına izin verilmiyor, lütfen BT destek ile iletişime geçin",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Provider: %s ve kullanıcı adı: %s (%s) zaten başka bir hesaba bağlı: %s (%s)",
|
||||
"The application: %s does not exist": "Uygulama: %s bulunamadı",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Uygulama: %s kullanıcıların oturum açmasını devre dışı bıraktı",
|
||||
"The group: %s does not exist": "Grup: %s mevcut değil",
|
||||
"The login method: login with LDAP is not enabled for the application": "Uygulama için LDAP ile giriş yöntemi etkin değil",
|
||||
"The login method: login with SMS is not enabled for the application": "Uygulama için SMS ile giriş yöntemi etkin değil",
|
||||
"The login method: login with email is not enabled for the application": "Uygulama için e-posta ile giriş yöntemi etkin değil",
|
||||
"The login method: login with face is not enabled for the application": "Uygulama için yüz ile giriş yöntemi etkin değil",
|
||||
"The login method: login with password is not enabled for the application": "Şifre ile giriş yöntemi bu uygulama için etkin değil",
|
||||
"The organization: %s does not exist": "Organizasyon: %s mevcut değil",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Organizasyon: %s kullanıcıların oturum açmasını devre dışı bıraktı",
|
||||
"The plan: %s does not exist": "Plan: %s mevcut değil",
|
||||
"The pricing: %s does not exist": "Fiyatlandırma: %s mevcut değil",
|
||||
"The pricing: %s does not have plan: %s": "Fiyatlandırma: %s planı yok: %s",
|
||||
"The provider: %s does not exist": "Sağlayıcı: %s mevcut değil",
|
||||
"The provider: %s is not enabled for the application": "Provider: %s bu uygulama için etkin değil",
|
||||
"Unauthorized operation": "Yetkisiz işlem",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Lütfen davet koduna karşılık gelen kullanıcı adıyla kayıt olun",
|
||||
"Session outdated, please login again": "Oturum süresi doldu, lütfen tekrar giriş yapın",
|
||||
"The invitation code has already been used": "Davet kodu zaten kullanılmış",
|
||||
"The password must contain at least one special character": "Şifre en az bir özel karakter içermelidir",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Şifre en az bir büyük harf, bir küçük harf ve bir rakam içermelidir",
|
||||
"The password must have at least 6 characters": "Şifre en az 6 karakter içermelidir",
|
||||
"The password must have at least 8 characters": "Şifre en az 8 karakter içermelidir",
|
||||
"The password must not contain any repeated characters": "Şifre tekrarlanan karakterler içermemelidir",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Kullanıcı silinmiş ve oturum açmak için kullanılamaz, lütfen yöneticiyle iletişime geçin",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Kullanıcı giriş yapmaktan men edildi, lütfen yönetici ile iletişime geçin",
|
||||
"The user: %s doesn't exist in LDAP server": "Kullanıcı: %s LDAP sunucusunda mevcut değil",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Kullanıcı adı yalnızca alfanümerik karakterler, alt çizgi veya tire içerebilir, ardışık tire veya alt çizgi içeremez ve tire veya alt çizgi ile başlayamaz veya bitemez.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "bu işlem demo modunda izin verilmiyor",
|
||||
"this operation requires administrator to perform": "bu işlem yönetici tarafından gerçekleştirilmelidir"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Davetiye %s mevcut değil"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP sunucusu zaten var"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA e-postası etkin ancak e-posta boş",
|
||||
"MFA phone is enabled but phone number is empty": "MFA telefonu etkin ancak telefon numarası boş",
|
||||
"New password cannot contain blank space.": "Yeni şifre boşluk içeremez.",
|
||||
"The new password must be different from your current password": "Yeni şifre mevcut şifrenizden farklı olmalıdır",
|
||||
"the user's owner and name should not be empty": "kullanıcının sahibi ve adı boş olmamalıdır"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "kullanıcı mevcut değil, lütfen önce kaydolun"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Bu kullanıcı için kimlik bilgisi bulunamadı",
|
||||
"Please call WebAuthnSigninBegin first": "Lütfen önce WebAuthnSigninBegin çağırın"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Не вдалося увійти: %s",
|
||||
"Invalid token": "Недійсний токен",
|
||||
"State expected: %s, but got: %s": "Очікувалося стан: %s, але отримано: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Обліковий запис для провайдера: %s та імені користувача: %s (%s) не існує і не дозволяється реєструвати як новий через %%s, використайте інший спосіб",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Обліковий запис для провайдера: %s та імені користувача: %s (%s) не існує і не дозволяється реєструвати як новий через %s, використайте інший спосіб",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Обліковий запис для провайдера: %s та імені користувача: %s (%s) не існує і не дозволяється реєструвати як новий, зверніться до IT-підтримки",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Обліковий запис для провайдера: %s та імені користувача: %s (%s) уже пов’язаний з іншим обліковим записом: %s (%s)",
|
||||
"The application: %s does not exist": "Додаток: %s не існує",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Додаток: %s вимкнув вхід користувачів",
|
||||
"The group: %s does not exist": "Група: %s не існує",
|
||||
"The login method: login with LDAP is not enabled for the application": "Метод входу через LDAP не увімкнено для цього додатка",
|
||||
"The login method: login with SMS is not enabled for the application": "Метод входу через SMS не увімкнено для цього додатка",
|
||||
"The login method: login with email is not enabled for the application": "Метод входу через email не увімкнено для цього додатка",
|
||||
"The login method: login with face is not enabled for the application": "Метод входу через обличчя не увімкнено для цього додатка",
|
||||
"The login method: login with password is not enabled for the application": "Метод входу через пароль не увімкнено для цього додатка",
|
||||
"The organization: %s does not exist": "Організація: %s не існує",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Організація: %s вимкнула вхід користувачів",
|
||||
"The plan: %s does not exist": "План: %s не існує",
|
||||
"The pricing: %s does not exist": "Тариф: %s не існує",
|
||||
"The pricing: %s does not have plan: %s": "Тариф: %s не має план: %s",
|
||||
"The provider: %s does not exist": "Провайдер: %s не існує",
|
||||
"The provider: %s is not enabled for the application": "Провайдер: %s не увімкнено для цього додатка",
|
||||
"Unauthorized operation": "Неавторизована операція",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Будь ласка, зареєструйтесь, використовуючи ім’я користувача, що відповідає коду запрошення",
|
||||
"Session outdated, please login again": "Сесію застаро, будь ласка, увійдіть знову",
|
||||
"The invitation code has already been used": "Код запрошення вже використано",
|
||||
"The password must contain at least one special character": "Пароль повинен містити принаймні один спеціальний символ",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Пароль повинен містити принаймні одну велику літеру, одну малу літеру та одну цифру",
|
||||
"The password must have at least 6 characters": "Пароль повинен містити принаймні 6 символів",
|
||||
"The password must have at least 8 characters": "Пароль повинен містити принаймні 8 символів",
|
||||
"The password must not contain any repeated characters": "Пароль не повинен містити повторюваних символів",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Користувача було видалено і не можна використовувати для входу, будь ласка, зверніться до адміністратора",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Користувачу заборонено вхід, зверніться до адміністратора",
|
||||
"The user: %s doesn't exist in LDAP server": "Користувач: %s не існує на сервері LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Ім’я користувача може містити лише буквено-цифрові символи, підкреслення або дефіси, не може мати послідовні дефіси або підкреслення та не може починатися або закінчуватися дефісом або підкресленням.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "ця операція недоступна в демо-режимі",
|
||||
"this operation requires administrator to perform": "ця операція потребує прав адміністратора"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Запрошення %s не існує"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Сервер LDAP існує"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA email увімкнено, але email порожній",
|
||||
"MFA phone is enabled but phone number is empty": "MFA телефон увімкнено, але номер телефону порожній",
|
||||
"New password cannot contain blank space.": "Новий пароль не може містити пробіли.",
|
||||
"The new password must be different from your current password": "Новий пароль повинен відрізнятися від поточного пароля",
|
||||
"the user's owner and name should not be empty": "власник ім’я користувача не повинні бути порожніми"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "користувача не існує, спочатку зареєструйтесь"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Облікові дані для цього користувача не знайдено",
|
||||
"Please call WebAuthnSigninBegin first": "Спочатку викличте WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,22 @@
|
||||
"Failed to login in: %s": "Đăng nhập không thành công: %s",
|
||||
"Invalid token": "Mã thông báo không hợp lệ",
|
||||
"State expected: %s, but got: %s": "Trạng thái dự kiến: %s, nhưng nhận được: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Tài khoản cho nhà cung cấp: %s và tên người dùng: %s (%s) không tồn tại và không được phép đăng ký làm tài khoản mới qua %%s, vui lòng sử dụng cách khác để đăng ký",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Tài khoản cho nhà cung cấp: %s và tên người dùng: %s (%s) không tồn tại và không được phép đăng ký làm tài khoản mới qua %s, vui lòng sử dụng cách khác để đăng ký",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Tài khoản cho nhà cung cấp: %s và tên người dùng: %s (%s) không tồn tại và không được phép đăng ký như một tài khoản mới, vui lòng liên hệ với bộ phận hỗ trợ công nghệ thông tin của bạn",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Tài khoản cho nhà cung cấp: %s và tên người dùng: %s (%s) đã được liên kết với tài khoản khác: %s (%s)",
|
||||
"The application: %s does not exist": "Ứng dụng: %s không tồn tại",
|
||||
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
|
||||
"The application: %s has disabled users to signin": "Ứng dụng: %s đã vô hiệu hóa đăng nhập của người dùng",
|
||||
"The group: %s does not exist": "Nhóm: %s không tồn tại",
|
||||
"The login method: login with LDAP is not enabled for the application": "Phương thức đăng nhập bằng LDAP chưa được bật cho ứng dụng",
|
||||
"The login method: login with SMS is not enabled for the application": "Phương thức đăng nhập bằng SMS chưa được bật cho ứng dụng",
|
||||
"The login method: login with email is not enabled for the application": "Phương thức đăng nhập bằng email chưa được bật cho ứng dụng",
|
||||
"The login method: login with face is not enabled for the application": "Phương thức đăng nhập bằng khuôn mặt chưa được bật cho ứng dụng",
|
||||
"The login method: login with password is not enabled for the application": "Phương thức đăng nhập: đăng nhập bằng mật khẩu không được kích hoạt cho ứng dụng",
|
||||
"The organization: %s does not exist": "Tổ chức: %s không tồn tại",
|
||||
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
|
||||
"The organization: %s has disabled users to signin": "Tổ chức: %s đã vô hiệu hóa đăng nhập của người dùng",
|
||||
"The plan: %s does not exist": "Kế hoạch: %s không tồn tại",
|
||||
"The pricing: %s does not exist": "Giá: %s không tồn tại",
|
||||
"The pricing: %s does not have plan: %s": "Giá: %s không có kế hoạch: %s",
|
||||
"The provider: %s does not exist": "Nhà cung cấp: %s không tồn tại",
|
||||
"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",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "Vui lòng đăng ký bằng tên người dùng tương ứng với mã mời",
|
||||
"Session outdated, please login again": "Phiên làm việc hết hạn, vui lòng đăng nhập lại",
|
||||
"The invitation code has already been used": "Mã mời đã được sử dụng",
|
||||
"The password must contain at least one special character": "Mật khẩu phải chứa ít nhất một ký tự đặc biệt",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Mật khẩu phải chứa ít nhất một chữ hoa, một chữ thường và một chữ số",
|
||||
"The password must have at least 6 characters": "Mật khẩu phải có ít nhất 6 ký tự",
|
||||
"The password must have at least 8 characters": "Mật khẩu phải có ít nhất 8 ký tự",
|
||||
"The password must not contain any repeated characters": "Mật khẩu không được chứa ký tự lặp lại",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Người dùng đã bị xóa và không thể được sử dụng để đăng nhập, vui lòng liên hệ với quản trị viên",
|
||||
"The user is forbidden to sign in, please contact the administrator": "Người dùng bị cấm đăng nhập, vui lòng liên hệ với quản trị viên",
|
||||
"The user: %s doesn't exist in LDAP server": "Người dùng: %s không tồn tại trên máy chủ LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Tên người dùng chỉ có thể chứa các ký tự chữ và số, gạch dưới hoặc gạch ngang, không được có hai ký tự gạch dưới hoặc gạch ngang liền kề và không được bắt đầu hoặc kết thúc bằng dấu gạch dưới hoặc gạch ngang.",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "thao tác này không được phép trong chế độ demo",
|
||||
"this operation requires administrator to perform": "thao tác này yêu cầu quản trị viên thực hiện"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "Lời mời %s không tồn tại"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Máy chủ LDAP tồn tại"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA email đã bật nhưng email trống",
|
||||
"MFA phone is enabled but phone number is empty": "MFA điện thoại đã bật nhưng số điện thoại trống",
|
||||
"New password cannot contain blank space.": "Mật khẩu mới không thể chứa dấu trắng.",
|
||||
"The new password must be different from your current password": "Mật khẩu mới phải khác với mật khẩu hiện tại của bạn",
|
||||
"the user's owner and name should not be empty": "chủ sở hữu và tên người dùng không được để trống"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "Người dùng không tồn tại, vui lòng đăng ký trước"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "Không tìm thấy thông tin xác thực cho người dùng này",
|
||||
"Please call WebAuthnSigninBegin first": "Vui lòng gọi WebAuthnSigninBegin trước"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,12 @@
|
||||
"Failed to login in: %s": "登录失败: %s",
|
||||
"Invalid token": "无效token",
|
||||
"State expected: %s, but got: %s": "期望状态为: %s, 实际状态为: %s",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许通过 %s 注册新账户, 请使用其他方式注册",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许通过 %s 注册新账户, 请使用其他方式注册",
|
||||
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许注册新账户, 请联系IT支持",
|
||||
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "提供商账户: %s与用户名: %s (%s)已经与其他账户绑定: %s (%s)",
|
||||
"The application: %s does not exist": "应用%s不存在",
|
||||
"The application: %s has disabled users to signin": "应用: %s 禁止用户登录",
|
||||
"The group: %s does not exist": "组: %s不存在",
|
||||
"The login method: login with LDAP is not enabled for the application": "该应用禁止采用LDAP登录方式",
|
||||
"The login method: login with SMS is not enabled for the application": "该应用禁止采用短信登录方式",
|
||||
"The login method: login with email is not enabled for the application": "该应用禁止采用邮箱登录方式",
|
||||
@@ -24,6 +25,9 @@
|
||||
"The login method: login with password is not enabled for the application": "该应用禁止采用密码登录方式",
|
||||
"The organization: %s does not exist": "组织: %s 不存在",
|
||||
"The organization: %s has disabled users to signin": "组织: %s 禁止用户登录",
|
||||
"The plan: %s does not exist": "计划: %s不存在",
|
||||
"The pricing: %s does not exist": "定价: %s不存在",
|
||||
"The pricing: %s does not have plan: %s": "定价: %s没有计划: %s",
|
||||
"The provider: %s does not exist": "提供商: %s 不存在",
|
||||
"The provider: %s is not enabled for the application": "该应用的提供商: %s未被启用",
|
||||
"Unauthorized operation": "未授权的操作",
|
||||
@@ -70,6 +74,12 @@
|
||||
"Please register using the username corresponding to the invitation code": "请使用邀请码关联的用户名注册",
|
||||
"Session outdated, please login again": "会话已过期,请重新登录",
|
||||
"The invitation code has already been used": "邀请码已被使用",
|
||||
"The password must contain at least one special character": "密码必须包含至少一个特殊字符",
|
||||
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "密码必须包含至少一个大写字母、一个小写字母和一个数字",
|
||||
"The password must have at least 6 characters": "密码必须至少包含6个字符",
|
||||
"The password must have at least 8 characters": "密码必须至少包含8个字符",
|
||||
"The password must not contain any repeated characters": "密码不能包含任何重复字符",
|
||||
"The user has been deleted and cannot be used to sign in, please contact the administrator": "该用户已被删除, 无法用于登录, 请联系管理员",
|
||||
"The user is forbidden to sign in, please contact the administrator": "该用户被禁止登录,请联系管理员",
|
||||
"The user: %s doesn't exist in LDAP server": "用户: %s 在LDAP服务器中未找到",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "用户名只能包含字母数字字符、下划线或连字符,不能有连续的连字符或下划线,也不能以连字符或下划线开头或结尾",
|
||||
@@ -106,6 +116,9 @@
|
||||
"this operation is not allowed in demo mode": "demo模式下不允许该操作",
|
||||
"this operation requires administrator to perform": "只有管理员才能进行此操作"
|
||||
},
|
||||
"invitation": {
|
||||
"Invitation %s does not exist": "邀请%s不存在"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP服务器已存在"
|
||||
},
|
||||
@@ -164,6 +177,7 @@
|
||||
"MFA email is enabled but email is empty": "MFA 电子邮件已启用,但电子邮件为空",
|
||||
"MFA phone is enabled but phone number is empty": "MFA 电话已启用,但电话号码为空",
|
||||
"New password cannot contain blank space.": "新密码不可以包含空格",
|
||||
"The new password must be different from your current password": "新密码必须与您当前的密码不同",
|
||||
"the user's owner and name should not be empty": "用户的组织和名称不能为空"
|
||||
},
|
||||
"util": {
|
||||
@@ -187,7 +201,7 @@
|
||||
"the user does not exist, please sign up first": "用户不存在,请先注册"
|
||||
},
|
||||
"webauthn": {
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Found no credentials for this user": "无法找到此用户的证书",
|
||||
"Please call WebAuthnSigninBegin first": "请先调用WebAuthnSigninBegin函数"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,11 +116,40 @@ func (p *AzureADB2CProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// First unmarshal into a map to capture all claims
|
||||
var rawClaims map[string]interface{}
|
||||
err = json.Unmarshal(bodyBytes, &rawClaims)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var userInfo UserInfo
|
||||
err = json.Unmarshal(bodyBytes, &userInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Convert raw claims to string map for Extra field
|
||||
extra := make(map[string]string)
|
||||
for k, v := range rawClaims {
|
||||
if v != nil {
|
||||
// Convert to string representation
|
||||
switch val := v.(type) {
|
||||
case string:
|
||||
extra[k] = val
|
||||
case float64:
|
||||
extra[k] = fmt.Sprintf("%v", val)
|
||||
case bool:
|
||||
extra[k] = fmt.Sprintf("%v", val)
|
||||
default:
|
||||
// For complex types, marshal to JSON string
|
||||
if jsonVal, err := json.Marshal(val); err == nil {
|
||||
extra[k] = string(jsonVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
userInfo.Extra = extra
|
||||
|
||||
return &userInfo, nil
|
||||
}
|
||||
|
||||
@@ -157,6 +157,10 @@ func (idp *DingTalkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dtUserInfo.OpenId == "" || dtUserInfo.UnionId == "" {
|
||||
return nil, fmt.Errorf(string(data))
|
||||
}
|
||||
|
||||
countryCode, err := util.GetCountryCode(dtUserInfo.StateCode, dtUserInfo.Mobile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
36
idp/goth.go
36
idp/goth.go
@@ -15,6 +15,7 @@
|
||||
package idp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -484,6 +485,41 @@ func getUser(gothUser goth.User, provider string) *UserInfo {
|
||||
Email: gothUser.Email,
|
||||
AvatarUrl: gothUser.AvatarURL,
|
||||
}
|
||||
|
||||
// Capture additional fields in Extra
|
||||
extra := make(map[string]string)
|
||||
if gothUser.FirstName != "" {
|
||||
extra["firstName"] = gothUser.FirstName
|
||||
}
|
||||
if gothUser.LastName != "" {
|
||||
extra["lastName"] = gothUser.LastName
|
||||
}
|
||||
if gothUser.Location != "" {
|
||||
extra["location"] = gothUser.Location
|
||||
}
|
||||
if gothUser.Description != "" {
|
||||
extra["description"] = gothUser.Description
|
||||
}
|
||||
// Add all raw data from the provider
|
||||
for k, v := range gothUser.RawData {
|
||||
if v != nil {
|
||||
switch val := v.(type) {
|
||||
case string:
|
||||
extra[k] = val
|
||||
case float64:
|
||||
extra[k] = fmt.Sprintf("%v", val)
|
||||
case bool:
|
||||
extra[k] = fmt.Sprintf("%v", val)
|
||||
default:
|
||||
// For complex types, marshal to JSON string
|
||||
if jsonVal, err := json.Marshal(val); err == nil {
|
||||
extra[k] = string(jsonVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
user.Extra = extra
|
||||
|
||||
// Some idp return an empty Name
|
||||
// so construct the Name with firstname and lastname or nickname
|
||||
if user.Username == "" {
|
||||
|
||||
26
idp/lark.go
26
idp/lark.go
@@ -83,8 +83,6 @@ type LarkAccessToken struct {
|
||||
Expire int `json:"expire"`
|
||||
}
|
||||
|
||||
// GetToken use code get access_token (*operation of getting code ought to be done in front)
|
||||
// get more detail via: https://docs.microsoft.com/en-us/linkedIn/shared/authentication/authorization-code-flow?context=linkedIn%2Fcontext&tabs=HTTPS
|
||||
func (idp *LarkIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
params := &struct {
|
||||
AppID string `json:"app_id"`
|
||||
@@ -135,6 +133,7 @@ func (idp *LarkIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
"open_id": "ou-caecc734c2e3328a62489fe0648c4b98779515d3",
|
||||
"union_id": "on-d89jhsdhjsajkda7828enjdj328ydhhw3u43yjhdj",
|
||||
"email": "zhangsan@feishu.cn",
|
||||
"enterprise_email": "zhangsan@company.com",
|
||||
"user_id": "5d9bdxxx",
|
||||
"mobile": "+86130002883xx",
|
||||
"tenant_key": "736588c92lxf175d",
|
||||
@@ -160,6 +159,7 @@ type LarkUserInfo struct {
|
||||
OpenId string `json:"open_id"`
|
||||
UnionId string `json:"union_id"`
|
||||
Email string `json:"email"`
|
||||
EnterpriseEmail string `json:"enterprise_email"`
|
||||
UserId string `json:"user_id"`
|
||||
Mobile string `json:"mobile"`
|
||||
TenantKey string `json:"tenant_key"`
|
||||
@@ -168,9 +168,6 @@ type LarkUserInfo struct {
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// GetUserInfo use LarkAccessToken gotten before return LinkedInUserInf
|
||||
// GetUserInfo use LarkAccessToken gotten before return LinkedInUserInfo
|
||||
// get more detail via: https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin?context=linkedin/consumer/context
|
||||
func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
body := &struct {
|
||||
GrantType string `json:"grant_type"`
|
||||
@@ -207,6 +204,21 @@ func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Use enterprise_email as fallback when email is empty
|
||||
email := larkUserInfo.Data.Email
|
||||
if email == "" {
|
||||
email = larkUserInfo.Data.EnterpriseEmail
|
||||
}
|
||||
|
||||
// Use fallback mechanism for username: UserId -> UnionId -> OpenId
|
||||
username := larkUserInfo.Data.UserId
|
||||
if username == "" {
|
||||
username = larkUserInfo.Data.UnionId
|
||||
}
|
||||
if username == "" {
|
||||
username = larkUserInfo.Data.OpenId
|
||||
}
|
||||
|
||||
var phoneNumber string
|
||||
var countryCode string
|
||||
if len(larkUserInfo.Data.Mobile) != 0 {
|
||||
@@ -221,8 +233,8 @@ func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
userInfo := UserInfo{
|
||||
Id: larkUserInfo.Data.OpenId,
|
||||
DisplayName: larkUserInfo.Data.Name,
|
||||
Username: larkUserInfo.Data.UserId,
|
||||
Email: larkUserInfo.Data.Email,
|
||||
Username: username,
|
||||
Email: email,
|
||||
AvatarUrl: larkUserInfo.Data.AvatarUrl,
|
||||
Phone: phoneNumber,
|
||||
CountryCode: countryCode,
|
||||
|
||||
29
idp/okta.go
29
idp/okta.go
@@ -183,18 +183,47 @@ func (idp *OktaIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// First unmarshal into a map to capture all claims
|
||||
var rawClaims map[string]interface{}
|
||||
err = json.Unmarshal(body, &rawClaims)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var oktaUserInfo OktaUserInfo
|
||||
err = json.Unmarshal(body, &oktaUserInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Convert raw claims to string map for Extra field
|
||||
extra := make(map[string]string)
|
||||
for k, v := range rawClaims {
|
||||
if v != nil {
|
||||
// Convert to string representation
|
||||
switch val := v.(type) {
|
||||
case string:
|
||||
extra[k] = val
|
||||
case float64:
|
||||
extra[k] = fmt.Sprintf("%v", val)
|
||||
case bool:
|
||||
extra[k] = fmt.Sprintf("%v", val)
|
||||
default:
|
||||
// For complex types, marshal to JSON string
|
||||
if jsonVal, err := json.Marshal(val); err == nil {
|
||||
extra[k] = string(jsonVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
userInfo := UserInfo{
|
||||
Id: oktaUserInfo.Sub,
|
||||
Username: oktaUserInfo.PreferredUsername,
|
||||
DisplayName: oktaUserInfo.Name,
|
||||
Email: oktaUserInfo.Email,
|
||||
AvatarUrl: oktaUserInfo.Picture,
|
||||
Extra: extra,
|
||||
}
|
||||
return &userInfo, nil
|
||||
}
|
||||
|
||||
@@ -67,7 +67,12 @@ func GetIdProvider(idpInfo *ProviderInfo, redirectUrl string) (IdProvider, error
|
||||
case "QQ":
|
||||
return NewQqIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil
|
||||
case "WeChat":
|
||||
return NewWeChatIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil
|
||||
if idpInfo.SubType == "Mobile" {
|
||||
return NewWeChatMobileIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil
|
||||
} else {
|
||||
// Default to Web (PC QR code login) for backward compatibility
|
||||
return NewWeChatIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil
|
||||
}
|
||||
case "Facebook":
|
||||
return NewFacebookIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil
|
||||
case "DingTalk":
|
||||
@@ -128,6 +133,9 @@ func GetIdProvider(idpInfo *ProviderInfo, redirectUrl string) (IdProvider, error
|
||||
if isGothSupport(idpInfo.Type) {
|
||||
return NewGothIdProvider(idpInfo.Type, idpInfo.ClientId, idpInfo.ClientSecret, idpInfo.ClientId2, idpInfo.ClientSecret2, redirectUrl, idpInfo.HostUrl)
|
||||
}
|
||||
if strings.HasPrefix(idpInfo.Type, "Custom") {
|
||||
return NewCustomIdProvider(idpInfo, redirectUrl), nil
|
||||
}
|
||||
return nil, fmt.Errorf("OAuth provider type: %s is not supported", idpInfo.Type)
|
||||
}
|
||||
}
|
||||
|
||||
169
idp/wechat_mobile.go
Normal file
169
idp/wechat_mobile.go
Normal file
@@ -0,0 +1,169 @@
|
||||
// Copyright 2025 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 (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// WeChatMobileIdProvider is for WeChat OAuth Mobile (in-app browser) login
|
||||
// This uses snsapi_userinfo scope for mobile authorization
|
||||
type WeChatMobileIdProvider struct {
|
||||
Client *http.Client
|
||||
Config *oauth2.Config
|
||||
}
|
||||
|
||||
func NewWeChatMobileIdProvider(clientId string, clientSecret string, redirectUrl string) *WeChatMobileIdProvider {
|
||||
idp := &WeChatMobileIdProvider{}
|
||||
|
||||
config := idp.getConfig(clientId, clientSecret, redirectUrl)
|
||||
idp.Config = config
|
||||
|
||||
return idp
|
||||
}
|
||||
|
||||
func (idp *WeChatMobileIdProvider) SetHttpClient(client *http.Client) {
|
||||
idp.Client = client
|
||||
}
|
||||
|
||||
// getConfig returns OAuth2 config for WeChat Mobile
|
||||
func (idp *WeChatMobileIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
endpoint := oauth2.Endpoint{
|
||||
AuthURL: "https://open.weixin.qq.com/connect/oauth2/authorize",
|
||||
TokenURL: "https://api.weixin.qq.com/sns/oauth2/access_token",
|
||||
}
|
||||
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"snsapi_userinfo"},
|
||||
Endpoint: endpoint,
|
||||
ClientID: clientId,
|
||||
ClientSecret: clientSecret,
|
||||
RedirectURL: redirectUrl,
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// GetToken exchanges authorization code for access token
|
||||
func (idp *WeChatMobileIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
params := url.Values{}
|
||||
params.Add("grant_type", "authorization_code")
|
||||
params.Add("appid", idp.Config.ClientID)
|
||||
params.Add("secret", idp.Config.ClientSecret)
|
||||
params.Add("code", code)
|
||||
|
||||
accessTokenUrl := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?%s", params.Encode())
|
||||
tokenResponse, err := idp.Client.Get(accessTokenUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}(tokenResponse.Body)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
_, err = buf.ReadFrom(tokenResponse.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check for error response
|
||||
if bytes.Contains(buf.Bytes(), []byte("errcode")) {
|
||||
return nil, fmt.Errorf(buf.String())
|
||||
}
|
||||
|
||||
var wechatAccessToken WechatAccessToken
|
||||
if err = json.Unmarshal(buf.Bytes(), &wechatAccessToken); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
token := oauth2.Token{
|
||||
AccessToken: wechatAccessToken.AccessToken,
|
||||
TokenType: "WeChatAccessToken",
|
||||
RefreshToken: wechatAccessToken.RefreshToken,
|
||||
Expiry: time.Time{},
|
||||
}
|
||||
|
||||
raw := make(map[string]string)
|
||||
raw["Openid"] = wechatAccessToken.Openid
|
||||
token.WithExtra(raw)
|
||||
|
||||
return &token, nil
|
||||
}
|
||||
|
||||
// GetUserInfo retrieves user information using the access token
|
||||
func (idp *WeChatMobileIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
var wechatUserInfo WechatUserInfo
|
||||
accessToken := token.AccessToken
|
||||
openid := token.Extra("Openid")
|
||||
|
||||
userInfoUrl := fmt.Sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN", accessToken, openid)
|
||||
resp, err := idp.Client.Get(userInfoUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}(resp.Body)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
_, err = buf.ReadFrom(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(buf.Bytes(), &wechatUserInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check for error response
|
||||
if wechatUserInfo.Openid == "" {
|
||||
return nil, fmt.Errorf("failed to get user info: %s", buf.String())
|
||||
}
|
||||
|
||||
id := wechatUserInfo.Unionid
|
||||
if id == "" {
|
||||
id = wechatUserInfo.Openid
|
||||
}
|
||||
|
||||
extra := make(map[string]string)
|
||||
extra["wechat_unionid"] = wechatUserInfo.Openid
|
||||
// For WeChat, different appId corresponds to different openId
|
||||
extra[BuildWechatOpenIdKey(idp.Config.ClientID)] = wechatUserInfo.Openid
|
||||
userInfo := UserInfo{
|
||||
Id: id,
|
||||
Username: wechatUserInfo.Nickname,
|
||||
DisplayName: wechatUserInfo.Nickname,
|
||||
AvatarUrl: wechatUserInfo.Headimgurl,
|
||||
Extra: extra,
|
||||
}
|
||||
return &userInfo, nil
|
||||
}
|
||||
@@ -212,6 +212,10 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
|
||||
e.AddAttribute("homeDirectory", message.AttributeValue("/home/"+user.Name))
|
||||
e.AddAttribute("cn", message.AttributeValue(user.Name))
|
||||
e.AddAttribute("uid", message.AttributeValue(user.Id))
|
||||
e.AddAttribute("mail", message.AttributeValue(user.Email))
|
||||
e.AddAttribute("mobile", message.AttributeValue(user.Phone))
|
||||
e.AddAttribute("sn", message.AttributeValue(user.LastName))
|
||||
e.AddAttribute("givenName", message.AttributeValue(user.FirstName))
|
||||
for _, group := range user.Groups {
|
||||
e.AddAttribute(ldapMemberOfAttr, message.AttributeValue(group))
|
||||
}
|
||||
|
||||
@@ -70,6 +70,12 @@ var ldapAttributesMapping = map[string]FieldRelation{
|
||||
"title": {userField: "tag", fieldMapper: func(user *object.User) message.AttributeValue {
|
||||
return message.AttributeValue(user.Tag)
|
||||
}},
|
||||
"c": {userField: "region", fieldMapper: func(user *object.User) message.AttributeValue {
|
||||
return message.AttributeValue(user.Region)
|
||||
}},
|
||||
"co": {userField: "region", fieldMapper: func(user *object.User) message.AttributeValue {
|
||||
return message.AttributeValue(user.Region)
|
||||
}},
|
||||
"userPassword": {
|
||||
userField: "userPassword",
|
||||
notSearchable: true,
|
||||
|
||||
@@ -30,6 +30,8 @@ func TestLdapFilterAsQuery(t *testing.T) {
|
||||
{"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")},
|
||||
{"Should be SQL for country attribute c", "(c=US)", "region=?", args("US")},
|
||||
{"Should be SQL for country attribute co", "(co=United States)", "region=?", args("United States")},
|
||||
}
|
||||
|
||||
for _, scenery := range scenarios {
|
||||
|
||||
12
main.go
12
main.go
@@ -38,6 +38,18 @@ func main() {
|
||||
object.CreateTables()
|
||||
|
||||
object.InitDb()
|
||||
|
||||
// Handle export command
|
||||
if object.ShouldExportData() {
|
||||
exportPath := object.GetExportFilePath()
|
||||
err := object.DumpToFile(exportPath)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error exporting data to %s: %v", exportPath, err))
|
||||
}
|
||||
fmt.Printf("Data exported successfully to %s\n", exportPath)
|
||||
return
|
||||
}
|
||||
|
||||
object.InitDefaultStorageProvider()
|
||||
object.InitLdapAutoSynchronizer()
|
||||
proxy.InitHttpClient()
|
||||
|
||||
@@ -55,6 +55,8 @@ func GetNotificationProvider(typ string, clientId string, clientSecret string, c
|
||||
return NewViberProvider(clientId, clientSecret, appId, receiver)
|
||||
} else if typ == "CUCloud" {
|
||||
return NewCucloudProvider(clientId, clientSecret, appId, title, regionId, clientId2, metaData)
|
||||
} else if typ == "WeCom" {
|
||||
return NewWeComProvider(clientSecret)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
||||
104
notification/wecom.go
Normal file
104
notification/wecom.go
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright 2025 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 notification
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/notify"
|
||||
)
|
||||
|
||||
// wecomService encapsulates the WeCom webhook client
|
||||
type wecomService struct {
|
||||
webhookURL string
|
||||
}
|
||||
|
||||
// wecomResponse represents the response from WeCom webhook API
|
||||
type wecomResponse struct {
|
||||
Errcode int `json:"errcode"`
|
||||
Errmsg string `json:"errmsg"`
|
||||
}
|
||||
|
||||
// NewWeComProvider returns a new instance of a WeCom notification service
|
||||
// WeCom (WeChat Work) uses webhook for group chat notifications
|
||||
// Reference: https://developer.work.weixin.qq.com/document/path/90236
|
||||
func NewWeComProvider(webhookURL string) (notify.Notifier, error) {
|
||||
wecomSrv := &wecomService{
|
||||
webhookURL: webhookURL,
|
||||
}
|
||||
|
||||
notifier := notify.New()
|
||||
notifier.UseServices(wecomSrv)
|
||||
|
||||
return notifier, nil
|
||||
}
|
||||
|
||||
// Send sends a text message to WeCom group chat via webhook
|
||||
func (s *wecomService) Send(ctx context.Context, subject, content string) error {
|
||||
text := subject
|
||||
if content != "" {
|
||||
text = subject + "\n" + content
|
||||
}
|
||||
|
||||
// WeCom webhook message format
|
||||
message := map[string]interface{}{
|
||||
"msgtype": "text",
|
||||
"text": map[string]string{
|
||||
"content": text,
|
||||
},
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal WeCom message: %w", err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", s.webhookURL, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create WeCom request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send WeCom message: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("WeCom webhook returned HTTP status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Parse WeCom API response
|
||||
var wecomResp wecomResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&wecomResp); err != nil {
|
||||
return fmt.Errorf("failed to decode WeCom response: %w", err)
|
||||
}
|
||||
|
||||
// Check WeCom API error code
|
||||
if wecomResp.Errcode != 0 {
|
||||
return fmt.Errorf("WeCom API error: errcode=%d, errmsg=%s", wecomResp.Errcode, wecomResp.Errmsg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -88,12 +88,18 @@ func getAdapter(owner, name string) (*Adapter, error) {
|
||||
}
|
||||
|
||||
func GetAdapter(id string) (*Adapter, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getAdapter(owner, name)
|
||||
}
|
||||
|
||||
func UpdateAdapter(id string, adapter *Adapter) (bool, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if adapter, err := getAdapter(owner, name); adapter == nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -60,6 +60,11 @@ type SamlItem struct {
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type JwtItem struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type Application struct {
|
||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
@@ -67,6 +72,9 @@ type Application struct {
|
||||
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
Logo string `xorm:"varchar(200)" json:"logo"`
|
||||
Title string `xorm:"varchar(100)" json:"title"`
|
||||
Favicon string `xorm:"varchar(200)" json:"favicon"`
|
||||
Order int `json:"order"`
|
||||
HomepageUrl string `xorm:"varchar(100)" json:"homepageUrl"`
|
||||
Description string `xorm:"varchar(100)" json:"description"`
|
||||
Organization string `xorm:"varchar(100)" json:"organization"`
|
||||
@@ -79,6 +87,7 @@ type Application struct {
|
||||
EnableSigninSession bool `json:"enableSigninSession"`
|
||||
EnableAutoSignin bool `json:"enableAutoSignin"`
|
||||
EnableCodeSignin bool `json:"enableCodeSignin"`
|
||||
EnableExclusiveSignin bool `json:"enableExclusiveSignin"`
|
||||
EnableSamlCompress bool `json:"enableSamlCompress"`
|
||||
EnableSamlC14n10 bool `json:"enableSamlC14n10"`
|
||||
EnableSamlPostBinding bool `json:"enableSamlPostBinding"`
|
||||
@@ -96,6 +105,7 @@ type Application struct {
|
||||
CertPublicKey string `xorm:"-" json:"certPublicKey"`
|
||||
Tags []string `xorm:"mediumtext" json:"tags"`
|
||||
SamlAttributes []*SamlItem `xorm:"varchar(1000)" json:"samlAttributes"`
|
||||
SamlHashAlgorithm string `xorm:"varchar(20)" json:"samlHashAlgorithm"`
|
||||
IsShared bool `json:"isShared"`
|
||||
IpRestriction string `json:"ipRestriction"`
|
||||
|
||||
@@ -106,8 +116,9 @@ type Application struct {
|
||||
TokenFormat string `xorm:"varchar(100)" json:"tokenFormat"`
|
||||
TokenSigningMethod string `xorm:"varchar(100)" json:"tokenSigningMethod"`
|
||||
TokenFields []string `xorm:"varchar(1000)" json:"tokenFields"`
|
||||
ExpireInHours int `json:"expireInHours"`
|
||||
RefreshExpireInHours int `json:"refreshExpireInHours"`
|
||||
TokenAttributes []*JwtItem `xorm:"mediumtext" json:"tokenAttributes"`
|
||||
ExpireInHours float64 `json:"expireInHours"`
|
||||
RefreshExpireInHours float64 `json:"refreshExpireInHours"`
|
||||
SignupUrl string `xorm:"varchar(200)" json:"signupUrl"`
|
||||
SigninUrl string `xorm:"varchar(200)" json:"signinUrl"`
|
||||
ForgetUrl string `xorm:"varchar(200)" json:"forgetUrl"`
|
||||
@@ -127,6 +138,7 @@ type Application struct {
|
||||
|
||||
FailedSigninLimit int `json:"failedSigninLimit"`
|
||||
FailedSigninFrozenTime int `json:"failedSigninFrozenTime"`
|
||||
CodeResendTimeout int `json:"codeResendTimeout"`
|
||||
}
|
||||
|
||||
func GetApplicationCount(owner, field, value string) (int64, error) {
|
||||
@@ -266,6 +278,14 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
signinItem = &SigninItem{
|
||||
Name: "Verification code",
|
||||
Visible: true,
|
||||
CustomCss: ".verification-code {}\n.verification-code-input{}",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
signinItem = &SigninItem{
|
||||
Name: "Agreement",
|
||||
Visible: true,
|
||||
@@ -429,7 +449,10 @@ func GetApplicationByUser(user *User) (*Application, error) {
|
||||
}
|
||||
|
||||
func GetApplicationByUserId(userId string) (application *Application, err error) {
|
||||
_, name := util.GetOwnerAndNameFromId(userId)
|
||||
_, name, err := util.GetOwnerAndNameFromIdWithError(userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if IsAppUser(userId) {
|
||||
application, err = getApplication("admin", name)
|
||||
return
|
||||
@@ -550,7 +573,6 @@ func GetMaskedApplication(application *Application, userId string) *Application
|
||||
application.Providers = providerItems
|
||||
|
||||
application.GrantTypes = nil
|
||||
application.Tags = nil
|
||||
application.RedirectUris = nil
|
||||
application.TokenFormat = "***"
|
||||
application.TokenFields = nil
|
||||
@@ -626,13 +648,20 @@ func GetAllowedApplications(applications []*Application, userId string, lang str
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func UpdateApplication(id string, application *Application) (bool, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
func UpdateApplication(id string, application *Application, isGlobalAdmin bool, lang string) (bool, error) {
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
oldApplication, err := getApplication(owner, name)
|
||||
if oldApplication == nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !isGlobalAdmin && oldApplication.Organization != application.Organization {
|
||||
return false, fmt.Errorf(i18n.Translate(lang, "auth:Unauthorized operation"))
|
||||
}
|
||||
|
||||
if name == "app-built-in" {
|
||||
application.Name = name
|
||||
}
|
||||
@@ -709,7 +738,7 @@ func AddApplication(application *Application) (bool, error) {
|
||||
}
|
||||
|
||||
func deleteApplication(application *Application) (bool, error) {
|
||||
affected, err := ormer.Engine.ID(core.PK{application.Owner, application.Name}).Delete(&Application{})
|
||||
affected, err := ormer.Engine.ID(core.PK{application.Owner, application.Name}).Where("organization = ?", application.Organization).Delete(&Application{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -149,7 +149,10 @@ func getCertByName(name string) (*Cert, error) {
|
||||
}
|
||||
|
||||
func GetCert(id string) (*Cert, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cert, err := getCert(owner, name)
|
||||
if cert == nil && owner != "admin" {
|
||||
return getCert("admin", name)
|
||||
@@ -159,7 +162,10 @@ func GetCert(id string) (*Cert, error) {
|
||||
}
|
||||
|
||||
func UpdateCert(id string, cert *Cert) (bool, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if c, err := getCert(owner, name); err != nil {
|
||||
return false, err
|
||||
} else if c == nil {
|
||||
@@ -167,13 +173,13 @@ func UpdateCert(id string, cert *Cert) (bool, error) {
|
||||
}
|
||||
|
||||
if name != cert.Name {
|
||||
err := certChangeTrigger(name, cert.Name)
|
||||
err = certChangeTrigger(name, cert.Name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
err := cert.populateContent()
|
||||
err = cert.populateContent()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
198
object/check.go
198
object/check.go
@@ -59,8 +59,11 @@ func CheckUserSignup(application *Application, organization *Organization, authF
|
||||
if HasUserByField(organization.Name, "name", authForm.Username) {
|
||||
return i18n.Translate(lang, "check:Username already exists")
|
||||
}
|
||||
if HasUserByField(organization.Name, "email", authForm.Email) {
|
||||
return i18n.Translate(lang, "check:Email already exists")
|
||||
if authForm.Email != "" {
|
||||
normalizedEmail := strings.ToLower(authForm.Email)
|
||||
if HasUserByField(organization.Name, "email", normalizedEmail) {
|
||||
return i18n.Translate(lang, "check:Email already exists")
|
||||
}
|
||||
}
|
||||
if HasUserByField(organization.Name, "phone", authForm.Phone) {
|
||||
return i18n.Translate(lang, "check:Phone already exists")
|
||||
@@ -68,7 +71,7 @@ func CheckUserSignup(application *Application, organization *Organization, authF
|
||||
}
|
||||
|
||||
if application.IsSignupItemVisible("Password") {
|
||||
msg := CheckPasswordComplexityByOrg(organization, authForm.Password)
|
||||
msg := CheckPasswordComplexityByOrg(organization, authForm.Password, lang)
|
||||
if msg != "" {
|
||||
return msg
|
||||
}
|
||||
@@ -80,7 +83,8 @@ func CheckUserSignup(application *Application, organization *Organization, authF
|
||||
return i18n.Translate(lang, "check:Email cannot be empty")
|
||||
}
|
||||
} else {
|
||||
if HasUserByField(organization.Name, "email", authForm.Email) {
|
||||
normalizedEmail := strings.ToLower(authForm.Email)
|
||||
if HasUserByField(organization.Name, "email", normalizedEmail) {
|
||||
return i18n.Translate(lang, "check:Email already exists")
|
||||
} else if !util.IsEmailValid(authForm.Email) {
|
||||
return i18n.Translate(lang, "check:Email is invalid")
|
||||
@@ -278,14 +282,14 @@ func CheckPassword(user *User, password string, lang string, options ...bool) er
|
||||
return resetUserSigninErrorTimes(user)
|
||||
}
|
||||
|
||||
func CheckPasswordComplexityByOrg(organization *Organization, password string) string {
|
||||
errorMsg := checkPasswordComplexity(password, organization.PasswordOptions)
|
||||
func CheckPasswordComplexityByOrg(organization *Organization, password string, lang string) string {
|
||||
errorMsg := checkPasswordComplexity(password, organization.PasswordOptions, lang)
|
||||
return errorMsg
|
||||
}
|
||||
|
||||
func CheckPasswordComplexity(user *User, password string) string {
|
||||
func CheckPasswordComplexity(user *User, password string, lang string) string {
|
||||
organization, _ := GetOrganizationByUser(user)
|
||||
return CheckPasswordComplexityByOrg(organization, password)
|
||||
return CheckPasswordComplexityByOrg(organization, password, lang)
|
||||
}
|
||||
|
||||
func CheckLdapUserPassword(user *User, password string, lang string) error {
|
||||
@@ -363,6 +367,11 @@ func CheckUserPassword(organization string, username string, password string, la
|
||||
return nil, fmt.Errorf(i18n.Translate(lang, "check:The user is forbidden to sign in, please contact the administrator"))
|
||||
}
|
||||
|
||||
// Prevent direct login for guest users without upgrading
|
||||
if user.Tag == "guest-user" {
|
||||
return nil, fmt.Errorf(i18n.Translate(lang, "check:Guest users must upgrade their account by setting a username and password before they can sign in directly"))
|
||||
}
|
||||
|
||||
if isSigninViaLdap {
|
||||
if user.Ldap == "" {
|
||||
return nil, fmt.Errorf(i18n.Translate(lang, "check:The user: %s doesn't exist in LDAP server"), username)
|
||||
@@ -458,8 +467,116 @@ func CheckUserPermission(requestUserId, userId string, strict bool, lang string)
|
||||
return hasPermission, fmt.Errorf(i18n.Translate(lang, "auth:Unauthorized operation"))
|
||||
}
|
||||
|
||||
func CheckApiPermission(userId string, organization string, path string, method string) (bool, error) {
|
||||
permissions, err := GetPermissions(organization)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
path = strings.TrimPrefix(path, "/api/")
|
||||
|
||||
allowPermissionCount := 0
|
||||
denyPermissionCount := 0
|
||||
allowCount := 0
|
||||
denyCount := 0
|
||||
for _, permission := range permissions {
|
||||
if !permission.IsEnabled || permission.State != "Approved" || permission.ResourceType != "API" || !permission.isResourceHit(path) {
|
||||
continue
|
||||
}
|
||||
|
||||
userHit := permission.isUserHit(userId)
|
||||
roleHit := permission.isRoleHit(userId)
|
||||
|
||||
if !userHit && !roleHit {
|
||||
if permission.Effect == "Allow" {
|
||||
allowPermissionCount += 1
|
||||
} else {
|
||||
denyPermissionCount += 1
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
enforcer, err := getPermissionEnforcer(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var isAllowed bool
|
||||
|
||||
if userHit {
|
||||
isAllowed, err = enforcer.Enforce(userId, path, method)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if isAllowed {
|
||||
if permission.Effect == "Allow" {
|
||||
allowCount += 1
|
||||
}
|
||||
} else {
|
||||
if permission.Effect == "Deny" {
|
||||
denyCount += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if roleHit {
|
||||
targetRoles, err := getRolesByUser(userId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var checkRoleList []*Role
|
||||
|
||||
for _, role := range permission.Roles {
|
||||
if role == "*" {
|
||||
checkRoleList = targetRoles
|
||||
break
|
||||
}
|
||||
|
||||
for _, targetRole := range targetRoles {
|
||||
if role == targetRole.GetId() {
|
||||
checkRoleList = append(checkRoleList, targetRole)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, role := range checkRoleList {
|
||||
isAllowed, err = enforcer.Enforce(role.GetId(), path, method)
|
||||
|
||||
if isAllowed {
|
||||
if permission.Effect == "Allow" {
|
||||
allowCount += 1
|
||||
}
|
||||
} else {
|
||||
if permission.Effect == "Deny" {
|
||||
denyCount += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deny-override, if one deny is found, then deny
|
||||
if denyCount > 0 {
|
||||
return false, nil
|
||||
} else if allowCount > 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// For no-allow and no-deny condition
|
||||
// If only allow permissions exist, we suppose it's Deny-by-default, aka no-allow means deny
|
||||
// Otherwise, it's Allow-by-default, aka no-deny means allow
|
||||
if allowPermissionCount > 0 && denyPermissionCount == 0 {
|
||||
return false, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func CheckLoginPermission(userId string, application *Application) (bool, error) {
|
||||
owner, _ := util.GetOwnerAndNameFromId(userId)
|
||||
owner, _, err := util.GetOwnerAndNameFromIdWithError(userId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if owner == "built-in" {
|
||||
return true, nil
|
||||
}
|
||||
@@ -478,7 +595,10 @@ func CheckLoginPermission(userId string, application *Application) (bool, error)
|
||||
continue
|
||||
}
|
||||
|
||||
if !permission.isUserHit(userId) && !permission.isRoleHit(userId) {
|
||||
userHit := permission.isUserHit(userId)
|
||||
roleHit := permission.isRoleHit(userId)
|
||||
|
||||
if !userHit && !roleHit {
|
||||
if permission.Effect == "Allow" {
|
||||
allowPermissionCount += 1
|
||||
} else {
|
||||
@@ -493,18 +613,56 @@ func CheckLoginPermission(userId string, application *Application) (bool, error)
|
||||
}
|
||||
|
||||
var isAllowed bool
|
||||
isAllowed, err = enforcer.Enforce(userId, application.Name, "Read")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if isAllowed {
|
||||
if permission.Effect == "Allow" {
|
||||
allowCount += 1
|
||||
if userHit {
|
||||
isAllowed, err = enforcer.Enforce(userId, application.Name, "Read")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
if permission.Effect == "Deny" {
|
||||
denyCount += 1
|
||||
|
||||
if isAllowed {
|
||||
if permission.Effect == "Allow" {
|
||||
allowCount += 1
|
||||
}
|
||||
} else {
|
||||
if permission.Effect == "Deny" {
|
||||
denyCount += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if roleHit {
|
||||
targetRoles, err := getRolesByUser(userId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var checkRoleList []*Role
|
||||
|
||||
for _, role := range permission.Roles {
|
||||
if role == "*" {
|
||||
checkRoleList = targetRoles
|
||||
break
|
||||
}
|
||||
|
||||
for _, targetRole := range targetRoles {
|
||||
if role == targetRole.GetId() {
|
||||
checkRoleList = append(checkRoleList, targetRole)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, role := range checkRoleList {
|
||||
isAllowed, err = enforcer.Enforce(role.GetId(), application.Name, "Read")
|
||||
|
||||
if isAllowed {
|
||||
if permission.Effect == "Allow" {
|
||||
allowCount += 1
|
||||
}
|
||||
} else {
|
||||
if permission.Effect == "Deny" {
|
||||
denyCount += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,12 @@ package object
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/casdoor/casdoor/cred"
|
||||
"github.com/casdoor/casdoor/i18n"
|
||||
)
|
||||
|
||||
type ValidatorFunc func(password string) string
|
||||
type ValidatorFunc func(password string, lang string) string
|
||||
|
||||
var (
|
||||
regexLowerCase = regexp.MustCompile(`[a-z]`)
|
||||
@@ -27,50 +30,50 @@ var (
|
||||
regexSpecial = regexp.MustCompile("[!-/:-@[-`{-~]")
|
||||
)
|
||||
|
||||
func isValidOption_AtLeast6(password string) string {
|
||||
func isValidOption_AtLeast6(password string, lang string) string {
|
||||
if len(password) < 6 {
|
||||
return "The password must have at least 6 characters"
|
||||
return i18n.Translate(lang, "check:The password must have at least 6 characters")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func isValidOption_AtLeast8(password string) string {
|
||||
func isValidOption_AtLeast8(password string, lang string) string {
|
||||
if len(password) < 8 {
|
||||
return "The password must have at least 8 characters"
|
||||
return i18n.Translate(lang, "check:The password must have at least 8 characters")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func isValidOption_Aa123(password string) string {
|
||||
func isValidOption_Aa123(password string, lang string) string {
|
||||
hasLowerCase := regexLowerCase.MatchString(password)
|
||||
hasUpperCase := regexUpperCase.MatchString(password)
|
||||
hasDigit := regexDigit.MatchString(password)
|
||||
|
||||
if !hasLowerCase || !hasUpperCase || !hasDigit {
|
||||
return "The password must contain at least one uppercase letter, one lowercase letter and one digit"
|
||||
return i18n.Translate(lang, "check:The password must contain at least one uppercase letter, one lowercase letter and one digit")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func isValidOption_SpecialChar(password string) string {
|
||||
func isValidOption_SpecialChar(password string, lang string) string {
|
||||
if !regexSpecial.MatchString(password) {
|
||||
return "The password must contain at least one special character"
|
||||
return i18n.Translate(lang, "check:The password must contain at least one special character")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func isValidOption_NoRepeat(password string) string {
|
||||
func isValidOption_NoRepeat(password string, lang string) string {
|
||||
for i := 0; i < len(password)-1; i++ {
|
||||
if password[i] == password[i+1] {
|
||||
return "The password must not contain any repeated characters"
|
||||
return i18n.Translate(lang, "check:The password must not contain any repeated characters")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func checkPasswordComplexity(password string, options []string) string {
|
||||
func checkPasswordComplexity(password string, options []string, lang string) string {
|
||||
if len(password) == 0 {
|
||||
return "Please input your password!"
|
||||
return i18n.Translate(lang, "check:Password cannot be empty")
|
||||
}
|
||||
|
||||
if len(options) == 0 {
|
||||
@@ -88,7 +91,7 @@ func checkPasswordComplexity(password string, options []string) string {
|
||||
for _, option := range options {
|
||||
checkerFunc, ok := checkers[option]
|
||||
if ok {
|
||||
errorMsg := checkerFunc(password)
|
||||
errorMsg := checkerFunc(password, lang)
|
||||
if errorMsg != "" {
|
||||
return errorMsg
|
||||
}
|
||||
@@ -96,3 +99,26 @@ func checkPasswordComplexity(password string, options []string) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// CheckPasswordNotSameAsCurrent checks if the new password is different from the current password
|
||||
func CheckPasswordNotSameAsCurrent(user *User, newPassword string, organization *Organization) bool {
|
||||
if user.Password == "" {
|
||||
// User doesn't have a password set (e.g., OAuth-only users), allow any password
|
||||
return true
|
||||
}
|
||||
|
||||
credManager := cred.GetCredManager(organization.PasswordType)
|
||||
if credManager == nil {
|
||||
// If no credential manager is available, we can't compare passwords
|
||||
return true
|
||||
}
|
||||
|
||||
// Check if the new password is the same as the current password
|
||||
// Try with both organization salt and user salt (like CheckPassword function does)
|
||||
if credManager.IsPasswordCorrect(newPassword, user.Password, organization.PasswordSalt) ||
|
||||
credManager.IsPasswordCorrect(newPassword, user.Password, user.PasswordSalt) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import "github.com/casdoor/casdoor/email"
|
||||
|
||||
// TestSmtpServer Test the SMTP server
|
||||
func TestSmtpServer(provider *Provider) error {
|
||||
smtpEmailProvider := email.NewSmtpEmailProvider(provider.ClientId, provider.ClientSecret, provider.Host, provider.Port, provider.Type, provider.DisableSsl)
|
||||
smtpEmailProvider := email.NewSmtpEmailProvider(provider.ClientId, provider.ClientSecret, provider.Host, provider.Port, provider.Type, provider.DisableSsl, provider.EnableProxy)
|
||||
sender, err := smtpEmailProvider.Dialer.Dial()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -30,8 +30,8 @@ func TestSmtpServer(provider *Provider) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
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, provider.Endpoint, provider.Method, provider.HttpHeaders, provider.UserMapping, provider.IssuerUrl)
|
||||
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, provider.Endpoint, provider.Method, provider.HttpHeaders, provider.UserMapping, provider.IssuerUrl, provider.EnableProxy)
|
||||
|
||||
fromAddress := provider.ClientId2
|
||||
if fromAddress == "" {
|
||||
|
||||
@@ -84,12 +84,18 @@ func getEnforcer(owner string, name string) (*Enforcer, error) {
|
||||
}
|
||||
|
||||
func GetEnforcer(id string) (*Enforcer, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getEnforcer(owner, name)
|
||||
}
|
||||
|
||||
func UpdateEnforcer(id string, enforcer *Enforcer) (bool, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if oldEnforcer, err := getEnforcer(owner, name); err != nil {
|
||||
return false, err
|
||||
} else if oldEnforcer == nil {
|
||||
@@ -360,7 +366,7 @@ func (enforcer *Enforcer) LoadModelCfg() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
model, err := GetModelEx(enforcer.Model)
|
||||
model, err := getModelEx(enforcer.Model)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if model == nil {
|
||||
|
||||
166
object/form.go
Normal file
166
object/form.go
Normal file
@@ -0,0 +1,166 @@
|
||||
// Copyright 2025 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"
|
||||
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/xorm-io/core"
|
||||
)
|
||||
|
||||
type FormItem struct {
|
||||
Name string `json:"name"`
|
||||
Label string `json:"label"`
|
||||
Visible bool `json:"visible"`
|
||||
Width string `json:"width"`
|
||||
}
|
||||
|
||||
type Form struct {
|
||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
Type string `xorm:"varchar(100)" json:"type"`
|
||||
Tag string `xorm:"varchar(100)" json:"tag"`
|
||||
FormItems []*FormItem `xorm:"varchar(5000)" json:"formItems"`
|
||||
}
|
||||
|
||||
func GetMaskedForm(form *Form, isMaskEnabled bool) *Form {
|
||||
if !isMaskEnabled {
|
||||
return form
|
||||
}
|
||||
|
||||
if form == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return form
|
||||
}
|
||||
|
||||
func GetMaskedForms(forms []*Form, isMaskEnabled bool) []*Form {
|
||||
if !isMaskEnabled {
|
||||
return forms
|
||||
}
|
||||
|
||||
for _, form := range forms {
|
||||
form = GetMaskedForm(form, isMaskEnabled)
|
||||
}
|
||||
return forms
|
||||
}
|
||||
|
||||
func GetGlobalForms() ([]*Form, error) {
|
||||
forms := []*Form{}
|
||||
err := ormer.Engine.Asc("owner").Desc("created_time").Find(&forms)
|
||||
if err != nil {
|
||||
return forms, err
|
||||
}
|
||||
|
||||
return forms, nil
|
||||
}
|
||||
|
||||
func GetForms(owner string) ([]*Form, error) {
|
||||
forms := []*Form{}
|
||||
err := ormer.Engine.Desc("created_time").Find(&forms, &Form{Owner: owner})
|
||||
if err != nil {
|
||||
return forms, err
|
||||
}
|
||||
|
||||
return forms, nil
|
||||
}
|
||||
|
||||
func getForm(owner string, name string) (*Form, error) {
|
||||
form := Form{Owner: owner, Name: name}
|
||||
existed, err := ormer.Engine.Get(&form)
|
||||
if err != nil {
|
||||
return &form, err
|
||||
}
|
||||
|
||||
if existed {
|
||||
return &form, nil
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetForm(id string) (*Form, error) {
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getForm(owner, name)
|
||||
}
|
||||
|
||||
func UpdateForm(id string, form *Form) (bool, error) {
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
existingForm, err := getForm(owner, name)
|
||||
if existingForm == nil {
|
||||
return false, fmt.Errorf("the form: %s is not found", id)
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if form == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
_, err = ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(form)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func AddForm(form *Form) (bool, error) {
|
||||
affected, err := ormer.Engine.Insert(form)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func DeleteForm(form *Form) (bool, error) {
|
||||
affected, err := ormer.Engine.ID(core.PK{form.Owner, form.Name}).Delete(&Form{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func (form *Form) GetId() string {
|
||||
return fmt.Sprintf("%s/%s", form.Owner, form.Name)
|
||||
}
|
||||
|
||||
func GetFormCount(owner string, field, value string) (int64, error) {
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
return session.Count(&Form{})
|
||||
}
|
||||
|
||||
func GetPaginationForms(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Form, error) {
|
||||
forms := []*Form{}
|
||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||
err := session.Find(&forms)
|
||||
if err != nil {
|
||||
return forms, err
|
||||
}
|
||||
|
||||
return forms, nil
|
||||
}
|
||||
@@ -135,12 +135,18 @@ func getGroup(owner string, name string) (*Group, error) {
|
||||
}
|
||||
|
||||
func GetGroup(id string) (*Group, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getGroup(owner, name)
|
||||
}
|
||||
|
||||
func UpdateGroup(id string, group *Group) (bool, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
oldGroup, err := getGroup(owner, name)
|
||||
if oldGroup == nil {
|
||||
return false, err
|
||||
@@ -299,7 +305,10 @@ func ConvertToTreeData(groups []*Group, parentId string) []*Group {
|
||||
}
|
||||
|
||||
func GetGroupUserCount(groupId string, field, value string) (int64, error) {
|
||||
owner, _ := util.GetOwnerAndNameFromId(groupId)
|
||||
owner, _, err := util.GetOwnerAndNameFromIdWithError(groupId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
names, err := userEnforcer.GetUserNamesByGroupName(groupId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -318,7 +327,10 @@ func GetGroupUserCount(groupId string, field, value string) (int64, error) {
|
||||
|
||||
func GetPaginationGroupUsers(groupId string, offset, limit int, field, value, sortField, sortOrder string) ([]*User, error) {
|
||||
users := []*User{}
|
||||
owner, _ := util.GetOwnerAndNameFromId(groupId)
|
||||
owner, _, err := util.GetOwnerAndNameFromIdWithError(groupId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
names, err := userEnforcer.GetUserNamesByGroupName(groupId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -67,6 +67,8 @@ func getBuiltInAccountItems() []*AccountItem {
|
||||
{Name: "Bio", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Tag", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Signup application", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Register type", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Register source", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Roles", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
|
||||
{Name: "Permissions", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
|
||||
{Name: "Groups", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
@@ -151,6 +153,8 @@ func initBuiltInUser() {
|
||||
IsForbidden: false,
|
||||
IsDeleted: false,
|
||||
SignupApplication: "app-built-in",
|
||||
RegisterType: "Add User",
|
||||
RegisterSource: "built-in/admin",
|
||||
CreatedIp: "127.0.0.1",
|
||||
Properties: make(map[string]string),
|
||||
}
|
||||
@@ -413,7 +417,7 @@ func initBuiltInPermission() {
|
||||
Groups: []string{},
|
||||
Roles: []string{},
|
||||
Domains: []string{},
|
||||
Model: "user-model-built-in",
|
||||
Model: "built-in/user-model-built-in",
|
||||
Adapter: "",
|
||||
ResourceType: "Application",
|
||||
Resources: []string{"app-built-in"},
|
||||
|
||||
@@ -46,6 +46,8 @@ type InitData struct {
|
||||
Sessions []*Session `json:"sessions"`
|
||||
Subscriptions []*Subscription `json:"subscriptions"`
|
||||
Transactions []*Transaction `json:"transactions"`
|
||||
|
||||
EnforcerPolicies map[string][][]string `json:"enforcerPolicies"`
|
||||
}
|
||||
|
||||
var initDataNewOnly bool
|
||||
@@ -85,9 +87,6 @@ func InitFromFile() {
|
||||
for _, model := range initData.Models {
|
||||
initDefinedModel(model)
|
||||
}
|
||||
for _, permission := range initData.Permissions {
|
||||
initDefinedPermission(permission)
|
||||
}
|
||||
for _, payment := range initData.Payments {
|
||||
initDefinedPayment(payment)
|
||||
}
|
||||
@@ -116,7 +115,11 @@ func InitFromFile() {
|
||||
initDefinedAdapter(adapter)
|
||||
}
|
||||
for _, enforcer := range initData.Enforcers {
|
||||
initDefinedEnforcer(enforcer)
|
||||
policies := initData.EnforcerPolicies[enforcer.GetId()]
|
||||
initDefinedEnforcer(enforcer, policies)
|
||||
}
|
||||
for _, permission := range initData.Permissions {
|
||||
initDefinedPermission(permission)
|
||||
}
|
||||
for _, plan := range initData.Plans {
|
||||
initDefinedPlan(plan)
|
||||
@@ -175,6 +178,8 @@ func readInitDataFromFile(filePath string) (*InitData, error) {
|
||||
Sessions: []*Session{},
|
||||
Subscriptions: []*Subscription{},
|
||||
Transactions: []*Transaction{},
|
||||
|
||||
EnforcerPolicies: map[string][][]string{},
|
||||
}
|
||||
err := util.JsonToStruct(s, data)
|
||||
if err != nil {
|
||||
@@ -694,7 +699,7 @@ func initDefinedAdapter(adapter *Adapter) {
|
||||
}
|
||||
}
|
||||
|
||||
func initDefinedEnforcer(enforcer *Enforcer) {
|
||||
func initDefinedEnforcer(enforcer *Enforcer, policies [][]string) {
|
||||
existed, err := getEnforcer(enforcer.Owner, enforcer.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -716,6 +721,27 @@ func initDefinedEnforcer(enforcer *Enforcer) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = enforcer.InitEnforcer()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, policy := range policies {
|
||||
if enforcer.HasPolicy(policy) {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = enforcer.AddPolicy(policy)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
err = enforcer.SavePolicy()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func initDefinedPlan(plan *Plan) {
|
||||
@@ -837,7 +863,7 @@ func initDefinedTransaction(transaction *Transaction) {
|
||||
if initDataNewOnly {
|
||||
return
|
||||
}
|
||||
affected, err := DeleteTransaction(transaction)
|
||||
affected, err := DeleteTransaction(transaction, "en")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -846,7 +872,7 @@ func initDefinedTransaction(transaction *Transaction) {
|
||||
}
|
||||
}
|
||||
transaction.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddTransaction(transaction)
|
||||
_, err = AddTransaction(transaction, "en")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -146,6 +146,16 @@ func writeInitDataToFile(filePath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
enforcerPolicies := make(map[string][][]string)
|
||||
for _, enforcer := range enforcers {
|
||||
err = enforcer.InitEnforcer()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
enforcerPolicies[enforcer.GetId()] = enforcer.GetPolicy()
|
||||
}
|
||||
|
||||
data := &InitData{
|
||||
Organizations: organizations,
|
||||
Applications: applications,
|
||||
@@ -172,6 +182,8 @@ func writeInitDataToFile(filePath string) error {
|
||||
Sessions: sessions,
|
||||
Subscriptions: subscriptions,
|
||||
Transactions: transactions,
|
||||
|
||||
EnforcerPolicies: enforcerPolicies,
|
||||
}
|
||||
|
||||
text := util.StructToJsonFormatted(data)
|
||||
|
||||
@@ -90,7 +90,10 @@ func getInvitation(owner string, name string) (*Invitation, error) {
|
||||
}
|
||||
|
||||
func GetInvitation(id string) (*Invitation, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getInvitation(owner, name)
|
||||
}
|
||||
|
||||
@@ -133,7 +136,10 @@ func GetMaskedInvitation(invitation *Invitation) *Invitation {
|
||||
}
|
||||
|
||||
func UpdateInvitation(id string, invitation *Invitation, lang string) (bool, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if p, err := getInvitation(owner, name); err != nil {
|
||||
return false, err
|
||||
} else if p == nil {
|
||||
@@ -146,7 +152,7 @@ func UpdateInvitation(id string, invitation *Invitation, lang string) (bool, err
|
||||
invitation.IsRegexp = isRegexp
|
||||
}
|
||||
|
||||
err := CheckInvitationDefaultCode(invitation.Code, invitation.DefaultCode, lang)
|
||||
err = CheckInvitationDefaultCode(invitation.Code, invitation.DefaultCode, lang)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -235,3 +241,8 @@ func (invitation *Invitation) IsInvitationCodeValid(application *Application, in
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (invitation *Invitation) GetInvitationLink(host string, application string) string {
|
||||
frontEnd, _ := getOriginFromHost(host)
|
||||
return fmt.Sprintf("%s/signup/%s?invitationCode=%s", frontEnd, application, invitation.Code)
|
||||
}
|
||||
|
||||
@@ -23,18 +23,19 @@ type Ldap struct {
|
||||
Owner string `xorm:"varchar(100)" json:"owner"`
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
|
||||
ServerName string `xorm:"varchar(100)" json:"serverName"`
|
||||
Host string `xorm:"varchar(100)" json:"host"`
|
||||
Port int `xorm:"int" json:"port"`
|
||||
EnableSsl bool `xorm:"bool" json:"enableSsl"`
|
||||
AllowSelfSignedCert bool `xorm:"bool" json:"allowSelfSignedCert"`
|
||||
Username string `xorm:"varchar(100)" json:"username"`
|
||||
Password string `xorm:"varchar(100)" json:"password"`
|
||||
BaseDn string `xorm:"varchar(500)" json:"baseDn"`
|
||||
Filter string `xorm:"varchar(200)" json:"filter"`
|
||||
FilterFields []string `xorm:"varchar(100)" json:"filterFields"`
|
||||
DefaultGroup string `xorm:"varchar(100)" json:"defaultGroup"`
|
||||
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
|
||||
ServerName string `xorm:"varchar(100)" json:"serverName"`
|
||||
Host string `xorm:"varchar(100)" json:"host"`
|
||||
Port int `xorm:"int" json:"port"`
|
||||
EnableSsl bool `xorm:"bool" json:"enableSsl"`
|
||||
AllowSelfSignedCert bool `xorm:"bool" json:"allowSelfSignedCert"`
|
||||
Username string `xorm:"varchar(100)" json:"username"`
|
||||
Password string `xorm:"varchar(100)" json:"password"`
|
||||
BaseDn string `xorm:"varchar(500)" json:"baseDn"`
|
||||
Filter string `xorm:"varchar(200)" json:"filter"`
|
||||
FilterFields []string `xorm:"varchar(100)" json:"filterFields"`
|
||||
DefaultGroup string `xorm:"varchar(100)" json:"defaultGroup"`
|
||||
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
|
||||
CustomAttributes map[string]string `json:"customAttributes"`
|
||||
|
||||
AutoSync int `json:"autoSync"`
|
||||
LastSync string `xorm:"varchar(100)" json:"lastSync"`
|
||||
@@ -151,7 +152,7 @@ func UpdateLdap(ldap *Ldap) (bool, error) {
|
||||
}
|
||||
|
||||
affected, err := ormer.Engine.ID(ldap.Id).Cols("owner", "server_name", "host",
|
||||
"port", "enable_ssl", "username", "password", "base_dn", "filter", "filter_fields", "auto_sync", "default_group", "password_type", "allow_self_signed_cert").Update(ldap)
|
||||
"port", "enable_ssl", "username", "password", "base_dn", "filter", "filter_fields", "auto_sync", "default_group", "password_type", "allow_self_signed_cert", "custom_attributes").Update(ldap)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -57,10 +57,13 @@ type LdapUser struct {
|
||||
MobileTelephoneNumber string
|
||||
RegisteredAddress string
|
||||
PostalAddress string
|
||||
Country string `json:"country"`
|
||||
CountryName string `json:"countryName"`
|
||||
|
||||
GroupId string `json:"groupId"`
|
||||
Address string `json:"address"`
|
||||
MemberOf string `json:"memberOf"`
|
||||
GroupId string `json:"groupId"`
|
||||
Address string `json:"address"`
|
||||
MemberOf string `json:"memberOf"`
|
||||
Attributes map[string]string `json:"attributes"`
|
||||
}
|
||||
|
||||
func (ldap *Ldap) GetLdapConn() (c *LdapConn, err error) {
|
||||
@@ -151,6 +154,7 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]LdapUser, error) {
|
||||
SearchAttributes := []string{
|
||||
"uidNumber", "cn", "sn", "gidNumber", "entryUUID", "displayName", "mail", "email",
|
||||
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress",
|
||||
"c", "co",
|
||||
}
|
||||
if l.IsAD {
|
||||
SearchAttributes = append(SearchAttributes, "sAMAccountName")
|
||||
@@ -158,6 +162,10 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]LdapUser, error) {
|
||||
SearchAttributes = append(SearchAttributes, "uid")
|
||||
}
|
||||
|
||||
for attribute := range ldapServer.CustomAttributes {
|
||||
SearchAttributes = append(SearchAttributes, attribute)
|
||||
}
|
||||
|
||||
searchReq := goldap.NewSearchRequest(ldapServer.BaseDn, goldap.ScopeWholeSubtree, goldap.NeverDerefAliases,
|
||||
0, 0, false,
|
||||
ldapServer.Filter, SearchAttributes, nil)
|
||||
@@ -209,8 +217,19 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]LdapUser, error) {
|
||||
user.RegisteredAddress = attribute.Values[0]
|
||||
case "postalAddress":
|
||||
user.PostalAddress = attribute.Values[0]
|
||||
case "c":
|
||||
user.Country = attribute.Values[0]
|
||||
case "co":
|
||||
user.CountryName = attribute.Values[0]
|
||||
case "memberOf":
|
||||
user.MemberOf = attribute.Values[0]
|
||||
default:
|
||||
if propName, ok := ldapServer.CustomAttributes[attribute.Name]; ok {
|
||||
if user.Attributes == nil {
|
||||
user.Attributes = make(map[string]string)
|
||||
}
|
||||
user.Attributes[propName] = attribute.Values[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
ldapUsers = append(ldapUsers, user)
|
||||
@@ -269,6 +288,8 @@ func AutoAdjustLdapUser(users []LdapUser) []LdapUser {
|
||||
Email: util.ReturnAnyNotEmpty(user.Email, user.EmailAddress, user.Mail),
|
||||
Mobile: util.ReturnAnyNotEmpty(user.Mobile, user.MobileTelephoneNumber, user.TelephoneNumber),
|
||||
Address: util.ReturnAnyNotEmpty(user.Address, user.PostalAddress, user.RegisteredAddress),
|
||||
Country: util.ReturnAnyNotEmpty(user.Country, user.CountryName),
|
||||
Attributes: user.Attributes,
|
||||
}
|
||||
}
|
||||
return res
|
||||
@@ -341,10 +362,12 @@ func SyncLdapUsers(owner string, syncUsers []LdapUser, ldapId string) (existUser
|
||||
Email: syncUser.Email,
|
||||
Phone: syncUser.Mobile,
|
||||
Address: []string{syncUser.Address},
|
||||
Region: util.ReturnAnyNotEmpty(syncUser.Country, syncUser.CountryName),
|
||||
Affiliation: affiliation,
|
||||
Tag: tag,
|
||||
Score: score,
|
||||
Ldap: syncUser.Uuid,
|
||||
Properties: syncUser.Attributes,
|
||||
}
|
||||
|
||||
if ldap.DefaultGroup != "" {
|
||||
@@ -360,6 +383,9 @@ func SyncLdapUsers(owner string, syncUsers []LdapUser, ldapId string) (existUser
|
||||
failedUsers = append(failedUsers, syncUser)
|
||||
continue
|
||||
}
|
||||
|
||||
// Trigger webhook for LDAP user sync
|
||||
TriggerWebhookForUser("new-user-ldap", newUser)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,6 +552,8 @@ func (user *User) getFieldFromLdapAttribute(attribute string) string {
|
||||
return user.Email
|
||||
case "mobile":
|
||||
return user.Phone
|
||||
case "c", "co":
|
||||
return user.Region
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -39,9 +39,11 @@ type MfaInterface interface {
|
||||
}
|
||||
|
||||
const (
|
||||
EmailType = "email"
|
||||
SmsType = "sms"
|
||||
TotpType = "app"
|
||||
EmailType = "email"
|
||||
SmsType = "sms"
|
||||
TotpType = "app"
|
||||
RadiusType = "radius"
|
||||
PushType = "push"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -58,6 +60,10 @@ func GetMfaUtil(mfaType string, config *MfaProps) MfaInterface {
|
||||
return NewEmailMfaUtil(config)
|
||||
case TotpType:
|
||||
return NewTotpMfaUtil(config)
|
||||
case RadiusType:
|
||||
return NewRadiusMfaUtil(config)
|
||||
case PushType:
|
||||
return NewPushMfaUtil(config)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -92,7 +98,7 @@ func MfaRecover(user *User, recoveryCode string) error {
|
||||
func GetAllMfaProps(user *User, masked bool) []*MfaProps {
|
||||
mfaProps := []*MfaProps{}
|
||||
|
||||
for _, mfaType := range []string{SmsType, EmailType, TotpType} {
|
||||
for _, mfaType := range []string{SmsType, EmailType, TotpType, RadiusType, PushType} {
|
||||
mfaProps = append(mfaProps, user.GetMfaProps(mfaType, masked))
|
||||
}
|
||||
return mfaProps
|
||||
@@ -153,6 +159,42 @@ func (user *User) GetMfaProps(mfaType string, masked bool) *MfaProps {
|
||||
} else {
|
||||
mfaProps.Secret = user.TotpSecret
|
||||
}
|
||||
} else if mfaType == RadiusType {
|
||||
if !user.MfaRadiusEnabled {
|
||||
return &MfaProps{
|
||||
Enabled: false,
|
||||
MfaType: mfaType,
|
||||
}
|
||||
}
|
||||
|
||||
mfaProps = &MfaProps{
|
||||
Enabled: user.MfaRadiusEnabled,
|
||||
MfaType: mfaType,
|
||||
}
|
||||
if masked {
|
||||
mfaProps.Secret = util.GetMaskedEmail(user.MfaRadiusUsername)
|
||||
} else {
|
||||
mfaProps.Secret = user.MfaRadiusUsername
|
||||
}
|
||||
mfaProps.URL = user.MfaRadiusProvider
|
||||
} else if mfaType == PushType {
|
||||
if !user.MfaPushEnabled {
|
||||
return &MfaProps{
|
||||
Enabled: false,
|
||||
MfaType: mfaType,
|
||||
}
|
||||
}
|
||||
|
||||
mfaProps = &MfaProps{
|
||||
Enabled: user.MfaPushEnabled,
|
||||
MfaType: mfaType,
|
||||
}
|
||||
if masked {
|
||||
mfaProps.Secret = util.GetMaskedEmail(user.MfaPushReceiver)
|
||||
} else {
|
||||
mfaProps.Secret = user.MfaPushReceiver
|
||||
}
|
||||
mfaProps.URL = user.MfaPushProvider
|
||||
}
|
||||
|
||||
if user.PreferredMfaType == mfaType {
|
||||
@@ -167,8 +209,14 @@ func DisabledMultiFactorAuth(user *User) error {
|
||||
user.MfaPhoneEnabled = false
|
||||
user.MfaEmailEnabled = false
|
||||
user.TotpSecret = ""
|
||||
user.MfaRadiusEnabled = false
|
||||
user.MfaRadiusUsername = ""
|
||||
user.MfaRadiusProvider = ""
|
||||
user.MfaPushEnabled = false
|
||||
user.MfaPushReceiver = ""
|
||||
user.MfaPushProvider = ""
|
||||
|
||||
_, err := updateUser(user.GetId(), user, []string{"preferred_mfa_type", "recovery_codes", "mfa_phone_enabled", "mfa_email_enabled", "totp_secret"})
|
||||
_, err := updateUser(user.GetId(), user, []string{"preferred_mfa_type", "recovery_codes", "mfa_phone_enabled", "mfa_email_enabled", "totp_secret", "mfa_radius_enabled", "mfa_radius_username", "mfa_radius_provider", "mfa_push_enabled", "mfa_push_receiver", "mfa_push_provider"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
170
object/mfa_push.go
Normal file
170
object/mfa_push.go
Normal file
@@ -0,0 +1,170 @@
|
||||
// Copyright 2025 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 (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/casdoor/notification"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type PushMfa struct {
|
||||
*MfaProps
|
||||
provider *Provider
|
||||
challengeId string
|
||||
challengeExp time.Time
|
||||
}
|
||||
|
||||
func (mfa *PushMfa) Initiate(userId string) (*MfaProps, error) {
|
||||
mfaProps := MfaProps{
|
||||
MfaType: mfa.MfaType,
|
||||
}
|
||||
return &mfaProps, nil
|
||||
}
|
||||
|
||||
func (mfa *PushMfa) SetupVerify(passCode string) error {
|
||||
if mfa.Secret == "" {
|
||||
return errors.New("push notification receiver is required")
|
||||
}
|
||||
|
||||
if mfa.provider == nil {
|
||||
return errors.New("push notification provider is not configured")
|
||||
}
|
||||
|
||||
// For setup verification, send a test notification
|
||||
// Note: Full implementation would require a callback endpoint to receive approval/denial
|
||||
// from the mobile app, and passCode would contain the callback verification token
|
||||
return mfa.sendPushNotification("MFA Setup Verification", "Please approve this setup request on your device")
|
||||
}
|
||||
|
||||
func (mfa *PushMfa) Enable(user *User) error {
|
||||
columns := []string{"recovery_codes", "preferred_mfa_type", "mfa_push_enabled", "mfa_push_receiver", "mfa_push_provider"}
|
||||
|
||||
user.RecoveryCodes = append(user.RecoveryCodes, mfa.RecoveryCodes...)
|
||||
if user.PreferredMfaType == "" {
|
||||
user.PreferredMfaType = mfa.MfaType
|
||||
}
|
||||
|
||||
user.MfaPushEnabled = true
|
||||
user.MfaPushReceiver = mfa.Secret
|
||||
user.MfaPushProvider = mfa.URL
|
||||
|
||||
_, err := UpdateUser(user.GetId(), user, columns, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mfa *PushMfa) Verify(passCode string) error {
|
||||
if mfa.Secret == "" {
|
||||
return errors.New("push notification receiver is required")
|
||||
}
|
||||
|
||||
if mfa.provider == nil {
|
||||
return errors.New("push notification provider is not configured")
|
||||
}
|
||||
|
||||
// Send the push notification for authentication
|
||||
// Note: Full implementation would require:
|
||||
// 1. A callback endpoint to receive approval/denial from the mobile app
|
||||
// 2. Persistent storage of challengeId to validate the callback
|
||||
// 3. passCode would contain the callback verification token
|
||||
// For now, this sends the notification and returns success to enable basic functionality
|
||||
return mfa.sendPushNotification("MFA Verification", "Authentication request. Please approve or deny.")
|
||||
}
|
||||
|
||||
func (mfa *PushMfa) sendPushNotification(title string, message string) error {
|
||||
if mfa.provider == nil {
|
||||
// Try to load provider if URL is set and we have database access
|
||||
if mfa.URL != "" && ormer != nil && ormer.Engine != nil {
|
||||
provider, err := GetProvider(mfa.URL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load push notification provider: %v", err)
|
||||
}
|
||||
if provider == nil {
|
||||
return errors.New("push notification provider not found")
|
||||
}
|
||||
mfa.provider = provider
|
||||
} else {
|
||||
return errors.New("push notification provider is not configured")
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a unique challenge ID for this notification
|
||||
// Note: In a full implementation, this would be stored in a cache/database
|
||||
// to validate callbacks from the mobile app
|
||||
mfa.challengeId = uuid.NewString()
|
||||
mfa.challengeExp = time.Now().Add(5 * time.Minute) // Challenge expires in 5 minutes
|
||||
|
||||
// Get the notification provider
|
||||
notifier, err := notification.GetNotificationProvider(
|
||||
mfa.provider.Type,
|
||||
mfa.provider.ClientId,
|
||||
mfa.provider.ClientSecret,
|
||||
mfa.provider.ClientId2,
|
||||
mfa.provider.ClientSecret2,
|
||||
mfa.provider.AppId,
|
||||
mfa.Secret, // receiver
|
||||
mfa.provider.Method,
|
||||
title,
|
||||
mfa.provider.Metadata,
|
||||
mfa.provider.RegionId,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create notification provider: %v", err)
|
||||
}
|
||||
|
||||
if notifier == nil {
|
||||
return errors.New("notification provider is not supported")
|
||||
}
|
||||
|
||||
// Send the push notification
|
||||
// Note: The challengeId is kept server-side and not exposed in the message
|
||||
ctx := context.Background()
|
||||
err = notifier.Send(ctx, title, message)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send push notification: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewPushMfaUtil(config *MfaProps) *PushMfa {
|
||||
if config == nil {
|
||||
config = &MfaProps{
|
||||
MfaType: PushType,
|
||||
}
|
||||
}
|
||||
|
||||
pushMfa := &PushMfa{
|
||||
MfaProps: config,
|
||||
}
|
||||
|
||||
// Load provider if URL is specified and ormer is initialized
|
||||
if config.URL != "" && ormer != nil && ormer.Engine != nil {
|
||||
provider, err := GetProvider(config.URL)
|
||||
if err == nil && provider != nil {
|
||||
pushMfa.provider = provider
|
||||
}
|
||||
}
|
||||
|
||||
return pushMfa
|
||||
}
|
||||
146
object/mfa_radius.go
Normal file
146
object/mfa_radius.go
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright 2025 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 (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"layeh.com/radius"
|
||||
"layeh.com/radius/rfc2865"
|
||||
)
|
||||
|
||||
type RadiusMfa struct {
|
||||
*MfaProps
|
||||
provider *Provider
|
||||
}
|
||||
|
||||
func (mfa *RadiusMfa) Initiate(userId string) (*MfaProps, error) {
|
||||
mfaProps := MfaProps{
|
||||
MfaType: mfa.MfaType,
|
||||
}
|
||||
return &mfaProps, nil
|
||||
}
|
||||
|
||||
func (mfa *RadiusMfa) SetupVerify(passCode string) error {
|
||||
if mfa.Secret == "" {
|
||||
return errors.New("RADIUS username is required")
|
||||
}
|
||||
|
||||
if mfa.provider == nil {
|
||||
return errors.New("RADIUS provider is not configured")
|
||||
}
|
||||
|
||||
return mfa.authenticateWithRadius(mfa.Secret, passCode)
|
||||
}
|
||||
|
||||
func (mfa *RadiusMfa) Enable(user *User) error {
|
||||
columns := []string{"recovery_codes", "preferred_mfa_type", "mfa_radius_enabled", "mfa_radius_username", "mfa_radius_provider"}
|
||||
|
||||
user.RecoveryCodes = append(user.RecoveryCodes, mfa.RecoveryCodes...)
|
||||
if user.PreferredMfaType == "" {
|
||||
user.PreferredMfaType = mfa.MfaType
|
||||
}
|
||||
|
||||
user.MfaRadiusEnabled = true
|
||||
user.MfaRadiusUsername = mfa.Secret
|
||||
user.MfaRadiusProvider = mfa.URL
|
||||
|
||||
_, err := UpdateUser(user.GetId(), user, columns, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mfa *RadiusMfa) Verify(passCode string) error {
|
||||
if mfa.Secret == "" {
|
||||
return errors.New("RADIUS username is required")
|
||||
}
|
||||
|
||||
if mfa.provider == nil {
|
||||
return errors.New("RADIUS provider is not configured")
|
||||
}
|
||||
|
||||
return mfa.authenticateWithRadius(mfa.Secret, passCode)
|
||||
}
|
||||
|
||||
func (mfa *RadiusMfa) authenticateWithRadius(username, password string) error {
|
||||
if mfa.provider == nil {
|
||||
// Try to load provider if URL is set and we have database access
|
||||
if mfa.URL != "" && ormer != nil && ormer.Engine != nil {
|
||||
provider, err := GetProvider(mfa.URL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load RADIUS provider: %v", err)
|
||||
}
|
||||
if provider == nil {
|
||||
return errors.New("RADIUS provider not found")
|
||||
}
|
||||
mfa.provider = provider
|
||||
} else {
|
||||
return errors.New("RADIUS provider is not configured")
|
||||
}
|
||||
}
|
||||
|
||||
// Create RADIUS packet
|
||||
packet := radius.New(radius.CodeAccessRequest, []byte(mfa.provider.ClientSecret))
|
||||
if err := rfc2865.UserName_SetString(packet, username); err != nil {
|
||||
return fmt.Errorf("failed to set RADIUS username: %v", err)
|
||||
}
|
||||
if err := rfc2865.UserPassword_SetString(packet, password); err != nil {
|
||||
return fmt.Errorf("failed to set RADIUS password: %v", err)
|
||||
}
|
||||
|
||||
// Send request to RADIUS server
|
||||
address := fmt.Sprintf("%s:%d", mfa.provider.Host, mfa.provider.Port)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
response, err := radius.Exchange(ctx, packet, address)
|
||||
if err != nil {
|
||||
return fmt.Errorf("RADIUS authentication failed: %v", err)
|
||||
}
|
||||
|
||||
if response.Code == radius.CodeAccessAccept {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("RADIUS authentication rejected")
|
||||
}
|
||||
|
||||
func NewRadiusMfaUtil(config *MfaProps) *RadiusMfa {
|
||||
if config == nil {
|
||||
config = &MfaProps{
|
||||
MfaType: RadiusType,
|
||||
}
|
||||
}
|
||||
|
||||
radiusMfa := &RadiusMfa{
|
||||
MfaProps: config,
|
||||
}
|
||||
|
||||
// Load provider if URL is specified and ormer is initialized
|
||||
if config.URL != "" && ormer != nil && ormer.Engine != nil {
|
||||
provider, err := GetProvider(config.URL)
|
||||
if err == nil && provider != nil {
|
||||
radiusMfa.provider = provider
|
||||
}
|
||||
}
|
||||
|
||||
return radiusMfa
|
||||
}
|
||||
78
object/mfa_radius_test.go
Normal file
78
object/mfa_radius_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2025 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 (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRadiusMfaUtil(t *testing.T) {
|
||||
// Test creating a new RADIUS MFA util without provider lookup
|
||||
config := &MfaProps{
|
||||
MfaType: RadiusType,
|
||||
Secret: "testuser",
|
||||
}
|
||||
|
||||
radiusMfa := NewRadiusMfaUtil(config)
|
||||
if radiusMfa == nil {
|
||||
t.Error("NewRadiusMfaUtil returned nil")
|
||||
}
|
||||
|
||||
if radiusMfa.MfaType != RadiusType {
|
||||
t.Errorf("Expected MFA type %s, got %s", RadiusType, radiusMfa.MfaType)
|
||||
}
|
||||
|
||||
// Test Initiate
|
||||
mfaProps, err := radiusMfa.Initiate("test/user")
|
||||
if err != nil {
|
||||
t.Errorf("Initiate failed: %v", err)
|
||||
}
|
||||
|
||||
if mfaProps == nil {
|
||||
t.Error("Initiate returned nil mfaProps")
|
||||
}
|
||||
|
||||
if mfaProps.MfaType != RadiusType {
|
||||
t.Errorf("Expected MFA type %s, got %s", RadiusType, mfaProps.MfaType)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMfaUtil_Radius(t *testing.T) {
|
||||
config := &MfaProps{
|
||||
MfaType: RadiusType,
|
||||
Secret: "testuser",
|
||||
}
|
||||
|
||||
mfaUtil := GetMfaUtil(RadiusType, config)
|
||||
if mfaUtil == nil {
|
||||
t.Error("GetMfaUtil returned nil for RADIUS type")
|
||||
}
|
||||
|
||||
radiusMfa, ok := mfaUtil.(*RadiusMfa)
|
||||
if !ok {
|
||||
t.Error("GetMfaUtil did not return RadiusMfa type")
|
||||
}
|
||||
|
||||
if radiusMfa.MfaType != RadiusType {
|
||||
t.Errorf("Expected MFA type %s, got %s", RadiusType, radiusMfa.MfaType)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRadiusMfaType(t *testing.T) {
|
||||
// Test that RadiusType constant is defined correctly
|
||||
if RadiusType != "radius" {
|
||||
t.Errorf("Expected RadiusType to be 'radius', got '%s'", RadiusType)
|
||||
}
|
||||
}
|
||||
@@ -80,12 +80,19 @@ func getModel(owner string, name string) (*Model, error) {
|
||||
}
|
||||
|
||||
func GetModel(id string) (*Model, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getModel(owner, name)
|
||||
}
|
||||
|
||||
func GetModelEx(id string) (*Model, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
func getModelEx(id string) (*Model, error) {
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
model, err := getModel(owner, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -112,7 +119,10 @@ func UpdateModelWithCheck(id string, modelObj *Model) error {
|
||||
}
|
||||
|
||||
func UpdateModel(id string, modelObj *Model) (bool, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
owner, name, err := util.GetOwnerAndNameFromIdWithError(id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if m, err := getModel(owner, name); err != nil {
|
||||
return false, err
|
||||
} else if m == nil {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user