Compare commits

..

1 Commits

Author SHA1 Message Date
488f48a714 Revert "feat: use i18next-resources-to-backend to lazy load i18n (#2738)"
This reverts commit dc3131c683.
2024-02-23 23:38:15 +08:00
301 changed files with 8305 additions and 24666 deletions

View File

@ -35,7 +35,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 20 node-version: 18
cache: 'yarn' cache: 'yarn'
cache-dependency-path: ./web/yarn.lock cache-dependency-path: ./web/yarn.lock
- run: yarn install && CI=false yarn run build - run: yarn install && CI=false yarn run build
@ -101,25 +101,24 @@ jobs:
working-directory: ./ working-directory: ./
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 20 node-version: 18
cache: 'yarn' cache: 'yarn'
cache-dependency-path: ./web/yarn.lock cache-dependency-path: ./web/yarn.lock
- run: yarn install - run: yarn install
working-directory: ./web working-directory: ./web
- uses: cypress-io/github-action@v5 - uses: cypress-io/github-action@v5
with: with:
browser: chrome
start: yarn start start: yarn start
wait-on: 'http://localhost:7001' wait-on: 'http://localhost:7001'
wait-on-timeout: 210 wait-on-timeout: 210
working-directory: ./web working-directory: ./web
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
if: failure() if: failure()
with: with:
name: cypress-screenshots name: cypress-screenshots
path: ./web/cypress/screenshots path: ./web/cypress/screenshots
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
if: always() if: always()
with: with:
name: cypress-videos name: cypress-videos
@ -138,7 +137,7 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 20 node-version: 18
- name: Fetch Previous version - name: Fetch Previous version
id: get-previous-tag id: get-previous-tag
@ -147,7 +146,7 @@ jobs:
- name: Release - name: Release
run: yarn global add semantic-release@17.4.4 && semantic-release run: yarn global add semantic-release@17.4.4 && semantic-release
env: env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}
- name: Fetch Current version - name: Fetch Current version
id: get-current-tag id: get-current-tag
@ -194,7 +193,7 @@ jobs:
with: with:
context: . context: .
target: STANDARD target: STANDARD
platforms: linux/amd64,linux/arm64 platforms: linux/amd64
push: true push: true
tags: casbin/casdoor:${{steps.get-current-tag.outputs.tag }},casbin/casdoor:latest tags: casbin/casdoor:${{steps.get-current-tag.outputs.tag }},casbin/casdoor:latest
@ -204,7 +203,7 @@ jobs:
with: with:
context: . context: .
target: ALLINONE target: ALLINONE
platforms: linux/amd64,linux/arm64 platforms: linux/amd64
push: true push: true
tags: casbin/casdoor-all-in-one:${{steps.get-current-tag.outputs.tag }},casbin/casdoor-all-in-one:latest tags: casbin/casdoor-all-in-one:${{steps.get-current-tag.outputs.tag }},casbin/casdoor-all-in-one:latest

View File

@ -1,10 +1,10 @@
FROM --platform=$BUILDPLATFORM node:18.19.0 AS FRONT FROM node:18.19.0 AS FRONT
WORKDIR /web WORKDIR /web
COPY ./web . COPY ./web .
RUN yarn install --frozen-lockfile --network-timeout 1000000 && NODE_OPTIONS="--max-old-space-size=4096" yarn run build RUN yarn install --frozen-lockfile --network-timeout 1000000 && yarn run build
FROM --platform=$BUILDPLATFORM golang:1.20.12 AS BACK FROM golang:1.20.12 AS BACK
WORKDIR /go/src/casdoor WORKDIR /go/src/casdoor
COPY . . COPY . .
RUN ./build.sh RUN ./build.sh
@ -13,13 +13,9 @@ RUN go test -v -run TestGetVersionInfo ./util/system_test.go ./util/system.go >
FROM alpine:latest AS STANDARD FROM alpine:latest AS STANDARD
LABEL MAINTAINER="https://casdoor.org/" LABEL MAINTAINER="https://casdoor.org/"
ARG USER=casdoor ARG USER=casdoor
ARG TARGETOS
ARG TARGETARCH
ENV BUILDX_ARCH="${TARGETOS:-linux}_${TARGETARCH:-amd64}"
RUN sed -i 's/https/http/' /etc/apk/repositories RUN sed -i 's/https/http/' /etc/apk/repositories
RUN apk add --update sudo RUN apk add --update sudo
RUN apk add tzdata
RUN apk add curl RUN apk add curl
RUN apk add ca-certificates && update-ca-certificates RUN apk add ca-certificates && update-ca-certificates
@ -31,7 +27,7 @@ RUN adduser -D $USER -u 1000 \
USER 1000 USER 1000
WORKDIR / WORKDIR /
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/server_${BUILDX_ARCH} ./server COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/server ./server
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/swagger ./swagger COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/swagger ./swagger
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/conf/app.conf ./conf/app.conf COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/conf/app.conf ./conf/app.conf
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/version_info.txt ./go/src/casdoor/version_info.txt COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/version_info.txt ./go/src/casdoor/version_info.txt
@ -50,15 +46,12 @@ RUN apt update \
FROM db AS ALLINONE FROM db AS ALLINONE
LABEL MAINTAINER="https://casdoor.org/" LABEL MAINTAINER="https://casdoor.org/"
ARG TARGETOS
ARG TARGETARCH
ENV BUILDX_ARCH="${TARGETOS:-linux}_${TARGETARCH:-amd64}"
RUN apt update RUN apt update
RUN apt install -y ca-certificates && update-ca-certificates RUN apt install -y ca-certificates && update-ca-certificates
WORKDIR / WORKDIR /
COPY --from=BACK /go/src/casdoor/server_${BUILDX_ARCH} ./server COPY --from=BACK /go/src/casdoor/server ./server
COPY --from=BACK /go/src/casdoor/swagger ./swagger COPY --from=BACK /go/src/casdoor/swagger ./swagger
COPY --from=BACK /go/src/casdoor/docker-entrypoint.sh /docker-entrypoint.sh COPY --from=BACK /go/src/casdoor/docker-entrypoint.sh /docker-entrypoint.sh
COPY --from=BACK /go/src/casdoor/conf/app.conf ./conf/app.conf COPY --from=BACK /go/src/casdoor/conf/app.conf ./conf/app.conf

View File

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

View File

@ -77,7 +77,6 @@ p, *, *, POST, /api/verify-code, *, *
p, *, *, POST, /api/reset-email-or-phone, *, * p, *, *, POST, /api/reset-email-or-phone, *, *
p, *, *, POST, /api/upload-resource, *, * p, *, *, POST, /api/upload-resource, *, *
p, *, *, GET, /.well-known/openid-configuration, *, * p, *, *, GET, /.well-known/openid-configuration, *, *
p, *, *, GET, /.well-known/webfinger, *, *
p, *, *, *, /.well-known/jwks, *, * p, *, *, *, /.well-known/jwks, *, *
p, *, *, GET, /api/get-saml-login, *, * p, *, *, GET, /api/get-saml-login, *, *
p, *, *, POST, /api/acs, *, * p, *, *, POST, /api/acs, *, *
@ -98,10 +97,7 @@ p, *, *, GET, /api/get-organization-names, *, *
p, *, *, GET, /api/get-all-objects, *, * p, *, *, GET, /api/get-all-objects, *, *
p, *, *, GET, /api/get-all-actions, *, * p, *, *, GET, /api/get-all-actions, *, *
p, *, *, GET, /api/get-all-roles, *, * p, *, *, GET, /api/get-all-roles, *, *
p, *, *, GET, /api/run-casbin-command, *, *
p, *, *, POST, /api/refresh-engines, *, *
p, *, *, GET, /api/get-invitation-info, *, * p, *, *, GET, /api/get-invitation-info, *, *
p, *, *, GET, /api/faceid-signin-begin, *, *
` `
sa := stringadapter.NewAdapter(ruleText) sa := stringadapter.NewAdapter(ruleText)
@ -157,7 +153,7 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool { func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
if method == "POST" { 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/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" {
return true return true
} else if urlPath == "/api/update-user" { } else if urlPath == "/api/update-user" {
// Allow ordinary users to update their own information // Allow ordinary users to update their own information
@ -165,11 +161,6 @@ func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath
return true return true
} }
return false return false
} else if urlPath == "/api/upload-resource" {
if subOwner == "app" && subName == "app-casibase" {
return true
}
return false
} else { } else {
return false return false
} }

View File

@ -8,6 +8,4 @@ else
echo "Google is blocked, Go proxy is enabled: GOPROXY=https://goproxy.cn,direct" echo "Google is blocked, Go proxy is enabled: GOPROXY=https://goproxy.cn,direct"
export GOPROXY="https://goproxy.cn,direct" export GOPROXY="https://goproxy.cn,direct"
fi fi
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server .
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server_linux_amd64 .
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="-w -s" -o server_linux_arm64 .

View File

@ -26,10 +26,6 @@ func GetCaptchaProvider(captchaType string) CaptchaProvider {
return NewDefaultCaptchaProvider() return NewDefaultCaptchaProvider()
case "reCAPTCHA": case "reCAPTCHA":
return NewReCaptchaProvider() return NewReCaptchaProvider()
case "reCAPTCHA v2":
return NewReCaptchaProvider()
case "reCAPTCHA v3":
return NewReCaptchaProvider()
case "Aliyun Captcha": case "Aliyun Captcha":
return NewAliyunCaptchaProvider() return NewAliyunCaptchaProvider()
case "hCaptcha": case "hCaptcha":

View File

@ -15,23 +15,16 @@ socks5Proxy = "127.0.0.1:10808"
verificationCodeTimeout = 10 verificationCodeTimeout = 10
initScore = 0 initScore = 0
logPostOnly = true logPostOnly = true
isUsernameLowered = false
origin = origin =
originFrontend = originFrontend =
staticBaseUrl = "https://cdn.casbin.org" staticBaseUrl = "https://cdn.casbin.org"
isDemoMode = false isDemoMode = false
batchSize = 100 batchSize = 100
enableErrorMask = false
enableGzip = true enableGzip = true
inactiveTimeoutMinutes =
ldapServerPort = 389 ldapServerPort = 389
ldapsCertId = ""
ldapsServerPort = 636
radiusServerPort = 1812 radiusServerPort = 1812
radiusDefaultOrganization = "built-in"
radiusSecret = "secret" radiusSecret = "secret"
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1} quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}
logConfig = {"filename": "logs/casdoor.log", "maxdays":99999, "perm":"0770"} logConfig = {"filename": "logs/casdoor.log", "maxdays":99999, "perm":"0770"}
initDataNewOnly = false
initDataFile = "./init_data.json" initDataFile = "./init_data.json"
frontendBaseDir = "../cc_0" frontendBaseDir = "../casdoor"

View File

@ -44,8 +44,6 @@ type Response struct {
} }
type Captcha struct { type Captcha struct {
Owner string `json:"owner"`
Name string `json:"name"`
Type string `json:"type"` Type string `json:"type"`
AppKey string `json:"appKey"` AppKey string `json:"appKey"`
Scene string `json:"scene"` Scene string `json:"scene"`
@ -116,13 +114,6 @@ func (c *ApiController) Signup() {
return return
} }
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
err = object.CheckEntryIp(clientIp, nil, application, organization, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
msg := object.CheckUserSignup(application, organization, &authForm, c.GetAcceptLanguage()) msg := object.CheckUserSignup(application, organization, &authForm, c.GetAcceptLanguage())
if msg != "" { if msg != "" {
c.ResponseError(msg) c.ResponseError(msg)
@ -176,11 +167,7 @@ func (c *ApiController) Signup() {
username := authForm.Username username := authForm.Username
if !application.IsSignupItemVisible("Username") { if !application.IsSignupItemVisible("Username") {
if organization.UseEmailAsUsername && application.IsSignupItemVisible("Email") { username = id
username = authForm.Email
} else {
username = id
}
} }
initScore, err := organization.GetInitScore() initScore, err := organization.GetInitScore()
@ -207,10 +194,6 @@ func (c *ApiController) Signup() {
Type: userType, Type: userType,
Password: authForm.Password, Password: authForm.Password,
DisplayName: authForm.Name, DisplayName: authForm.Name,
Gender: authForm.Gender,
Bio: authForm.Bio,
Tag: authForm.Tag,
Education: authForm.Education,
Avatar: organization.DefaultAvatar, Avatar: organization.DefaultAvatar,
Email: authForm.Email, Email: authForm.Email,
Phone: authForm.Phone, Phone: authForm.Phone,
@ -245,14 +228,6 @@ func (c *ApiController) Signup() {
} }
} }
if invitation != nil && invitation.SignupGroup != "" {
user.Groups = []string{invitation.SignupGroup}
}
if application.DefaultGroup != "" && user.Groups == nil {
user.Groups = []string{application.DefaultGroup}
}
affected, err := object.AddUser(user) affected, err := object.AddUser(user)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
@ -284,24 +259,22 @@ func (c *ApiController) Signup() {
c.SetSessionUsername(user.GetId()) c.SetSessionUsername(user.GetId())
} }
if authForm.Email != "" { err = object.DisableVerificationCode(authForm.Email)
err = object.DisableVerificationCode(authForm.Email) if err != nil {
if err != nil { c.ResponseError(err.Error())
c.ResponseError(err.Error()) return
return
}
} }
if checkPhone != "" { err = object.DisableVerificationCode(checkPhone)
err = object.DisableVerificationCode(checkPhone) if err != nil {
if err != nil { c.ResponseError(err.Error())
c.ResponseError(err.Error()) return
return
}
} }
c.Ctx.Input.SetParam("recordUserId", user.GetId()) record := object.NewRecord(c.Ctx)
c.Ctx.Input.SetParam("recordSignup", "true") record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
userId := user.GetId() userId := user.GetId()
util.LogInfo(c.Ctx, "API: [%s] is signed up as new user", userId) util.LogInfo(c.Ctx, "API: [%s] is signed up as new user", userId)
@ -334,7 +307,6 @@ func (c *ApiController) Logout() {
} }
c.ClearUserSession() c.ClearUserSession()
c.ClearTokenSession()
owner, username := util.GetOwnerAndNameFromId(user) owner, username := util.GetOwnerAndNameFromId(user)
_, err := object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID()) _, err := object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
if err != nil { if err != nil {
@ -381,7 +353,6 @@ func (c *ApiController) Logout() {
} }
c.ClearUserSession() c.ClearUserSession()
c.ClearTokenSession()
// TODO https://github.com/casdoor/casdoor/pull/1494#discussion_r1095675265 // TODO https://github.com/casdoor/casdoor/pull/1494#discussion_r1095675265
owner, username := util.GetOwnerAndNameFromId(user) owner, username := util.GetOwnerAndNameFromId(user)
@ -462,21 +433,6 @@ func (c *ApiController) GetAccount() {
return return
} }
if organization != nil && len(organization.CountryCodes) == 1 && u != nil && u.CountryCode == "" {
u.CountryCode = organization.CountryCodes[0]
}
accessToken := c.GetSessionToken()
if accessToken == "" {
accessToken, err = object.GetAccessTokenByUser(user, c.Ctx.Request.Host)
if err != nil {
c.ResponseError(err.Error())
return
}
c.SetSessionToken(accessToken)
}
u.AccessToken = accessToken
resp := Response{ resp := Response{
Status: "ok", Status: "ok",
Sub: user.Id, Sub: user.Id,
@ -503,12 +459,7 @@ func (c *ApiController) GetUserinfo() {
scope, aud := c.GetSessionOidc() scope, aud := c.GetSessionOidc()
host := c.Ctx.Request.Host host := c.Ctx.Request.Host
userInfo := object.GetUserInfo(user, scope, aud, host)
userInfo, err := object.GetUserInfo(user, scope, aud, host)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = userInfo c.Data["json"] = userInfo
c.ServeJSON() c.ServeJSON()
@ -563,12 +514,10 @@ func (c *ApiController) GetCaptcha() {
return return
} }
c.ResponseOk(Captcha{Owner: captchaProvider.Owner, Name: captchaProvider.Name, Type: captchaProvider.Type, CaptchaId: id, CaptchaImage: img}) c.ResponseOk(Captcha{Type: captchaProvider.Type, CaptchaId: id, CaptchaImage: img})
return return
} else if captchaProvider.Type != "" { } else if captchaProvider.Type != "" {
c.ResponseOk(Captcha{ c.ResponseOk(Captcha{
Owner: captchaProvider.Owner,
Name: captchaProvider.Name,
Type: captchaProvider.Type, Type: captchaProvider.Type,
SubType: captchaProvider.SubType, SubType: captchaProvider.SubType,
ClientId: captchaProvider.ClientId, ClientId: captchaProvider.ClientId,

View File

@ -110,9 +110,6 @@ func (c *ApiController) GetApplication() {
} }
} }
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
object.CheckEntryIp(clientIp, nil, application, nil, c.GetAcceptLanguage())
c.ResponseOk(object.GetMaskedApplication(application, userId)) c.ResponseOk(object.GetMaskedApplication(application, userId))
} }
@ -180,7 +177,7 @@ func (c *ApiController) GetOrganizationApplications() {
return return
} }
applications, err = object.GetAllowedApplications(applications, userId, c.GetAcceptLanguage()) applications, err = object.GetAllowedApplications(applications, userId)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -197,19 +194,13 @@ func (c *ApiController) GetOrganizationApplications() {
} }
paginator := pagination.SetPaginator(c.Ctx, limit, count) paginator := pagination.SetPaginator(c.Ctx, limit, count)
applications, err := object.GetPaginationOrganizationApplications(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder) application, err := object.GetPaginationOrganizationApplications(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
applications, err = object.GetAllowedApplications(applications, userId, c.GetAcceptLanguage()) applications := object.GetMaskedApplications(application, userId)
if err != nil {
c.ResponseError(err.Error())
return
}
applications = object.GetMaskedApplications(applications, userId)
c.ResponseOk(applications, paginator.Nums()) c.ResponseOk(applications, paginator.Nums())
} }
} }
@ -232,11 +223,6 @@ func (c *ApiController) UpdateApplication() {
return return
} }
if err = object.CheckIpWhitelist(application.IpWhitelist, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application)) c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application))
c.ServeJSON() c.ServeJSON()
} }
@ -267,11 +253,6 @@ func (c *ApiController) AddApplication() {
return return
} }
if err = object.CheckIpWhitelist(application.IpWhitelist, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddApplication(&application)) c.Data["json"] = wrapActionResponse(object.AddApplication(&application))
c.ServeJSON() c.ServeJSON()
} }

View File

@ -22,14 +22,12 @@ import (
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"regexp"
"strconv" "strconv"
"strings" "strings"
"github.com/casdoor/casdoor/captcha" "github.com/casdoor/casdoor/captcha"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/form" "github.com/casdoor/casdoor/form"
"github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/idp" "github.com/casdoor/casdoor/idp"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/proxy" "github.com/casdoor/casdoor/proxy"
@ -55,20 +53,8 @@ func tokenToResponse(token *object.Token) *Response {
// HandleLoggedIn ... // HandleLoggedIn ...
func (c *ApiController) HandleLoggedIn(application *object.Application, user *object.User, form *form.AuthForm) (resp *Response) { func (c *ApiController) HandleLoggedIn(application *object.Application, user *object.User, form *form.AuthForm) (resp *Response) {
if user.IsForbidden {
c.ResponseError(c.T("check:The user is forbidden to sign in, please contact the administrator"))
return
}
userId := user.GetId() userId := user.GetId()
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
err := object.CheckEntryIp(clientIp, user, application, application.OrganizationObj, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
allowed, err := object.CheckLoginPermission(userId, application) allowed, err := object.CheckLoginPermission(userId, application)
if err != nil { if err != nil {
c.ResponseError(err.Error(), nil) c.ResponseError(err.Error(), nil)
@ -131,7 +117,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
if form.Type == ResponseTypeLogin { if form.Type == ResponseTypeLogin {
c.SetSessionUsername(userId) c.SetSessionUsername(userId)
util.LogInfo(c.Ctx, "API: [%s] signed in", userId) util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
resp = &Response{Status: "ok", Msg: "", Data: userId, Data2: user.NeedUpdatePassword} resp = &Response{Status: "ok", Msg: "", Data: userId}
} else if form.Type == ResponseTypeCode { } else if form.Type == ResponseTypeCode {
clientId := c.Input().Get("clientId") clientId := c.Input().Get("clientId")
responseType := c.Input().Get("responseType") responseType := c.Input().Get("responseType")
@ -153,7 +139,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
} }
resp = codeToResponse(code) resp = codeToResponse(code)
resp.Data2 = user.NeedUpdatePassword
if application.EnableSigninSession || application.HasPromptPage() { if application.EnableSigninSession || application.HasPromptPage() {
// The prompt page needs the user to be signed in // The prompt page needs the user to be signed in
c.SetSessionUsername(userId) c.SetSessionUsername(userId)
@ -166,8 +152,6 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
nonce := c.Input().Get("nonce") nonce := c.Input().Get("nonce")
token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host) token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host)
resp = tokenToResponse(token) resp = tokenToResponse(token)
resp.Data2 = user.NeedUpdatePassword
} }
} else if form.Type == ResponseTypeSaml { // saml flow } else if form.Type == ResponseTypeSaml { // saml flow
res, redirectUrl, method, err := object.GetSamlResponse(application, user, form.SamlRequest, c.Ctx.Request.Host) res, redirectUrl, method, err := object.GetSamlResponse(application, user, form.SamlRequest, c.Ctx.Request.Host)
@ -175,7 +159,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
c.ResponseError(err.Error(), nil) c.ResponseError(err.Error(), nil)
return return
} }
resp = &Response{Status: "ok", Msg: "", Data: res, Data2: map[string]interface{}{"redirectUrl": redirectUrl, "method": method, "needUpdatePassword": user.NeedUpdatePassword}} resp = &Response{Status: "ok", Msg: "", Data: res, Data2: map[string]string{"redirectUrl": redirectUrl, "method": method}}
if application.EnableSigninSession || application.HasPromptPage() { if application.EnableSigninSession || application.HasPromptPage() {
// The prompt page needs the user to be signed in // The prompt page needs the user to be signed in
@ -270,9 +254,6 @@ func (c *ApiController) GetApplicationLogin() {
} }
} }
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
object.CheckEntryIp(clientIp, nil, application, nil, c.GetAcceptLanguage())
application = object.GetMaskedApplication(application, "") application = object.GetMaskedApplication(application, "")
if msg != "" { if msg != "" {
c.ResponseError(msg, application) c.ResponseError(msg, application)
@ -312,35 +293,6 @@ func isProxyProviderType(providerType string) bool {
return false return false
} }
func checkMfaEnable(c *ApiController, user *object.User, organization *object.Organization, verificationType string) bool {
if object.IsNeedPromptMfa(organization, user) {
// The prompt page needs the user to be srigned in
c.SetSessionUsername(user.GetId())
c.ResponseOk(object.RequiredMfa)
return true
}
if user.IsMfaEnabled() {
c.setMfaUserSession(user.GetId())
mfaList := object.GetAllMfaProps(user, true)
mfaAllowList := []*object.MfaProps{}
for _, prop := range mfaList {
if prop.MfaType == verificationType || !prop.Enabled {
continue
}
mfaAllowList = append(mfaAllowList, prop)
}
if len(mfaAllowList) >= 1 {
c.SetSession("verificationCodeType", verificationType)
c.Ctx.Input.CruSession.SessionRelease(c.Ctx.ResponseWriter)
c.ResponseOk(object.NextMfa, mfaAllowList)
return true
}
}
return false
}
// Login ... // Login ...
// @Title Login // @Title Login
// @Tag Login API // @Tag Login API
@ -366,8 +318,6 @@ func (c *ApiController) Login() {
return return
} }
verificationType := ""
if authForm.Username != "" { if authForm.Username != "" {
if authForm.Type == ResponseTypeLogin { if authForm.Type == ResponseTypeLogin {
if c.GetSessionUsername() != "" { if c.GetSessionUsername() != "" {
@ -377,54 +327,7 @@ func (c *ApiController) Login() {
} }
var user *object.User var user *object.User
if authForm.SigninMethod == "Face ID" { if authForm.Password == "" {
if user, err = object.GetUserByFields(authForm.Organization, authForm.Username); err != nil {
c.ResponseError(err.Error(), nil)
return
} else if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(authForm.Organization, authForm.Username)))
return
}
var application *object.Application
application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
if err != nil {
c.ResponseError(err.Error(), nil)
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
return
}
if !application.IsFaceIdEnabled() {
c.ResponseError(c.T("auth:The login method: login with face is not enabled for the application"))
return
}
faceIdProvider, err := object.GetFaceIdProviderByApplication(util.GetId(application.Owner, application.Name), "false", c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
}
if faceIdProvider == nil {
if err := object.CheckFaceId(user, authForm.FaceId, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error(), nil)
return
}
} else {
ok, err := user.CheckUserFace(authForm.FaceIdImage, faceIdProvider)
if err != nil {
c.ResponseError(err.Error(), nil)
}
if !ok {
c.ResponseError(i18n.Translate(c.GetAcceptLanguage(), "check:Face data does not exist, cannot log in"))
return
}
}
} else if authForm.Password == "" {
if user, err = object.GetUserByFields(authForm.Organization, authForm.Username); err != nil { if user, err = object.GetUserByFields(authForm.Organization, authForm.Username); err != nil {
c.ResponseError(err.Error(), nil) c.ResponseError(err.Error(), nil)
return return
@ -478,12 +381,6 @@ func (c *ApiController) Login() {
c.ResponseError(err.Error(), nil) c.ResponseError(err.Error(), nil)
return return
} }
if verificationCodeType == object.VerifyTypePhone {
verificationType = "sms"
} else {
verificationType = "email"
}
} else { } else {
var application *object.Application var application *object.Application
application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application)) application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
@ -533,15 +430,6 @@ func (c *ApiController) Login() {
} }
password := authForm.Password password := authForm.Password
if application.OrganizationObj != nil {
password, err = util.GetUnobfuscatedPassword(application.OrganizationObj.PasswordObfuscatorType, application.OrganizationObj.PasswordObfuscatorKey, authForm.Password)
if err != nil {
c.ResponseError(err.Error())
return
}
}
isSigninViaLdap := authForm.SigninMethod == "LDAP" isSigninViaLdap := authForm.SigninMethod == "LDAP"
var isPasswordWithLdapEnabled bool var isPasswordWithLdapEnabled bool
if authForm.SigninMethod == "Password" { if authForm.SigninMethod == "Password" {
@ -574,13 +462,25 @@ func (c *ApiController) Login() {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
} }
if checkMfaEnable(c, user, organization, verificationType) { if object.IsNeedPromptMfa(organization, user) {
// The prompt page needs the user to be signed in
c.SetSessionUsername(user.GetId())
c.ResponseOk(object.RequiredMfa)
return
}
if user.IsMfaEnabled() {
c.setMfaUserSession(user.GetId())
c.ResponseOk(object.NextMfa, user.GetPreferredMfaProps(true))
return return
} }
resp = c.HandleLoggedIn(application, user, &authForm) resp = c.HandleLoggedIn(application, user, &authForm)
c.Ctx.Input.SetParam("recordUserId", user.GetId()) record := object.NewRecord(c.Ctx)
record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
} }
} else if authForm.Provider != "" { } else if authForm.Provider != "" {
var application *object.Application var application *object.Application
@ -615,9 +515,6 @@ func (c *ApiController) Login() {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
if provider == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The provider: %s does not exist"), authForm.Provider))
}
providerItem := application.GetProviderItem(provider.Name) providerItem := application.GetProviderItem(provider.Name)
if !providerItem.IsProviderVisible() { if !providerItem.IsProviderVisible() {
@ -671,17 +568,6 @@ func (c *ApiController) Login() {
c.ResponseError(fmt.Sprintf(c.T("auth:Failed to login in: %s"), err.Error())) c.ResponseError(fmt.Sprintf(c.T("auth:Failed to login in: %s"), err.Error()))
return return
} }
if provider.EmailRegex != "" {
reg, err := regexp.Compile(provider.EmailRegex)
if err != nil {
c.ResponseError(fmt.Sprintf(c.T("auth:Failed to login in: %s"), err.Error()))
return
}
if !reg.MatchString(userInfo.Email) {
c.ResponseError(fmt.Sprintf(c.T("check:Email is invalid")))
}
}
} }
if authForm.Method == "signup" { if authForm.Method == "signup" {
@ -703,20 +589,22 @@ func (c *ApiController) Login() {
if user != nil && !user.IsDeleted { if user != nil && !user.IsDeleted {
// Sign in via OAuth (want to sign up but already have account) // Sign in via OAuth (want to sign up but already have account)
if user.IsForbidden {
c.ResponseError(c.T("check:The user is forbidden to sign in, please contact the administrator"))
}
// sync info from 3rd-party if possible // sync info from 3rd-party if possible
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo) _, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
if checkMfaEnable(c, user, organization, verificationType) {
return
}
resp = c.HandleLoggedIn(application, user, &authForm) resp = c.HandleLoggedIn(application, user, &authForm)
c.Ctx.Input.SetParam("recordUserId", user.GetId()) record := object.NewRecord(c.Ctx)
record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
} else if provider.Category == "OAuth" || provider.Category == "Web3" { } else if provider.Category == "OAuth" || provider.Category == "Web3" {
// Sign up via OAuth // Sign up via OAuth
if application.EnableLinkWithEmail { if application.EnableLinkWithEmail {
@ -750,11 +638,6 @@ func (c *ApiController) Login() {
return return
} }
if application.IsSignupItemRequired("Invitation code") {
c.ResponseError(c.T("check:Invitation code cannot be blank"))
return
}
// Handle username conflicts // Handle username conflicts
var tmpUser *object.User var tmpUser *object.User
tmpUser, err = object.GetUser(util.GetId(application.Organization, userInfo.Username)) tmpUser, err = object.GetUser(util.GetId(application.Organization, userInfo.Username))
@ -854,8 +737,16 @@ func (c *ApiController) Login() {
resp = c.HandleLoggedIn(application, user, &authForm) resp = c.HandleLoggedIn(application, user, &authForm)
c.Ctx.Input.SetParam("recordUserId", user.GetId()) record := object.NewRecord(c.Ctx)
c.Ctx.Input.SetParam("recordSignup", "true") record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
record2 := object.NewRecord(c.Ctx)
record2.Action = "signup"
record2.Organization = application.Organization
record2.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record2) })
} else if provider.Category == "SAML" { } else if provider.Category == "SAML" {
// TODO: since we get the user info from SAML response, we can try to create the user // TODO: since we get the user info from SAML response, we can try to create the user
resp = &Response{Status: "error", Msg: fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(application.Organization, userInfo.Id))} resp = &Response{Status: "error", Msg: fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(application.Organization, userInfo.Id))}
@ -920,32 +811,17 @@ func (c *ApiController) Login() {
} }
if authForm.Passcode != "" { if authForm.Passcode != "" {
if authForm.MfaType == c.GetSession("verificationCodeType") { mfaUtil := object.GetMfaUtil(authForm.MfaType, user.GetPreferredMfaProps(false))
c.ResponseError("Invalid multi-factor authentication type")
return
}
user.CountryCode = user.GetCountryCode(user.CountryCode)
mfaUtil := object.GetMfaUtil(authForm.MfaType, user.GetMfaProps(authForm.MfaType, false))
if mfaUtil == nil { if mfaUtil == nil {
c.ResponseError("Invalid multi-factor authentication type") c.ResponseError("Invalid multi-factor authentication type")
return return
} }
passed, err := c.checkOrgMasterVerificationCode(user, authForm.Passcode) err = mfaUtil.Verify(authForm.Passcode)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
if !passed {
err = mfaUtil.Verify(authForm.Passcode)
if err != nil {
c.ResponseError(err.Error())
return
}
}
c.SetSession("verificationCodeType", "")
} else if authForm.RecoveryCode != "" { } else if authForm.RecoveryCode != "" {
err = object.MfaRecover(user, authForm.RecoveryCode) err = object.MfaRecover(user, authForm.RecoveryCode)
if err != nil { if err != nil {
@ -958,11 +834,7 @@ func (c *ApiController) Login() {
} }
var application *object.Application var application *object.Application
if authForm.ClientId == "" { application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
} else {
application, err = object.GetApplicationByClientId(authForm.ClientId)
}
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -976,7 +848,10 @@ func (c *ApiController) Login() {
resp = c.HandleLoggedIn(application, user, &authForm) resp = c.HandleLoggedIn(application, user, &authForm)
c.setMfaUserSession("") c.setMfaUserSession("")
c.Ctx.Input.SetParam("recordUserId", user.GetId()) record := object.NewRecord(c.Ctx)
record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
} else { } else {
if c.GetSessionUsername() != "" { if c.GetSessionUsername() != "" {
// user already signed in to Casdoor, so let the user click the avatar button to do the quick sign-in // user already signed in to Casdoor, so let the user click the avatar button to do the quick sign-in
@ -992,32 +867,19 @@ func (c *ApiController) Login() {
return return
} }
if authForm.Provider == "" {
authForm.Provider = authForm.ProviderBack
}
user := c.getCurrentUser() user := c.getCurrentUser()
resp = c.HandleLoggedIn(application, user, &authForm) resp = c.HandleLoggedIn(application, user, &authForm)
c.Ctx.Input.SetParam("recordUserId", user.GetId()) record := object.NewRecord(c.Ctx)
record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
} else { } else {
c.ResponseError(fmt.Sprintf(c.T("auth:Unknown authentication type (not password or provider), form = %s"), util.StructToJson(authForm))) c.ResponseError(fmt.Sprintf(c.T("auth:Unknown authentication type (not password or provider), form = %s"), util.StructToJson(authForm)))
return return
} }
} }
if authForm.Language != "" {
user := c.getCurrentUser()
if user != nil {
user.Language = authForm.Language
_, err = object.UpdateUser(user.GetId(), user, []string{"language"}, user.IsAdmin)
if err != nil {
c.ResponseError(err.Error())
return
}
}
}
c.Data["json"] = resp c.Data["json"] = resp
c.ServeJSON() c.ServeJSON()
} }

View File

@ -73,7 +73,7 @@ func (c *ApiController) IsAdminOrSelf(user2 *object.User) bool {
func (c *ApiController) isGlobalAdmin() (bool, *object.User) { func (c *ApiController) isGlobalAdmin() (bool, *object.User) {
username := c.GetSessionUsername() username := c.GetSessionUsername()
if object.IsAppUser(username) { if strings.HasPrefix(username, "app/") {
// e.g., "app/app-casnode" // e.g., "app/app-casnode"
return true, nil return true, nil
} }
@ -122,15 +122,6 @@ func (c *ApiController) GetSessionUsername() string {
return user.(string) return user.(string)
} }
func (c *ApiController) GetSessionToken() string {
accessToken := c.GetSession("accessToken")
if accessToken == nil {
return ""
}
return accessToken.(string)
}
func (c *ApiController) GetSessionApplication() *object.Application { func (c *ApiController) GetSessionApplication() *object.Application {
clientId := c.GetSession("aud") clientId := c.GetSession("aud")
if clientId == nil { if clientId == nil {
@ -150,10 +141,6 @@ func (c *ApiController) ClearUserSession() {
c.SetSessionData(nil) c.SetSessionData(nil)
} }
func (c *ApiController) ClearTokenSession() {
c.SetSessionToken("")
}
func (c *ApiController) GetSessionOidc() (string, string) { func (c *ApiController) GetSessionOidc() (string, string) {
sessionData := c.GetSessionData() sessionData := c.GetSessionData()
if sessionData != nil && if sessionData != nil &&
@ -180,10 +167,6 @@ func (c *ApiController) SetSessionUsername(user string) {
c.SetSession("username", user) c.SetSession("username", user)
} }
func (c *ApiController) SetSessionToken(accessToken string) {
c.SetSession("accessToken", accessToken)
}
// GetSessionData ... // GetSessionData ...
func (c *ApiController) GetSessionData() *SessionData { func (c *ApiController) GetSessionData() *SessionData {
session := c.GetSession("SessionData") session := c.GetSession("SessionData")

View File

@ -1,247 +0,0 @@
// 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"
"os"
"os/exec"
"sort"
"strings"
"sync"
"time"
)
type CLIVersionInfo struct {
Version string
BinaryPath string
BinaryTime time.Time
}
var (
cliVersionCache = make(map[string]*CLIVersionInfo)
cliVersionMutex sync.RWMutex
)
// getCLIVersion
// @Title getCLIVersion
// @Description Get CLI version with cache mechanism
// @Param language string The language of CLI (go/java/rust etc.)
// @Return string The version string of CLI
// @Return error Error if CLI execution fails
func getCLIVersion(language string) (string, error) {
binaryName := fmt.Sprintf("casbin-%s-cli", language)
binaryPath, err := exec.LookPath(binaryName)
if err != nil {
return "", fmt.Errorf("executable file not found: %v", err)
}
fileInfo, err := os.Stat(binaryPath)
if err != nil {
return "", fmt.Errorf("failed to get binary info: %v", err)
}
cliVersionMutex.RLock()
if info, exists := cliVersionCache[language]; exists {
if info.BinaryPath == binaryPath && info.BinaryTime == fileInfo.ModTime() {
cliVersionMutex.RUnlock()
return info.Version, nil
}
}
cliVersionMutex.RUnlock()
cmd := exec.Command(binaryName, "--version")
output, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("failed to get CLI version: %v", err)
}
version := strings.TrimSpace(string(output))
cliVersionMutex.Lock()
cliVersionCache[language] = &CLIVersionInfo{
Version: version,
BinaryPath: binaryPath,
BinaryTime: fileInfo.ModTime(),
}
cliVersionMutex.Unlock()
return version, nil
}
func processArgsToTempFiles(args []string) ([]string, []string, error) {
tempFiles := []string{}
newArgs := []string{}
for i := 0; i < len(args); i++ {
if (args[i] == "-m" || args[i] == "-p") && i+1 < len(args) {
pattern := fmt.Sprintf("casbin_temp_%s_*.conf", args[i])
tempFile, err := os.CreateTemp("", pattern)
if err != nil {
return nil, nil, fmt.Errorf("failed to create temp file: %v", err)
}
_, err = tempFile.WriteString(args[i+1])
if err != nil {
tempFile.Close()
return nil, nil, fmt.Errorf("failed to write to temp file: %v", err)
}
tempFile.Close()
tempFiles = append(tempFiles, tempFile.Name())
newArgs = append(newArgs, args[i], tempFile.Name())
i++
} else {
newArgs = append(newArgs, args[i])
}
}
return tempFiles, newArgs, nil
}
// RunCasbinCommand
// @Title RunCasbinCommand
// @Tag Enforcer API
// @Description Call Casbin CLI commands
// @Success 200 {object} controllers.Response The Response object
// @router /run-casbin-command [get]
func (c *ApiController) RunCasbinCommand() {
if err := validateIdentifier(c); err != nil {
c.ResponseError(err.Error())
return
}
language := c.Input().Get("language")
argString := c.Input().Get("args")
if language == "" {
language = "go"
}
// use "casbin-go-cli" by default, can be also "casbin-java-cli", "casbin-node-cli", etc.
// the pre-built binary of "casbin-go-cli" can be found at: https://github.com/casbin/casbin-go-cli/releases
binaryName := fmt.Sprintf("casbin-%s-cli", language)
_, err := exec.LookPath(binaryName)
if err != nil {
c.ResponseError(fmt.Sprintf("executable file: %s not found in PATH", binaryName))
return
}
// RBAC model & policy example:
// https://door.casdoor.com/api/run-casbin-command?language=go&args=["enforce", "-m", "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n[matchers]\nm = g(r.sub, p.sub) %26%26 r.obj == p.obj %26%26 r.act == p.act", "-p", "p, alice, data1, read\np, bob, data2, write\np, data2_admin, data2, read\np, data2_admin, data2, write\ng, alice, data2_admin", "alice", "data1", "read"]
// Casbin CLI usage:
// https://github.com/jcasbin/casbin-java-cli?tab=readme-ov-file#get-started
var args []string
err = json.Unmarshal([]byte(argString), &args)
if err != nil {
c.ResponseError(err.Error())
return
}
if len(args) > 0 && args[0] == "--version" {
version, err := getCLIVersion(language)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(version)
return
}
tempFiles, processedArgs, err := processArgsToTempFiles(args)
defer func() {
for _, file := range tempFiles {
os.Remove(file)
}
}()
if err != nil {
c.ResponseError(err.Error())
return
}
command := exec.Command(binaryName, processedArgs...)
outputBytes, err := command.CombinedOutput()
if err != nil {
errorString := err.Error()
if outputBytes != nil {
output := string(outputBytes)
errorString = fmt.Sprintf("%s, error: %s", output, err.Error())
}
c.ResponseError(errorString)
return
}
output := string(outputBytes)
output = strings.TrimSuffix(output, "\n")
c.ResponseOk(output)
}
// validateIdentifier
// @Title validateIdentifier
// @Description Validate the request hash and timestamp
// @Param hash string The SHA-256 hash string
// @Return error Returns error if validation fails, nil if successful
func validateIdentifier(c *ApiController) error {
language := c.Input().Get("language")
args := c.Input().Get("args")
hash := c.Input().Get("m")
timestamp := c.Input().Get("t")
if hash == "" || timestamp == "" || language == "" || args == "" {
return fmt.Errorf("invalid identifier")
}
requestTime, err := time.Parse(time.RFC3339, timestamp)
if err != nil {
return fmt.Errorf("invalid identifier")
}
timeDiff := time.Since(requestTime)
if timeDiff > 5*time.Minute || timeDiff < -5*time.Minute {
return fmt.Errorf("invalid identifier")
}
params := map[string]string{
"language": language,
"args": args,
}
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
var paramParts []string
for _, k := range keys {
paramParts = append(paramParts, fmt.Sprintf("%s=%s", k, params[k]))
}
paramString := strings.Join(paramParts, "&")
version := "casbin-editor-v1"
rawString := fmt.Sprintf("%s|%s|%s", version, timestamp, paramString)
hasher := sha256.New()
hasher.Write([]byte(rawString))
calculatedHash := strings.ToLower(hex.EncodeToString(hasher.Sum(nil)))
if calculatedHash != strings.ToLower(hash) {
return fmt.Errorf("invalid identifier")
}
return nil
}

View File

@ -68,7 +68,7 @@ func (c *ApiController) GetCerts() {
// GetGlobalCerts // GetGlobalCerts
// @Title GetGlobalCerts // @Title GetGlobalCerts
// @Tag Cert API // @Tag Cert API
// @Description get global certs // @Description get globle certs
// @Success 200 {array} object.Cert The Response object // @Success 200 {array} object.Cert The Response object
// @router /get-global-certs [get] // @router /get-global-certs [get]
func (c *ApiController) GetGlobalCerts() { func (c *ApiController) GetGlobalCerts() {

View File

@ -1,519 +0,0 @@
package controllers
import (
"archive/tar"
"archive/zip"
"compress/gzip"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/beego/beego"
"github.com/casdoor/casdoor/proxy"
"github.com/casdoor/casdoor/util"
)
const (
javaCliRepo = "https://api.github.com/repos/jcasbin/casbin-java-cli/releases/latest"
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"
downloadFolder = "bin"
)
type ReleaseInfo struct {
TagName string `json:"tag_name"`
Assets []struct {
Name string `json:"name"`
URL string `json:"browser_download_url"`
} `json:"assets"`
}
// @Title getBinaryNames
// @Description Get binary names for different platforms and architectures
// @Success 200 {map[string]string} map[string]string "Binary names map"
func getBinaryNames() map[string]string {
const (
golang = "go"
java = "java"
rust = "rust"
)
arch := runtime.GOARCH
archMap := map[string]struct{ goArch, rustArch string }{
"amd64": {"x86_64", "x86_64"},
"arm64": {"arm64", "aarch64"},
}
archNames, ok := archMap[arch]
if !ok {
archNames = struct{ goArch, rustArch string }{arch, arch}
}
switch runtime.GOOS {
case "windows":
return map[string]string{
golang: fmt.Sprintf("casbin-go-cli_Windows_%s.zip", archNames.goArch),
java: "casbin-java-cli.jar",
rust: fmt.Sprintf("casbin-rust-cli-%s-pc-windows-gnu", archNames.rustArch),
}
case "darwin":
return map[string]string{
golang: fmt.Sprintf("casbin-go-cli_Darwin_%s.tar.gz", archNames.goArch),
java: "casbin-java-cli.jar",
rust: fmt.Sprintf("casbin-rust-cli-%s-apple-darwin", archNames.rustArch),
}
case "linux":
return map[string]string{
golang: fmt.Sprintf("casbin-go-cli_Linux_%s.tar.gz", archNames.goArch),
java: "casbin-java-cli.jar",
rust: fmt.Sprintf("casbin-rust-cli-%s-unknown-linux-gnu", archNames.rustArch),
}
default:
return nil
}
}
// @Title getFinalBinaryName
// @Description Get final binary name for specific language
// @Param lang string true "Language type (go/java/rust)"
// @Success 200 {string} string "Final binary name"
func getFinalBinaryName(lang string) string {
switch lang {
case "go":
if runtime.GOOS == "windows" {
return "casbin-go-cli.exe"
}
return "casbin-go-cli"
case "java":
return "casbin-java-cli.jar"
case "rust":
if runtime.GOOS == "windows" {
return "casbin-rust-cli.exe"
}
return "casbin-rust-cli"
default:
return ""
}
}
// @Title getLatestCLIURL
// @Description Get latest CLI download URL from GitHub
// @Param repoURL string true "GitHub repository URL"
// @Param language string true "Language type"
// @Success 200 {string} string "Download URL and version"
func getLatestCLIURL(repoURL string, language string) (string, string, error) {
client := proxy.GetHttpClient(repoURL)
resp, err := client.Get(repoURL)
if err != nil {
return "", "", fmt.Errorf("failed to fetch release info: %v", err)
}
defer resp.Body.Close()
var release ReleaseInfo
if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
return "", "", err
}
binaryNames := getBinaryNames()
if binaryNames == nil {
return "", "", fmt.Errorf("unsupported OS: %s", runtime.GOOS)
}
binaryName := binaryNames[language]
for _, asset := range release.Assets {
if asset.Name == binaryName {
return asset.URL, release.TagName, nil
}
}
return "", "", fmt.Errorf("no suitable binary found for OS: %s, language: %s", runtime.GOOS, language)
}
// @Title extractGoCliFile
// @Description Extract the Go CLI file
// @Param filePath string true "The file path"
// @Success 200 {string} string "The extracted file path"
// @router /extractGoCliFile [post]
func extractGoCliFile(filePath string) error {
tempDir := filepath.Join(downloadFolder, "temp")
if err := os.MkdirAll(tempDir, 0o755); err != nil {
return err
}
defer os.RemoveAll(tempDir)
if runtime.GOOS == "windows" {
if err := unzipFile(filePath, tempDir); err != nil {
return err
}
} else {
if err := untarFile(filePath, tempDir); err != nil {
return err
}
}
execName := "casbin-go-cli"
if runtime.GOOS == "windows" {
execName += ".exe"
}
var execPath string
err := filepath.Walk(tempDir, func(path string, info os.FileInfo, err error) error {
if info.Name() == execName {
execPath = path
return nil
}
return nil
})
if err != nil {
return err
}
finalPath := filepath.Join(downloadFolder, execName)
if err := os.Rename(execPath, finalPath); err != nil {
return err
}
return os.Remove(filePath)
}
// @Title unzipFile
// @Description Unzip the file
// @Param zipPath string true "The zip file path"
// @Param destDir string true "The destination directory"
// @Success 200 {string} string "The extracted file path"
// @router /unzipFile [post]
func unzipFile(zipPath, destDir string) error {
r, err := zip.OpenReader(zipPath)
if err != nil {
return err
}
defer r.Close()
for _, f := range r.File {
fpath := filepath.Join(destDir, f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(fpath, os.ModePerm)
continue
}
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
return err
}
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
rc, err := f.Open()
if err != nil {
outFile.Close()
return err
}
_, err = io.Copy(outFile, rc)
outFile.Close()
rc.Close()
if err != nil {
return err
}
}
return nil
}
// @Title untarFile
// @Description Untar the file
// @Param tarPath string true "The tar file path"
// @Param destDir string true "The destination directory"
// @Success 200 {string} string "The extracted file path"
// @router /untarFile [post]
func untarFile(tarPath, destDir string) error {
file, err := os.Open(tarPath)
if err != nil {
return err
}
defer file.Close()
gzr, err := gzip.NewReader(file)
if err != nil {
return err
}
defer gzr.Close()
tr := tar.NewReader(gzr)
for {
header, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
path := filepath.Join(destDir, header.Name)
switch header.Typeflag {
case tar.TypeDir:
if err := os.MkdirAll(path, 0o755); err != nil {
return err
}
case tar.TypeReg:
outFile, err := os.Create(path)
if err != nil {
return err
}
if _, err := io.Copy(outFile, tr); err != nil {
outFile.Close()
return err
}
outFile.Close()
}
}
return nil
}
// @Title createJavaCliWrapper
// @Description Create the Java CLI wrapper
// @Param binPath string true "The binary path"
// @Success 200 {string} string "The created file path"
// @router /createJavaCliWrapper [post]
func createJavaCliWrapper(binPath string) error {
if runtime.GOOS == "windows" {
// Create a Windows CMD file
cmdPath := filepath.Join(binPath, "casbin-java-cli.cmd")
cmdContent := fmt.Sprintf(`@echo off
java -jar "%s\casbin-java-cli.jar" %%*`, binPath)
err := os.WriteFile(cmdPath, []byte(cmdContent), 0o755)
if err != nil {
return fmt.Errorf("failed to create Java CLI wrapper: %v", err)
}
} else {
// Create Unix shell script
shPath := filepath.Join(binPath, "casbin-java-cli")
shContent := fmt.Sprintf(`#!/bin/sh
java -jar "%s/casbin-java-cli.jar" "$@"`, binPath)
err := os.WriteFile(shPath, []byte(shContent), 0o755)
if err != nil {
return fmt.Errorf("failed to create Java CLI wrapper: %v", err)
}
}
return nil
}
// @Title downloadCLI
// @Description Download and setup CLI tools
// @Success 200 {error} error "Error if any"
func downloadCLI() error {
pathEnv := os.Getenv("PATH")
binPath, err := filepath.Abs(downloadFolder)
if err != nil {
return fmt.Errorf("failed to get absolute path to download directory: %v", err)
}
if !strings.Contains(pathEnv, binPath) {
newPath := fmt.Sprintf("%s%s%s", binPath, string(os.PathListSeparator), pathEnv)
if err := os.Setenv("PATH", newPath); err != nil {
return fmt.Errorf("failed to update PATH environment variable: %v", err)
}
}
if err := os.MkdirAll(downloadFolder, 0o755); err != nil {
return fmt.Errorf("failed to create download directory: %v", err)
}
repos := map[string]string{
"java": javaCliRepo,
"go": goCliRepo,
"rust": rustCliRepo,
}
for lang, repo := range repos {
cliURL, version, err := getLatestCLIURL(repo, lang)
if err != nil {
fmt.Printf("failed to get %s CLI URL: %v\n", lang, err)
continue
}
originalPath := filepath.Join(downloadFolder, getBinaryNames()[lang])
fmt.Printf("downloading %s CLI: %s\n", lang, cliURL)
client := proxy.GetHttpClient(cliURL)
resp, err := client.Get(cliURL)
if err != nil {
fmt.Printf("failed to download %s CLI: %v\n", lang, err)
continue
}
func() {
defer resp.Body.Close()
if err := os.MkdirAll(filepath.Dir(originalPath), 0o755); err != nil {
fmt.Printf("failed to create directory for %s CLI: %v\n", lang, err)
return
}
tmpFile := originalPath + ".tmp"
out, err := os.Create(tmpFile)
if err != nil {
fmt.Printf("failed to create or write %s CLI: %v\n", lang, err)
return
}
defer func() {
out.Close()
os.Remove(tmpFile)
}()
if _, err = io.Copy(out, resp.Body); err != nil ||
out.Close() != nil ||
os.Rename(tmpFile, originalPath) != nil {
fmt.Printf("failed to download %s CLI: %v\n", lang, err)
return
}
}()
if lang == "go" {
if err := extractGoCliFile(originalPath); err != nil {
fmt.Printf("failed to extract Go CLI: %v\n", err)
continue
}
} else {
finalPath := filepath.Join(downloadFolder, getFinalBinaryName(lang))
if err := os.Rename(originalPath, finalPath); err != nil {
fmt.Printf("failed to rename %s CLI: %v\n", lang, err)
continue
}
}
if runtime.GOOS != "windows" {
execPath := filepath.Join(downloadFolder, getFinalBinaryName(lang))
if err := os.Chmod(execPath, 0o755); err != nil {
fmt.Printf("failed to set %s CLI execution permission: %v\n", lang, err)
continue
}
}
fmt.Printf("downloaded %s CLI version: %s\n", lang, version)
if lang == "java" {
if err := createJavaCliWrapper(binPath); err != nil {
fmt.Printf("failed to create Java CLI wrapper: %v\n", err)
continue
}
}
}
return nil
}
// @Title RefreshEngines
// @Tag CLI API
// @Description Refresh all CLI engines
// @Param m query string true "Hash for request validation"
// @Param t query string true "Timestamp for request validation"
// @Success 200 {object} controllers.Response The Response object
// @router /refresh-engines [post]
func (c *ApiController) RefreshEngines() {
if !beego.AppConfig.DefaultBool("isDemoMode", false) {
c.ResponseError("refresh engines is only available in demo mode")
return
}
hash := c.Input().Get("m")
timestamp := c.Input().Get("t")
if hash == "" || timestamp == "" {
c.ResponseError("invalid identifier")
return
}
requestTime, err := time.Parse(time.RFC3339, timestamp)
if err != nil {
c.ResponseError("invalid identifier")
return
}
timeDiff := time.Since(requestTime)
if timeDiff > 5*time.Minute || timeDiff < -5*time.Minute {
c.ResponseError("invalid identifier")
return
}
version := "casbin-editor-v1"
rawString := fmt.Sprintf("%s|%s", version, timestamp)
hasher := sha256.New()
hasher.Write([]byte(rawString))
calculatedHash := strings.ToLower(hex.EncodeToString(hasher.Sum(nil)))
if calculatedHash != strings.ToLower(hash) {
c.ResponseError("invalid identifier")
return
}
err = downloadCLI()
if err != nil {
c.ResponseError(fmt.Sprintf("failed to refresh engines: %v", err))
return
}
c.ResponseOk(map[string]string{
"status": "success",
"message": "CLI engines updated successfully",
})
}
// @Title ScheduleCLIUpdater
// @Description Start periodic CLI update scheduler
func ScheduleCLIUpdater() {
if !beego.AppConfig.DefaultBool("isDemoMode", false) {
return
}
ticker := time.NewTicker(1 * time.Hour)
defer ticker.Stop()
for range ticker.C {
err := downloadCLI()
if err != nil {
fmt.Printf("failed to update CLI: %v\n", err)
} else {
fmt.Println("CLI updated successfully")
}
}
}
// @Title DownloadCLI
// @Description Download the CLI
// @Success 200 {string} string "The downloaded file path"
// @router /downloadCLI [post]
func DownloadCLI() error {
return downloadCLI()
}
// @Title InitCLIDownloader
// @Description Initialize CLI downloader and start update scheduler
func InitCLIDownloader() {
if !beego.AppConfig.DefaultBool("isDemoMode", false) {
return
}
util.SafeGoroutine(func() {
err := DownloadCLI()
if err != nil {
fmt.Printf("failed to initialize CLI downloader: %v\n", err)
}
ScheduleCLIUpdater()
})
}

View File

@ -16,7 +16,6 @@ package controllers
import ( import (
"encoding/json" "encoding/json"
"fmt"
"github.com/beego/beego/utils/pagination" "github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
@ -164,17 +163,11 @@ func (c *ApiController) GetPolicies() {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
if adapter == nil {
c.ResponseError(fmt.Sprintf(c.T("the adapter: %s is not found"), adapterId))
return
}
err = adapter.InitAdapter() err = adapter.InitAdapter()
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
c.ResponseOk() c.ResponseOk()
return return
} }

View File

@ -1,55 +0,0 @@
// 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.
// Casdoor will expose its providers as services to SDK
// We are going to implement those services as APIs here
package controllers
import (
"fmt"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// FaceIDSigninBegin
// @Title FaceIDSigninBegin
// @Tag Login API
// @Description FaceId Login Flow 1st stage
// @Param owner query string true "owner"
// @Param name query string true "name"
// @Success 200 {object} controllers.Response The Response object
// @router /faceid-signin-begin [get]
func (c *ApiController) FaceIDSigninBegin() {
userOwner := c.Input().Get("owner")
userName := c.Input().Get("name")
user, err := object.GetUserByFields(userOwner, userName)
if err != nil {
c.ResponseError(err.Error())
return
}
if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(userOwner, userName)))
return
}
if len(user.FaceIds) == 0 {
c.ResponseError(c.T("check:Face data does not exist, cannot log in"))
return
}
c.ResponseOk()
}

View File

@ -43,20 +43,13 @@ func (c *ApiController) GetGroups() {
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} else {
if withTree == "true" {
c.ResponseOk(object.ConvertToTreeData(groups, owner))
return
}
c.ResponseOk(groups)
} }
err = object.ExtendGroupsWithUsers(groups)
if err != nil {
c.ResponseError(err.Error())
return
}
if withTree == "true" {
c.ResponseOk(object.ConvertToTreeData(groups, owner))
return
}
c.ResponseOk(groups)
} else { } else {
limit := util.ParseInt(limit) limit := util.ParseInt(limit)
count, err := object.GetGroupCount(owner, field, value) count, err := object.GetGroupCount(owner, field, value)
@ -70,33 +63,9 @@ func (c *ApiController) GetGroups() {
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} else {
c.ResponseOk(groups, paginator.Nums())
} }
groupsHaveChildrenMap, err := object.GetGroupsHaveChildrenMap(groups)
if err != nil {
c.ResponseError(err.Error())
return
}
for _, group := range groups {
_, ok := groupsHaveChildrenMap[group.Name]
if ok {
group.HaveChildren = true
}
parent, ok := groupsHaveChildrenMap[group.ParentId]
if ok {
group.ParentName = parent.DisplayName
}
}
err = object.ExtendGroupsWithUsers(groups)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(groups, paginator.Nums())
} }
} }
@ -115,13 +84,6 @@ func (c *ApiController) GetGroup() {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
err = object.ExtendGroupWithUsers(group)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(group) c.ResponseOk(group)
} }

View File

@ -60,6 +60,7 @@ func (c *ApiController) Unlink() {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
if application == nil { if application == nil {
c.ResponseError(c.T("link:You can't unlink yourself, you are not a member of any application")) c.ResponseError(c.T("link:You can't unlink yourself, you are not a member of any application"))
return return

View File

@ -22,6 +22,13 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
) )
const (
MfaRecoveryCodesSession = "mfa_recovery_codes"
MfaCountryCodeSession = "mfa_country_code"
MfaDestSession = "mfa_dest"
MfaTotpSecretSession = "mfa_totp_secret"
)
// MfaSetupInitiate // MfaSetupInitiate
// @Title MfaSetupInitiate // @Title MfaSetupInitiate
// @Tag MFA API // @Tag MFA API
@ -65,6 +72,11 @@ func (c *ApiController) MfaSetupInitiate() {
} }
recoveryCode := uuid.NewString() recoveryCode := uuid.NewString()
c.SetSession(MfaRecoveryCodesSession, recoveryCode)
if mfaType == object.TotpType {
c.SetSession(MfaTotpSecretSession, mfaProps.Secret)
}
mfaProps.RecoveryCodes = []string{recoveryCode} mfaProps.RecoveryCodes = []string{recoveryCode}
resp := mfaProps resp := mfaProps
@ -82,9 +94,6 @@ func (c *ApiController) MfaSetupInitiate() {
func (c *ApiController) MfaSetupVerify() { func (c *ApiController) MfaSetupVerify() {
mfaType := c.Ctx.Request.Form.Get("mfaType") mfaType := c.Ctx.Request.Form.Get("mfaType")
passcode := c.Ctx.Request.Form.Get("passcode") passcode := c.Ctx.Request.Form.Get("passcode")
secret := c.Ctx.Request.Form.Get("secret")
dest := c.Ctx.Request.Form.Get("dest")
countryCode := c.Ctx.Request.Form.Get("countryCode")
if mfaType == "" || passcode == "" { if mfaType == "" || passcode == "" {
c.ResponseError("missing auth type or passcode") c.ResponseError("missing auth type or passcode")
@ -95,28 +104,32 @@ func (c *ApiController) MfaSetupVerify() {
MfaType: mfaType, MfaType: mfaType,
} }
if mfaType == object.TotpType { if mfaType == object.TotpType {
if secret == "" { secret := c.GetSession(MfaTotpSecretSession)
if secret == nil {
c.ResponseError("totp secret is missing") c.ResponseError("totp secret is missing")
return return
} }
config.Secret = secret config.Secret = secret.(string)
} else if mfaType == object.SmsType { } else if mfaType == object.SmsType {
if dest == "" { dest := c.GetSession(MfaDestSession)
if dest == nil {
c.ResponseError("destination is missing") c.ResponseError("destination is missing")
return return
} }
config.Secret = dest config.Secret = dest.(string)
if countryCode == "" { countryCode := c.GetSession(MfaCountryCodeSession)
if countryCode == nil {
c.ResponseError("country code is missing") c.ResponseError("country code is missing")
return return
} }
config.CountryCode = countryCode config.CountryCode = countryCode.(string)
} else if mfaType == object.EmailType { } else if mfaType == object.EmailType {
if dest == "" { dest := c.GetSession(MfaDestSession)
if dest == nil {
c.ResponseError("destination is missing") c.ResponseError("destination is missing")
return return
} }
config.Secret = dest config.Secret = dest.(string)
} }
mfaUtil := object.GetMfaUtil(mfaType, config) mfaUtil := object.GetMfaUtil(mfaType, config)
@ -146,10 +159,6 @@ func (c *ApiController) MfaSetupEnable() {
owner := c.Ctx.Request.Form.Get("owner") owner := c.Ctx.Request.Form.Get("owner")
name := c.Ctx.Request.Form.Get("name") name := c.Ctx.Request.Form.Get("name")
mfaType := c.Ctx.Request.Form.Get("mfaType") mfaType := c.Ctx.Request.Form.Get("mfaType")
secret := c.Ctx.Request.Form.Get("secret")
dest := c.Ctx.Request.Form.Get("dest")
countryCode := c.Ctx.Request.Form.Get("secret")
recoveryCodes := c.Ctx.Request.Form.Get("recoveryCodes")
user, err := object.GetUser(util.GetId(owner, name)) user, err := object.GetUser(util.GetId(owner, name))
if err != nil { if err != nil {
@ -167,39 +176,43 @@ func (c *ApiController) MfaSetupEnable() {
} }
if mfaType == object.TotpType { if mfaType == object.TotpType {
if secret == "" { secret := c.GetSession(MfaTotpSecretSession)
if secret == nil {
c.ResponseError("totp secret is missing") c.ResponseError("totp secret is missing")
return return
} }
config.Secret = secret config.Secret = secret.(string)
} else if mfaType == object.EmailType { } else if mfaType == object.EmailType {
if user.Email == "" { if user.Email == "" {
if dest == "" { dest := c.GetSession(MfaDestSession)
if dest == nil {
c.ResponseError("destination is missing") c.ResponseError("destination is missing")
return return
} }
user.Email = dest user.Email = dest.(string)
} }
} else if mfaType == object.SmsType { } else if mfaType == object.SmsType {
if user.Phone == "" { if user.Phone == "" {
if dest == "" { dest := c.GetSession(MfaDestSession)
if dest == nil {
c.ResponseError("destination is missing") c.ResponseError("destination is missing")
return return
} }
user.Phone = dest user.Phone = dest.(string)
if countryCode == "" { countryCode := c.GetSession(MfaCountryCodeSession)
if countryCode == nil {
c.ResponseError("country code is missing") c.ResponseError("country code is missing")
return return
} }
user.CountryCode = countryCode user.CountryCode = countryCode.(string)
} }
} }
recoveryCodes := c.GetSession(MfaRecoveryCodesSession)
if recoveryCodes == "" { if recoveryCodes == nil {
c.ResponseError("recovery codes is missing") c.ResponseError("recovery codes is missing")
return return
} }
config.RecoveryCodes = []string{recoveryCodes} config.RecoveryCodes = []string{recoveryCodes.(string)}
mfaUtil := object.GetMfaUtil(mfaType, config) mfaUtil := object.GetMfaUtil(mfaType, config)
if mfaUtil == nil { if mfaUtil == nil {
@ -213,6 +226,14 @@ func (c *ApiController) MfaSetupEnable() {
return return
} }
c.DelSession(MfaRecoveryCodesSession)
if mfaType == object.TotpType {
c.DelSession(MfaTotpSecretSession)
} else {
c.DelSession(MfaCountryCodeSession)
c.DelSession(MfaDestSession)
}
c.ResponseOk(http.StatusText(http.StatusOK)) c.ResponseOk(http.StatusText(http.StatusOK))
} }

View File

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

View File

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

View File

@ -17,7 +17,6 @@ package controllers
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strconv"
"github.com/beego/beego/utils/pagination" "github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
@ -165,16 +164,6 @@ func (c *ApiController) BuyProduct() {
host := c.Ctx.Request.Host host := c.Ctx.Request.Host
providerName := c.Input().Get("providerName") providerName := c.Input().Get("providerName")
paymentEnv := c.Input().Get("paymentEnv") paymentEnv := c.Input().Get("paymentEnv")
customPriceStr := c.Input().Get("customPrice")
if customPriceStr == "" {
customPriceStr = "0"
}
customPrice, err := strconv.ParseFloat(customPriceStr, 64)
if err != nil {
c.ResponseError(err.Error())
return
}
// buy `pricingName/planName` for `paidUserName` // buy `pricingName/planName` for `paidUserName`
pricingName := c.Input().Get("pricingName") pricingName := c.Input().Get("pricingName")
@ -182,10 +171,6 @@ func (c *ApiController) BuyProduct() {
paidUserName := c.Input().Get("userName") paidUserName := c.Input().Get("userName")
owner, _ := util.GetOwnerAndNameFromId(id) owner, _ := util.GetOwnerAndNameFromId(id)
userId := util.GetId(owner, paidUserName) userId := util.GetId(owner, paidUserName)
if paidUserName != "" && !c.IsAdmin() {
c.ResponseError(c.T("general:Only admin user can specify user"))
return
}
if paidUserName == "" { if paidUserName == "" {
userId = c.GetSessionUsername() userId = c.GetSessionUsername()
} }
@ -204,7 +189,7 @@ func (c *ApiController) BuyProduct() {
return return
} }
payment, attachInfo, err := object.BuyProduct(id, user, providerName, pricingName, planName, host, paymentEnv, customPrice) payment, attachInfo, err := object.BuyProduct(id, user, providerName, pricingName, planName, host, paymentEnv)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return

View File

@ -141,20 +141,6 @@ func (c *ApiController) GetProvider() {
c.ResponseOk(object.GetMaskedProvider(provider, isMaskEnabled)) c.ResponseOk(object.GetMaskedProvider(provider, isMaskEnabled))
} }
func (c *ApiController) requireProviderPermission(provider *object.Provider) bool {
isGlobalAdmin, user := c.isGlobalAdmin()
if isGlobalAdmin {
return true
}
if provider.Owner == "admin" || user.Owner != provider.Owner {
c.ResponseError(c.T("auth:Unauthorized operation"))
return false
}
return true
}
// UpdateProvider // UpdateProvider
// @Title UpdateProvider // @Title UpdateProvider
// @Tag Provider API // @Tag Provider API
@ -173,11 +159,6 @@ func (c *ApiController) UpdateProvider() {
return return
} }
ok := c.requireProviderPermission(&provider)
if !ok {
return
}
c.Data["json"] = wrapActionResponse(object.UpdateProvider(id, &provider)) c.Data["json"] = wrapActionResponse(object.UpdateProvider(id, &provider))
c.ServeJSON() c.ServeJSON()
} }
@ -203,17 +184,11 @@ func (c *ApiController) AddProvider() {
return return
} }
err = checkQuotaForProvider(int(count)) if err := checkQuotaForProvider(int(count)); err != nil {
if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
ok := c.requireProviderPermission(&provider)
if !ok {
return
}
c.Data["json"] = wrapActionResponse(object.AddProvider(&provider)) c.Data["json"] = wrapActionResponse(object.AddProvider(&provider))
c.ServeJSON() c.ServeJSON()
} }
@ -233,11 +208,6 @@ func (c *ApiController) DeleteProvider() {
return return
} }
ok := c.requireProviderPermission(&provider)
if !ok {
return
}
c.Data["json"] = wrapActionResponse(object.DeleteProvider(&provider)) c.Data["json"] = wrapActionResponse(object.DeleteProvider(&provider))
c.ServeJSON() c.ServeJSON()
} }

View File

@ -85,11 +85,6 @@ func (c *ApiController) GetRecords() {
// @Success 200 {object} object.Record The Response object // @Success 200 {object} object.Record The Response object
// @router /get-records-filter [post] // @router /get-records-filter [post]
func (c *ApiController) GetRecordsByFilter() { func (c *ApiController) GetRecordsByFilter() {
_, ok := c.RequireAdmin()
if !ok {
return
}
body := string(c.Ctx.Input.RequestBody) body := string(c.Ctx.Input.RequestBody)
record := &casvisorsdk.Record{} record := &casvisorsdk.Record{}

View File

@ -52,15 +52,6 @@ func (c *ApiController) GetResources() {
sortField := c.Input().Get("sortField") sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder") sortOrder := c.Input().Get("sortOrder")
isOrgAdmin, ok := c.IsOrgAdmin()
if !ok {
return
}
if isOrgAdmin {
user = ""
}
if sortField == "Direct" { if sortField == "Direct" {
provider, err := c.GetProviderFromContext("Storage") provider, err := c.GetProviderFromContext("Storage")
if err != nil { if err != nil {
@ -257,7 +248,7 @@ func (c *ApiController) UploadResource() {
fileType, _ = util.GetOwnerAndNameFromIdNoCheck(mimeType + "/") fileType, _ = util.GetOwnerAndNameFromIdNoCheck(mimeType + "/")
} }
fullFilePath = object.GetTruncatedPath(provider, fullFilePath, 450) fullFilePath = object.GetTruncatedPath(provider, fullFilePath, 175)
if tag != "avatar" && tag != "termsOfUse" && !strings.HasPrefix(tag, "idCard") { if tag != "avatar" && tag != "termsOfUse" && !strings.HasPrefix(tag, "idCard") {
ext := filepath.Ext(filepath.Base(fullFilePath)) ext := filepath.Ext(filepath.Base(fullFilePath))
index := len(fullFilePath) - len(ext) index := len(fullFilePath) - len(ext)

View File

@ -21,11 +21,6 @@ import (
) )
func (c *RootController) HandleScim() { func (c *RootController) HandleScim() {
_, ok := c.RequireAdmin()
if !ok {
return
}
path := c.Ctx.Request.URL.Path path := c.Ctx.Request.URL.Path
c.Ctx.Request.URL.Path = strings.TrimPrefix(path, "/scim") c.Ctx.Request.URL.Path = strings.TrimPrefix(path, "/scim")
scim.Server.ServeHTTP(c.Ctx.ResponseWriter, c.Ctx.Request) scim.Server.ServeHTTP(c.Ctx.ResponseWriter, c.Ctx.Request)

View File

@ -27,12 +27,11 @@ import (
) )
type EmailForm struct { type EmailForm struct {
Title string `json:"title"` Title string `json:"title"`
Content string `json:"content"` Content string `json:"content"`
Sender string `json:"sender"` Sender string `json:"sender"`
Receivers []string `json:"receivers"` Receivers []string `json:"receivers"`
Provider string `json:"provider"` Provider string `json:"provider"`
ProviderObject object.Provider `json:"providerObject"`
} }
type SmsForm struct { type SmsForm struct {
@ -61,6 +60,7 @@ func (c *ApiController) SendEmail() {
} }
var emailForm EmailForm var emailForm EmailForm
err := json.Unmarshal(c.Ctx.Input.RequestBody, &emailForm) err := json.Unmarshal(c.Ctx.Input.RequestBody, &emailForm)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
@ -75,6 +75,7 @@ func (c *ApiController) SendEmail() {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
} else { } else {
// called by Casdoor SDK via Client ID & Client Secret, so the used Email provider will be the application' Email provider or the default Email provider // called by Casdoor SDK via Client ID & Client Secret, so the used Email provider will be the application' Email provider or the default Email provider
provider, err = c.GetProviderFromContext("Email") provider, err = c.GetProviderFromContext("Email")
@ -84,16 +85,9 @@ func (c *ApiController) SendEmail() {
} }
} }
if emailForm.ProviderObject.Name != "" {
if emailForm.ProviderObject.ClientSecret == "***" {
emailForm.ProviderObject.ClientSecret = provider.ClientSecret
}
provider = &emailForm.ProviderObject
}
// when receiver is the reserved keyword: "TestSmtpServer", it means to test the SMTP server instead of sending a real Email // when receiver is the reserved keyword: "TestSmtpServer", it means to test the SMTP server instead of sending a real Email
if len(emailForm.Receivers) == 1 && emailForm.Receivers[0] == "TestSmtpServer" { if len(emailForm.Receivers) == 1 && emailForm.Receivers[0] == "TestSmtpServer" {
err = object.TestSmtpServer(provider) err := object.DailSmtpServer(provider)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -118,27 +112,22 @@ func (c *ApiController) SendEmail() {
return return
} }
content := emailForm.Content
if content == "" {
content = provider.Content
}
code := "123456" code := "123456"
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes." // "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
content = strings.Replace(content, "%s", code, 1) content := strings.Replace(provider.Content, "%s", code, 1)
userString := "Hi" if !strings.HasPrefix(userId, "app/") {
if !object.IsAppUser(userId) {
var user *object.User var user *object.User
user, err = object.GetUser(userId) user, err = object.GetUser(userId)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
if user != nil { if user != nil {
userString = user.GetFriendlyName() content = strings.Replace(content, "%{user.friendlyName}", user.GetFriendlyName(), 1)
} }
} }
content = strings.Replace(content, "%{user.friendlyName}", userString, 1)
for _, receiver := range emailForm.Receivers { for _, receiver := range emailForm.Receivers {
err = object.SendEmail(provider, emailForm.Title, content, receiver, emailForm.Sender) err = object.SendEmail(provider, emailForm.Title, content, receiver, emailForm.Sender)

View File

@ -46,10 +46,10 @@ func (c *ApiController) GetSystemInfo() {
// @Success 200 {object} util.VersionInfo The Response object // @Success 200 {object} util.VersionInfo The Response object
// @router /get-version-info [get] // @router /get-version-info [get]
func (c *ApiController) GetVersionInfo() { func (c *ApiController) GetVersionInfo() {
errInfo := ""
versionInfo, err := util.GetVersionInfo() versionInfo, err := util.GetVersionInfo()
if err != nil { if err != nil {
errInfo = "Git error: " + err.Error() c.ResponseError(err.Error())
return
} }
if versionInfo.Version != "" { if versionInfo.Version != "" {
@ -59,11 +59,9 @@ func (c *ApiController) GetVersionInfo() {
versionInfo, err = util.GetVersionInfoFromFile() versionInfo, err = util.GetVersionInfoFromFile()
if err != nil { if err != nil {
errInfo = errInfo + ", File error: " + err.Error() c.ResponseError(err.Error())
c.ResponseError(errInfo)
return return
} }
c.ResponseOk(versionInfo) c.ResponseOk(versionInfo)
} }

View File

@ -164,7 +164,6 @@ func (c *ApiController) GetOAuthToken() {
code := c.Input().Get("code") code := c.Input().Get("code")
verifier := c.Input().Get("code_verifier") verifier := c.Input().Get("code_verifier")
scope := c.Input().Get("scope") scope := c.Input().Get("scope")
nonce := c.Input().Get("nonce")
username := c.Input().Get("username") username := c.Input().Get("username")
password := c.Input().Get("password") password := c.Input().Get("password")
tag := c.Input().Get("tag") tag := c.Input().Get("tag")
@ -198,9 +197,6 @@ func (c *ApiController) GetOAuthToken() {
if scope == "" { if scope == "" {
scope = tokenRequest.Scope scope = tokenRequest.Scope
} }
if nonce == "" {
nonce = tokenRequest.Nonce
}
if username == "" { if username == "" {
username = tokenRequest.Username username = tokenRequest.Username
} }
@ -220,7 +216,7 @@ func (c *ApiController) GetOAuthToken() {
} }
host := c.Ctx.Request.Host host := c.Ctx.Request.Host
token, err := object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, nonce, username, password, host, refreshToken, tag, avatar, c.GetAcceptLanguage()) token, err := object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host, refreshToken, tag, avatar, c.GetAcceptLanguage())
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -321,89 +317,40 @@ func (c *ApiController) IntrospectToken() {
return return
} }
tokenTypeHint := c.Input().Get("token_type_hint") token, err := object.GetTokenByTokenValue(tokenValue)
var token *object.Token if err != nil {
if tokenTypeHint != "" { c.ResponseTokenError(err.Error())
token, err = object.GetTokenByTokenValue(tokenValue, tokenTypeHint) return
if err != nil { }
c.ResponseTokenError(err.Error()) if token == nil {
return c.Data["json"] = &object.IntrospectionResponse{Active: false}
} c.ServeJSON()
if token == nil { return
c.Data["json"] = &object.IntrospectionResponse{Active: false}
c.ServeJSON()
return
}
} }
var introspectionResponse object.IntrospectionResponse jwtToken, err := object.ParseJwtTokenByApplication(tokenValue, application)
if err != nil || jwtToken.Valid() != nil {
if application.TokenFormat == "JWT-Standard" { // and token revoked case. but we not implement
jwtToken, err := object.ParseStandardJwtTokenByApplication(tokenValue, application) // TODO: 2022-03-03 add token revoked check, when we implemented the Token Revocation(rfc7009) Specs.
if err != nil || jwtToken.Valid() != nil { // refs: https://tools.ietf.org/html/rfc7009
// and token revoked case. but we not implement c.Data["json"] = &object.IntrospectionResponse{Active: false}
// TODO: 2022-03-03 add token revoked check, when we implemented the Token Revocation(rfc7009) Specs. c.ServeJSON()
// refs: https://tools.ietf.org/html/rfc7009 return
c.Data["json"] = &object.IntrospectionResponse{Active: false}
c.ServeJSON()
return
}
introspectionResponse = object.IntrospectionResponse{
Active: true,
Scope: jwtToken.Scope,
ClientId: clientId,
Username: jwtToken.Name,
TokenType: jwtToken.TokenType,
Exp: jwtToken.ExpiresAt.Unix(),
Iat: jwtToken.IssuedAt.Unix(),
Nbf: jwtToken.NotBefore.Unix(),
Sub: jwtToken.Subject,
Aud: jwtToken.Audience,
Iss: jwtToken.Issuer,
Jti: jwtToken.ID,
}
} else {
jwtToken, err := object.ParseJwtTokenByApplication(tokenValue, application)
if err != nil || jwtToken.Valid() != nil {
// and token revoked case. but we not implement
// TODO: 2022-03-03 add token revoked check, when we implemented the Token Revocation(rfc7009) Specs.
// refs: https://tools.ietf.org/html/rfc7009
c.Data["json"] = &object.IntrospectionResponse{Active: false}
c.ServeJSON()
return
}
introspectionResponse = object.IntrospectionResponse{
Active: true,
Scope: jwtToken.Scope,
ClientId: clientId,
Username: jwtToken.Name,
TokenType: jwtToken.TokenType,
Exp: jwtToken.ExpiresAt.Unix(),
Iat: jwtToken.IssuedAt.Unix(),
Nbf: jwtToken.NotBefore.Unix(),
Sub: jwtToken.Subject,
Aud: jwtToken.Audience,
Iss: jwtToken.Issuer,
Jti: jwtToken.ID,
}
} }
if tokenTypeHint == "" { c.Data["json"] = &object.IntrospectionResponse{
token, err = object.GetTokenByTokenValue(tokenValue, introspectionResponse.TokenType) Active: true,
if err != nil { Scope: jwtToken.Scope,
c.ResponseTokenError(err.Error()) ClientId: clientId,
return Username: token.User,
} TokenType: token.TokenType,
if token == nil { Exp: jwtToken.ExpiresAt.Unix(),
c.Data["json"] = &object.IntrospectionResponse{Active: false} Iat: jwtToken.IssuedAt.Unix(),
c.ServeJSON() Nbf: jwtToken.NotBefore.Unix(),
return Sub: jwtToken.Subject,
} Aud: jwtToken.Audience,
Iss: jwtToken.Issuer,
Jti: jwtToken.ID,
} }
introspectionResponse.TokenType = token.TokenType
c.Data["json"] = introspectionResponse
c.ServeJSON() c.ServeJSON()
} }

View File

@ -1,167 +0,0 @@
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// GetTransactions
// @Title GetTransactions
// @Tag Transaction API
// @Description get transactions
// @Param owner query string true "The owner of transactions"
// @Success 200 {array} object.Transaction The Response object
// @router /get-transactions [get]
func (c *ApiController) GetTransactions() {
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 == "" {
transactions, err := object.GetTransactions(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(transactions)
} else {
limit := util.ParseInt(limit)
count, err := object.GetTransactionCount(owner, field, value)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
transactions, err := object.GetPaginationTransactions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(transactions, paginator.Nums())
}
}
// 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
// @Description get transaction
// @Param id query string true "The id ( owner/name ) of the transaction"
// @Success 200 {object} object.Transaction The Response object
// @router /get-transaction [get]
func (c *ApiController) GetTransaction() {
id := c.Input().Get("id")
transaction, err := object.GetTransaction(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(transaction)
}
// UpdateTransaction
// @Title UpdateTransaction
// @Tag Transaction API
// @Description update transaction
// @Param id query string true "The id ( owner/name ) of the transaction"
// @Param body body object.Transaction true "The details of the transaction"
// @Success 200 {object} controllers.Response The Response object
// @router /update-transaction [post]
func (c *ApiController) UpdateTransaction() {
id := c.Input().Get("id")
var transaction object.Transaction
err := json.Unmarshal(c.Ctx.Input.RequestBody, &transaction)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateTransaction(id, &transaction))
c.ServeJSON()
}
// AddTransaction
// @Title AddTransaction
// @Tag Transaction API
// @Description add transaction
// @Param body body object.Transaction true "The details of the transaction"
// @Success 200 {object} controllers.Response The Response object
// @router /add-transaction [post]
func (c *ApiController) AddTransaction() {
var transaction object.Transaction
err := json.Unmarshal(c.Ctx.Input.RequestBody, &transaction)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddTransaction(&transaction))
c.ServeJSON()
}
// DeleteTransaction
// @Title DeleteTransaction
// @Tag Transaction API
// @Description delete transaction
// @Param body body object.Transaction true "The details of the transaction"
// @Success 200 {object} controllers.Response The Response object
// @router /delete-transaction [post]
func (c *ApiController) DeleteTransaction() {
var transaction object.Transaction
err := json.Unmarshal(c.Ctx.Input.RequestBody, &transaction)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteTransaction(&transaction))
c.ServeJSON()
}

View File

@ -21,7 +21,6 @@ type TokenRequest struct {
Code string `json:"code"` Code string `json:"code"`
Verifier string `json:"code_verifier"` Verifier string `json:"code_verifier"`
Scope string `json:"scope"` Scope string `json:"scope"`
Nonce string `json:"nonce"`
Username string `json:"username"` Username string `json:"username"`
Password string `json:"password"` Password string `json:"password"`
Tag string `json:"tag"` Tag string `json:"tag"`

View File

@ -20,7 +20,6 @@ import (
"strings" "strings"
"github.com/beego/beego/utils/pagination" "github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
) )
@ -289,26 +288,11 @@ func (c *ApiController) UpdateUser() {
} }
} }
if user.MfaEmailEnabled && user.Email == "" {
c.ResponseError(c.T("user:MFA email is enabled but email is empty"))
return
}
if user.MfaPhoneEnabled && user.Phone == "" {
c.ResponseError(c.T("user:MFA phone is enabled but phone number is empty"))
return
}
if msg := object.CheckUpdateUser(oldUser, &user, c.GetAcceptLanguage()); msg != "" { if msg := object.CheckUpdateUser(oldUser, &user, c.GetAcceptLanguage()); msg != "" {
c.ResponseError(msg) c.ResponseError(msg)
return return
} }
isUsernameLowered := conf.GetConfigBool("isUsernameLowered")
if isUsernameLowered {
user.Name = strings.ToLower(user.Name)
}
isAdmin := c.IsAdmin() isAdmin := c.IsAdmin()
if pass, err := object.CheckPermissionForUpdateUser(oldUser, &user, isAdmin, c.GetAcceptLanguage()); !pass { if pass, err := object.CheckPermissionForUpdateUser(oldUser, &user, isAdmin, c.GetAcceptLanguage()); !pass {
c.ResponseError(err) c.ResponseError(err)
@ -353,13 +337,18 @@ func (c *ApiController) AddUser() {
return return
} }
if err := checkQuotaForUser(); err != nil { count, err := object.GetUserCount("", "", "", "")
if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
emptyUser := object.User{} if err := checkQuotaForUser(int(count)); err != nil {
msg := object.CheckUpdateUser(&emptyUser, &user, c.GetAcceptLanguage()) c.ResponseError(err.Error())
return
}
msg := object.CheckUsername(user.Name, c.GetAcceptLanguage())
if msg != "" { if msg != "" {
c.ResponseError(msg) c.ResponseError(msg)
return return
@ -405,12 +394,6 @@ func (c *ApiController) GetEmailAndPhone() {
organization := c.Ctx.Request.Form.Get("organization") organization := c.Ctx.Request.Form.Get("organization")
username := c.Ctx.Request.Form.Get("username") username := c.Ctx.Request.Form.Get("username")
enableErrorMask2 := conf.GetConfigBool("enableErrorMask2")
if enableErrorMask2 {
c.ResponseError("Error")
return
}
user, err := object.GetUserByFields(organization, username) user, err := object.GetUserByFields(organization, username)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
@ -457,10 +440,10 @@ func (c *ApiController) SetPassword() {
newPassword := c.Ctx.Request.Form.Get("newPassword") newPassword := c.Ctx.Request.Form.Get("newPassword")
code := c.Ctx.Request.Form.Get("code") code := c.Ctx.Request.Form.Get("code")
// if userOwner == "built-in" && userName == "admin" { //if userOwner == "built-in" && userName == "admin" {
// c.ResponseError(c.T("auth:Unauthorized operation")) // c.ResponseError(c.T("auth:Unauthorized operation"))
// return // return
// } //}
if strings.Contains(newPassword, " ") { if strings.Contains(newPassword, " ") {
c.ResponseError(c.T("user:New password cannot contain blank space.")) c.ResponseError(c.T("user:New password cannot contain blank space."))
@ -469,16 +452,6 @@ func (c *ApiController) SetPassword() {
userId := util.GetId(userOwner, userName) userId := util.GetId(userOwner, userName)
user, err := object.GetUser(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
return
}
requestUserId := c.GetSessionUsername() requestUserId := c.GetSessionUsername()
if requestUserId == "" && code == "" { if requestUserId == "" && code == "" {
c.ResponseError(c.T("general:Please login first"), "Please login first") c.ResponseError(c.T("general:Please login first"), "Please login first")
@ -494,12 +467,7 @@ func (c *ApiController) SetPassword() {
c.ResponseError(c.T("general:Missing parameter")) c.ResponseError(c.T("general:Missing parameter"))
return return
} }
if userId != c.GetSession("verifiedUserId") {
c.ResponseError(c.T("general:Wrong userId"))
return
}
c.SetSession("verifiedCode", "") c.SetSession("verifiedCode", "")
c.SetSession("verifiedUserId", "")
} }
targetUser, err := object.GetUser(userId) targetUser, err := object.GetUser(userId)
@ -522,11 +490,7 @@ func (c *ApiController) SetPassword() {
} }
} }
} else if code == "" { } else if code == "" {
if user.Ldap == "" { err = object.CheckPassword(targetUser, oldPassword, c.GetAcceptLanguage())
err = object.CheckPassword(targetUser, oldPassword, c.GetAcceptLanguage())
} else {
err = object.CheckLdapUserPassword(targetUser, oldPassword, c.GetAcceptLanguage())
}
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -539,48 +503,8 @@ func (c *ApiController) SetPassword() {
return return
} }
organization, err := object.GetOrganizationByUser(targetUser)
if err != nil {
c.ResponseError(err.Error())
return
}
if organization == nil {
c.ResponseError(fmt.Sprintf(c.T("the organization: %s is not found"), targetUser.Owner))
return
}
application, err := object.GetApplicationByUser(targetUser)
if err != nil {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:the application for user %s is not found"), userId))
return
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
err = object.CheckEntryIp(clientIp, targetUser, application, organization, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
targetUser.Password = newPassword targetUser.Password = newPassword
targetUser.UpdateUserPassword(organization) _, err = object.SetUserField(targetUser, "password", targetUser.Password)
targetUser.NeedUpdatePassword = false
targetUser.LastChangePasswordTime = util.GetCurrentTime()
if user.Ldap == "" {
_, err = object.UpdateUser(userId, targetUser, []string{"password", "need_update_password", "password_type", "last_change_password_time"}, false)
} else {
if isAdmin {
err = object.ResetLdapPassword(targetUser, "", newPassword, c.GetAcceptLanguage())
} else {
err = object.ResetLdapPassword(targetUser, oldPassword, newPassword, c.GetAcceptLanguage())
}
}
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -602,11 +526,7 @@ func (c *ApiController) CheckUserPassword() {
return return
} }
/* _, err = object.CheckUserPassword(user.Owner, user.Name, user.Password, c.GetAcceptLanguage())
* Verified password with user as subject, if field ldap not empty,
* then `isPasswordWithLdapEnabled` is true
*/
_, err = object.CheckUserPassword(user.Owner, user.Name, user.Password, c.GetAcceptLanguage(), false, false, user.Ldap != "")
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
} else { } else {

View File

@ -45,22 +45,6 @@ func (c *ApiController) ResponseOk(data ...interface{}) {
// ResponseError ... // ResponseError ...
func (c *ApiController) ResponseError(error string, data ...interface{}) { func (c *ApiController) ResponseError(error string, data ...interface{}) {
enableErrorMask2 := conf.GetConfigBool("enableErrorMask2")
if enableErrorMask2 {
error = c.T("subscription:Error")
resp := &Response{Status: "error", Msg: error}
c.ResponseJsonData(resp, data...)
return
}
enableErrorMask := conf.GetConfigBool("enableErrorMask")
if enableErrorMask {
if strings.HasPrefix(error, "The user: ") && strings.HasSuffix(error, " doesn't exist") || strings.HasPrefix(error, "用户: ") && strings.HasSuffix(error, "不存在") {
error = c.T("check:password or code is incorrect")
}
}
resp := &Response{Status: "error", Msg: error} resp := &Response{Status: "error", Msg: error}
c.ResponseJsonData(resp, data...) c.ResponseJsonData(resp, data...)
} }
@ -112,7 +96,7 @@ func (c *ApiController) RequireSignedInUser() (*object.User, bool) {
return nil, false return nil, false
} }
if object.IsAppUser(userId) { if strings.HasPrefix(userId, "app/") {
tmpUserId := c.Input().Get("userId") tmpUserId := c.Input().Get("userId")
if tmpUserId != "" { if tmpUserId != "" {
userId = tmpUserId userId = tmpUserId
@ -124,12 +108,12 @@ func (c *ApiController) RequireSignedInUser() (*object.User, bool) {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return nil, false return nil, false
} }
if user == nil { if user == nil {
c.ClearUserSession() c.ClearUserSession()
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId)) c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
return nil, false return nil, false
} }
return user, true return user, true
} }
@ -143,39 +127,9 @@ func (c *ApiController) RequireAdmin() (string, bool) {
if user.Owner == "built-in" { if user.Owner == "built-in" {
return "", true return "", true
} }
if !user.IsAdmin {
c.ResponseError(c.T("general:this operation requires administrator to perform"))
return "", false
}
return user.Owner, true return user.Owner, true
} }
func (c *ApiController) IsOrgAdmin() (bool, bool) {
userId, ok := c.RequireSignedIn()
if !ok {
return false, true
}
if object.IsAppUser(userId) {
return true, true
}
user, err := object.GetUser(userId)
if err != nil {
c.ResponseError(err.Error())
return false, false
}
if user == nil {
c.ClearUserSession()
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
return false, false
}
return user.IsAdmin, true
}
// IsMaskedEnabled ... // IsMaskedEnabled ...
func (c *ApiController) IsMaskedEnabled() (bool, bool) { func (c *ApiController) IsMaskedEnabled() (bool, bool) {
isMaskEnabled := true isMaskEnabled := true
@ -294,18 +248,12 @@ func checkQuotaForProvider(count int) error {
return nil return nil
} }
func checkQuotaForUser() error { func checkQuotaForUser(count int) error {
quota := conf.GetConfigQuota().User quota := conf.GetConfigQuota().User
if quota == -1 { if quota == -1 {
return nil return nil
} }
if count >= quota {
count, err := object.GetUserCount("", "", "", "")
if err != nil {
return err
}
if int(count) >= quota {
return fmt.Errorf("user quota is exceeded") return fmt.Errorf("user quota is exceeded")
} }
return nil return nil

View File

@ -20,7 +20,6 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/captcha" "github.com/casdoor/casdoor/captcha"
"github.com/casdoor/casdoor/form" "github.com/casdoor/casdoor/form"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
@ -36,90 +35,6 @@ const (
MfaAuthVerification = "mfaAuth" MfaAuthVerification = "mfaAuth"
) )
// GetVerifications
// @Title GetVerifications
// @Tag Verification API
// @Description get payments
// @Param owner query string true "The owner of payments"
// @Success 200 {array} object.Verification The Response object
// @router /get-payments [get]
func (c *ApiController) GetVerifications() {
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 == "" {
payments, err := object.GetVerifications(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(payments)
} else {
limit := util.ParseInt(limit)
count, err := object.GetVerificationCount(owner, 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)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(payments, paginator.Nums())
}
}
// GetUserVerifications
// @Title GetUserVerifications
// @Tag Verification API
// @Description get payments for a user
// @Param owner query string true "The owner of payments"
// @Param organization query string true "The organization of the user"
// @Param user query string true "The username of the user"
// @Success 200 {array} object.Verification The Response object
// @router /get-user-payments [get]
func (c *ApiController) GetUserVerifications() {
owner := c.Input().Get("owner")
user := c.Input().Get("user")
payments, err := object.GetUserVerifications(owner, user)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(payments)
}
// GetVerification
// @Title GetVerification
// @Tag Verification API
// @Description get payment
// @Param id query string true "The id ( owner/name ) of the payment"
// @Success 200 {object} object.Verification The Response object
// @router /get-payment [get]
func (c *ApiController) GetVerification() {
id := c.Input().Get("id")
payment, err := object.GetVerification(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(payment)
}
// SendVerificationCode ... // SendVerificationCode ...
// @Title SendVerificationCode // @Title SendVerificationCode
// @Tag Verification API // @Tag Verification API
@ -132,8 +47,7 @@ func (c *ApiController) SendVerificationCode() {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} }
remoteAddr := util.GetIPFromRequest(c.Ctx.Request)
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
if msg := vform.CheckParameter(form.SendVerifyCode, c.GetAcceptLanguage()); msg != "" { if msg := vform.CheckParameter(form.SendVerifyCode, c.GetAcceptLanguage()); msg != "" {
c.ResponseError(msg) c.ResponseError(msg)
@ -246,6 +160,8 @@ func (c *ApiController) SendVerificationCode() {
if user != nil && util.GetMaskedEmail(mfaProps.Secret) == vform.Dest { if user != nil && util.GetMaskedEmail(mfaProps.Secret) == vform.Dest {
vform.Dest = mfaProps.Secret vform.Dest = mfaProps.Secret
} }
} else if vform.Method == MfaSetupVerification {
c.SetSession(MfaDestSession, vform.Dest)
} }
provider, err = application.GetEmailProvider(vform.Method) provider, err = application.GetEmailProvider(vform.Method)
@ -258,7 +174,7 @@ func (c *ApiController) SendVerificationCode() {
return return
} }
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, clientIp, vform.Dest) sendResp = object.SendVerificationCodeToEmail(organization, user, provider, remoteAddr, vform.Dest)
case object.VerifyTypePhone: case object.VerifyTypePhone:
if vform.Method == LoginVerification || vform.Method == ForgetVerification { if vform.Method == LoginVerification || vform.Method == ForgetVerification {
if user != nil && util.GetMaskedPhone(user.Phone) == vform.Dest { if user != nil && util.GetMaskedPhone(user.Phone) == vform.Dest {
@ -280,6 +196,11 @@ func (c *ApiController) SendVerificationCode() {
vform.CountryCode = user.GetCountryCode(vform.CountryCode) vform.CountryCode = user.GetCountryCode(vform.CountryCode)
} }
} }
if vform.Method == MfaSetupVerification {
c.SetSession(MfaCountryCodeSession, vform.CountryCode)
c.SetSession(MfaDestSession, vform.Dest)
}
} else if vform.Method == MfaAuthVerification { } else if vform.Method == MfaAuthVerification {
mfaProps := user.GetPreferredMfaProps(false) mfaProps := user.GetPreferredMfaProps(false)
if user != nil && util.GetMaskedPhone(mfaProps.Secret) == vform.Dest { if user != nil && util.GetMaskedPhone(mfaProps.Secret) == vform.Dest {
@ -287,10 +208,9 @@ func (c *ApiController) SendVerificationCode() {
} }
vform.CountryCode = mfaProps.CountryCode vform.CountryCode = mfaProps.CountryCode
vform.CountryCode = user.GetCountryCode(vform.CountryCode)
} }
provider, err = application.GetSmsProvider(vform.Method, vform.CountryCode) provider, err = application.GetSmsProvider(vform.Method)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -304,7 +224,7 @@ func (c *ApiController) SendVerificationCode() {
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), vform.CountryCode)) c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), vform.CountryCode))
return return
} else { } else {
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, clientIp, phone) sendResp = object.SendVerificationCodeToPhone(organization, user, provider, remoteAddr, phone)
} }
} }
@ -510,31 +430,22 @@ func (c *ApiController) VerifyCode() {
} }
} }
passed, err := c.checkOrgMasterVerificationCode(user, authForm.Code) result, err := object.CheckVerificationCode(checkDest, authForm.Code, c.GetAcceptLanguage())
if err != nil { if err != nil {
c.ResponseError(c.T(err.Error())) c.ResponseError(c.T(err.Error()))
return return
} }
if result.Code != object.VerificationSuccess {
c.ResponseError(result.Msg)
return
}
if !passed { err = object.DisableVerificationCode(checkDest)
result, err := object.CheckVerificationCode(checkDest, authForm.Code, c.GetAcceptLanguage()) if err != nil {
if err != nil { c.ResponseError(err.Error())
c.ResponseError(err.Error()) return
return
}
if result.Code != object.VerificationSuccess {
c.ResponseError(result.Msg)
return
}
err = object.DisableVerificationCode(checkDest)
if err != nil {
c.ResponseError(err.Error())
return
}
} }
c.SetSession("verifiedCode", authForm.Code) c.SetSession("verifiedCode", authForm.Code)
c.SetSession("verifiedUserId", user.GetId())
c.ResponseOk() c.ResponseOk()
} }

View File

@ -1,36 +0,0 @@
// 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 (
"fmt"
"github.com/casdoor/casdoor/object"
)
func (c *ApiController) checkOrgMasterVerificationCode(user *object.User, code string) (bool, error) {
organization, err := object.GetOrganizationByUser(user)
if err != nil {
return false, err
}
if organization == nil {
return false, fmt.Errorf("The organization: %s does not exist", user.Owner)
}
if organization.MasterVerificationCode != "" && organization.MasterVerificationCode == code {
return true, nil
}
return false, nil
}

View File

@ -27,21 +27,7 @@ import (
) )
func deployStaticFiles(provider *object.Provider) { func deployStaticFiles(provider *object.Provider) {
certificate := "" storageProvider := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, provider.Endpoint)
if provider.Category == "Storage" && provider.Type == "Casdoor" {
cert, err := object.GetCert(util.GetId(provider.Owner, provider.Cert))
if err != nil {
panic(err)
}
if cert == nil {
panic(err)
}
certificate = cert.Certificate
}
storageProvider, err := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, provider.Endpoint, certificate, provider.Content)
if err != nil {
panic(err)
}
if storageProvider == nil { if storageProvider == nil {
panic(fmt.Sprintf("the provider type: %s is not supported", provider.Type)) panic(fmt.Sprintf("the provider type: %s is not supported", provider.Type))
} }

View File

@ -111,44 +111,46 @@ func newEmail(fromAddress string, toAddress string, subject string, content stri
Subject: subject, Subject: subject,
HTML: content, HTML: content,
}, },
Importance: importanceNormal, Importance: importanceNormal,
Attachments: []Attachment{},
} }
} }
func (a *AzureACSEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error { func (a *AzureACSEmailProvider) sendEmail(e *Email) error {
email := newEmail(fromAddress, toAddress, subject, content) postBody, err := json.Marshal(e)
postBody, err := json.Marshal(email)
if err != nil { if err != nil {
return err return fmt.Errorf("email JSON marshall failed: %s", err)
} }
bodyBuffer := bytes.NewBuffer(postBody)
endpoint := strings.TrimSuffix(a.Endpoint, "/") endpoint := strings.TrimSuffix(a.Endpoint, "/")
url := fmt.Sprintf("%s/emails:send?api-version=2023-03-31", endpoint) url := fmt.Sprintf("%s/emails:send?api-version=2023-03-31", endpoint)
bodyBuffer := bytes.NewBuffer(postBody)
req, err := http.NewRequest("POST", url, bodyBuffer) req, err := http.NewRequest("POST", url, bodyBuffer)
if err != nil { if err != nil {
return err return fmt.Errorf("error creating AzureACS API request: %s", err)
} }
// Sign the request using the AzureACS access key and HMAC-SHA256
err = signRequestHMAC(a.AccessKey, req) err = signRequestHMAC(a.AccessKey, req)
if err != nil { if err != nil {
return err return fmt.Errorf("error signing AzureACS API request: %s", err)
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
// Some important header
req.Header.Set("repeatability-request-id", uuid.New().String()) req.Header.Set("repeatability-request-id", uuid.New().String())
req.Header.Set("repeatability-first-sent", time.Now().UTC().Format(http.TimeFormat)) req.Header.Set("repeatability-first-sent", time.Now().UTC().Format(http.TimeFormat))
// Send request
client := &http.Client{} client := &http.Client{}
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return err return fmt.Errorf("error sending AzureACS API request: %s", err)
} }
defer resp.Body.Close() defer resp.Body.Close()
// Response error Handling
if resp.StatusCode == http.StatusBadRequest || resp.StatusCode == http.StatusUnauthorized { if resp.StatusCode == http.StatusBadRequest || resp.StatusCode == http.StatusUnauthorized {
commError := ErrorResponse{} commError := ErrorResponse{}
@ -157,11 +159,11 @@ func (a *AzureACSEmailProvider) Send(fromAddress string, fromName string, toAddr
return err return err
} }
return fmt.Errorf("status code: %d, error message: %s", resp.StatusCode, commError.Error.Message) return fmt.Errorf("error sending email: %s", commError.Error.Message)
} }
if resp.StatusCode != http.StatusAccepted { if resp.StatusCode != http.StatusAccepted {
return fmt.Errorf("status code: %d", resp.StatusCode) return fmt.Errorf("error sending email: status: %d", resp.StatusCode)
} }
return nil return nil
@ -219,3 +221,9 @@ func GetHmac(content string, key []byte) string {
return base64.StdEncoding.EncodeToString(hmac.Sum(nil)) return base64.StdEncoding.EncodeToString(hmac.Sum(nil))
} }
func (a *AzureACSEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
e := newEmail(fromAddress, toAddress, subject, content)
return a.sendEmail(e)
}

View File

@ -23,8 +23,6 @@ func GetEmailProvider(typ string, clientId string, clientSecret string, host str
return NewAzureACSEmailProvider(clientSecret, host) return NewAzureACSEmailProvider(clientSecret, host)
} else if typ == "Custom HTTP Email" { } else if typ == "Custom HTTP Email" {
return NewHttpEmailProvider(endpoint, method) return NewHttpEmailProvider(endpoint, method)
} else if typ == "SendGrid" {
return NewSendgridEmailProvider(clientSecret, host, endpoint)
} else { } else {
return NewSmtpEmailProvider(clientId, clientSecret, host, port, typ, disableSsl) return NewSmtpEmailProvider(clientId, clientSecret, host, port, typ, disableSsl)
} }

View File

@ -1,87 +0,0 @@
// 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 email
import (
"encoding/json"
"fmt"
"net/http"
"github.com/sendgrid/sendgrid-go"
"github.com/sendgrid/sendgrid-go/helpers/mail"
)
type SendgridEmailProvider struct {
ApiKey string
Host string
Endpoint string
}
type SendgridResponseBody struct {
Errors []struct {
Message string `json:"message"`
Field interface{} `json:"field"`
Help interface{} `json:"help"`
} `json:"errors"`
}
func NewSendgridEmailProvider(apiKey string, host string, endpoint string) *SendgridEmailProvider {
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()
from := mail.NewEmail(fromName, fromAddress)
to := mail.NewEmail("", toAddress)
message := mail.NewSingleEmail(from, subject, to, "", content)
resp, err := client.Send(message)
if err != nil {
return err
}
if resp.StatusCode >= 300 {
var responseBody SendgridResponseBody
err = json.Unmarshal([]byte(resp.Body), &responseBody)
if err != nil {
return err
}
messages := []string{}
for _, sendgridError := range responseBody.Errors {
messages = append(messages, sendgridError.Message)
}
return fmt.Errorf("status code: %d, error message: %s", resp.StatusCode, messages)
}
if resp.StatusCode != http.StatusAccepted {
return fmt.Errorf("status code: %d", resp.StatusCode)
}
return nil
}
func (s *SendgridEmailProvider) initSendgridClient() *sendgrid.Client {
if s.Host == "" || s.Endpoint == "" {
return sendgrid.NewSendClient(s.ApiKey)
}
request := sendgrid.GetRequest(s.ApiKey, s.Endpoint, s.Host)
request.Method = "POST"
return &sendgrid.Client{Request: request}
}

View File

@ -16,9 +16,7 @@ package email
import ( import (
"crypto/tls" "crypto/tls"
"strings"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/gomail/v2" "github.com/casdoor/gomail/v2"
) )
@ -35,13 +33,6 @@ func NewSmtpEmailProvider(userName string, password string, host string, port in
dialer.SSL = !disableSsl dialer.SSL = !disableSsl
if strings.HasSuffix(host, ".amazonaws.com") {
socks5Proxy := conf.GetConfigString("socks5Proxy")
if socks5Proxy != "" {
dialer.SetSocks5Proxy(socks5Proxy)
}
}
return &SmtpEmailProvider{Dialer: dialer} return &SmtpEmailProvider{Dialer: dialer}
} }

View File

@ -1,81 +0,0 @@
// 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 faceId
import (
"strings"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
facebody20191230 "github.com/alibabacloud-go/facebody-20191230/v5/client"
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
)
type AliyunFaceIdProvider struct {
AccessKey string
AccessSecret string
Endpoint string
QualityScoreThreshold float32
}
func NewAliyunFaceIdProvider(accessKey string, accessSecret string, endPoint string) *AliyunFaceIdProvider {
return &AliyunFaceIdProvider{
AccessKey: accessKey,
AccessSecret: accessSecret,
Endpoint: endPoint,
QualityScoreThreshold: 0.65,
}
}
func (provider *AliyunFaceIdProvider) Check(base64ImageA string, base64ImageB string) (bool, error) {
config := openapi.Config{
AccessKeyId: tea.String(provider.AccessKey),
AccessKeySecret: tea.String(provider.AccessSecret),
}
config.Endpoint = tea.String(provider.Endpoint)
client, err := facebody20191230.NewClient(&config)
if err != nil {
return false, err
}
compareFaceRequest := &facebody20191230.CompareFaceRequest{
QualityScoreThreshold: tea.Float32(provider.QualityScoreThreshold),
ImageDataA: tea.String(strings.Replace(base64ImageA, "data:image/png;base64,", "", -1)),
ImageDataB: tea.String(strings.Replace(base64ImageB, "data:image/png;base64,", "", -1)),
}
runtime := &util.RuntimeOptions{}
defer func() {
if r := tea.Recover(recover()); r != nil {
err = r
}
}()
result, err := client.CompareFaceWithOptions(compareFaceRequest, runtime)
if err != nil {
return false, err
}
if result == nil {
return false, nil
}
if *result.Body.Data.Thresholds[0] < *result.Body.Data.Confidence {
return true, nil
}
return false, nil
}

View File

@ -1,23 +0,0 @@
// 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 faceId
type FaceIdProvider interface {
Check(base64ImageA string, base64ImageB string) (bool, error)
}
func GetFaceIdProvider(typ string, clientId string, clientSecret string, endPoint string) FaceIdProvider {
return NewAliyunFaceIdProvider(clientId, clientSecret, endPoint)
}

View File

@ -26,26 +26,20 @@ type AuthForm struct {
Name string `json:"name"` Name string `json:"name"`
FirstName string `json:"firstName"` FirstName string `json:"firstName"`
LastName string `json:"lastName"` LastName string `json:"lastName"`
Gender string `json:"gender"`
Bio string `json:"bio"`
Tag string `json:"tag"`
Education string `json:"education"`
Email string `json:"email"` Email string `json:"email"`
Phone string `json:"phone"` Phone string `json:"phone"`
Affiliation string `json:"affiliation"` Affiliation string `json:"affiliation"`
IdCard string `json:"idCard"` IdCard string `json:"idCard"`
Language string `json:"language"`
Region string `json:"region"` Region string `json:"region"`
InvitationCode string `json:"invitationCode"` InvitationCode string `json:"invitationCode"`
Application string `json:"application"` Application string `json:"application"`
ClientId string `json:"clientId"` ClientId string `json:"clientId"`
Provider string `json:"provider"` Provider string `json:"provider"`
ProviderBack string `json:"providerBack"` Code string `json:"code"`
Code string `json:"code"` State string `json:"state"`
State string `json:"state"` RedirectUri string `json:"redirectUri"`
RedirectUri string `json:"redirectUri"` Method string `json:"method"`
Method string `json:"method"`
EmailCode string `json:"emailCode"` EmailCode string `json:"emailCode"`
PhoneCode string `json:"phoneCode"` PhoneCode string `json:"phoneCode"`
@ -67,9 +61,6 @@ type AuthForm struct {
Plan string `json:"plan"` Plan string `json:"plan"`
Pricing string `json:"pricing"` Pricing string `json:"pricing"`
FaceId []float64 `json:"faceId"`
FaceIdImage []string `json:"faceIdImage"`
} }
func GetAuthFormFieldValue(form *AuthForm, fieldName string) (bool, string) { func GetAuthFormFieldValue(form *AuthForm, fieldName string) (bool, string) {

219
go.mod
View File

@ -1,31 +1,28 @@
module github.com/casdoor/casdoor module github.com/casdoor/casdoor
go 1.18 go 1.16
require ( require (
github.com/Masterminds/squirrel v1.5.3 github.com/Masterminds/squirrel v1.5.3
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4
github.com/alibabacloud-go/facebody-20191230/v5 v5.1.2
github.com/alibabacloud-go/tea v1.3.2
github.com/alibabacloud-go/tea-utils/v2 v2.0.7
github.com/aws/aws-sdk-go v1.45.5 github.com/aws/aws-sdk-go v1.45.5
github.com/beego/beego v1.12.12 github.com/beego/beego v1.12.12
github.com/beevik/etree v1.1.0 github.com/beevik/etree v1.1.0
github.com/casbin/casbin/v2 v2.77.2 github.com/casbin/casbin/v2 v2.77.2
github.com/casdoor/go-sms-sender v0.25.0 github.com/casdoor/go-sms-sender v0.19.0
github.com/casdoor/gomail/v2 v2.1.0 github.com/casdoor/gomail/v2 v2.0.1
github.com/casdoor/ldapserver v1.2.0 github.com/casdoor/notify v0.45.0
github.com/casdoor/notify v1.0.0 github.com/casdoor/oss v1.5.0
github.com/casdoor/oss v1.8.0
github.com/casdoor/xorm-adapter/v3 v3.1.0 github.com/casdoor/xorm-adapter/v3 v3.1.0
github.com/casvisor/casvisor-go-sdk v1.4.0 github.com/casvisor/casvisor-go-sdk v1.0.3
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
github.com/denisenkom/go-mssqldb v0.9.0 github.com/denisenkom/go-mssqldb v0.9.0
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
github.com/elimity-com/scim v0.0.0-20230426070224-941a5eac92f3 github.com/elimity-com/scim v0.0.0-20230426070224-941a5eac92f3
github.com/fogleman/gg v1.3.0 github.com/fogleman/gg v1.3.0
github.com/forestmgy/ldapserver v1.1.0
github.com/go-asn1-ber/asn1-ber v1.5.5 github.com/go-asn1-ber/asn1-ber v1.5.5
github.com/go-git/go-git/v5 v5.11.0 github.com/go-git/go-git/v5 v5.6.0
github.com/go-ldap/ldap/v3 v3.4.6 github.com/go-ldap/ldap/v3 v3.4.6
github.com/go-mysql-org/go-mysql v1.7.0 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.72
@ -33,12 +30,12 @@ require (
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
github.com/go-webauthn/webauthn v0.6.0 github.com/go-webauthn/webauthn v0.6.0
github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang-jwt/jwt/v4 v4.5.0
github.com/google/uuid v1.6.0 github.com/google/uuid v1.4.0
github.com/json-iterator/go v1.1.12 github.com/json-iterator/go v1.1.12
github.com/lestrrat-go/jwx v1.2.29 github.com/lestrrat-go/jwx v1.2.21
github.com/lib/pq v1.10.9 github.com/lib/pq v1.10.9
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
github.com/markbates/goth v1.79.0 github.com/markbates/goth v1.78.0
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/nyaruka/phonenumbers v1.1.5 github.com/nyaruka/phonenumbers v1.1.5
github.com/pquerna/otp v1.4.0 github.com/pquerna/otp v1.4.0
@ -48,201 +45,27 @@ require (
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/russellhaering/gosaml2 v0.9.0 github.com/russellhaering/gosaml2 v0.9.0
github.com/russellhaering/goxmldsig v1.2.0 github.com/russellhaering/goxmldsig v1.2.0
github.com/sendgrid/sendgrid-go v3.14.0+incompatible github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil v3.21.11+incompatible
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.8.4
github.com/stripe/stripe-go/v74 v74.29.0 github.com/stripe/stripe-go/v74 v74.29.0
github.com/tealeg/xlsx v1.0.5 github.com/tealeg/xlsx v1.0.5
github.com/thanhpk/randstr v1.0.4 github.com/thanhpk/randstr v1.0.4
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/xorm-io/builder v0.3.13 github.com/xorm-io/builder v0.3.13
github.com/xorm-io/core v0.7.4 github.com/xorm-io/core v0.7.4
github.com/xorm-io/xorm v1.1.6 github.com/xorm-io/xorm v1.1.6
golang.org/x/crypto v0.32.0 github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/net v0.34.0 golang.org/x/crypto v0.19.0
golang.org/x/oauth2 v0.17.0 golang.org/x/net v0.17.0
golang.org/x/text v0.21.0 golang.org/x/oauth2 v0.13.0
google.golang.org/api v0.150.0 google.golang.org/api v0.150.0
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/square/go-jose.v2 v2.6.0
layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68 layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68
maunium.net/go/mautrix v0.16.0 maunium.net/go/mautrix v0.16.0
modernc.org/sqlite v1.18.2 modernc.org/sqlite v1.18.2
) )
require (
cloud.google.com/go v0.110.8 // indirect
cloud.google.com/go/compute v1.23.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.3 // indirect
cloud.google.com/go/storage v1.35.1 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/azure-pipeline-go v0.2.3 // indirect
github.com/Azure/azure-storage-blob-go v0.15.0 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20221121042443-a3fd332d56d9 // indirect
github.com/SherClockHolmes/webpush-go v1.2.0 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
github.com/alibabacloud-go/darabonba-number v1.0.4 // indirect
github.com/alibabacloud-go/debug v1.0.1 // indirect
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
github.com/alibabacloud-go/openapi-util v0.1.0 // indirect
github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1 // indirect
github.com/alibabacloud-go/tea-fileform v1.1.1 // indirect
github.com/alibabacloud-go/tea-oss-sdk v1.1.3 // indirect
github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect
github.com/alibabacloud-go/tea-utils v1.3.6 // indirect
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.62.545 // indirect
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible // indirect
github.com/aliyun/credentials-go v1.3.10 // indirect
github.com/apistd/uni-go-sdk v0.0.2 // indirect
github.com/atc0005/go-teams-notify/v2 v2.6.1 // indirect
github.com/baidubce/bce-sdk-go v0.9.156 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blinkbean/dingtalk v0.0.0-20210905093040-7d935c0f7e19 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/bwmarrin/discordgo v0.27.1 // indirect
github.com/casdoor/casdoor-go-sdk v0.50.0 // indirect
github.com/casdoor/go-reddit/v2 v2.1.0 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/cschomburg/go-pushbullet v0.0.0-20171206132031-67759df45fbb // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/dghubble/oauth1 v0.7.2 // indirect
github.com/dghubble/sling v1.4.0 // indirect
github.com/di-wu/parser v0.2.2 // indirect
github.com/di-wu/xsd-datetime v1.0.0 // indirect
github.com/drswork/go-twitter v0.0.0-20221107160839-dea1b6ed53d7 // indirect
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/go-lark/lark v1.9.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-webauthn/revoke v0.1.6 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // 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
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gomodule/redigo v2.0.0+incompatible // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/go-tpm v0.3.3 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gregdel/pushover v1.2.1 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jonboulle/clockwork v0.2.2 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/line/line-bot-sdk-go v7.8.0+incompatible // indirect
github.com/markbates/going v1.0.0 // indirect
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-ieproxy v0.0.1 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mileusna/viber v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7 // indirect
github.com/pingcap/tidb/parser v0.0.0-20221126021158-6b02a5d8ba7d // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/common v0.30.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/qiniu/go-sdk/v7 v7.12.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/rs/zerolog v1.30.0 // indirect
github.com/scim2/filter-parser/v2 v2.2.0 // indirect
github.com/sendgrid/rest v2.6.9+incompatible // indirect
github.com/sergi/go-diff v1.1.0 // indirect
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/skeema/knownhosts v1.2.1 // indirect
github.com/slack-go/slack v0.12.3 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.744 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.744 // indirect
github.com/tidwall/gjson v1.16.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/twilio/twilio-go v1.13.0 // indirect
github.com/ucloud/ucloud-sdk-go v0.22.5 // indirect
github.com/utahta/go-linenotify v0.5.0 // indirect
github.com/volcengine/volc-sdk-golang v1.0.117 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.mau.fi/util v0.0.0-20230805171708-199bf3eec776 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.19.1 // indirect
golang.org/x/exp v0.0.0-20230810033253-352e893a4cad // indirect
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // 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
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
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.1.1 // indirect
maunium.net/go/maulogger/v2 v2.4.1 // indirect
modernc.org/cc/v3 v3.37.0 // indirect
modernc.org/ccgo/v3 v3.16.9 // indirect
modernc.org/libc v1.18.0 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.3.0 // indirect
modernc.org/opt v0.1.1 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
)

1854
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -45,8 +45,6 @@ func TestGenerateI18nFrontend(t *testing.T) {
applyToOtherLanguage("frontend", "uk", data) applyToOtherLanguage("frontend", "uk", data)
applyToOtherLanguage("frontend", "kk", data) applyToOtherLanguage("frontend", "kk", data)
applyToOtherLanguage("frontend", "fa", data) applyToOtherLanguage("frontend", "fa", data)
applyToOtherLanguage("frontend", "cs", data)
applyToOtherLanguage("frontend", "sk", data)
} }
func TestGenerateI18nBackend(t *testing.T) { func TestGenerateI18nBackend(t *testing.T) {
@ -75,6 +73,4 @@ func TestGenerateI18nBackend(t *testing.T) {
applyToOtherLanguage("backend", "uk", data) applyToOtherLanguage("backend", "uk", data)
applyToOtherLanguage("backend", "kk", data) applyToOtherLanguage("backend", "kk", data)
applyToOtherLanguage("backend", "fa", data) applyToOtherLanguage("backend", "fa", data)
applyToOtherLanguage("backend", "cs", data)
applyToOtherLanguage("backend", "sk", data)
} }

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -1,167 +0,0 @@
{
"account": {
"Failed to add user": "Nepodařilo se přidat uživatele",
"Get init score failed, error: %w": "Nepodařilo se získat počáteční skóre, chyba: %w",
"Please sign out first": "Nejprve se prosím odhlaste",
"The application does not allow to sign up new account": "Aplikace neumožňuje registraci nového účtu"
},
"auth": {
"Challenge method should be S256": "Metoda výzvy by měla být S256",
"Failed to create user, user information is invalid: %s": "Nepodařilo se vytvořit uživatele, informace o uživateli jsou neplatné: %s",
"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, 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 login method: login with LDAP is not enabled for the application": "Metoda přihlášení: přihlášení pomocí LDAP není pro aplikaci povolena",
"The login method: login with SMS is not enabled for the application": "Metoda přihlášení: přihlášení pomocí SMS není pro aplikaci povolena",
"The login method: login with email is not enabled for the application": "Metoda přihlášení: přihlášení pomocí emailu není pro aplikaci povolena",
"The login method: login with face is not enabled for the application": "Metoda přihlášení: 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 provider: %s is not enabled for the application": "Poskytovatel: %s není pro aplikaci povolen",
"Unauthorized operation": "Neoprávněná operace",
"Unknown authentication type (not password or provider), form = %s": "Neznámý typ autentizace (není heslo nebo poskytovatel), formulář = %s",
"User's tag: %s is not listed in the application's tags": "Štítek uživatele: %s není uveden v štítcích aplikace",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "Placený uživatel %s nemá aktivní nebo čekající předplatné a aplikace: %s nemá výchozí ceny"
},
"cas": {
"Service %s and %s do not match": "Služba %s a %s se neshodují"
},
"check": {
"Affiliation cannot be blank": "Příslušnost nemůže být prázdná",
"Default code does not match the code's matching rules": "Výchozí kód neodpovídá pravidlům pro shodu kódů",
"DisplayName cannot be blank": "Zobrazované jméno nemůže být prázdné",
"DisplayName is not valid real name": "Zobrazované jméno není platné skutečné jméno",
"Email already exists": "Email již existuje",
"Email cannot be empty": "Email nemůže být prázdný",
"Email is invalid": "Email je neplatný",
"Empty username.": "Prázdné uživatelské jméno.",
"Face data does not exist, cannot log in": "Data obličeje neexistují, nelze se přihlásit",
"Face data mismatch": "Neshoda dat obličeje",
"FirstName cannot be blank": "Křestní jméno nemůže být prázdné",
"Invitation code cannot be blank": "Pozvánkový kód nemůže být prázdný",
"Invitation code exhausted": "Pozvánkový kód vyčerpán",
"Invitation code is invalid": "Pozvánkový kód je neplatný",
"Invitation code suspended": "Pozvánkový kód pozastaven",
"LDAP user name or password incorrect": "Uživatelské jméno nebo heslo LDAP je nesprávné",
"LastName cannot be blank": "Příjmení nemůže být prázdné",
"Multiple accounts with same uid, please check your ldap server": "Více účtů se stejným uid, prosím zkontrolujte svůj ldap server",
"Organization does not exist": "Organizace neexistuje",
"Phone already exists": "Telefon již existuje",
"Phone cannot be empty": "Telefon nemůže být prázdný",
"Phone number is invalid": "Telefonní číslo je neplatné",
"Please register using the email corresponding to the invitation code": "Prosím zaregistrujte se pomocí emailu odpovídajícího pozvánkovému kódu",
"Please register using the phone corresponding to the invitation code": "Prosím zaregistrujte se pomocí telefonu odpovídajícího pozvánkovému kódu",
"Please register using the username corresponding to the invitation code": "Prosím zaregistrujte 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 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.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "Hodnota \\\"%s\\\" pro pole účtu \\\"%s\\\" neodpovídá regulárnímu výrazu položky účtu",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "Hodnota \\\"%s\\\" pro pole registrace \\\"%s\\\" neodpovídá regulárnímu výrazu položky registrace aplikace \\\"%s\\\"",
"Username already exists": "Uživatelské jméno již existuje",
"Username cannot be an email address": "Uživatelské jméno nemůže být emailová adresa",
"Username cannot contain white spaces": "Uživatelské jméno nemůže obsahovat mezery",
"Username cannot start with a digit": "Uživatelské jméno nemůže začínat číslicí",
"Username is too long (maximum is 255 characters).": "Uživatelské jméno je příliš dlouhé (maximálně 255 znaků).",
"Username must have at least 2 characters": "Uživatelské jméno musí mít alespoň 2 znaky",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Zadali jste špatné heslo nebo kód příliš mnohokrát, prosím počkejte %d minut a zkuste to znovu",
"Your region is not allow to signup by phone": "Vaše oblast neumožňuje registraci pomocí telefonu",
"password or code is incorrect": "heslo nebo kód je nesprávné",
"password or code is incorrect, you have %d remaining chances": "heslo nebo kód je nesprávné, máte %d zbývajících pokusů",
"unsupported password type: %s": "nepodporovaný typ hesla: %s"
},
"general": {
"Missing parameter": "Chybějící parametr",
"Please login first": "Prosím, přihlaste se nejprve",
"The organization: %s should have one application at least": "Organizace: %s by měla mít alespoň jednu aplikaci",
"The user: %s doesn't exist": "Uživatel: %s neexistuje",
"don't support captchaProvider: ": "nepodporuje captchaProvider: ",
"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"
},
"ldap": {
"Ldap server exist": "Ldap server existuje"
},
"link": {
"Please link first": "Prosím, nejprve propojte",
"This application has no providers": "Tato aplikace nemá žádné poskytovatele",
"This application has no providers of type": "Tato aplikace nemá žádné poskytovatele typu",
"This provider can't be unlinked": "Tento poskytovatel nemůže být odpojen",
"You are not the global admin, you can't unlink other users": "Nejste globální administrátor, nemůžete odpojovat jiné uživatele",
"You can't unlink yourself, you are not a member of any application": "Nemůžete odpojit sami sebe, nejste členem žádné aplikace"
},
"organization": {
"Only admin can modify the %s.": "Pouze administrátor může upravit %s.",
"The %s is immutable.": "%s je neměnný.",
"Unknown modify rule %s.": "Neznámé pravidlo úpravy %s."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "Oprávnění: \\\"%s\\\" neexistuje"
},
"provider": {
"Invalid application id": "Neplatné ID aplikace",
"the provider: %s does not exist": "poskytovatel: %s neexistuje"
},
"resource": {
"User is nil for tag: avatar": "Uživatel je nil pro tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Uživatelské jméno nebo úplná cesta k souboru je prázdná: uživatelské jméno = %s, úplná cesta k souboru = %s"
},
"saml": {
"Application %s not found": "Aplikace %s nebyla nalezena"
},
"saml_sp": {
"provider %s's category is not SAML": "poskytovatel %s není kategorie SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Prázdné parametry pro emailForm: %v",
"Invalid Email receivers: %s": "Neplatní příjemci emailu: %s",
"Invalid phone receivers: %s": "Neplatní příjemci telefonu: %s"
},
"storage": {
"The objectKey: %s is not allowed": "objectKey: %s není povolen",
"The provider type: %s is not supported": "typ poskytovatele: %s není podporován"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s není v této aplikaci podporován",
"Invalid application or wrong clientSecret": "Neplatná aplikace nebo špatný clientSecret",
"Invalid client_id": "Neplatné client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Přesměrovací URI: %s neexistuje v seznamu povolených přesměrovacích URI",
"Token not found, invalid accessToken": "Token nenalezen, neplatný accessToken"
},
"user": {
"Display name cannot be empty": "Zobrazované jméno nemůže být prázdné",
"New password cannot contain blank space.": "Nové heslo nemůže obsahovat prázdné místo."
},
"user_upload": {
"Failed to import users": "Nepodařilo se importovat uživatele"
},
"util": {
"No application is found for userId: %s": "Pro userId: %s nebyla nalezena žádná aplikace",
"No provider for category: %s is found for application: %s": "Pro kategorii: %s nebyl nalezen žádný poskytovatel pro aplikaci: %s",
"The provider: %s is not found": "Poskytovatel: %s nebyl nalezen"
},
"verification": {
"Invalid captcha provider.": "Neplatný poskytovatel captcha.",
"Phone number is invalid in your region %s": "Telefonní číslo je ve vaší oblasti %s neplatné",
"The verification code has not been sent yet!": "Ověřovací kód ještě nebyl odeslán!",
"The verification code has not been sent yet, or has already been used!": "Ověřovací kód ještě nebyl odeslán, nebo již byl použit!",
"Turing test failed.": "Turingův test selhal.",
"Unable to get the email modify rule.": "Nelze získat pravidlo pro úpravu emailu.",
"Unable to get the phone modify rule.": "Nelze získat pravidlo pro úpravu telefonu.",
"Unknown type": "Neznámý typ",
"Wrong verification code!": "Špatný ověřovací kód!",
"You should verify your code in %d min!": "Měli byste ověřit svůj kód do %d minut!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "prosím přidejte poskytovatele SMS do seznamu \\\"Providers\\\" pro aplikaci: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "prosím přidejte poskytovatele emailu do seznamu \\\"Providers\\\" pro aplikaci: %s",
"the user does not exist, please sign up first": "uživatel neexistuje, prosím nejprve se zaregistrujte"
},
"webauthn": {
"Found no credentials for this user": "Nebyly nalezeny žádné přihlašovací údaje pro tohoto uživatele",
"Please call WebAuthnSigninBegin first": "Prosím, nejprve zavolejte WebAuthnSigninBegin"
}
}

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "Die Anmeldeart \"Anmeldung mit Passwort\" 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": "The organization: %s does not exist", "The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "Der Anbieter: %s ist nicht für die Anwendung aktiviert", "The provider: %s is not enabled for the application": "Der Anbieter: %s ist nicht für die Anwendung aktiviert",
@ -39,8 +38,6 @@
"Email cannot be empty": "E-Mail darf nicht leer sein", "Email cannot be empty": "E-Mail darf nicht leer sein",
"Email is invalid": "E-Mail ist ungültig", "Email is invalid": "E-Mail ist ungültig",
"Empty username.": "Leerer Benutzername.", "Empty username.": "Leerer Benutzername.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "Vorname darf nicht leer sein", "FirstName cannot be blank": "Vorname darf nicht leer sein",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Benutzername kann keine E-Mail-Adresse sein", "Username cannot be an email address": "Benutzername kann keine E-Mail-Adresse sein",
"Username cannot contain white spaces": "Benutzername darf keine Leerzeichen enthalten", "Username cannot contain white spaces": "Benutzername darf keine Leerzeichen enthalten",
"Username cannot start with a digit": "Benutzername darf nicht mit einer Ziffer beginnen", "Username cannot start with a digit": "Benutzername darf nicht mit einer Ziffer beginnen",
"Username is too long (maximum is 255 characters).": "Benutzername ist zu lang (das Maximum beträgt 255 Zeichen).", "Username is too long (maximum is 39 characters).": "Benutzername ist zu lang (das Maximum beträgt 39 Zeichen).",
"Username must have at least 2 characters": "Benutzername muss mindestens 2 Zeichen lang sein", "Username must have at least 2 characters": "Benutzername muss mindestens 2 Zeichen lang sein",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Sie haben zu oft das falsche Passwort oder den falschen Code eingegeben. Bitte warten Sie %d Minuten und versuchen Sie es erneut", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Sie haben zu oft das falsche Passwort oder den falschen Code eingegeben. Bitte warten Sie %d Minuten und versuchen Sie es erneut",
"Your region is not allow to signup by phone": "Ihre Region ist nicht berechtigt, sich telefonisch anzumelden", "Your region is not allow to signup by phone": "Ihre Region ist nicht berechtigt, sich telefonisch anzumelden",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "Der Benutzer %s existiert nicht", "The user: %s doesn't exist": "Der Benutzer %s existiert nicht",
"don't support captchaProvider: ": "Unterstütze captchaProvider nicht:", "don't support captchaProvider: ": "Unterstütze captchaProvider nicht:",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Es gibt einen LDAP-Server" "Ldap server exist": "Es gibt einen LDAP-Server"
@ -146,10 +142,9 @@
"The provider: %s is not found": "Der Anbieter: %s wurde nicht gefunden" "The provider: %s is not found": "Der Anbieter: %s wurde nicht gefunden"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Der Code wurde noch nicht versendet!",
"Invalid captcha provider.": "Ungültiger Captcha-Anbieter.", "Invalid captcha provider.": "Ungültiger Captcha-Anbieter.",
"Phone number is invalid in your region %s": "Die Telefonnummer ist in Ihrer Region %s ungültig", "Phone number is invalid in your region %s": "Die Telefonnummer ist in Ihrer Region %s ungültig",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing-Test fehlgeschlagen.", "Turing test failed.": "Turing-Test fehlgeschlagen.",
"Unable to get the email modify rule.": "Nicht in der Lage, die E-Mail-Änderungsregel zu erhalten.", "Unable to get the email modify rule.": "Nicht in der Lage, die E-Mail-Änderungsregel zu erhalten.",
"Unable to get the phone modify rule.": "Nicht in der Lage, die Telefon-Änderungsregel zu erhalten.", "Unable to get the phone modify rule.": "Nicht in der Lage, die Telefon-Änderungsregel zu erhalten.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "El método de inicio de sesión: inicio de sesión con contraseña 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": "The organization: %s does not exist", "The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "El proveedor: %s no está habilitado para la aplicación", "The provider: %s is not enabled for the application": "El proveedor: %s no está habilitado para la aplicación",
@ -39,8 +38,6 @@
"Email cannot be empty": "El correo electrónico no puede estar vacío", "Email cannot be empty": "El correo electrónico no puede estar vacío",
"Email is invalid": "El correo electrónico no es válido", "Email is invalid": "El correo electrónico no es válido",
"Empty username.": "Nombre de usuario vacío.", "Empty username.": "Nombre de usuario vacío.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "El nombre no puede estar en blanco", "FirstName cannot be blank": "El nombre no puede estar en blanco",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Nombre de usuario no puede ser una dirección de correo electrónico", "Username cannot be an email address": "Nombre de usuario no puede ser una dirección de correo electrónico",
"Username cannot contain white spaces": "Nombre de usuario no puede contener espacios en blanco", "Username cannot contain white spaces": "Nombre de usuario no puede contener espacios en blanco",
"Username cannot start with a digit": "El nombre de usuario no puede empezar con un dígito", "Username cannot start with a digit": "El nombre de usuario no puede empezar con un dígito",
"Username is too long (maximum is 255 characters).": "El nombre de usuario es demasiado largo (el máximo es de 255 caracteres).", "Username is too long (maximum is 39 characters).": "El nombre de usuario es demasiado largo (el máximo es de 39 caracteres).",
"Username must have at least 2 characters": "Nombre de usuario debe tener al menos 2 caracteres", "Username must have at least 2 characters": "Nombre de usuario debe tener al menos 2 caracteres",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Has ingresado la contraseña o código incorrecto demasiadas veces, por favor espera %d minutos e intenta de nuevo", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Has ingresado la contraseña o código incorrecto demasiadas veces, por favor espera %d minutos e intenta de nuevo",
"Your region is not allow to signup by phone": "Tu región no está permitida para registrarse por teléfono", "Your region is not allow to signup by phone": "Tu región no está permitida para registrarse por teléfono",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "El usuario: %s no existe", "The user: %s doesn't exist": "El usuario: %s no existe",
"don't support captchaProvider: ": "No apoyo a captchaProvider", "don't support captchaProvider: ": "No apoyo a captchaProvider",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "El servidor LDAP existe" "Ldap server exist": "El servidor LDAP existe"
@ -146,10 +142,9 @@
"The provider: %s is not found": "El proveedor: %s no se encuentra" "The provider: %s is not found": "El proveedor: %s no se encuentra"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "¡El código aún no ha sido enviado!",
"Invalid captcha provider.": "Proveedor de captcha no válido.", "Invalid captcha provider.": "Proveedor de captcha no válido.",
"Phone number is invalid in your region %s": "El número de teléfono es inválido en tu región %s", "Phone number is invalid in your region %s": "El número de teléfono es inválido en tu región %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "El test de Turing falló.", "Turing test failed.": "El test de Turing falló.",
"Unable to get the email modify rule.": "No se puede obtener la regla de modificación de correo electrónico.", "Unable to get the email modify rule.": "No se puede obtener la regla de modificación de correo electrónico.",
"Unable to get the phone modify rule.": "No se pudo obtener la regla de modificación del teléfono.", "Unable to get the phone modify rule.": "No se pudo obtener la regla de modificación del teléfono.",

View File

@ -1,167 +1,162 @@
{ {
"account": { "account": {
"Failed to add user": "عدم موفقیت در افزودن کاربر", "Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "عدم موفقیت در دریافت امتیاز اولیه، خطا: %w", "Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "لطفاً ابتدا خارج شوید", "Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "برنامه اجازه ثبت‌نام حساب جدید را نمی‌دهد" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"auth": { "auth": {
"Challenge method should be S256": "روش چالش باید S256 باشد", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "عدم موفقیت در ایجاد کاربر، اطلاعات کاربر نامعتبر است: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "عدم موفقیت در ورود: %s", "Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "توکن نامعتبر", "Invalid token": "Invalid token",
"State expected: %s, but got: %s": "وضعیت مورد انتظار: %s، اما دریافت شد: %s", "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": "حساب برای ارائه‌دهنده: %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": "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": "حساب برای ارائه‌دهنده: %s و نام کاربری: %s (%s) وجود ندارد و مجاز به ثبت‌نام به‌عنوان حساب جدید نیست، لطفاً با پشتیبانی IT خود تماس بگیرید", "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)": "حساب برای ارائه‌دهنده: %s و نام کاربری: %s (%s) در حال حاضر به حساب دیگری مرتبط است: %s (%s)", "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": "برنامه: %s وجود ندارد", "The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "روش ورود: ورود با LDAP برای برنامه فعال نیست", "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 SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "روش ورود: ورود با ایمیل برای برنامه فعال نیست", "The login method: login with email is not enabled for the application": "The login method: login with 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 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 does not exist": "سازمان: %s وجود ندارد", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"The provider: %s is not enabled for the application": "ارائه‌دهنده: %s برای برنامه فعال نیست", "Unauthorized operation": "Unauthorized operation",
"Unauthorized operation": "عملیات غیرمجاز", "Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"Unknown authentication type (not password or provider), form = %s": "نوع احراز هویت ناشناخته (نه رمز عبور و نه ارائه‌دهنده)، فرم = %s", "User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"User's tag: %s is not listed in the application's tags": "برچسب کاربر: %s در برچسب‌های برنامه فهرست نشده است", "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing"
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "کاربر پرداختی %s اشتراک فعال یا در انتظار ندارد و برنامه: %s قیمت‌گذاری پیش‌فرض ندارد"
}, },
"cas": { "cas": {
"Service %s and %s do not match": "سرویس %s و %s مطابقت ندارند" "Service %s and %s do not match": "Service %s and %s do not match"
}, },
"check": { "check": {
"Affiliation cannot be blank": "وابستگی نمی‌تواند خالی باشد", "Affiliation cannot be blank": "Affiliation cannot be blank",
"Default code does not match the code's matching rules": "کد پیش‌فرض با قوانین تطبیق کد مطابقت ندارد", "Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "نام نمایشی نمی‌تواند خالی باشد", "DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "نام نمایشی یک نام واقعی معتبر نیست", "DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "ایمیل قبلاً وجود دارد", "Email already exists": "Email already exists",
"Email cannot be empty": "ایمیل نمی‌تواند خالی باشد", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "ایمیل نامعتبر است", "Email is invalid": "Email is invalid",
"Empty username.": "نام کاربری خالی است.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "داده‌های چهره وجود ندارد، نمی‌توان وارد شد", "FirstName cannot be blank": "FirstName cannot be blank",
"Face data mismatch": "عدم تطابق داده‌های چهره", "Invitation code cannot be blank": "Invitation code cannot be blank",
"FirstName cannot be blank": "نام نمی‌تواند خالی باشد", "Invitation code exhausted": "Invitation code exhausted",
"Invitation code cannot be blank": "کد دعوت نمی‌تواند خالی باشد", "Invitation code is invalid": "Invitation code is invalid",
"Invitation code exhausted": "کد دعوت استفاده شده است", "Invitation code suspended": "Invitation code suspended",
"Invitation code is invalid": "کد دعوت نامعتبر است", "LDAP user name or password incorrect": "LDAP user name or password incorrect",
"Invitation code suspended": "کد دعوت معلق است", "LastName cannot be blank": "LastName cannot be blank",
"LDAP user name or password incorrect": "نام کاربری یا رمز عبور LDAP نادرست است", "Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"LastName cannot be blank": "نام خانوادگی نمی‌تواند خالی باشد", "Organization does not exist": "Organization does not exist",
"Multiple accounts with same uid, please check your ldap server": "چندین حساب با uid یکسان، لطفاً سرور LDAP خود را بررسی کنید", "Phone already exists": "Phone already exists",
"Organization does not exist": "سازمان وجود ندارد", "Phone cannot be empty": "Phone cannot be empty",
"Phone already exists": "تلفن قبلاً وجود دارد", "Phone number is invalid": "Phone number is invalid",
"Phone cannot be empty": "تلفن نمی‌تواند خالی باشد", "Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Phone number is invalid": "شماره تلفن نامعتبر است", "Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the email corresponding to the invitation code": "لطفاً با استفاده از ایمیل مربوط به کد دعوت ثبت‌نام کنید", "Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "لطفاً با استفاده از تلفن مربوط به کد دعوت ثبت‌نام کنید", "Session outdated, please login again": "Session outdated, please login again",
"Please register using the username corresponding to the invitation code": "لطفاً با استفاده از نام کاربری مربوط به کد دعوت ثبت‌نام کنید", "The invitation code has already been used": "The invitation code has already been used",
"Session outdated, please login again": "جلسه منقضی شده است، لطفاً دوباره وارد شوید", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The invitation code has already been used": "کد دعوت قبلاً استفاده شده است", "The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The user is forbidden to sign in, please contact the administrator": "ورود کاربر ممنوع است، لطفاً با مدیر تماس بگیرید", "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"The user: %s doesn't exist in LDAP server": "کاربر: %s در سرور LDAP وجود ندارد", "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "نام کاربری فقط می‌تواند حاوی کاراکترهای الفبایی عددی، زیرخط یا خط تیره باشد، نمی‌تواند خط تیره یا زیرخط متوالی داشته باشد، و نمی‌تواند با خط تیره یا زیرخط شروع یا پایان یابد.", "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"The value \"%s\" for account field \"%s\" doesn't match the account item regex": "مقدار \"%s\" برای فیلد حساب \"%s\" با عبارت منظم مورد حساب مطابقت ندارد", "Username already exists": "Username already exists",
"The value \"%s\" for signup field \"%s\" doesn't match the signup item regex of the application \"%s\"": "مقدار \"%s\" برای فیلد ثبت‌نام \"%s\" با عبارت منظم مورد ثبت‌نام برنامه \"%s\" مطابقت ندارد", "Username cannot be an email address": "Username cannot be an email address",
"Username already exists": "نام کاربری قبلاً وجود دارد", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot be an email address": "نام کاربری نمی‌تواند یک آدرس ایمیل باشد", "Username cannot start with a digit": "Username cannot start with a digit",
"Username cannot contain white spaces": "نام کاربری نمی‌تواند حاوی فاصله باشد", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username cannot start with a digit": "نام کاربری نمی‌تواند با یک رقم شروع شود", "Username must have at least 2 characters": "Username must have at least 2 characters",
"Username is too long (maximum is 255 characters).": "نام کاربری بیش از حد طولانی است (حداکثر ۳۹ کاراکتر).", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Username must have at least 2 characters": "نام کاربری باید حداقل ۲ کاراکتر داشته باشد", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "شما رمز عبور یا کد اشتباه را بیش از حد وارد کرده‌اید، لطفاً %d دقیقه صبر کنید و دوباره تلاش کنید", "password or code is incorrect": "password or code is incorrect",
"Your region is not allow to signup by phone": "منطقه شما اجازه ثبت‌نام با تلفن را ندارد", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"password or code is incorrect": "رمز عبور یا کد نادرست است", "unsupported password type: %s": "unsupported password type: %s"
"password or code is incorrect, you have %d remaining chances": "رمز عبور یا کد نادرست است، شما %d فرصت باقی‌مانده دارید",
"unsupported password type: %s": "نوع رمز عبور پشتیبانی نشده: %s"
}, },
"general": { "general": {
"Missing parameter": "پارامتر گمشده", "Missing parameter": "Missing parameter",
"Please login first": "لطفاً ابتدا وارد شوید", "Please login first": "Please login first",
"The organization: %s should have one application at least": "سازمان: %s باید حداقل یک برنامه داشته باشد", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "کاربر: %s وجود ندارد", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "از captchaProvider پشتیبانی نمی‌شود: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "این عملیات در حالت دمو مجاز نیست", "this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation requires administrator to perform": "این عملیات نیاز به مدیر برای انجام دارد"
}, },
"ldap": { "ldap": {
"Ldap server exist": "سرور LDAP وجود دارد" "Ldap server exist": "Ldap server exist"
}, },
"link": { "link": {
"Please link first": "لطفاً ابتدا پیوند دهید", "Please link first": "Please link first",
"This application has no providers": "این برنامه ارائه‌دهنده‌ای ندارد", "This application has no providers": "This application has no providers",
"This application has no providers of type": "این برنامه ارائه‌دهنده‌ای از نوع ندارد", "This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "این ارائه‌دهنده نمی‌تواند لغو پیوند شود", "This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "شما مدیر جهانی نیستید، نمی‌توانید کاربران دیگر را لغو پیوند کنید", "You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "شما نمی‌توانید خودتان را لغو پیوند کنید، شما عضو هیچ برنامه‌ای نیستید" "You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
}, },
"organization": { "organization": {
"Only admin can modify the %s.": "فقط مدیر می‌تواند %s را تغییر دهد.", "Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "%s غیرقابل تغییر است.", "The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "قانون تغییر ناشناخته %s." "Unknown modify rule %s.": "Unknown modify rule %s."
}, },
"permission": { "permission": {
"The permission: \"%s\" doesn't exist": "مجوز: \"%s\" وجود ندارد" "The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
}, },
"provider": { "provider": {
"Invalid application id": "شناسه برنامه نامعتبر", "Invalid application id": "Invalid application id",
"the provider: %s does not exist": "ارائه‌دهنده: %s وجود ندارد" "the provider: %s does not exist": "the provider: %s does not exist"
}, },
"resource": { "resource": {
"User is nil for tag: avatar": "کاربر برای برچسب: آواتار تهی است", "User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "نام کاربری یا مسیر کامل فایل خالی است: نام کاربری = %s، مسیر کامل فایل = %s" "Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
}, },
"saml": { "saml": {
"Application %s not found": "برنامه %s یافت نشد" "Application %s not found": "Application %s not found"
}, },
"saml_sp": { "saml_sp": {
"provider %s's category is not SAML": "دسته‌بندی ارائه‌دهنده %s SAML نیست" "provider %s's category is not SAML": "provider %s's category is not SAML"
}, },
"service": { "service": {
"Empty parameters for emailForm: %v": "پارامترهای خالی برای emailForm: %v", "Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "گیرندگان ایمیل نامعتبر: %s", "Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "گیرندگان تلفن نامعتبر: %s" "Invalid phone receivers: %s": "Invalid phone receivers: %s"
}, },
"storage": { "storage": {
"The objectKey: %s is not allowed": "objectKey: %s مجاز نیست", "The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "نوع ارائه‌دهنده: %s پشتیبانی نمی‌شود" "The provider type: %s is not supported": "The provider type: %s is not supported"
}, },
"token": { "token": {
"Grant_type: %s is not supported in this application": "grant_type: %s در این برنامه پشتیبانی نمی‌شود", "Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "برنامه نامعتبر یا clientSecret نادرست", "Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "client_id نامعتبر", "Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "آدرس بازگشت: %s در لیست آدرس‌های بازگشت مجاز وجود ندارد", "Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "توکن یافت نشد، accessToken نامعتبر" "Token not found, invalid accessToken": "Token not found, invalid accessToken"
}, },
"user": { "user": {
"Display name cannot be empty": "نام نمایشی نمی‌تواند خالی باشد", "Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "رمز عبور جدید نمی‌تواند حاوی فاصله خالی باشد." "New password cannot contain blank space.": "New password cannot contain blank space."
}, },
"user_upload": { "user_upload": {
"Failed to import users": "عدم موفقیت در وارد کردن کاربران" "Failed to import users": "Failed to import users"
}, },
"util": { "util": {
"No application is found for userId: %s": "هیچ برنامه‌ای برای userId: %s یافت نشد", "No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "هیچ ارائه‌دهنده‌ای برای دسته‌بندی: %s برای برنامه: %s یافت نشد", "No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"The provider: %s is not found": "ارائه‌دهنده: %s یافت نشد" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Invalid captcha provider.": "ارائه‌دهنده کپچا نامعتبر.", "Code has not been sent yet!": "Code has not been sent yet!",
"Phone number is invalid in your region %s": "شماره تلفن در منطقه شما نامعتبر است %s", "Invalid captcha provider.": "Invalid captcha provider.",
"The verification code has not been sent yet!": "کد تأیید هنوز ارسال نشده است!", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet, or has already been used!": "کد تأیید هنوز ارسال نشده است، یا قبلاً استفاده شده است!", "Turing test failed.": "Turing test failed.",
"Turing test failed.": "تست تورینگ ناموفق بود.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the email modify rule.": "عدم توانایی در دریافت قانون تغییر ایمیل.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unable to get the phone modify rule.": "عدم توانایی در دریافت قانون تغییر تلفن.", "Unknown type": "Unknown type",
"Unknown type": "نوع ناشناخته", "Wrong verification code!": "Wrong verification code!",
"Wrong verification code!": "کد تأیید اشتباه!", "You should verify your code in %d min!": "You should verify your code in %d min!",
"You should verify your code in %d min!": "شما باید کد خود را در %d دقیقه تأیید کنید!", "please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add a SMS provider to the \"Providers\" list for the application: %s": "لطفاً یک ارائه‌دهنده پیامک به لیست \"ارائه‌دهندگان\" برای برنامه: %s اضافه کنید", "please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \"Providers\" list for the application: %s": "لطفاً یک ارائه‌دهنده ایمیل به لیست \"ارائه‌دهندگان\" برای برنامه: %s اضافه کنید", "the user does not exist, please sign up first": "the user does not exist, please sign up first"
"the user does not exist, please sign up first": "کاربر وجود ندارد، لطفاً ابتدا ثبت‌نام کنید"
}, },
"webauthn": { "webauthn": {
"Found no credentials for this user": "هیچ اعتباری برای این کاربر یافت نشد", "Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "لطفاً ابتدا WebAuthnSigninBegin را فراخوانی کنید" "Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
} }
} }

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "La méthode de connexion : connexion avec mot de passe 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": "The organization: %s does not exist", "The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "Le fournisseur :%s n'est pas activé pour l'application", "The provider: %s is not enabled for the application": "Le fournisseur :%s n'est pas activé pour l'application",
@ -39,8 +38,6 @@
"Email cannot be empty": "L'e-mail ne peut pas être vide", "Email cannot be empty": "L'e-mail ne peut pas être vide",
"Email is invalid": "L'adresse e-mail est invalide", "Email is invalid": "L'adresse e-mail est invalide",
"Empty username.": "Nom d'utilisateur vide.", "Empty username.": "Nom d'utilisateur vide.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "Le prénom ne peut pas être laissé vide", "FirstName cannot be blank": "Le prénom ne peut pas être laissé vide",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Nom d'utilisateur ne peut pas être une adresse e-mail", "Username cannot be an email address": "Nom d'utilisateur ne peut pas être une adresse e-mail",
"Username cannot contain white spaces": "Nom d'utilisateur ne peut pas contenir d'espaces blancs", "Username cannot contain white spaces": "Nom d'utilisateur ne peut pas contenir d'espaces blancs",
"Username cannot start with a digit": "Nom d'utilisateur ne peut pas commencer par un chiffre", "Username cannot start with a digit": "Nom d'utilisateur ne peut pas commencer par un chiffre",
"Username is too long (maximum is 255 characters).": "Nom d'utilisateur est trop long (maximum de 255 caractères).", "Username is too long (maximum is 39 characters).": "Nom d'utilisateur est trop long (maximum de 39 caractères).",
"Username must have at least 2 characters": "Le nom d'utilisateur doit comporter au moins 2 caractères", "Username must have at least 2 characters": "Le nom d'utilisateur doit comporter au moins 2 caractères",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Vous avez entré le mauvais mot de passe ou code plusieurs fois, veuillez attendre %d minutes et réessayer", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Vous avez entré le mauvais mot de passe ou code plusieurs fois, veuillez attendre %d minutes et réessayer",
"Your region is not allow to signup by phone": "Votre région n'est pas autorisée à s'inscrire par téléphone", "Your region is not allow to signup by phone": "Votre région n'est pas autorisée à s'inscrire par téléphone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "L'utilisateur : %s n'existe pas", "The user: %s doesn't exist": "L'utilisateur : %s n'existe pas",
"don't support captchaProvider: ": "ne prend pas en charge captchaProvider: ", "don't support captchaProvider: ": "ne prend pas en charge captchaProvider: ",
"this operation is not allowed in demo mode": "cette opération nest pas autorisée en mode démo", "this operation is not allowed in demo mode": "cette opération nest pas autorisée en mode démo"
"this operation requires administrator to perform": "this operation requires administrator to perform"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Le serveur LDAP existe" "Ldap server exist": "Le serveur LDAP existe"
@ -146,10 +142,9 @@
"The provider: %s is not found": "Le fournisseur : %s n'a pas été trouvé" "The provider: %s is not found": "Le fournisseur : %s n'a pas été trouvé"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Le code n'a pas encore été envoyé !",
"Invalid captcha provider.": "Fournisseur de captcha invalide.", "Invalid captcha provider.": "Fournisseur de captcha invalide.",
"Phone number is invalid in your region %s": "Le numéro de téléphone n'est pas valide dans votre région %s", "Phone number is invalid in your region %s": "Le numéro de téléphone n'est pas valide dans votre région %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Le test de Turing a échoué.", "Turing test failed.": "Le test de Turing a échoué.",
"Unable to get the email modify rule.": "Incapable d'obtenir la règle de modification de courriel.", "Unable to get the email modify rule.": "Incapable d'obtenir la règle de modification de courriel.",
"Unable to get the phone modify rule.": "Impossible d'obtenir la règle de modification de téléphone.", "Unable to get the phone modify rule.": "Impossible d'obtenir la règle de modification de téléphone.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "Metode login: login dengan kata sandi tidak diaktifkan untuk aplikasi tersebut", "The login method: login with password is not enabled for the application": "Metode login: login dengan kata sandi tidak diaktifkan untuk aplikasi tersebut",
"The organization: %s does not exist": "The organization: %s does not exist", "The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "Penyedia: %s tidak diaktifkan untuk aplikasi ini", "The provider: %s is not enabled for the application": "Penyedia: %s tidak diaktifkan untuk aplikasi ini",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email tidak boleh kosong", "Email cannot be empty": "Email tidak boleh kosong",
"Email is invalid": "Email tidak valid", "Email is invalid": "Email tidak valid",
"Empty username.": "Nama pengguna kosong.", "Empty username.": "Nama pengguna kosong.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "Nama depan tidak boleh kosong", "FirstName cannot be blank": "Nama depan tidak boleh kosong",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username tidak bisa menjadi alamat email", "Username cannot be an email address": "Username tidak bisa menjadi alamat email",
"Username cannot contain white spaces": "Username tidak boleh mengandung spasi", "Username cannot contain white spaces": "Username tidak boleh mengandung spasi",
"Username cannot start with a digit": "Username tidak dapat dimulai dengan angka", "Username cannot start with a digit": "Username tidak dapat dimulai dengan angka",
"Username is too long (maximum is 255 characters).": "Nama pengguna terlalu panjang (maksimum 255 karakter).", "Username is too long (maximum is 39 characters).": "Nama pengguna terlalu panjang (maksimum 39 karakter).",
"Username must have at least 2 characters": "Nama pengguna harus memiliki setidaknya 2 karakter", "Username must have at least 2 characters": "Nama pengguna harus memiliki setidaknya 2 karakter",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Anda telah memasukkan kata sandi atau kode yang salah terlalu banyak kali, mohon tunggu selama %d menit dan coba lagi", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Anda telah memasukkan kata sandi atau kode yang salah terlalu banyak kali, mohon tunggu selama %d menit dan coba lagi",
"Your region is not allow to signup by phone": "Wilayah Anda tidak diizinkan untuk mendaftar melalui telepon", "Your region is not allow to signup by phone": "Wilayah Anda tidak diizinkan untuk mendaftar melalui telepon",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "Pengguna: %s tidak ada", "The user: %s doesn't exist": "Pengguna: %s tidak ada",
"don't support captchaProvider: ": "Jangan mendukung captchaProvider:", "don't support captchaProvider: ": "Jangan mendukung captchaProvider:",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Server ldap ada" "Ldap server exist": "Server ldap ada"
@ -146,10 +142,9 @@
"The provider: %s is not found": "Penyedia: %s tidak ditemukan" "The provider: %s is not found": "Penyedia: %s tidak ditemukan"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Kode belum dikirimkan!",
"Invalid captcha provider.": "Penyedia captcha tidak valid.", "Invalid captcha provider.": "Penyedia captcha tidak valid.",
"Phone number is invalid in your region %s": "Nomor telepon tidak valid di wilayah anda %s", "Phone number is invalid in your region %s": "Nomor telepon tidak valid di wilayah anda %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Tes Turing gagal.", "Turing test failed.": "Tes Turing gagal.",
"Unable to get the email modify rule.": "Tidak dapat memperoleh aturan modifikasi email.", "Unable to get the email modify rule.": "Tidak dapat memperoleh aturan modifikasi email.",
"Unable to get the phone modify rule.": "Tidak dapat memodifikasi aturan telepon.", "Unable to get the phone modify rule.": "Tidak dapat memodifikasi aturan telepon.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "ログイン方法:パスワードでのログインはアプリケーションで有効になっていません", "The login method: login with password is not enabled for the application": "ログイン方法:パスワードでのログインはアプリケーションで有効になっていません",
"The organization: %s does not exist": "The organization: %s does not exist", "The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "プロバイダー:%sはアプリケーションでは有効化されていません", "The provider: %s is not enabled for the application": "プロバイダー:%sはアプリケーションでは有効化されていません",
@ -39,8 +38,6 @@
"Email cannot be empty": "メールが空白にできません", "Email cannot be empty": "メールが空白にできません",
"Email is invalid": "電子メールは無効です", "Email is invalid": "電子メールは無効です",
"Empty username.": "空のユーザー名。", "Empty username.": "空のユーザー名。",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "ファーストネームは空白にできません", "FirstName cannot be blank": "ファーストネームは空白にできません",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "ユーザー名には電子メールアドレスを使用できません", "Username cannot be an email address": "ユーザー名には電子メールアドレスを使用できません",
"Username cannot contain white spaces": "ユーザ名にはスペースを含めることはできません", "Username cannot contain white spaces": "ユーザ名にはスペースを含めることはできません",
"Username cannot start with a digit": "ユーザー名は数字で始めることはできません", "Username cannot start with a digit": "ユーザー名は数字で始めることはできません",
"Username is too long (maximum is 255 characters).": "ユーザー名が長すぎます(最大255文字)。", "Username is too long (maximum is 39 characters).": "ユーザー名が長すぎます(最大39文字)。",
"Username must have at least 2 characters": "ユーザー名は少なくとも2文字必要です", "Username must have at least 2 characters": "ユーザー名は少なくとも2文字必要です",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "あなたは間違ったパスワードまたはコードを何度も入力しました。%d 分間待ってから再度お試しください", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "あなたは間違ったパスワードまたはコードを何度も入力しました。%d 分間待ってから再度お試しください",
"Your region is not allow to signup by phone": "あなたの地域は電話でサインアップすることができません", "Your region is not allow to signup by phone": "あなたの地域は電話でサインアップすることができません",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "そのユーザー:%sは存在しません", "The user: %s doesn't exist": "そのユーザー:%sは存在しません",
"don't support captchaProvider: ": "captchaProviderをサポートしないでください", "don't support captchaProvider: ": "captchaProviderをサポートしないでください",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "LDAPサーバーは存在します" "Ldap server exist": "LDAPサーバーは存在します"
@ -146,10 +142,9 @@
"The provider: %s is not found": "プロバイダー:%sが見つかりません" "The provider: %s is not found": "プロバイダー:%sが見つかりません"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "まだコードが送信されていません!",
"Invalid captcha provider.": "無効なCAPTCHAプロバイダー。", "Invalid captcha provider.": "無効なCAPTCHAプロバイダー。",
"Phone number is invalid in your region %s": "電話番号はあなたの地域で無効です %s", "Phone number is invalid in your region %s": "電話番号はあなたの地域で無効です %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "チューリングテストは失敗しました。", "Turing test failed.": "チューリングテストは失敗しました。",
"Unable to get the email modify rule.": "電子メール変更規則を取得できません。", "Unable to get the email modify rule.": "電子メール変更規則を取得できません。",
"Unable to get the phone modify rule.": "電話の変更ルールを取得できません。", "Unable to get the phone modify rule.": "電話の変更ルールを取得できません。",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "어플리케이션에서는 암호를 사용한 로그인 방법이 활성화되어 있지 않습니다", "The login method: login with password is not enabled for the application": "어플리케이션에서는 암호를 사용한 로그인 방법이 활성화되어 있지 않습니다",
"The organization: %s does not exist": "The organization: %s does not exist", "The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "제공자 %s은(는) 응용 프로그램에서 활성화되어 있지 않습니다", "The provider: %s is not enabled for the application": "제공자 %s은(는) 응용 프로그램에서 활성화되어 있지 않습니다",
@ -39,8 +38,6 @@
"Email cannot be empty": "이메일은 비어 있을 수 없습니다", "Email cannot be empty": "이메일은 비어 있을 수 없습니다",
"Email is invalid": "이메일이 유효하지 않습니다", "Email is invalid": "이메일이 유효하지 않습니다",
"Empty username.": "빈 사용자 이름.", "Empty username.": "빈 사용자 이름.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "이름은 공백일 수 없습니다", "FirstName cannot be blank": "이름은 공백일 수 없습니다",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "사용자 이름은 이메일 주소가 될 수 없습니다", "Username cannot be an email address": "사용자 이름은 이메일 주소가 될 수 없습니다",
"Username cannot contain white spaces": "사용자 이름에는 공백이 포함될 수 없습니다", "Username cannot contain white spaces": "사용자 이름에는 공백이 포함될 수 없습니다",
"Username cannot start with a digit": "사용자 이름은 숫자로 시작할 수 없습니다", "Username cannot start with a digit": "사용자 이름은 숫자로 시작할 수 없습니다",
"Username is too long (maximum is 255 characters).": "사용자 이름이 너무 깁니다 (최대 255자).", "Username is too long (maximum is 39 characters).": "사용자 이름이 너무 깁니다 (최대 39자).",
"Username must have at least 2 characters": "사용자 이름은 적어도 2개의 문자가 있어야 합니다", "Username must have at least 2 characters": "사용자 이름은 적어도 2개의 문자가 있어야 합니다",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "올바르지 않은 비밀번호나 코드를 여러 번 입력했습니다. %d분 동안 기다리신 후 다시 시도해주세요", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "올바르지 않은 비밀번호나 코드를 여러 번 입력했습니다. %d분 동안 기다리신 후 다시 시도해주세요",
"Your region is not allow to signup by phone": "당신의 지역은 전화로 가입할 수 없습니다", "Your region is not allow to signup by phone": "당신의 지역은 전화로 가입할 수 없습니다",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "사용자 %s는 존재하지 않습니다", "The user: %s doesn't exist": "사용자 %s는 존재하지 않습니다",
"don't support captchaProvider: ": "CaptchaProvider를 지원하지 마세요", "don't support captchaProvider: ": "CaptchaProvider를 지원하지 마세요",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "LDAP 서버가 존재합니다" "Ldap server exist": "LDAP 서버가 존재합니다"
@ -146,10 +142,9 @@
"The provider: %s is not found": "제공자: %s를 찾을 수 없습니다" "The provider: %s is not found": "제공자: %s를 찾을 수 없습니다"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "코드는 아직 전송되지 않았습니다!",
"Invalid captcha provider.": "잘못된 captcha 제공자입니다.", "Invalid captcha provider.": "잘못된 captcha 제공자입니다.",
"Phone number is invalid in your region %s": "전화 번호가 당신의 지역 %s에서 유효하지 않습니다", "Phone number is invalid in your region %s": "전화 번호가 당신의 지역 %s에서 유효하지 않습니다",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "튜링 테스트 실패.", "Turing test failed.": "튜링 테스트 실패.",
"Unable to get the email modify rule.": "이메일 수정 규칙을 가져올 수 없습니다.", "Unable to get the email modify rule.": "이메일 수정 규칙을 가져올 수 없습니다.",
"Unable to get the phone modify rule.": "전화 수정 규칙을 가져올 수 없습니다.", "Unable to get the phone modify rule.": "전화 수정 규칙을 가져올 수 없습니다.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "O nome de usuário não pode começar com um dígito", "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 is too long (maximum is 39 characters).": "Nome de usuário é muito longo (máximo é 39 caracteres).",
"Username must have at least 2 characters": "Nome de usuário deve ter pelo menos 2 caracteres", "Username must have at least 2 characters": "Nome de usuário deve ter pelo menos 2 caracteres",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -15,10 +15,9 @@
"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) 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 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 does not exist": "Приложение: %s не существует",
"The login method: login with LDAP is not enabled for the application": "Метод входа в систему: вход с помощью LDAP не включен для приложения", "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": "Метод входа: вход с помощью SMS не включен для приложения", "The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "Метод входа: вход с помощью электронной почты не включен для приложения", "The login method: login with email is not enabled for the application": "The login method: login with 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 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "Провайдер: %s не включен для приложения", "The provider: %s is not enabled for the application": "Провайдер: %s не включен для приложения",
@ -39,8 +38,6 @@
"Email cannot be empty": "Электронная почта не может быть пустой", "Email cannot be empty": "Электронная почта не может быть пустой",
"Email is invalid": "Адрес электронной почты недействительный", "Email is invalid": "Адрес электронной почты недействительный",
"Empty username.": "Пустое имя пользователя.", "Empty username.": "Пустое имя пользователя.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "Имя не может быть пустым", "FirstName cannot be blank": "Имя не может быть пустым",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -53,21 +50,21 @@
"Phone already exists": "Телефон уже существует", "Phone already exists": "Телефон уже существует",
"Phone cannot be empty": "Телефон не может быть пустым", "Phone cannot be empty": "Телефон не может быть пустым",
"Phone number is invalid": "Номер телефона является недействительным", "Phone number is invalid": "Номер телефона является недействительным",
"Please register using the email corresponding to the invitation code": "Пожалуйста, зарегистрируйтесь, используя электронную почту, соответствующую коду приглашения", "Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Пожалуйста, зарегистрируйтесь по телефону, соответствующему коду приглашения", "Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Пожалуйста, зарегистрируйтесь, используя имя пользователя, соответствующее коду приглашения", "Please register using the username corresponding to the invitation code": "Please register using the 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 invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "Пользователю запрещен вход, пожалуйста, обратитесь к администратору", "The user is forbidden to sign in, please contact the administrator": "Пользователю запрещен вход, пожалуйста, обратитесь к администратору",
"The user: %s doesn't exist in LDAP server": "Пользователь %s не существует на LDAP сервере", "The user: %s doesn't exist in LDAP server": "Пользователь %s не существует на LDAP сервере",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Имя пользователя может состоять только из буквенно-цифровых символов, нижних подчеркиваний или дефисов, не может содержать последовательные дефисы или подчеркивания, а также не может начинаться или заканчиваться на дефис или подчеркивание.", "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Имя пользователя может состоять только из буквенно-цифровых символов, нижних подчеркиваний или дефисов, не может содержать последовательные дефисы или подчеркивания, а также не может начинаться или заканчиваться на дефис или подчеркивание.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "Значение \\\"%s\\\" для поля аккаунта \\\"%s\\\" не соответствует регулярному значению", "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "Значение \\\"%s\\\" поля регистрации \\\"%s\\\" не соответствует регулярному выражению приложения \\\"%s\\\"", "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Имя пользователя уже существует", "Username already exists": "Имя пользователя уже существует",
"Username cannot be an email address": "Имя пользователя не может быть адресом электронной почты", "Username cannot be an email address": "Имя пользователя не может быть адресом электронной почты",
"Username cannot contain white spaces": "Имя пользователя не может содержать пробелы", "Username cannot contain white spaces": "Имя пользователя не может содержать пробелы",
"Username cannot start with a digit": "Имя пользователя не может начинаться с цифры", "Username cannot start with a digit": "Имя пользователя не может начинаться с цифры",
"Username is too long (maximum is 255 characters).": "Имя пользователя слишком длинное (максимальная длина - 255 символов).", "Username is too long (maximum is 39 characters).": "Имя пользователя слишком длинное (максимальная длина - 39 символов).",
"Username must have at least 2 characters": "Имя пользователя должно содержать не менее 2 символов", "Username must have at least 2 characters": "Имя пользователя должно содержать не менее 2 символов",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Вы ввели неправильный пароль или код слишком много раз, пожалуйста, подождите %d минут и попробуйте снова", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Вы ввели неправильный пароль или код слишком много раз, пожалуйста, подождите %d минут и попробуйте снова",
"Your region is not allow to signup by phone": "Ваш регион не разрешает регистрацию по телефону", "Your region is not allow to signup by phone": "Ваш регион не разрешает регистрацию по телефону",
@ -78,11 +75,10 @@
"general": { "general": {
"Missing parameter": "Отсутствующий параметр", "Missing parameter": "Отсутствующий параметр",
"Please login first": "Пожалуйста, сначала войдите в систему", "Please login first": "Пожалуйста, сначала войдите в систему",
"The organization: %s should have one application at least": "Организация: %s должна иметь хотя бы одно приложение", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "Пользователь %s не существует", "The user: %s doesn't exist": "Пользователь %s не существует",
"don't support captchaProvider: ": "неподдерживаемый captchaProvider: ", "don't support captchaProvider: ": "неподдерживаемый captchaProvider: ",
"this operation is not allowed in demo mode": "эта операция не разрешена в демо-режиме", "this operation is not allowed in demo mode": "эта операция не разрешена в демо-режиме"
"this operation requires administrator to perform": "для выполнения этой операции требуется администратор"
}, },
"ldap": { "ldap": {
"Ldap server exist": "LDAP-сервер существует" "Ldap server exist": "LDAP-сервер существует"
@ -101,11 +97,11 @@
"Unknown modify rule %s.": "Неизвестное изменение правила %s." "Unknown modify rule %s.": "Неизвестное изменение правила %s."
}, },
"permission": { "permission": {
"The permission: \\\"%s\\\" doesn't exist": "Разрешение: \\\"%s\\\" не существует" "The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
}, },
"provider": { "provider": {
"Invalid application id": "Неверный идентификатор приложения", "Invalid application id": "Неверный идентификатор приложения",
"the provider: %s does not exist": "Провайдер: %s не существует" "the provider: %s does not exist": "провайдер: %s не существует"
}, },
"resource": { "resource": {
"User is nil for tag: avatar": "Пользователь равен нулю для тега: аватар", "User is nil for tag: avatar": "Пользователь равен нулю для тега: аватар",
@ -115,7 +111,7 @@
"Application %s not found": "Приложение %s не найдено" "Application %s not found": "Приложение %s не найдено"
}, },
"saml_sp": { "saml_sp": {
"provider %s's category is not SAML": "Категория провайдера %s не является SAML" "provider %s's category is not SAML": "категория провайдера %s не является SAML"
}, },
"service": { "service": {
"Empty parameters for emailForm: %v": "Пустые параметры для emailForm: %v", "Empty parameters for emailForm: %v": "Пустые параметры для emailForm: %v",
@ -146,18 +142,17 @@
"The provider: %s is not found": "Поставщик: %s не найден" "The provider: %s is not found": "Поставщик: %s не найден"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Код еще не был отправлен!",
"Invalid captcha provider.": "Недействительный поставщик CAPTCHA.", "Invalid captcha provider.": "Недействительный поставщик CAPTCHA.",
"Phone number is invalid in your region %s": "Номер телефона недействителен в вашем регионе %s", "Phone number is invalid in your region %s": "Номер телефона недействителен в вашем регионе %s",
"The verification code has not been sent yet!": "Код проверки еще не отправлен!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Тест Тьюринга не удался.", "Turing test failed.": "Тест Тьюринга не удался.",
"Unable to get the email modify rule.": "Невозможно получить правило изменения электронной почты.", "Unable to get the email modify rule.": "Невозможно получить правило изменения электронной почты.",
"Unable to get the phone modify rule.": "Невозможно получить правило изменения телефона.", "Unable to get the phone modify rule.": "Невозможно получить правило изменения телефона.",
"Unknown type": "Неизвестный тип", "Unknown type": "Неизвестный тип",
"Wrong verification code!": "Неправильный код подтверждения!", "Wrong verification code!": "Неправильный код подтверждения!",
"You should verify your code in %d min!": "Вы должны проверить свой код через %d минут!", "You should verify your code in %d min!": "Вы должны проверить свой код через %d минут!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "Пожалуйста, добавьте поставщика SMS в список \\\"Провайдеры\\\" для приложения: %s", "please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "Пожалуйста, добавьте поставщика электронной почты в список \\\"Провайдеры\\\" для приложения: %s", "please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "Пользователь не существует, пожалуйста, сначала зарегистрируйтесь" "the user does not exist, please sign up first": "Пользователь не существует, пожалуйста, сначала зарегистрируйтесь"
}, },
"webauthn": { "webauthn": {

View File

@ -1,167 +0,0 @@
{
"account": {
"Failed to add user": "Nepodarilo sa pridať používateľa",
"Get init score failed, error: %w": "Získanie počiatočného skóre zlyhalo, chyba: %w",
"Please sign out first": "Najskôr sa prosím odhláste",
"The application does not allow to sign up new account": "Aplikácia neumožňuje registráciu nového účtu"
},
"auth": {
"Challenge method should be S256": "Metóda výzvy by mala byť S256",
"Failed to create user, user information is invalid: %s": "Nepodarilo sa vytvoriť používateľa, informácie o používateľovi sú neplatné: %s",
"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, 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 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 provider: %s is not enabled for the application": "Poskytovateľ: %s nie je pre aplikáciu povolený",
"Unauthorized operation": "Neautorizovaná operácia",
"Unknown authentication type (not password or provider), form = %s": "Neznámy typ autentifikácie (nie heslo alebo poskytovateľ), forma = %s",
"User's tag: %s is not listed in the application's tags": "Štítok používateľa: %s nie je uvedený v štítkoch aplikácie",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "platiaci používateľ %s nemá aktívne alebo čakajúce predplatné a aplikácia: %s nemá predvolenú cenovú politiku"
},
"cas": {
"Service %s and %s do not match": "Služba %s a %s sa nezhodujú"
},
"check": {
"Affiliation cannot be blank": "Príslušnosť nemôže byť prázdna",
"Default code does not match the code's matching rules": "Predvolený kód nezodpovedá pravidlám zodpovedania kódu",
"DisplayName cannot be blank": "Zobrazované meno nemôže byť prázdne",
"DisplayName is not valid real name": "Zobrazované meno nie je platné skutočné meno",
"Email already exists": "E-mail už existuje",
"Email cannot be empty": "E-mail nemôže byť prázdny",
"Email is invalid": "E-mail je neplatný",
"Empty username.": "Prázdne používateľské meno.",
"Face data does not exist, cannot log in": "Dáta o tvári neexistujú, nemožno sa prihlásiť",
"Face data mismatch": "Nesúlad dát o tvári",
"FirstName cannot be blank": "Meno nemôže byť prázdne",
"Invitation code cannot be blank": "Kód pozvania nemôže byť prázdny",
"Invitation code exhausted": "Kód pozvania bol vyčerpaný",
"Invitation code is invalid": "Kód pozvania je neplatný",
"Invitation code suspended": "Kód pozvania bol pozastavený",
"LDAP user name or password incorrect": "LDAP používateľské meno alebo heslo sú nesprávne",
"LastName cannot be blank": "Priezvisko nemôže byť prázdne",
"Multiple accounts with same uid, please check your ldap server": "Viacero účtov s rovnakým uid, skontrolujte svoj ldap server",
"Organization does not exist": "Organizácia neexistuje",
"Phone already exists": "Telefón už existuje",
"Phone cannot be empty": "Telefón nemôže byť prázdny",
"Phone number is invalid": "Telefónne číslo je neplatné",
"Please register using the email corresponding to the invitation code": "Prosím, zaregistrujte sa pomocou e-mailu zodpovedajúceho kódu pozvania",
"Please register using the phone corresponding to the invitation code": "Prosím, zaregistrujte sa pomocou telefónu zodpovedajúceho kódu pozvania",
"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 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.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "Hodnota \\\"%s\\\" pre pole účtu \\\"%s\\\" nezodpovedá regulárnemu výrazu položky účtu",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "Hodnota \\\"%s\\\" pre pole registrácie \\\"%s\\\" nezodpovedá regulárnemu výrazu položky registrácie aplikácie \\\"%s\\\"",
"Username already exists": "Používateľské meno už existuje",
"Username cannot be an email address": "Používateľské meno nemôže byť e-mailová adresa",
"Username cannot contain white spaces": "Používateľské meno nemôže obsahovať medzery",
"Username cannot start with a digit": "Používateľské meno nemôže začínať číslicou",
"Username is too long (maximum is 255 characters).": "Používateľské meno je príliš dlhé (maximum je 255 znakov).",
"Username must have at least 2 characters": "Používateľské meno musí mať aspoň 2 znaky",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Zadali ste nesprávne heslo alebo kód príliš veľa krát, prosím, počkajte %d minút a skúste to znova",
"Your region is not allow to signup by phone": "Váš región neumožňuje registráciu cez telefón",
"password or code is incorrect": "heslo alebo kód je nesprávne",
"password or code is incorrect, you have %d remaining chances": "heslo alebo kód je nesprávne, máte %d zostávajúcich pokusov",
"unsupported password type: %s": "nepodporovaný typ hesla: %s"
},
"general": {
"Missing parameter": "Chýbajúci parameter",
"Please login first": "Najskôr sa prosím prihláste",
"The organization: %s should have one application at least": "Organizácia: %s by mala mať aspoň jednu aplikáciu",
"The user: %s doesn't exist": "Používateľ: %s neexistuje",
"don't support captchaProvider: ": "nepodporuje captchaProvider: ",
"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"
},
"ldap": {
"Ldap server exist": "LDAP server existuje"
},
"link": {
"Please link first": "Najskôr sa prosím prepojte",
"This application has no providers": "Táto aplikácia nemá žiadnych poskytovateľov",
"This application has no providers of type": "Táto aplikácia nemá poskytovateľov typu",
"This provider can't be unlinked": "Tento poskytovateľ nemôže byť odpojený",
"You are not the global admin, you can't unlink other users": "Nie ste globálny administrátor, nemôžete odpojiť iných používateľov",
"You can't unlink yourself, you are not a member of any application": "Nemôžete sa odpojiť, nie ste členom žiadnej aplikácie"
},
"organization": {
"Only admin can modify the %s.": "Len administrátor môže upravovať %s.",
"The %s is immutable.": "%s je nemenný.",
"Unknown modify rule %s.": "Neznáme pravidlo úprav %s."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "Povolenie: \\\"%s\\\" neexistuje"
},
"provider": {
"Invalid application id": "Neplatné id aplikácie",
"the provider: %s does not exist": "poskytovateľ: %s neexistuje"
},
"resource": {
"User is nil for tag: avatar": "Používateľ je nil pre tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Používateľské meno alebo fullFilePath je prázdny: používateľské meno = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Aplikácia %s nebola nájdená"
},
"saml_sp": {
"provider %s's category is not SAML": "kategória poskytovateľa %s nie je SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Prázdne parametre pre emailForm: %v",
"Invalid Email receivers: %s": "Neplatní príjemcovia e-mailu: %s",
"Invalid phone receivers: %s": "Neplatní príjemcovia telefónu: %s"
},
"storage": {
"The objectKey: %s is not allowed": "objectKey: %s nie je povolený",
"The provider type: %s is not supported": "Typ poskytovateľa: %s nie je podporovaný"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s nie je podporovaný v tejto aplikácii",
"Invalid application or wrong clientSecret": "Neplatná aplikácia alebo nesprávny clientSecret",
"Invalid client_id": "Neplatný client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s neexistuje v zozname povolených Redirect URI",
"Token not found, invalid accessToken": "Token nebol nájdený, neplatný accessToken"
},
"user": {
"Display name cannot be empty": "Zobrazované meno nemôže byť prázdne",
"New password cannot contain blank space.": "Nové heslo nemôže obsahovať medzery."
},
"user_upload": {
"Failed to import users": "Nepodarilo sa importovať používateľov"
},
"util": {
"No application is found for userId: %s": "Nebola nájdená žiadna aplikácia pre userId: %s",
"No provider for category: %s is found for application: %s": "Pre aplikáciu: %s nebol nájdený žiadny poskytovateľ pre kategóriu: %s",
"The provider: %s is not found": "Poskytovateľ: %s nebol nájdený"
},
"verification": {
"Invalid captcha provider.": "Neplatný captcha poskytovateľ.",
"Phone number is invalid in your region %s": "Telefónne číslo je neplatné vo vašom regióne %s",
"The verification code has not been sent yet!": "Overovací kód ešte nebol odoslaný!",
"The verification code has not been sent yet, or has already been used!": "Overovací kód ešte nebol odoslaný, alebo bol už použitý!",
"Turing test failed.": "Test Turinga zlyhal.",
"Unable to get the email modify rule.": "Nepodarilo sa získať pravidlo úpravy e-mailu.",
"Unable to get the phone modify rule.": "Nepodarilo sa získať pravidlo úpravy telefónu.",
"Unknown type": "Neznámy typ",
"Wrong verification code!": "Nesprávny overovací kód!",
"You should verify your code in %d min!": "Overte svoj kód za %d minút!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "prosím pridajte SMS poskytovateľa do zoznamu \\\"Poskytovatelia\\\" pre aplikáciu: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "prosím pridajte e-mailového poskytovateľa do zoznamu \\\"Poskytovatelia\\\" pre aplikáciu: %s",
"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": "Nenašli sa žiadne prihlasovacie údaje pre tohto používateľa",
"Please call WebAuthnSigninBegin first": "Najskôr prosím zavolajte WebAuthnSigninBegin"
}
}

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Kullanıcı adı bir e-mail adresi olamaz", "Username cannot be an email address": "Kullanıcı adı bir e-mail adresi olamaz",
"Username cannot contain white spaces": "Kullanıcı adı boşluk karakteri içeremez", "Username cannot contain white spaces": "Kullanıcı adı boşluk karakteri içeremez",
"Username cannot start with a digit": "Kullanıcı adı rakamla başlayamaz", "Username cannot start with a digit": "Kullanıcı adı rakamla başlayamaz",
"Username is too long (maximum is 255 characters).": "Kullanıcı adı çok uzun (en fazla 255 karakter olmalı).", "Username is too long (maximum is 39 characters).": "Kullanıcı adı çok uzun (en fazla 39 karakter olmalı).",
"Username must have at least 2 characters": "Kullanıcı adı en az iki karakterden oluşmalı", "Username must have at least 2 characters": "Kullanıcı adı en az iki karakterden oluşmalı",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Çok fazla hatalı şifre denemesi yaptınız. %d dakika kadar bekleyip yeniden giriş yapmayı deneyebilirsiniz.", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Çok fazla hatalı şifre denemesi yaptınız. %d dakika kadar bekleyip yeniden giriş yapmayı deneyebilirsiniz.",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Telefon numaranızın bulunduğu bölgeye hizmet veremiyoruz", "Phone number is invalid in your region %s": "Telefon numaranızın bulunduğu bölgeye hizmet veremiyoruz",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The 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 does not exist": "The organization: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email cannot be empty", "Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Empty username.": "Empty username.", "Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "FirstName cannot be blank", "FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone", "Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist", "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ", "don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "this operation 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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@ -146,10 +142,9 @@
"The provider: %s is not found": "The provider: %s is not found" "The provider: %s is not found": "The provider: %s is not found"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@ -18,7 +18,6 @@
"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 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 SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application", "The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "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 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": "The organization: %s does not exist", "The organization: %s does not exist": "The organization: %s does not exist",
"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", "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",
@ -39,8 +38,6 @@
"Email cannot be empty": "Email không thể để trống", "Email cannot be empty": "Email không thể để trống",
"Email is invalid": "Địa chỉ email không hợp lệ", "Email is invalid": "Địa chỉ email không hợp lệ",
"Empty username.": "Tên đăng nhập trống.", "Empty username.": "Tên đăng nhập trống.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"FirstName cannot be blank": "Tên không được để trống", "FirstName cannot be blank": "Tên không được để trống",
"Invitation code cannot be blank": "Invitation code cannot be blank", "Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted", "Invitation code exhausted": "Invitation code exhausted",
@ -67,7 +64,7 @@
"Username cannot be an email address": "Tên người dùng không thể là địa chỉ email", "Username cannot be an email address": "Tên người dùng không thể là địa chỉ email",
"Username cannot contain white spaces": "Tên người dùng không thể chứa khoảng trắng", "Username cannot contain white spaces": "Tên người dùng không thể chứa khoảng trắng",
"Username cannot start with a digit": "Tên người dùng không thể bắt đầu bằng chữ số", "Username cannot start with a digit": "Tên người dùng không thể bắt đầu bằng chữ số",
"Username is too long (maximum is 255 characters).": "Tên đăng nhập quá dài (tối đa là 255 ký tự).", "Username is too long (maximum is 39 characters).": "Tên đăng nhập quá dài (tối đa là 39 ký tự).",
"Username must have at least 2 characters": "Tên đăng nhập phải có ít nhất 2 ký tự", "Username must have at least 2 characters": "Tên đăng nhập phải có ít nhất 2 ký tự",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Bạn đã nhập sai mật khẩu hoặc mã quá nhiều lần, vui lòng đợi %d phút và thử lại", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Bạn đã nhập sai mật khẩu hoặc mã quá nhiều lần, vui lòng đợi %d phút và thử lại",
"Your region is not allow to signup by phone": "Vùng của bạn không được phép đăng ký bằng điện thoại", "Your region is not allow to signup by phone": "Vùng của bạn không được phép đăng ký bằng điện thoại",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "The organization: %s should have one application at least", "The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "Người dùng: %s không tồn tại", "The user: %s doesn't exist": "Người dùng: %s không tồn tại",
"don't support captchaProvider: ": "không hỗ trợ captchaProvider: ", "don't support captchaProvider: ": "không hỗ trợ captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode", "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"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Máy chủ LDAP tồn tại" "Ldap server exist": "Máy chủ LDAP tồn tại"
@ -146,10 +142,9 @@
"The provider: %s is not found": "Nhà cung cấp: %s không được tìm thấy" "The provider: %s is not found": "Nhà cung cấp: %s không được tìm thấy"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Mã chưa được gửi đến!",
"Invalid captcha provider.": "Nhà cung cấp captcha không hợp lệ.", "Invalid captcha provider.": "Nhà cung cấp captcha không hợp lệ.",
"Phone number is invalid in your region %s": "Số điện thoại không hợp lệ trong vùng của bạn %s", "Phone number is invalid in your region %s": "Số điện thoại không hợp lệ trong vùng của bạn %s",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
"Turing test failed.": "Kiểm định Turing thất bại.", "Turing test failed.": "Kiểm định Turing thất bại.",
"Unable to get the email modify rule.": "Không thể lấy quy tắc sửa đổi email.", "Unable to get the email modify rule.": "Không thể lấy quy tắc sửa đổi email.",
"Unable to get the phone modify rule.": "Không thể thay đổi quy tắc trên điện thoại.", "Unable to get the phone modify rule.": "Không thể thay đổi quy tắc trên điện thoại.",

View File

@ -18,7 +18,6 @@
"The login method: login with LDAP is not enabled for the application": "该应用禁止采用LDAP登录方式", "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 SMS is not enabled for the application": "该应用禁止采用短信登录方式",
"The login method: login with email is not enabled for the application": "该应用禁止采用邮箱登录方式", "The login method: login with email is not enabled for the application": "该应用禁止采用邮箱登录方式",
"The login method: login with face is not enabled for the application": "该应用禁止采用人脸登录",
"The login method: login with 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": "组织: %s 不存在", "The organization: %s does not exist": "组织: %s 不存在",
"The provider: %s is not enabled for the application": "该应用的提供商: %s未被启用", "The provider: %s is not enabled for the application": "该应用的提供商: %s未被启用",
@ -39,8 +38,6 @@
"Email cannot be empty": "邮箱不可为空", "Email cannot be empty": "邮箱不可为空",
"Email is invalid": "无效邮箱", "Email is invalid": "无效邮箱",
"Empty username.": "用户名不可为空", "Empty username.": "用户名不可为空",
"Face data does not exist, cannot log in": "未录入人脸数据,无法登录",
"Face data mismatch": "人脸不匹配",
"FirstName cannot be blank": "名不可以为空", "FirstName cannot be blank": "名不可以为空",
"Invitation code cannot be blank": "邀请码不能为空", "Invitation code cannot be blank": "邀请码不能为空",
"Invitation code exhausted": "邀请码使用次数已耗尽", "Invitation code exhausted": "邀请码使用次数已耗尽",
@ -67,7 +64,7 @@
"Username cannot be an email address": "用户名不可以是邮箱地址", "Username cannot be an email address": "用户名不可以是邮箱地址",
"Username cannot contain white spaces": "用户名禁止包含空格", "Username cannot contain white spaces": "用户名禁止包含空格",
"Username cannot start with a digit": "用户名禁止使用数字开头", "Username cannot start with a digit": "用户名禁止使用数字开头",
"Username is too long (maximum is 255 characters).": "用户名过长(最大允许长度为255个字符)", "Username is too long (maximum is 39 characters).": "用户名过长(最大允许长度为39个字符)",
"Username must have at least 2 characters": "用户名至少要有2个字符", "Username must have at least 2 characters": "用户名至少要有2个字符",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "密码错误次数已达上限,请在 %d 分后重试", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "密码错误次数已达上限,请在 %d 分后重试",
"Your region is not allow to signup by phone": "所在地区不支持手机号注册", "Your region is not allow to signup by phone": "所在地区不支持手机号注册",
@ -81,8 +78,7 @@
"The organization: %s should have one application at least": "组织: %s 应该拥有至少一个应用", "The organization: %s should have one application at least": "组织: %s 应该拥有至少一个应用",
"The user: %s doesn't exist": "用户: %s不存在", "The user: %s doesn't exist": "用户: %s不存在",
"don't support captchaProvider: ": "不支持验证码提供商: ", "don't support captchaProvider: ": "不支持验证码提供商: ",
"this operation is not allowed in demo mode": "demo模式下不允许该操作", "this operation is not allowed in demo mode": "demo模式下不允许该操作"
"this operation requires administrator to perform": "只有管理员才能进行此操作"
}, },
"ldap": { "ldap": {
"Ldap server exist": "LDAP服务器已存在" "Ldap server exist": "LDAP服务器已存在"
@ -146,10 +142,9 @@
"The provider: %s is not found": "未找到提供商: %s" "The provider: %s is not found": "未找到提供商: %s"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "验证码还未发送",
"Invalid captcha provider.": "非法的验证码提供商", "Invalid captcha provider.": "非法的验证码提供商",
"Phone number is invalid in your region %s": "您所在地区的电话号码无效 %s", "Phone number is invalid in your region %s": "您所在地区的电话号码无效 %s",
"The verification code has not been sent yet!": "验证码未发送!",
"The verification code has not been sent yet, or has already been used!": "验证码未发送或已被使用!",
"Turing test failed.": "验证码还未发送", "Turing test failed.": "验证码还未发送",
"Unable to get the email modify rule.": "无法获取邮箱修改规则", "Unable to get the email modify rule.": "无法获取邮箱修改规则",
"Unable to get the phone modify rule.": "无法获取手机号修改规则", "Unable to get the phone modify rule.": "无法获取手机号修改规则",

View File

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

View File

@ -98,19 +98,11 @@ func (idp *CustomIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
return nil, err return nil, err
} }
requiredFields := []string{"id", "username", "displayName"}
for _, field := range requiredFields {
_, ok := idp.UserMapping[field]
if !ok {
return nil, fmt.Errorf("cannot find %s in userMapping, please check your configuration in custom provider", field)
}
}
// map user info // map user info
for k, v := range idp.UserMapping { for k, v := range idp.UserMapping {
_, ok := dataMap[v] _, ok := dataMap[v]
if !ok { if !ok {
return nil, fmt.Errorf("cannot find %s in user from custom provider", v) return nil, fmt.Errorf("cannot find %s in user from castom provider", v)
} }
dataMap[k] = dataMap[v] dataMap[k] = dataMap[v]
} }

View File

@ -188,23 +188,10 @@ type GitHubUserInfo struct {
} `json:"plan"` } `json:"plan"`
} }
type GitHubUserEmailInfo struct {
Email string `json:"email"`
Primary bool `json:"primary"`
Verified bool `json:"verified"`
Visibility string `json:"visibility"`
}
type GitHubErrorInfo struct {
Message string `json:"message"`
DocumentationUrl string `json:"documentation_url"`
Status string `json:"status"`
}
func (idp *GithubIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) { func (idp *GithubIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
req, err := http.NewRequest("GET", "https://api.github.com/user", nil) req, err := http.NewRequest("GET", "https://api.github.com/user", nil)
if err != nil { if err != nil {
return nil, err panic(err)
} }
req.Header.Add("Authorization", "token "+token.AccessToken) req.Header.Add("Authorization", "token "+token.AccessToken)
resp, err := idp.Client.Do(req) resp, err := idp.Client.Do(req)
@ -225,42 +212,6 @@ func (idp *GithubIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
return nil, err return nil, err
} }
if githubUserInfo.Email == "" {
reqEmail, err := http.NewRequest("GET", "https://api.github.com/user/emails", nil)
if err != nil {
return nil, err
}
reqEmail.Header.Add("Authorization", "token "+token.AccessToken)
respEmail, err := idp.Client.Do(reqEmail)
if err != nil {
return nil, err
}
defer respEmail.Body.Close()
emailBody, err := io.ReadAll(respEmail.Body)
if err != nil {
return nil, err
}
if respEmail.StatusCode != 200 {
var errMessage GitHubErrorInfo
err = json.Unmarshal(emailBody, &errMessage)
if err != nil {
return nil, err
}
fmt.Printf("GithubIdProvider:GetUserInfo() error, status code = %d, error message = %v\n", respEmail.StatusCode, errMessage)
} else {
var userEmails []GitHubUserEmailInfo
err = json.Unmarshal(emailBody, &userEmails)
if err != nil {
return nil, err
}
githubUserInfo.Email = idp.getEmailFromEmailsResult(userEmails)
}
}
userInfo := UserInfo{ userInfo := UserInfo{
Id: strconv.Itoa(githubUserInfo.Id), Id: strconv.Itoa(githubUserInfo.Id),
Username: githubUserInfo.Login, Username: githubUserInfo.Login,
@ -297,27 +248,3 @@ func (idp *GithubIdProvider) postWithBody(body interface{}, url string) ([]byte,
return data, nil return data, nil
} }
func (idp *GithubIdProvider) getEmailFromEmailsResult(emailInfo []GitHubUserEmailInfo) string {
primaryEmail := ""
verifiedEmail := ""
for _, addr := range emailInfo {
if !addr.Verified || strings.Contains(addr.Email, "users.noreply.github.com") {
continue
}
if addr.Primary {
primaryEmail = addr.Email
break
} else if verifiedEmail == "" {
verifiedEmail = addr.Email
}
}
if primaryEmail != "" {
return primaryEmail
}
return verifiedEmail
}

View File

@ -25,7 +25,6 @@ import (
"time" "time"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/nyaruka/phonenumbers"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
@ -131,23 +130,6 @@ type GoogleUserInfo struct {
Locale string `json:"locale"` Locale string `json:"locale"`
} }
type GooglePeopleApiPhoneNumberMetaData struct {
Primary bool `json:"primary"`
}
type GooglePeopleApiPhoneNumber struct {
CanonicalForm string `json:"canonicalForm"`
MetaData GooglePeopleApiPhoneNumberMetaData `json:"metadata"`
Value string `json:"value"`
Type string `json:"type"`
}
type GooglePeopleApiResult struct {
PhoneNumbers []GooglePeopleApiPhoneNumber `json:"phoneNumbers"`
Etag string `json:"etag"`
ResourceName string `json:"resourceName"`
}
func (idp *GoogleIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) { func (idp *GoogleIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
if strings.HasPrefix(token.AccessToken, GoogleIdTokenKey) { if strings.HasPrefix(token.AccessToken, GoogleIdTokenKey) {
googleIdToken, ok := token.Extra(GoogleIdTokenKey).(GoogleIdToken) googleIdToken, ok := token.Extra(GoogleIdTokenKey).(GoogleIdToken)
@ -185,49 +167,12 @@ func (idp *GoogleIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
return nil, errors.New("google email is empty") return nil, errors.New("google email is empty")
} }
url = fmt.Sprintf("https://people.googleapis.com/v1/people/me?personFields=phoneNumbers&access_token=%s", token.AccessToken)
resp, err = idp.Client.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err = io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var googlePeopleResult GooglePeopleApiResult
err = json.Unmarshal(body, &googlePeopleResult)
if err != nil {
return nil, err
}
var phoneNumber string
var countryCode string
if len(googlePeopleResult.PhoneNumbers) != 0 {
for _, phoneData := range googlePeopleResult.PhoneNumbers {
if phoneData.MetaData.Primary {
phoneNumber = phoneData.CanonicalForm
break
}
}
phoneNumberParsed, err := phonenumbers.Parse(phoneNumber, "")
if err != nil {
return nil, err
}
countryCode = phonenumbers.GetRegionCodeForNumber(phoneNumberParsed)
phoneNumber = fmt.Sprintf("%d", phoneNumberParsed.GetNationalNumber())
}
userInfo := UserInfo{ userInfo := UserInfo{
Id: googleUserInfo.Id, Id: googleUserInfo.Id,
Username: googleUserInfo.Email, Username: googleUserInfo.Email,
DisplayName: googleUserInfo.Name, DisplayName: googleUserInfo.Name,
Email: googleUserInfo.Email, Email: googleUserInfo.Email,
AvatarUrl: googleUserInfo.Picture, AvatarUrl: googleUserInfo.Picture,
Phone: phoneNumber,
CountryCode: countryCode,
} }
return &userInfo, nil return &userInfo, nil
} }

View File

@ -1,161 +0,0 @@
// 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 idp
import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"golang.org/x/oauth2"
)
type KwaiIdProvider struct {
Client *http.Client
Config *oauth2.Config
}
func NewKwaiIdProvider(clientId string, clientSecret string, redirectUrl string) *KwaiIdProvider {
idp := &KwaiIdProvider{}
idp.Config = idp.getConfig(clientId, clientSecret, redirectUrl)
return idp
}
func (idp *KwaiIdProvider) SetHttpClient(client *http.Client) {
idp.Client = client
}
func (idp *KwaiIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
endpoint := oauth2.Endpoint{
TokenURL: "https://open.kuaishou.com/oauth2/access_token",
AuthURL: "https://open.kuaishou.com/oauth2/authorize", // qr code: /oauth2/connect
}
config := &oauth2.Config{
Scopes: []string{"user_info"},
Endpoint: endpoint,
ClientID: clientId,
ClientSecret: clientSecret,
RedirectURL: redirectUrl,
}
return config
}
type KwaiTokenResp struct {
Result int `json:"result"`
ErrorMsg string `json:"error_msg"`
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
RefreshTokenExpiresIn int `json:"refresh_token_expires_in"`
OpenId string `json:"open_id"`
Scopes []string `json:"scopes"`
}
// GetToken use code to get access_token
func (idp *KwaiIdProvider) GetToken(code string) (*oauth2.Token, error) {
params := map[string]string{
"app_id": idp.Config.ClientID,
"app_secret": idp.Config.ClientSecret,
"code": code,
"grant_type": "authorization_code",
}
tokenUrl := fmt.Sprintf("%s?app_id=%s&app_secret=%s&code=%s&grant_type=authorization_code",
idp.Config.Endpoint.TokenURL, params["app_id"], params["app_secret"], params["code"])
resp, err := idp.Client.Get(tokenUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var tokenResp KwaiTokenResp
err = json.Unmarshal(body, &tokenResp)
if err != nil {
return nil, err
}
if tokenResp.Result != 1 {
return nil, fmt.Errorf("get token error: %s", tokenResp.ErrorMsg)
}
token := &oauth2.Token{
AccessToken: tokenResp.AccessToken,
RefreshToken: tokenResp.RefreshToken,
Expiry: time.Now().Add(time.Duration(tokenResp.ExpiresIn) * time.Second),
}
raw := make(map[string]interface{})
raw["open_id"] = tokenResp.OpenId
token = token.WithExtra(raw)
return token, nil
}
// More details: https://open.kuaishou.com/openapi/user_info
type KwaiUserInfo struct {
Result int `json:"result"`
ErrorMsg string `json:"error_msg"`
UserInfo struct {
Head string `json:"head"`
Name string `json:"name"`
Sex string `json:"sex"`
City string `json:"city"`
} `json:"user_info"`
}
// GetUserInfo use token to get user profile
func (idp *KwaiIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
userInfoUrl := fmt.Sprintf("https://open.kuaishou.com/openapi/user_info?app_id=%s&access_token=%s",
idp.Config.ClientID, token.AccessToken)
resp, err := idp.Client.Get(userInfoUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var kwaiUserInfo KwaiUserInfo
err = json.Unmarshal(body, &kwaiUserInfo)
if err != nil {
return nil, err
}
if kwaiUserInfo.Result != 1 {
return nil, fmt.Errorf("get user info error: %s", kwaiUserInfo.ErrorMsg)
}
userInfo := &UserInfo{
Id: token.Extra("open_id").(string),
Username: kwaiUserInfo.UserInfo.Name,
DisplayName: kwaiUserInfo.UserInfo.Name,
AvatarUrl: kwaiUserInfo.UserInfo.Head,
Extra: map[string]string{
"gender": kwaiUserInfo.UserInfo.Sex,
"city": kwaiUserInfo.UserInfo.City,
},
}
return userInfo, nil
}

View File

@ -22,7 +22,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/nyaruka/phonenumbers"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
@ -200,25 +199,12 @@ func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
return nil, err return nil, err
} }
var phoneNumber string
var countryCode string
if len(larkUserInfo.Data.Mobile) != 0 {
phoneNumberParsed, err := phonenumbers.Parse(larkUserInfo.Data.Mobile, "")
if err != nil {
return nil, err
}
countryCode = phonenumbers.GetRegionCodeForNumber(phoneNumberParsed)
phoneNumber = fmt.Sprintf("%d", phoneNumberParsed.GetNationalNumber())
}
userInfo := UserInfo{ userInfo := UserInfo{
Id: larkUserInfo.Data.OpenId, Id: larkUserInfo.Data.OpenId,
DisplayName: larkUserInfo.Data.Name, DisplayName: larkUserInfo.Data.EnName,
Username: larkUserInfo.Data.UserId, Username: larkUserInfo.Data.Name,
Email: larkUserInfo.Data.Email, Email: larkUserInfo.Data.Email,
AvatarUrl: larkUserInfo.Data.AvatarUrl, AvatarUrl: larkUserInfo.Data.AvatarUrl,
Phone: phoneNumber,
CountryCode: countryCode,
} }
return &userInfo, nil return &userInfo, nil
} }

View File

@ -113,8 +113,6 @@ func GetIdProvider(idpInfo *ProviderInfo, redirectUrl string) (IdProvider, error
return NewOktaIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl), nil return NewOktaIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl), nil
case "Douyin": case "Douyin":
return NewDouyinIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil return NewDouyinIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil
case "Kwai":
return NewKwaiIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil
case "Bilibili": case "Bilibili":
return NewBilibiliIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil return NewBilibiliIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl), nil
case "MetaMask": case "MetaMask":

View File

@ -35,9 +35,7 @@
"FI", "FI",
"SE", "SE",
"UA", "UA",
"KZ", "KZ"
"CZ",
"SK"
], ],
"defaultAvatar": "", "defaultAvatar": "",
"defaultApplication": "", "defaultApplication": "",
@ -64,9 +62,7 @@
"sv", "sv",
"uk", "uk",
"kk", "kk",
"fa", "fa"
"cs",
"sk"
], ],
"masterPassword": "", "masterPassword": "",
"defaultPassword": "", "defaultPassword": "",
@ -114,11 +110,6 @@
"name": "WebAuthn", "name": "WebAuthn",
"displayName": "WebAuthn", "displayName": "WebAuthn",
"rule": "None" "rule": "None"
},
{
"name": "Face ID",
"displayName": "Face ID",
"rule": "None"
} }
], ],
"signupItems": [ "signupItems": [
@ -188,10 +179,8 @@
"refresh_token" "refresh_token"
], ],
"redirectUris": [ "redirectUris": [
"http://localhost:9000/callback" ""
], ],
"tokenFormat": "JWT",
"tokenFields": [],
"expireInHours": 168, "expireInHours": 168,
"failedSigninLimit": 5, "failedSigninLimit": 5,
"failedSigninFrozenTime": 15 "failedSigninFrozenTime": 15
@ -434,7 +423,7 @@
"isTopGroup": true, "isTopGroup": true,
"title": "", "title": "",
"key": "", "key": "",
"children": [], "children": "",
"isEnabled": true "isEnabled": true
} }
], ],

View File

@ -15,81 +15,33 @@
package ldap package ldap
import ( import (
"crypto/tls"
"fmt" "fmt"
"hash/fnv" "hash/fnv"
"log" "log"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
ldap "github.com/casdoor/ldapserver" ldap "github.com/forestmgy/ldapserver"
"github.com/lor00x/goldap/message" "github.com/lor00x/goldap/message"
) )
func StartLdapServer() { func StartLdapServer() {
ldapServerPort := conf.GetConfigString("ldapServerPort") ldapServerPort := conf.GetConfigString("ldapServerPort")
ldapsServerPort := conf.GetConfigString("ldapsServerPort") if ldapServerPort == "" || ldapServerPort == "0" {
return
}
server := ldap.NewServer() server := ldap.NewServer()
serverSsl := ldap.NewServer()
routes := ldap.NewRouteMux() routes := ldap.NewRouteMux()
routes.Bind(handleBind) routes.Bind(handleBind)
routes.Search(handleSearch).Label(" SEARCH****") routes.Search(handleSearch).Label(" SEARCH****")
server.Handle(routes) server.Handle(routes)
serverSsl.Handle(routes) err := server.ListenAndServe("0.0.0.0:" + ldapServerPort)
go func() {
if ldapServerPort == "" || ldapServerPort == "0" {
return
}
err := server.ListenAndServe("0.0.0.0:" + ldapServerPort)
if err != nil {
log.Printf("StartLdapServer() failed, err = %s", err.Error())
}
}()
go func() {
if ldapsServerPort == "" || ldapsServerPort == "0" {
return
}
ldapsCertId := conf.GetConfigString("ldapsCertId")
if ldapsCertId == "" {
return
}
config, err := getTLSconfig(ldapsCertId)
if err != nil {
log.Printf("StartLdapsServer() failed, err = %s", err.Error())
return
}
secureConn := func(s *ldap.Server) {
s.Listener = tls.NewListener(s.Listener, config)
}
err = serverSsl.ListenAndServe("0.0.0.0:"+ldapsServerPort, secureConn)
if err != nil {
log.Printf("StartLdapsServer() failed, err = %s", err.Error())
}
}()
}
func getTLSconfig(ldapsCertId string) (*tls.Config, error) {
rawCert, err := object.GetCert(ldapsCertId)
if err != nil { if err != nil {
return nil, err log.Printf("StartLdapServer() failed, err = %s", err.Error())
} }
if rawCert == nil {
return nil, fmt.Errorf("cert is empty")
}
cert, err := tls.X509KeyPair([]byte(rawCert.Certificate), []byte(rawCert.PrivateKey))
if err != nil {
return &tls.Config{}, err
}
return &tls.Config{
MinVersion: tls.VersionTLS10,
MaxVersion: tls.VersionTLS13,
Certificates: []tls.Certificate{cert},
}, nil
} }
func handleBind(w ldap.ResponseWriter, m *ldap.Message) { func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
@ -107,15 +59,7 @@ func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
} }
bindPassword := string(r.AuthenticationSimple()) bindPassword := string(r.AuthenticationSimple())
bindUser, err := object.CheckUserPassword(bindOrg, bindUsername, bindPassword, "en")
enableCaptcha := false
isSigninViaLdap := false
isPasswordWithLdapEnabled := false
if bindPassword != "" {
isPasswordWithLdapEnabled = true
}
bindUser, err := object.CheckUserPassword(bindOrg, bindUsername, bindPassword, "en", enableCaptcha, isSigninViaLdap, isPasswordWithLdapEnabled)
if err != nil { if err != nil {
log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err) log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err)
res.SetResultCode(ldap.LDAPResultInvalidCredentials) res.SetResultCode(ldap.LDAPResultInvalidCredentials)
@ -178,9 +122,6 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
e.AddAttribute("homeDirectory", message.AttributeValue("/home/"+user.Name)) e.AddAttribute("homeDirectory", message.AttributeValue("/home/"+user.Name))
e.AddAttribute("cn", message.AttributeValue(user.Name)) e.AddAttribute("cn", message.AttributeValue(user.Name))
e.AddAttribute("uid", message.AttributeValue(user.Id)) e.AddAttribute("uid", message.AttributeValue(user.Id))
for _, group := range user.Groups {
e.AddAttribute(ldapMemberOfAttr, message.AttributeValue(group))
}
attrs := r.Attributes() attrs := r.Attributes()
for _, attr := range attrs { for _, attr := range attrs {
if string(attr) == "*" { if string(attr) == "*" {
@ -190,7 +131,7 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
} }
for _, attr := range attrs { for _, attr := range attrs {
e.AddAttribute(message.AttributeDescription(attr), getAttribute(string(attr), user)) e.AddAttribute(message.AttributeDescription(attr), getAttribute(string(attr), user))
if string(attr) == "title" { if string(attr) == "cn" {
e.AddAttribute(message.AttributeDescription(attr), getAttribute("title", user)) e.AddAttribute(message.AttributeDescription(attr), getAttribute("title", user))
} }
} }

View File

@ -23,7 +23,7 @@ import (
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/lor00x/goldap/message" "github.com/lor00x/goldap/message"
ldap "github.com/casdoor/ldapserver" ldap "github.com/forestmgy/ldapserver"
"github.com/xorm-io/builder" "github.com/xorm-io/builder"
) )
@ -79,8 +79,6 @@ var ldapAttributesMapping = map[string]FieldRelation{
}, },
} }
const ldapMemberOfAttr = "memberOf"
var AdditionalLdapAttributes []message.LDAPString var AdditionalLdapAttributes []message.LDAPString
func init() { func init() {
@ -182,19 +180,7 @@ func buildUserFilterCondition(filter interface{}) (builder.Cond, error) {
} }
return builder.Not{cond}, nil return builder.Not{cond}, nil
case message.FilterEqualityMatch: case message.FilterEqualityMatch:
attr := string(f.AttributeDesc()) field, err := getUserFieldFromAttribute(string(f.AttributeDesc()))
if attr == ldapMemberOfAttr {
var names []string
groupId := string(f.AssertionValue())
users := object.GetGroupUsersWithoutError(groupId)
for _, user := range users {
names = append(names, user.Name)
}
return builder.In("name", names), nil
}
field, err := getUserFieldFromAttribute(attr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -246,7 +232,7 @@ func buildSafeCondition(filter interface{}) builder.Cond {
condition, err := buildUserFilterCondition(filter) condition, err := buildUserFilterCondition(filter)
if err != nil { if err != nil {
log.Printf("err = %v", err.Error()) log.Printf("err = %v", err.Error())
return builder.And(builder.Expr("1 != 1")) return nil
} }
return condition return condition
} }
@ -260,7 +246,7 @@ func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int)
return nil, code return nil, code
} }
if name == "*" { // get all users from organization 'org' if name == "*" && m.Client.IsOrgAdmin { // get all users from organization 'org'
if m.Client.IsGlobalAdmin && org == "*" { if m.Client.IsGlobalAdmin && org == "*" {
filteredUsers, err = object.GetGlobalUsersWithFilter(buildSafeCondition(r.Filter())) filteredUsers, err = object.GetGlobalUsersWithFilter(buildSafeCondition(r.Filter()))
if err != nil { if err != nil {

10
main.go
View File

@ -22,7 +22,6 @@ import (
_ "github.com/beego/beego/session/redis" _ "github.com/beego/beego/session/redis"
"github.com/casdoor/casdoor/authz" "github.com/casdoor/casdoor/authz"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/controllers"
"github.com/casdoor/casdoor/ldap" "github.com/casdoor/casdoor/ldap"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/proxy" "github.com/casdoor/casdoor/proxy"
@ -46,7 +45,6 @@ func main() {
object.InitCasvisorConfig() object.InitCasvisorConfig()
util.SafeGoroutine(func() { object.RunSyncUsersJob() }) util.SafeGoroutine(func() { object.RunSyncUsersJob() })
util.SafeGoroutine(func() { controllers.InitCLIDownloader() })
// beego.DelStaticPath("/static") // beego.DelStaticPath("/static")
// beego.SetStaticPath("/static", "web/build/static") // beego.SetStaticPath("/static", "web/build/static")
@ -58,11 +56,9 @@ func main() {
beego.InsertFilter("*", beego.BeforeRouter, routers.StaticFilter) beego.InsertFilter("*", beego.BeforeRouter, routers.StaticFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.AutoSigninFilter) beego.InsertFilter("*", beego.BeforeRouter, routers.AutoSigninFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter) beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.TimeoutFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.ApiFilter) beego.InsertFilter("*", beego.BeforeRouter, routers.ApiFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.PrometheusFilter) beego.InsertFilter("*", beego.BeforeRouter, routers.PrometheusFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage) beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
beego.InsertFilter("*", beego.AfterExec, routers.AfterRecordMessage, false)
beego.BConfig.WebConfig.Session.SessionOn = true beego.BConfig.WebConfig.Session.SessionOn = true
beego.BConfig.WebConfig.Session.SessionName = "casdoor_session_id" beego.BConfig.WebConfig.Session.SessionName = "casdoor_session_id"
@ -74,7 +70,6 @@ func main() {
beego.BConfig.WebConfig.Session.SessionProviderConfig = conf.GetConfigString("redisEndpoint") beego.BConfig.WebConfig.Session.SessionProviderConfig = conf.GetConfigString("redisEndpoint")
} }
beego.BConfig.WebConfig.Session.SessionCookieLifeTime = 3600 * 24 * 30 beego.BConfig.WebConfig.Session.SessionCookieLifeTime = 3600 * 24 * 30
beego.BConfig.WebConfig.Session.SessionGCMaxLifetime = 3600 * 24 * 30
// beego.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteNoneMode // beego.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteNoneMode
err := logs.SetLogger(logs.AdapterFile, conf.GetConfigString("logConfig")) err := logs.SetLogger(logs.AdapterFile, conf.GetConfigString("logConfig"))
@ -85,11 +80,6 @@ func main() {
// logs.SetLevel(logs.LevelInformational) // logs.SetLevel(logs.LevelInformational)
logs.SetLogFuncCall(false) logs.SetLogFuncCall(false)
err = util.StopOldInstance(port)
if err != nil {
panic(err)
}
go ldap.StartLdapServer() go ldap.StartLdapServer()
go radius.StartRadiusServer() go radius.StartRadiusServer()
go object.ClearThroughputPerSecond() go object.ClearThroughputPerSecond()

View File

@ -1,29 +0,0 @@
// 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 (
"github.com/casdoor/notify"
"github.com/casdoor/notify/service/cucloud"
)
func NewCucloudProvider(accessKey, secretKey, topicName, messageTitle, cloudRegionCode, accountId, notifyType string) (notify.Notifier, error) {
cucloud := cucloud.New(accessKey, secretKey, topicName, messageTitle, cloudRegionCode, accountId, notifyType)
notifier := notify.New()
notifier.UseServices(cucloud)
return notifier, nil
}

View File

@ -16,7 +16,7 @@ package notification
import "github.com/casdoor/notify" import "github.com/casdoor/notify"
func GetNotificationProvider(typ string, clientId string, clientSecret string, clientId2 string, clientSecret2 string, appId string, receiver string, method string, title string, metaData string, regionId string) (notify.Notifier, error) { func GetNotificationProvider(typ string, clientId string, clientSecret string, clientId2 string, clientSecret2 string, appId string, receiver string, method string, title string, metaData string) (notify.Notifier, error) {
if typ == "Telegram" { if typ == "Telegram" {
return NewTelegramProvider(clientSecret, receiver) return NewTelegramProvider(clientSecret, receiver)
} else if typ == "Custom HTTP" { } else if typ == "Custom HTTP" {
@ -53,8 +53,6 @@ func GetNotificationProvider(typ string, clientId string, clientSecret string, c
return NewRocketChatProvider(clientId, clientSecret, appId, receiver) return NewRocketChatProvider(clientId, clientSecret, appId, receiver)
} else if typ == "Viber" { } else if typ == "Viber" {
return NewViberProvider(clientId, clientSecret, appId, receiver) return NewViberProvider(clientId, clientSecret, appId, receiver)
} else if typ == "CUCloud" {
return NewCucloudProvider(clientId, clientSecret, appId, title, regionId, clientId2, metaData)
} }
return nil, nil return nil, nil

View File

@ -191,7 +191,12 @@ func (adapter *Adapter) InitAdapter() error {
} }
} }
tableName := adapter.Table var tableName string
if driverName == "mssql" {
tableName = fmt.Sprintf("[%s]", adapter.Table)
} else {
tableName = adapter.Table
}
adapter.Adapter, err = xormadapter.NewAdapterByEngineWithTableName(engine, tableName, "") adapter.Adapter, err = xormadapter.NewAdapterByEngineWithTableName(engine, tableName, "")
if err != nil { if err != nil {

View File

@ -19,7 +19,6 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/xorm-io/core" "github.com/xorm-io/core"
) )
@ -31,24 +30,20 @@ type SigninMethod struct {
} }
type SignupItem struct { type SignupItem struct {
Name string `json:"name"` Name string `json:"name"`
Visible bool `json:"visible"` Visible bool `json:"visible"`
Required bool `json:"required"` Required bool `json:"required"`
Prompted bool `json:"prompted"` Prompted bool `json:"prompted"`
Type string `json:"type"` Label string `json:"label"`
CustomCss string `json:"customCss"` Placeholder string `json:"placeholder"`
Label string `json:"label"` Regex string `json:"regex"`
Placeholder string `json:"placeholder"` Rule string `json:"rule"`
Options []string `json:"options"`
Regex string `json:"regex"`
Rule string `json:"rule"`
} }
type SigninItem struct { type SigninItem struct {
Name string `json:"name"` Name string `json:"name"`
Visible bool `json:"visible"` Visible bool `json:"visible"`
Label string `json:"label"` Label string `json:"label"`
CustomCss string `json:"customCss"`
Placeholder string `json:"placeholder"` Placeholder string `json:"placeholder"`
Rule string `json:"rule"` Rule string `json:"rule"`
IsCustom bool `json:"isCustom"` IsCustom bool `json:"isCustom"`
@ -71,7 +66,6 @@ type Application struct {
Description string `xorm:"varchar(100)" json:"description"` Description string `xorm:"varchar(100)" json:"description"`
Organization string `xorm:"varchar(100)" json:"organization"` Organization string `xorm:"varchar(100)" json:"organization"`
Cert string `xorm:"varchar(100)" json:"cert"` Cert string `xorm:"varchar(100)" json:"cert"`
DefaultGroup string `xorm:"varchar(100)" json:"defaultGroup"`
HeaderHtml string `xorm:"mediumtext" json:"headerHtml"` HeaderHtml string `xorm:"mediumtext" json:"headerHtml"`
EnablePassword bool `json:"enablePassword"` EnablePassword bool `json:"enablePassword"`
EnableSignUp bool `json:"enableSignUp"` EnableSignUp bool `json:"enableSignUp"`
@ -81,48 +75,40 @@ type Application struct {
EnableSamlCompress bool `json:"enableSamlCompress"` EnableSamlCompress bool `json:"enableSamlCompress"`
EnableSamlC14n10 bool `json:"enableSamlC14n10"` EnableSamlC14n10 bool `json:"enableSamlC14n10"`
EnableSamlPostBinding bool `json:"enableSamlPostBinding"` EnableSamlPostBinding bool `json:"enableSamlPostBinding"`
UseEmailAsSamlNameId bool `json:"useEmailAsSamlNameId"`
EnableWebAuthn bool `json:"enableWebAuthn"` EnableWebAuthn bool `json:"enableWebAuthn"`
EnableLinkWithEmail bool `json:"enableLinkWithEmail"` EnableLinkWithEmail bool `json:"enableLinkWithEmail"`
OrgChoiceMode string `json:"orgChoiceMode"` OrgChoiceMode string `json:"orgChoiceMode"`
SamlReplyUrl string `xorm:"varchar(100)" json:"samlReplyUrl"` SamlReplyUrl string `xorm:"varchar(100)" json:"samlReplyUrl"`
Providers []*ProviderItem `xorm:"mediumtext" json:"providers"` Providers []*ProviderItem `xorm:"mediumtext" json:"providers"`
SigninMethods []*SigninMethod `xorm:"varchar(2000)" json:"signinMethods"` SigninMethods []*SigninMethod `xorm:"varchar(2000)" json:"signinMethods"`
SignupItems []*SignupItem `xorm:"varchar(3000)" json:"signupItems"` SignupItems []*SignupItem `xorm:"varchar(2000)" json:"signupItems"`
SigninItems []*SigninItem `xorm:"mediumtext" json:"signinItems"` SigninItems []*SigninItem `xorm:"mediumtext" json:"signinItems"`
GrantTypes []string `xorm:"varchar(1000)" json:"grantTypes"` GrantTypes []string `xorm:"varchar(1000)" json:"grantTypes"`
OrganizationObj *Organization `xorm:"-" json:"organizationObj"` OrganizationObj *Organization `xorm:"-" json:"organizationObj"`
CertPublicKey string `xorm:"-" json:"certPublicKey"` CertPublicKey string `xorm:"-" json:"certPublicKey"`
Tags []string `xorm:"mediumtext" json:"tags"` Tags []string `xorm:"mediumtext" json:"tags"`
SamlAttributes []*SamlItem `xorm:"varchar(1000)" json:"samlAttributes"` SamlAttributes []*SamlItem `xorm:"varchar(1000)" json:"samlAttributes"`
IsShared bool `json:"isShared"`
IpRestriction string `json:"ipRestriction"`
ClientId string `xorm:"varchar(100)" json:"clientId"` ClientId string `xorm:"varchar(100)" json:"clientId"`
ClientSecret string `xorm:"varchar(100)" json:"clientSecret"` ClientSecret string `xorm:"varchar(100)" json:"clientSecret"`
RedirectUris []string `xorm:"varchar(1000)" json:"redirectUris"` RedirectUris []string `xorm:"varchar(1000)" json:"redirectUris"`
ForcedRedirectOrigin string `xorm:"varchar(100)" json:"forcedRedirectOrigin"` TokenFormat string `xorm:"varchar(100)" json:"tokenFormat"`
TokenFormat string `xorm:"varchar(100)" json:"tokenFormat"` TokenFields []string `xorm:"varchar(1000)" json:"tokenFields"`
TokenSigningMethod string `xorm:"varchar(100)" json:"tokenSigningMethod"` ExpireInHours int `json:"expireInHours"`
TokenFields []string `xorm:"varchar(1000)" json:"tokenFields"` RefreshExpireInHours int `json:"refreshExpireInHours"`
ExpireInHours int `json:"expireInHours"` SignupUrl string `xorm:"varchar(200)" json:"signupUrl"`
RefreshExpireInHours int `json:"refreshExpireInHours"` SigninUrl string `xorm:"varchar(200)" json:"signinUrl"`
SignupUrl string `xorm:"varchar(200)" json:"signupUrl"` ForgetUrl string `xorm:"varchar(200)" json:"forgetUrl"`
SigninUrl string `xorm:"varchar(200)" json:"signinUrl"` AffiliationUrl string `xorm:"varchar(100)" json:"affiliationUrl"`
ForgetUrl string `xorm:"varchar(200)" json:"forgetUrl"` TermsOfUse string `xorm:"varchar(100)" json:"termsOfUse"`
AffiliationUrl string `xorm:"varchar(100)" json:"affiliationUrl"` SignupHtml string `xorm:"mediumtext" json:"signupHtml"`
IpWhitelist string `xorm:"varchar(200)" json:"ipWhitelist"` SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
TermsOfUse string `xorm:"varchar(100)" json:"termsOfUse"` ThemeData *ThemeData `xorm:"json" json:"themeData"`
SignupHtml string `xorm:"mediumtext" json:"signupHtml"` FormCss string `xorm:"text" json:"formCss"`
SigninHtml string `xorm:"mediumtext" json:"signinHtml"` FormCssMobile string `xorm:"text" json:"formCssMobile"`
ThemeData *ThemeData `xorm:"json" json:"themeData"` FormOffset int `json:"formOffset"`
FooterHtml string `xorm:"mediumtext" json:"footerHtml"` FormSideHtml string `xorm:"mediumtext" json:"formSideHtml"`
FormCss string `xorm:"text" json:"formCss"` FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
FormCssMobile string `xorm:"text" json:"formCssMobile"`
FormOffset int `json:"formOffset"`
FormSideHtml string `xorm:"mediumtext" json:"formSideHtml"`
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
FormBackgroundUrlMobile string `xorm:"varchar(200)" json:"formBackgroundUrlMobile"`
FailedSigninLimit int `json:"failedSigninLimit"` FailedSigninLimit int `json:"failedSigninLimit"`
FailedSigninFrozenTime int `json:"failedSigninFrozenTime"` FailedSigninFrozenTime int `json:"failedSigninFrozenTime"`
@ -133,9 +119,9 @@ func GetApplicationCount(owner, field, value string) (int64, error) {
return session.Count(&Application{}) return session.Count(&Application{})
} }
func GetOrganizationApplicationCount(owner, organization, field, value string) (int64, error) { func GetOrganizationApplicationCount(owner, Organization, field, value string) (int64, error) {
session := GetSession(owner, -1, -1, field, value, "", "") session := GetSession(owner, -1, -1, field, value, "", "")
return session.Where("organization = ? or is_shared = ? ", organization, true).Count(&Application{}) return session.Count(&Application{Organization: Organization})
} }
func GetApplications(owner string) ([]*Application, error) { func GetApplications(owner string) ([]*Application, error) {
@ -150,7 +136,7 @@ func GetApplications(owner string) ([]*Application, error) {
func GetOrganizationApplications(owner string, organization string) ([]*Application, error) { func GetOrganizationApplications(owner string, organization string) ([]*Application, error) {
applications := []*Application{} applications := []*Application{}
err := ormer.Engine.Desc("created_time").Where("organization = ? or is_shared = ? ", organization, true).Find(&applications, &Application{}) err := ormer.Engine.Desc("created_time").Find(&applications, &Application{Organization: organization})
if err != nil { if err != nil {
return applications, err return applications, err
} }
@ -172,7 +158,7 @@ func GetPaginationApplications(owner string, offset, limit int, field, value, so
func GetPaginationOrganizationApplications(owner, organization string, offset, limit int, field, value, sortField, sortOrder string) ([]*Application, error) { func GetPaginationOrganizationApplications(owner, organization string, offset, limit int, field, value, sortField, sortOrder string) ([]*Application, error) {
applications := []*Application{} applications := []*Application{}
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder) session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Where("organization = ? or is_shared = ? ", organization, true).Find(&applications, &Application{}) err := session.Find(&applications, &Application{Organization: organization})
if err != nil { if err != nil {
return applications, err return applications, err
} }
@ -220,7 +206,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
signinItem := &SigninItem{ signinItem := &SigninItem{
Name: "Back button", Name: "Back button",
Visible: true, Visible: true,
CustomCss: ".back-button {\n top: 65px;\n left: 15px;\n position: absolute;\n}\n.back-inner-button{}", Label: "\n<style>\n .back-button {\n top: 65px;\n left: 15px;\n position: absolute;\n }\n</style>\n",
Placeholder: "", Placeholder: "",
Rule: "None", Rule: "None",
} }
@ -228,7 +214,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
signinItem = &SigninItem{ signinItem = &SigninItem{
Name: "Languages", Name: "Languages",
Visible: true, Visible: true,
CustomCss: ".login-languages {\n top: 55px;\n right: 5px;\n position: absolute;\n}", Label: "\n<style>\n .login-languages {\n top: 55px;\n right: 5px;\n position: absolute;\n }\n</style>\n",
Placeholder: "", Placeholder: "",
Rule: "None", Rule: "None",
} }
@ -236,7 +222,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
signinItem = &SigninItem{ signinItem = &SigninItem{
Name: "Logo", Name: "Logo",
Visible: true, Visible: true,
CustomCss: ".login-logo-box {}", Label: "\n<style>\n .login-logo-box {\n }\n<style>\n",
Placeholder: "", Placeholder: "",
Rule: "None", Rule: "None",
} }
@ -244,7 +230,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
signinItem = &SigninItem{ signinItem = &SigninItem{
Name: "Signin methods", Name: "Signin methods",
Visible: true, Visible: true,
CustomCss: ".signin-methods {}", Label: "\n<style>\n .signin-methods {\n }\n<style>\n",
Placeholder: "", Placeholder: "",
Rule: "None", Rule: "None",
} }
@ -252,7 +238,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
signinItem = &SigninItem{ signinItem = &SigninItem{
Name: "Username", Name: "Username",
Visible: true, Visible: true,
CustomCss: ".login-username {}\n.login-username-input{}", Label: "\n<style>\n .login-username {\n }\n<style>\n",
Placeholder: "", Placeholder: "",
Rule: "None", Rule: "None",
} }
@ -260,7 +246,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
signinItem = &SigninItem{ signinItem = &SigninItem{
Name: "Password", Name: "Password",
Visible: true, Visible: true,
CustomCss: ".login-password {}\n.login-password-input{}", Label: "\n<style>\n .login-password {\n }\n<style>\n",
Placeholder: "", Placeholder: "",
Rule: "None", Rule: "None",
} }
@ -268,7 +254,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
signinItem = &SigninItem{ signinItem = &SigninItem{
Name: "Agreement", Name: "Agreement",
Visible: true, Visible: true,
CustomCss: ".login-agreement {}", Label: "\n<style>\n .login-agreement {\n }\n<style>\n",
Placeholder: "", Placeholder: "",
Rule: "None", Rule: "None",
} }
@ -276,7 +262,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
signinItem = &SigninItem{ signinItem = &SigninItem{
Name: "Forgot password?", Name: "Forgot password?",
Visible: true, Visible: true,
CustomCss: ".login-forget-password {\n display: inline-flex;\n justify-content: space-between;\n width: 320px;\n margin-bottom: 25px;\n}", Label: "\n<style>\n .login-forget-password {\n display: inline-flex;\n justify-content: space-between;\n width: 320px;\n margin-bottom: 25px;\n }\n<style>\n",
Placeholder: "", Placeholder: "",
Rule: "None", Rule: "None",
} }
@ -284,7 +270,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
signinItem = &SigninItem{ signinItem = &SigninItem{
Name: "Login button", Name: "Login button",
Visible: true, Visible: true,
CustomCss: ".login-button-box {\n margin-bottom: 5px;\n}\n.login-button {\n width: 100%;\n}", Label: "\n<style>\n .login-button-box {\n margin-bottom: 5px;\n }\n .login-button {\n width: 100%;\n }\n<style>\n",
Placeholder: "", Placeholder: "",
Rule: "None", Rule: "None",
} }
@ -292,7 +278,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
signinItem = &SigninItem{ signinItem = &SigninItem{
Name: "Signup link", Name: "Signup link",
Visible: true, Visible: true,
CustomCss: ".login-signup-link {\n margin-bottom: 24px;\n display: flex;\n justify-content: end;\n}", Label: "\n<style>\n .login-signup-link {\n margin-bottom: 24px;\n display: flex;\n justify-content: end;\n}\n<style>\n",
Placeholder: "", Placeholder: "",
Rule: "None", Rule: "None",
} }
@ -300,18 +286,12 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
signinItem = &SigninItem{ signinItem = &SigninItem{
Name: "Providers", Name: "Providers",
Visible: true, Visible: true,
CustomCss: ".provider-img {\n width: 30px;\n margin: 5px;\n}\n.provider-big-img {\n margin-bottom: 10px;\n}", Label: "\n<style>\n .provider-img {\n width: 30px;\n margin: 5px;\n }\n .provider-big-img {\n margin-bottom: 10px;\n }\n</style>\n",
Placeholder: "", Placeholder: "",
Rule: "None", Rule: "None",
} }
application.SigninItems = append(application.SigninItems, signinItem) application.SigninItems = append(application.SigninItems, signinItem)
} }
for idx, item := range application.SigninItems {
if item.Label != "" && item.CustomCss == "" {
application.SigninItems[idx].CustomCss = item.Label
application.SigninItems[idx].Label = ""
}
}
return return
} }
@ -329,9 +309,6 @@ func extendApplicationWithSigninMethods(application *Application) (err error) {
signinMethod := &SigninMethod{Name: "WebAuthn", DisplayName: "WebAuthn", Rule: "None"} signinMethod := &SigninMethod{Name: "WebAuthn", DisplayName: "WebAuthn", Rule: "None"}
application.SigninMethods = append(application.SigninMethods, signinMethod) application.SigninMethods = append(application.SigninMethods, signinMethod)
} }
signinMethod := &SigninMethod{Name: "Face ID", DisplayName: "Face ID", Rule: "None"}
application.SigninMethods = append(application.SigninMethods, signinMethod)
} }
if len(application.SigninMethods) == 0 { if len(application.SigninMethods) == 0 {
@ -347,18 +324,12 @@ func getApplication(owner string, name string) (*Application, error) {
return nil, nil return nil, nil
} }
realApplicationName, sharedOrg := util.GetSharedOrgFromApp(name) application := Application{Owner: owner, Name: name}
application := Application{Owner: owner, Name: realApplicationName}
existed, err := ormer.Engine.Get(&application) existed, err := ormer.Engine.Get(&application)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if application.IsShared && sharedOrg != "" {
application.Organization = sharedOrg
}
if existed { if existed {
err = extendApplicationWithProviders(&application) err = extendApplicationWithProviders(&application)
if err != nil { if err != nil {
@ -428,8 +399,8 @@ func GetApplicationByUser(user *User) (*Application, error) {
} }
func GetApplicationByUserId(userId string) (application *Application, err error) { func GetApplicationByUserId(userId string) (application *Application, err error) {
_, name := util.GetOwnerAndNameFromId(userId) owner, name := util.GetOwnerAndNameFromId(userId)
if IsAppUser(userId) { if owner == "app" {
application, err = getApplication("admin", name) application, err = getApplication("admin", name)
return return
} }
@ -444,18 +415,11 @@ func GetApplicationByUserId(userId string) (application *Application, err error)
func GetApplicationByClientId(clientId string) (*Application, error) { func GetApplicationByClientId(clientId string) (*Application, error) {
application := Application{} application := Application{}
existed, err := ormer.Engine.Where("client_id=?", clientId).Get(&application)
realClientId, sharedOrg := util.GetSharedOrgFromApp(clientId)
existed, err := ormer.Engine.Where("client_id=?", realClientId).Get(&application)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if application.IsShared && sharedOrg != "" {
application.Organization = sharedOrg
}
if existed { if existed {
err = extendApplicationWithProviders(&application) err = extendApplicationWithProviders(&application)
if err != nil { if err != nil {
@ -484,10 +448,7 @@ func GetApplicationByClientId(clientId string) (*Application, error) {
} }
func GetApplication(id string) (*Application, error) { func GetApplication(id string) (*Application, error) {
owner, name, err := util.GetOwnerAndNameFromIdWithError(id) owner, name := util.GetOwnerAndNameFromId(id)
if err != nil {
return nil, err
}
return getApplication(owner, name) return getApplication(owner, name)
} }
@ -507,71 +468,36 @@ func GetMaskedApplication(application *Application, userId string) *Application
application.FailedSigninFrozenTime = DefaultFailedSigninFrozenTime application.FailedSigninFrozenTime = DefaultFailedSigninFrozenTime
} }
isOrgUser := false
if userId != "" { if userId != "" {
if isUserIdGlobalAdmin(userId) { if isUserIdGlobalAdmin(userId) {
return application return application
} }
user, err := GetUser(userId) user, _ := GetUser(userId)
if err != nil { if user != nil && user.IsApplicationAdmin(application) {
panic(err) return application
}
if user != nil {
if user.IsApplicationAdmin(application) {
return application
}
if user.Owner == application.Organization {
isOrgUser = true
}
} }
} }
application.ClientSecret = "***" if application.ClientSecret != "" {
application.Cert = "***" application.ClientSecret = "***"
application.EnablePassword = false
application.EnableSigninSession = false
application.EnableCodeSignin = false
application.EnableSamlCompress = false
application.EnableSamlC14n10 = false
application.EnableSamlPostBinding = false
application.EnableWebAuthn = false
application.EnableLinkWithEmail = false
application.SamlReplyUrl = "***"
providerItems := []*ProviderItem{}
for _, providerItem := range application.Providers {
if providerItem.Provider != nil && (providerItem.Provider.Category == "OAuth" || providerItem.Provider.Category == "Web3" || providerItem.Provider.Category == "Captcha" || providerItem.Provider.Category == "SAML" || providerItem.Provider.Category == "Face ID") {
providerItems = append(providerItems, providerItem)
}
} }
application.Providers = providerItems
application.GrantTypes = nil
application.Tags = nil
application.RedirectUris = nil
application.TokenFormat = "***"
application.TokenFields = nil
application.ExpireInHours = -1
application.RefreshExpireInHours = -1
application.FailedSigninLimit = -1
application.FailedSigninFrozenTime = -1
if application.OrganizationObj != nil { if application.OrganizationObj != nil {
application.OrganizationObj.MasterPassword = "***" if application.OrganizationObj.MasterPassword != "" {
application.OrganizationObj.DefaultPassword = "***" application.OrganizationObj.MasterPassword = "***"
application.OrganizationObj.MasterVerificationCode = "***" }
application.OrganizationObj.PasswordType = "***" if application.OrganizationObj.DefaultPassword != "" {
application.OrganizationObj.PasswordSalt = "***" application.OrganizationObj.DefaultPassword = "***"
application.OrganizationObj.InitScore = -1 }
application.OrganizationObj.EnableSoftDeletion = false if application.OrganizationObj.MasterVerificationCode != "" {
application.OrganizationObj.MasterVerificationCode = "***"
if !isOrgUser { }
application.OrganizationObj.MfaItems = nil if application.OrganizationObj.PasswordType != "" {
if !application.OrganizationObj.IsProfilePublic { application.OrganizationObj.PasswordType = "***"
application.OrganizationObj.AccountItems = nil }
} if application.OrganizationObj.PasswordSalt != "" {
application.OrganizationObj.PasswordSalt = "***"
} }
} }
@ -589,12 +515,8 @@ func GetMaskedApplications(applications []*Application, userId string) []*Applic
return applications return applications
} }
func GetAllowedApplications(applications []*Application, userId string, lang string) ([]*Application, error) { func GetAllowedApplications(applications []*Application, userId string) ([]*Application, error) {
if userId == "" { if userId == "" || isUserIdGlobalAdmin(userId) {
return nil, fmt.Errorf(i18n.Translate(lang, "auth:Unauthorized operation"))
}
if isUserIdGlobalAdmin(userId) {
return applications, nil return applications, nil
} }
@ -602,11 +524,7 @@ func GetAllowedApplications(applications []*Application, userId string, lang str
if err != nil { if err != nil {
return nil, err return nil, err
} }
if user == nil { if user != nil && user.IsAdmin {
return nil, fmt.Errorf(i18n.Translate(lang, "auth:Unauthorized operation"))
}
if user.IsAdmin {
return applications, nil return applications, nil
} }
@ -652,10 +570,6 @@ func UpdateApplication(id string, application *Application) (bool, error) {
return false, err return false, err
} }
if application.IsShared == true && application.Organization != "built-in" {
return false, fmt.Errorf("only applications belonging to built-in organization can be shared")
}
for _, providerItem := range application.Providers { for _, providerItem := range application.Providers {
providerItem.Provider = nil providerItem.Provider = nil
} }
@ -707,7 +621,11 @@ func AddApplication(application *Application) (bool, error) {
return affected != 0, nil return affected != 0, nil
} }
func deleteApplication(application *Application) (bool, error) { func DeleteApplication(application *Application) (bool, error) {
if application.Name == "app-built-in" {
return false, nil
}
affected, err := ormer.Engine.ID(core.PK{application.Owner, application.Name}).Delete(&Application{}) affected, err := ormer.Engine.ID(core.PK{application.Owner, application.Name}).Delete(&Application{})
if err != nil { if err != nil {
return false, err return false, err
@ -716,28 +634,13 @@ func deleteApplication(application *Application) (bool, error) {
return affected != 0, nil return affected != 0, nil
} }
func DeleteApplication(application *Application) (bool, error) {
if application.Name == "app-built-in" {
return false, nil
}
return deleteApplication(application)
}
func (application *Application) GetId() string { func (application *Application) GetId() string {
return fmt.Sprintf("%s/%s", application.Owner, application.Name) return fmt.Sprintf("%s/%s", application.Owner, application.Name)
} }
func (application *Application) IsRedirectUriValid(redirectUri string) bool { func (application *Application) IsRedirectUriValid(redirectUri string) bool {
isValid, err := util.IsValidOrigin(redirectUri) redirectUris := append([]string{"http://localhost:", "https://localhost:", "http://127.0.0.1:", "http://casdoor-app"}, application.RedirectUris...)
if err != nil { for _, targetUri := range redirectUris {
panic(err)
}
if isValid {
return true
}
for _, targetUri := range application.RedirectUris {
targetUriRegex := regexp.MustCompile(targetUri) targetUriRegex := regexp.MustCompile(targetUri)
if targetUriRegex.MatchString(redirectUri) || strings.Contains(redirectUri, targetUri) { if targetUriRegex.MatchString(redirectUri) || strings.Contains(redirectUri, targetUri) {
return true return true
@ -809,17 +712,6 @@ func (application *Application) IsLdapEnabled() bool {
return false return false
} }
func (application *Application) IsFaceIdEnabled() bool {
if len(application.SigninMethods) > 0 {
for _, signinMethod := range application.SigninMethods {
if signinMethod.Name == "Face ID" {
return true
}
}
}
return false
}
func IsOriginAllowed(origin string) (bool, error) { func IsOriginAllowed(origin string) (bool, error) {
applications, err := GetApplications("") applications, err := GetApplications("")
if err != nil { if err != nil {

View File

@ -38,20 +38,7 @@ func (application *Application) GetProviderByCategory(category string) (*Provide
return nil, nil return nil, nil
} }
func isProviderItemCountryCodeMatched(providerItem *ProviderItem, countryCode string) bool { func (application *Application) GetProviderByCategoryAndRule(category string, method string) (*Provider, error) {
if len(providerItem.CountryCodes) == 0 {
return true
}
for _, countryCode2 := range providerItem.CountryCodes {
if countryCode2 == "" || countryCode2 == "All" || countryCode2 == "all" || countryCode2 == countryCode {
return true
}
}
return false
}
func (application *Application) GetProviderByCategoryAndRule(category string, method string, countryCode string) (*Provider, error) {
providers, err := GetProviders(application.Organization) providers, err := GetProviders(application.Organization)
if err != nil { if err != nil {
return nil, err return nil, err
@ -67,13 +54,7 @@ func (application *Application) GetProviderByCategoryAndRule(category string, me
} }
for _, providerItem := range application.Providers { for _, providerItem := range application.Providers {
if providerItem.Provider != nil && providerItem.Provider.Category == "SMS" { if providerItem.Rule == method || providerItem.Rule == "all" {
if !isProviderItemCountryCodeMatched(providerItem, countryCode) {
continue
}
}
if providerItem.Rule == method || providerItem.Rule == "" || providerItem.Rule == "All" || providerItem.Rule == "all" || providerItem.Rule == "None" {
if provider, ok := m[providerItem.Name]; ok { if provider, ok := m[providerItem.Name]; ok {
return provider, nil return provider, nil
} }
@ -84,11 +65,11 @@ func (application *Application) GetProviderByCategoryAndRule(category string, me
} }
func (application *Application) GetEmailProvider(method string) (*Provider, error) { func (application *Application) GetEmailProvider(method string) (*Provider, error) {
return application.GetProviderByCategoryAndRule("Email", method, "All") return application.GetProviderByCategoryAndRule("Email", method)
} }
func (application *Application) GetSmsProvider(method string, countryCode string) (*Provider, error) { func (application *Application) GetSmsProvider(method string) (*Provider, error) {
return application.GetProviderByCategoryAndRule("SMS", method, countryCode) return application.GetProviderByCategoryAndRule("SMS", method)
} }
func (application *Application) GetStorageProvider() (*Provider, error) { func (application *Application) GetStorageProvider() (*Provider, error) {

View File

@ -146,12 +146,7 @@ func getCertByName(name string) (*Cert, error) {
func GetCert(id string) (*Cert, error) { func GetCert(id string) (*Cert, error) {
owner, name := util.GetOwnerAndNameFromId(id) owner, name := util.GetOwnerAndNameFromId(id)
cert, err := getCert(owner, name) return getCert(owner, name)
if cert == nil && owner != "admin" {
return getCert("admin", name)
} else {
return cert, err
}
} }
func UpdateCert(id string, cert *Cert) (bool, error) { func UpdateCert(id string, cert *Cert) (bool, error) {
@ -210,41 +205,16 @@ func (p *Cert) GetId() string {
} }
func (p *Cert) populateContent() error { func (p *Cert) populateContent() error {
if p.Certificate != "" && p.PrivateKey != "" { if p.Certificate == "" || p.PrivateKey == "" {
return nil certificate, privateKey, err := generateRsaKeys(p.BitSize, p.ExpireInYears, p.Name, p.Owner)
if err != nil {
return err
}
p.Certificate = certificate
p.PrivateKey = privateKey
} }
if len(p.CryptoAlgorithm) < 3 {
err := fmt.Errorf("populateContent() error, unsupported crypto algorithm: %s", p.CryptoAlgorithm)
return err
}
if p.CryptoAlgorithm == "RSA" {
p.CryptoAlgorithm = "RS256"
}
sigAlgorithm := p.CryptoAlgorithm[:2]
shaSize, err := util.ParseIntWithError(p.CryptoAlgorithm[2:])
if err != nil {
return err
}
var certificate, privateKey string
if sigAlgorithm == "RS" {
certificate, privateKey, err = generateRsaKeys(p.BitSize, shaSize, p.ExpireInYears, p.Name, p.Owner)
} else if sigAlgorithm == "ES" {
certificate, privateKey, err = generateEsKeys(shaSize, p.ExpireInYears, p.Name, p.Owner)
} else if sigAlgorithm == "PS" {
certificate, privateKey, err = generateRsaPssKeys(p.BitSize, shaSize, p.ExpireInYears, p.Name, p.Owner)
} else {
err = fmt.Errorf("populateContent() error, unsupported signature algorithm: %s", sigAlgorithm)
}
if err != nil {
return err
}
p.Certificate = certificate
p.PrivateKey = privateKey
return nil return nil
} }

View File

@ -241,10 +241,6 @@ func CheckPassword(user *User, password string, lang string, options ...bool) er
return fmt.Errorf(i18n.Translate(lang, "check:Organization does not exist")) return fmt.Errorf(i18n.Translate(lang, "check:Organization does not exist"))
} }
if password == "" {
return fmt.Errorf(i18n.Translate(lang, "check:Password cannot be empty"))
}
passwordType := user.PasswordType passwordType := user.PasswordType
if passwordType == "" { if passwordType == "" {
passwordType = organization.PasswordType passwordType = organization.PasswordType
@ -252,7 +248,7 @@ func CheckPassword(user *User, password string, lang string, options ...bool) er
credManager := cred.GetCredManager(passwordType) credManager := cred.GetCredManager(passwordType)
if credManager != nil { if credManager != nil {
if organization.MasterPassword != "" { if organization.MasterPassword != "" {
if password == organization.MasterPassword || credManager.IsPasswordCorrect(password, organization.MasterPassword, "", organization.PasswordSalt) { if credManager.IsPasswordCorrect(password, organization.MasterPassword, "", organization.PasswordSalt) {
return resetUserSigninErrorTimes(user) return resetUserSigninErrorTimes(user)
} }
} }
@ -277,7 +273,7 @@ func CheckPasswordComplexity(user *User, password string) string {
return CheckPasswordComplexityByOrg(organization, password) return CheckPasswordComplexityByOrg(organization, password)
} }
func CheckLdapUserPassword(user *User, password string, lang string) error { func checkLdapUserPassword(user *User, password string, lang string) error {
ldaps, err := GetLdaps(user.Owner) ldaps, err := GetLdaps(user.Owner)
if err != nil { if err != nil {
return err return err
@ -372,7 +368,7 @@ func CheckUserPassword(organization string, username string, password string, la
} }
// only for LDAP users // only for LDAP users
err = CheckLdapUserPassword(user, password, lang) err = checkLdapUserPassword(user, password, lang)
if err != nil { if err != nil {
if err.Error() == "user not exist" { if err.Error() == "user not exist" {
return nil, fmt.Errorf(i18n.Translate(lang, "check:The user: %s doesn't exist in LDAP server"), username) return nil, fmt.Errorf(i18n.Translate(lang, "check:The user: %s doesn't exist in LDAP server"), username)
@ -385,13 +381,7 @@ func CheckUserPassword(organization string, username string, password string, la
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = checkPasswordExpired(user, lang)
if err != nil {
return nil, err
}
} }
return user, nil return user, nil
} }
@ -420,7 +410,7 @@ func CheckUserPermission(requestUserId, userId string, strict bool, lang string)
} }
hasPermission := false hasPermission := false
if IsAppUser(requestUserId) { if strings.HasPrefix(requestUserId, "app/") {
hasPermission = true hasPermission = true
} else { } else {
requestUser, err := GetUser(requestUserId) requestUser, err := GetUser(requestUserId)
@ -517,8 +507,8 @@ func CheckLoginPermission(userId string, application *Application) (bool, error)
func CheckUsername(username string, lang string) string { func CheckUsername(username string, lang string) string {
if username == "" { if username == "" {
return i18n.Translate(lang, "check:Empty username.") return i18n.Translate(lang, "check:Empty username.")
} else if len(username) > 255 { } else if len(username) > 39 {
return i18n.Translate(lang, "check:Username is too long (maximum is 255 characters).") return i18n.Translate(lang, "check:Username is too long (maximum is 39 characters).")
} }
// https://stackoverflow.com/questions/58726546/github-username-convention-using-regex // https://stackoverflow.com/questions/58726546/github-username-convention-using-regex
@ -530,46 +520,11 @@ func CheckUsername(username string, lang string) string {
return "" return ""
} }
func CheckUsernameWithEmail(username string, lang string) string {
if username == "" {
return i18n.Translate(lang, "check:Empty username.")
} else if len(username) > 255 {
return i18n.Translate(lang, "check:Username is too long (maximum is 255 characters).")
}
// https://stackoverflow.com/questions/58726546/github-username-convention-using-regex
if !util.ReUserNameWithEmail.MatchString(username) {
return i18n.Translate(lang, "check:Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.")
}
return ""
}
func CheckUpdateUser(oldUser, user *User, lang string) string { func CheckUpdateUser(oldUser, user *User, lang string) string {
if oldUser.Name != user.Name { if oldUser.Name != user.Name {
organizationName := oldUser.Owner if msg := CheckUsername(user.Name, lang); msg != "" {
if organizationName == "" { return msg
organizationName = user.Owner
} }
organization, err := getOrganization("admin", organizationName)
if err != nil {
return err.Error()
}
if organization == nil {
return fmt.Sprintf(i18n.Translate(lang, "auth:The organization: %s does not exist"), organizationName)
}
if organization.UseEmailAsUsername {
if msg := CheckUsernameWithEmail(user.Name, lang); msg != "" {
return msg
}
} else {
if msg := CheckUsername(user.Name, lang); msg != "" {
return msg
}
}
if HasUserByField(user.Owner, "name", user.Name) { if HasUserByField(user.Owner, "name", user.Name) {
return i18n.Translate(lang, "check:Username already exists") return i18n.Translate(lang, "check:Username already exists")
} }
@ -584,11 +539,6 @@ func CheckUpdateUser(oldUser, user *User, lang string) string {
return i18n.Translate(lang, "check:Phone already exists") return i18n.Translate(lang, "check:Phone already exists")
} }
} }
if oldUser.IpWhitelist != user.IpWhitelist {
if err := CheckIpWhitelist(user.IpWhitelist, lang); err != nil {
return err.Error()
}
}
return "" return ""
} }

View File

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

View File

@ -74,7 +74,7 @@ func checkPasswordComplexity(password string, options []string) string {
} }
if len(options) == 0 { if len(options) == 0 {
return "" options = []string{"AtLeast6"}
} }
checkers := map[string]ValidatorFunc{ checkers := map[string]ValidatorFunc{

View File

@ -1,53 +0,0 @@
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"time"
"github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/util"
)
func checkPasswordExpired(user *User, lang string) error {
organization, err := GetOrganizationByUser(user)
if err != nil {
return err
}
if organization == nil {
return fmt.Errorf(i18n.Translate(lang, "check:Organization does not exist"))
}
passwordExpireDays := organization.PasswordExpireDays
if passwordExpireDays <= 0 {
return nil
}
lastChangePasswordTime := user.LastChangePasswordTime
if lastChangePasswordTime == "" {
if user.CreatedTime == "" {
return fmt.Errorf(i18n.Translate(lang, "check:Your password has expired. Please reset your password by clicking \"Forgot password\""))
}
lastChangePasswordTime = user.CreatedTime
}
lastTime := util.String2Time(lastChangePasswordTime)
expireTime := lastTime.AddDate(0, 0, passwordExpireDays)
if time.Now().After(expireTime) {
return fmt.Errorf(i18n.Translate(lang, "check:Your password has expired. Please reset your password by clicking \"Forgot password\""))
}
return nil
}

View File

@ -52,9 +52,6 @@ func GetFailedSigninConfigByUser(user *User) (int, int, error) {
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err
} }
if application == nil {
return 0, 0, fmt.Errorf("the application for user %s is not found", user.GetId())
}
failedSigninLimit := application.FailedSigninLimit failedSigninLimit := application.FailedSigninLimit
if failedSigninLimit == 0 { if failedSigninLimit == 0 {

View File

@ -16,18 +16,23 @@
package object package object
import "github.com/casdoor/casdoor/email" import (
"crypto/tls"
// TestSmtpServer Test the SMTP server "github.com/casdoor/casdoor/email"
func TestSmtpServer(provider *Provider) error { "github.com/casdoor/gomail/v2"
smtpEmailProvider := email.NewSmtpEmailProvider(provider.ClientId, provider.ClientSecret, provider.Host, provider.Port, provider.Type, provider.DisableSsl) )
sender, err := smtpEmailProvider.Dialer.Dial()
if err != nil { func getDialer(provider *Provider) *gomail.Dialer {
return err dialer := &gomail.Dialer{}
dialer = gomail.NewDialer(provider.Host, provider.Port, provider.ClientId, provider.ClientSecret)
if provider.Type == "SUBMAIL" {
dialer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
} }
defer sender.Close()
return nil dialer.SSL = !provider.DisableSsl
return dialer
} }
func SendEmail(provider *Provider, title string, content string, dest string, sender string) error { func SendEmail(provider *Provider, title string, content string, dest string, sender string) error {
@ -45,3 +50,16 @@ func SendEmail(provider *Provider, title string, content string, dest string, se
return emailProvider.Send(fromAddress, fromName, dest, title, content) return emailProvider.Send(fromAddress, fromName, dest, title, content)
} }
// DailSmtpServer Dail Smtp server
func DailSmtpServer(provider *Provider) error {
dialer := getDialer(provider)
sender, err := dialer.Dial()
if err != nil {
return err
}
defer sender.Close()
return nil
}

View File

@ -17,95 +17,123 @@ package object
import ( import (
"sync" "sync"
"time" "time"
"github.com/casdoor/casdoor/conf"
) )
type DashboardDateItem struct { type Dashboard struct {
CreatedTime string `json:"createTime"` OrganizationCounts []int `json:"organizationCounts"`
UserCounts []int `json:"userCounts"`
ProviderCounts []int `json:"providerCounts"`
ApplicationCounts []int `json:"applicationCounts"`
SubscriptionCounts []int `json:"subscriptionCounts"`
} }
type DashboardMapItem struct { func GetDashboard(owner string) (*Dashboard, error) {
dashboardDateItems []DashboardDateItem dashboard := &Dashboard{
itemCount int64 OrganizationCounts: make([]int, 31),
} UserCounts: make([]int, 31),
ProviderCounts: make([]int, 31),
func GetDashboard(owner string) (*map[string][]int64, error) { ApplicationCounts: make([]int, 31),
if owner == "All" { SubscriptionCounts: make([]int, 31),
owner = ""
} }
dashboard := make(map[string][]int64)
dashboardMap := sync.Map{}
tableNames := []string{"organization", "user", "provider", "application", "subscription", "role", "group", "resource", "cert", "permission", "transaction", "model", "adapter", "enforcer"}
time30day := time.Now().AddDate(0, 0, -30)
var wg sync.WaitGroup var wg sync.WaitGroup
var err error
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
wg.Add(len(tableNames))
ch := make(chan error, len(tableNames))
for _, tableName := range tableNames {
dashboard[tableName+"Counts"] = make([]int64, 31)
tableFullName := tableNamePrefix + tableName
go func(ch chan error) {
defer wg.Done()
dashboardDateItems := []DashboardDateItem{}
var countResult int64
dbQueryBefore := ormer.Engine.Cols("created_time") organizations := []Organization{}
dbQueryAfter := ormer.Engine.Cols("created_time") users := []User{}
providers := []Provider{}
applications := []Application{}
subscriptions := []Subscription{}
if owner != "" { wg.Add(5)
dbQueryAfter = dbQueryAfter.And("owner = ?", owner) go func() {
dbQueryBefore = dbQueryBefore.And("owner = ?", owner) defer wg.Done()
} if err := ormer.Engine.Find(&organizations, &Organization{Owner: owner}); err != nil {
panic(err)
if countResult, err = dbQueryBefore.And("created_time < ?", time30day).Table(tableFullName).Count(); err != nil {
ch <- err
return
}
if err = dbQueryAfter.And("created_time >= ?", time30day).Table(tableFullName).Find(&dashboardDateItems); err != nil {
ch <- err
return
}
dashboardMap.Store(tableFullName, DashboardMapItem{
dashboardDateItems: dashboardDateItems,
itemCount: countResult,
})
}(ch)
}
wg.Wait()
close(ch)
for err = range ch {
if err != nil {
return nil, err
} }
} }()
go func() {
defer wg.Done()
if err := ormer.Engine.Find(&users, &User{Owner: owner}); err != nil {
panic(err)
}
}()
go func() {
defer wg.Done()
if err := ormer.Engine.Find(&providers, &Provider{Owner: owner}); err != nil {
panic(err)
}
}()
go func() {
defer wg.Done()
if err := ormer.Engine.Find(&applications, &Application{Owner: owner}); err != nil {
panic(err)
}
}()
go func() {
defer wg.Done()
if err := ormer.Engine.Find(&subscriptions, &Subscription{Owner: owner}); err != nil {
panic(err)
}
}()
wg.Wait()
nowTime := time.Now() nowTime := time.Now()
for i := 30; i >= 0; i-- { for i := 30; i >= 0; i-- {
cutTime := nowTime.AddDate(0, 0, -i) cutTime := nowTime.AddDate(0, 0, -i)
for _, tableName := range tableNames { dashboard.OrganizationCounts[30-i] = countCreatedBefore(organizations, cutTime)
item, exist := dashboardMap.Load(tableName) dashboard.UserCounts[30-i] = countCreatedBefore(users, cutTime)
if !exist { dashboard.ProviderCounts[30-i] = countCreatedBefore(providers, cutTime)
continue dashboard.ApplicationCounts[30-i] = countCreatedBefore(applications, cutTime)
} dashboard.SubscriptionCounts[30-i] = countCreatedBefore(subscriptions, cutTime)
dashboard[tableName+"Counts"][30-i] = countCreatedBefore(item.(DashboardMapItem), cutTime)
}
} }
return &dashboard, nil return dashboard, nil
} }
func countCreatedBefore(dashboardMapItem DashboardMapItem, before time.Time) int64 { func countCreatedBefore(objects interface{}, before time.Time) int {
count := dashboardMapItem.itemCount count := 0
for _, e := range dashboardMapItem.dashboardDateItems { switch obj := objects.(type) {
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", e.CreatedTime) case []Organization:
if createdTime.Before(before) { for _, o := range obj {
count++ createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", o.CreatedTime)
if createdTime.Before(before) {
count++
}
}
case []User:
for _, u := range obj {
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", u.CreatedTime)
if createdTime.Before(before) {
count++
}
}
case []Provider:
for _, p := range obj {
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", p.CreatedTime)
if createdTime.Before(before) {
count++
}
}
case []Application:
for _, a := range obj {
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", a.CreatedTime)
if createdTime.Before(before) {
count++
}
}
case []Subscription:
for _, s := range obj {
createdTime, _ := time.Parse("2006-01-02T15:04:05-07:00", s.CreatedTime)
if createdTime.Before(before) {
count++
}
} }
} }
return count return count

View File

@ -30,19 +30,17 @@ type Group struct {
CreatedTime string `xorm:"varchar(100)" json:"createdTime"` CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"` UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"` DisplayName string `xorm:"varchar(100)" json:"displayName"`
Manager string `xorm:"varchar(100)" json:"manager"` Manager string `xorm:"varchar(100)" json:"manager"`
ContactEmail string `xorm:"varchar(100)" json:"contactEmail"` ContactEmail string `xorm:"varchar(100)" json:"contactEmail"`
Type string `xorm:"varchar(100)" json:"type"` Type string `xorm:"varchar(100)" json:"type"`
ParentId string `xorm:"varchar(100)" json:"parentId"` ParentId string `xorm:"varchar(100)" json:"parentId"`
ParentName string `xorm:"-" json:"parentName"` IsTopGroup bool `xorm:"bool" json:"isTopGroup"`
IsTopGroup bool `xorm:"bool" json:"isTopGroup"` Users []*User `xorm:"-" json:"users"`
Users []string `xorm:"-" json:"users"`
Title string `json:"title,omitempty"` Title string `json:"title,omitempty"`
Key string `json:"key,omitempty"` Key string `json:"key,omitempty"`
HaveChildren bool `xorm:"-" json:"haveChildren"` Children []*Group `json:"children,omitempty"`
Children []*Group `json:"children,omitempty"`
IsEnabled bool `json:"isEnabled"` IsEnabled bool `json:"isEnabled"`
} }
@ -80,30 +78,6 @@ func GetPaginationGroups(owner string, offset, limit int, field, value, sortFiel
return groups, nil return groups, nil
} }
func GetGroupsHaveChildrenMap(groups []*Group) (map[string]*Group, error) {
groupsHaveChildren := []*Group{}
resultMap := make(map[string]*Group)
groupMap := map[string]*Group{}
groupIds := []string{}
for _, group := range groups {
groupMap[group.Name] = group
groupIds = append(groupIds, group.Name)
if !group.IsTopGroup {
groupIds = append(groupIds, group.ParentId)
}
}
err := ormer.Engine.Cols("owner", "name", "parent_id", "display_name").Distinct("parent_id").In("parent_id", groupIds).Find(&groupsHaveChildren)
if err != nil {
return nil, err
}
for _, group := range groupsHaveChildren {
resultMap[group.ParentId] = groupMap[group.ParentId]
}
return resultMap, nil
}
func getGroup(owner string, name string) (*Group, error) { func getGroup(owner string, name string) (*Group, error) {
if owner == "" || name == "" { if owner == "" || name == "" {
return nil, nil return nil, nil
@ -179,15 +153,6 @@ func AddGroups(groups []*Group) (bool, error) {
return affected != 0, nil return affected != 0, nil
} }
func deleteGroup(group *Group) (bool, error) {
affected, err := ormer.Engine.ID(core.PK{group.Owner, group.Name}).Delete(&Group{})
if err != nil {
return false, err
}
return affected != 0, nil
}
func DeleteGroup(group *Group) (bool, error) { func DeleteGroup(group *Group) (bool, error) {
_, err := ormer.Engine.Get(group) _, err := ormer.Engine.Get(group)
if err != nil { if err != nil {
@ -206,7 +171,12 @@ func DeleteGroup(group *Group) (bool, error) {
return false, errors.New("group has users") return false, errors.New("group has users")
} }
return deleteGroup(group) affected, err := ormer.Engine.ID(core.PK{group.Owner, group.Name}).Delete(&Group{})
if err != nil {
return false, err
}
return affected != 0, nil
} }
func checkGroupName(name string) error { func checkGroupName(name string) error {
@ -306,10 +276,7 @@ func GetPaginationGroupUsers(groupId string, offset, limit int, field, value, so
func GetGroupUsers(groupId string) ([]*User, error) { func GetGroupUsers(groupId string) ([]*User, error) {
users := []*User{} users := []*User{}
owner, _, err := util.GetOwnerAndNameFromIdWithError(groupId) owner, _ := util.GetOwnerAndNameFromId(groupId)
if err != nil {
return nil, err
}
names, err := userEnforcer.GetUserNamesByGroupName(groupId) names, err := userEnforcer.GetUserNamesByGroupName(groupId)
if err != nil { if err != nil {
return nil, err return nil, err
@ -321,39 +288,6 @@ func GetGroupUsers(groupId string) ([]*User, error) {
return users, nil return users, nil
} }
func GetGroupUsersWithoutError(groupId string) []*User {
users, _ := GetGroupUsers(groupId)
return users
}
func ExtendGroupWithUsers(group *Group) error {
if group == nil {
return nil
}
groupId := group.GetId()
userIds := []string{}
userIds, err := userEnforcer.GetAllUsersByGroup(groupId)
if err != nil {
return err
}
group.Users = userIds
return nil
}
func ExtendGroupsWithUsers(groups []*Group) error {
for _, group := range groups {
users, err := userEnforcer.GetAllUsersByGroup(group.GetId())
if err != nil {
return err
}
group.Users = users
}
return nil
}
func GroupChangeTrigger(oldName, newName string) error { func GroupChangeTrigger(oldName, newName string) error {
session := ormer.Engine.NewSession() session := ormer.Engine.NewSession()
defer session.Close() defer session.Close()

View File

@ -71,14 +71,13 @@ func getBuiltInAccountItems() []*AccountItem {
{Name: "Permissions", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"}, {Name: "Permissions", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "Groups", Visible: true, ViewRule: "Public", ModifyRule: "Admin"}, {Name: "Groups", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"}, {Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Properties", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"}, {Name: "Properties", Visible: false, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"}, {Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"}, {Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"}, {Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Multi-factor authentication", Visible: true, ViewRule: "Self", ModifyRule: "Self"}, {Name: "Multi-factor authentication", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "WebAuthn credentials", Visible: true, ViewRule: "Self", ModifyRule: "Self"}, {Name: "WebAuthn credentials", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Managed accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"}, {Name: "Managed accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "MFA accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
} }
} }
@ -103,15 +102,12 @@ func initBuiltInOrganization() bool {
PasswordOptions: []string{"AtLeast6"}, PasswordOptions: []string{"AtLeast6"},
CountryCodes: []string{"US", "ES", "FR", "DE", "GB", "CN", "JP", "KR", "VN", "ID", "SG", "IN"}, CountryCodes: []string{"US", "ES", "FR", "DE", "GB", "CN", "JP", "KR", "VN", "ID", "SG", "IN"},
DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")), DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
UserTypes: []string{},
Tags: []string{}, Tags: []string{},
Languages: []string{"en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi", "pt"}, Languages: []string{"en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi", "pt"},
InitScore: 2000, InitScore: 2000,
AccountItems: getBuiltInAccountItems(), AccountItems: getBuiltInAccountItems(),
EnableSoftDeletion: false, EnableSoftDeletion: false,
IsProfilePublic: false, IsProfilePublic: false,
UseEmailAsUsername: false,
EnableTour: true,
} }
_, err = AddOrganization(organization) _, err = AddOrganization(organization)
if err != nil { if err != nil {
@ -188,7 +184,6 @@ func initBuiltInApplication() {
{Name: "Password", DisplayName: "Password", Rule: "All"}, {Name: "Password", DisplayName: "Password", Rule: "All"},
{Name: "Verification code", DisplayName: "Verification code", Rule: "All"}, {Name: "Verification code", DisplayName: "Verification code", Rule: "All"},
{Name: "WebAuthn", DisplayName: "WebAuthn", Rule: "None"}, {Name: "WebAuthn", DisplayName: "WebAuthn", Rule: "None"},
{Name: "Face ID", DisplayName: "Face ID", Rule: "None"},
}, },
SignupItems: []*SignupItem{ SignupItems: []*SignupItem{
{Name: "ID", Visible: false, Required: true, Prompted: false, Rule: "Random"}, {Name: "ID", Visible: false, Required: true, Prompted: false, Rule: "Random"},
@ -202,7 +197,6 @@ func initBuiltInApplication() {
}, },
Tags: []string{}, Tags: []string{},
RedirectUris: []string{}, RedirectUris: []string{},
TokenFormat: "JWT",
TokenFields: []string{}, TokenFields: []string{},
ExpireInHours: 168, ExpireInHours: 168,
FormOffset: 2, FormOffset: 2,
@ -413,7 +407,7 @@ func initBuiltInPermission() {
Groups: []string{}, Groups: []string{},
Roles: []string{}, Roles: []string{},
Domains: []string{}, Domains: []string{},
Model: "user-model-built-in", Model: "model-built-in",
Adapter: "", Adapter: "",
ResourceType: "Application", ResourceType: "Application",
Resources: []string{"app-built-in"}, Resources: []string{"app-built-in"},

View File

@ -17,47 +17,37 @@ package object
import ( import (
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/casvisor/casvisor-go-sdk/casvisorsdk"
) )
type InitData struct { type InitData struct {
Organizations []*Organization `json:"organizations"` Organizations []*Organization `json:"organizations"`
Applications []*Application `json:"applications"` Applications []*Application `json:"applications"`
Users []*User `json:"users"` Users []*User `json:"users"`
Certs []*Cert `json:"certs"` Certs []*Cert `json:"certs"`
Providers []*Provider `json:"providers"` Providers []*Provider `json:"providers"`
Ldaps []*Ldap `json:"ldaps"` Ldaps []*Ldap `json:"ldaps"`
Models []*Model `json:"models"` Models []*Model `json:"models"`
Permissions []*Permission `json:"permissions"` Permissions []*Permission `json:"permissions"`
Payments []*Payment `json:"payments"` Payments []*Payment `json:"payments"`
Products []*Product `json:"products"` Products []*Product `json:"products"`
Resources []*Resource `json:"resources"` Resources []*Resource `json:"resources"`
Roles []*Role `json:"roles"` Roles []*Role `json:"roles"`
Syncers []*Syncer `json:"syncers"` Syncers []*Syncer `json:"syncers"`
Tokens []*Token `json:"tokens"` Tokens []*Token `json:"tokens"`
Webhooks []*Webhook `json:"webhooks"` Webhooks []*Webhook `json:"webhooks"`
Groups []*Group `json:"groups"` Groups []*Group `json:"groups"`
Adapters []*Adapter `json:"adapters"` Adapters []*Adapter `json:"adapters"`
Enforcers []*Enforcer `json:"enforcers"` Enforcers []*Enforcer `json:"enforcers"`
Plans []*Plan `json:"plans"` Plans []*Plan `json:"plans"`
Pricings []*Pricing `json:"pricings"` Pricings []*Pricing `json:"pricings"`
Invitations []*Invitation `json:"invitations"`
Records []*casvisorsdk.Record `json:"records"`
Sessions []*Session `json:"sessions"`
Subscriptions []*Subscription `json:"subscriptions"`
Transactions []*Transaction `json:"transactions"`
} }
var initDataNewOnly bool
func InitFromFile() { func InitFromFile() {
initDataFile := conf.GetConfigString("initDataFile") initDataFile := conf.GetConfigString("initDataFile")
if initDataFile == "" { if initDataFile == "" {
return return
} }
initDataNewOnly = conf.GetConfigBool("initDataNewOnly")
initData, err := readInitDataFromFile(initDataFile) initData, err := readInitDataFromFile(initDataFile)
if err != nil { if err != nil {
panic(err) panic(err)
@ -124,21 +114,6 @@ func InitFromFile() {
for _, pricing := range initData.Pricings { for _, pricing := range initData.Pricings {
initDefinedPricing(pricing) initDefinedPricing(pricing)
} }
for _, invitation := range initData.Invitations {
initDefinedInvitation(invitation)
}
for _, record := range initData.Records {
initDefinedRecord(record)
}
for _, session := range initData.Sessions {
initDefinedSession(session)
}
for _, subscription := range initData.Subscriptions {
initDefinedSubscription(subscription)
}
for _, transaction := range initData.Transactions {
initDefinedTransaction(transaction)
}
} }
} }
@ -170,11 +145,6 @@ func readInitDataFromFile(filePath string) (*InitData, error) {
Enforcers: []*Enforcer{}, Enforcers: []*Enforcer{},
Plans: []*Plan{}, Plans: []*Plan{},
Pricings: []*Pricing{}, Pricings: []*Pricing{},
Invitations: []*Invitation{},
Records: []*casvisorsdk.Record{},
Sessions: []*Session{},
Subscriptions: []*Subscription{},
Transactions: []*Transaction{},
} }
err := util.JsonToStruct(s, data) err := util.JsonToStruct(s, data)
if err != nil { if err != nil {
@ -186,9 +156,6 @@ func readInitDataFromFile(filePath string) (*InitData, error) {
if organization.Tags == nil { if organization.Tags == nil {
organization.Tags = []string{} organization.Tags = []string{}
} }
if organization.AccountItems == nil {
organization.AccountItems = []*AccountItem{}
}
} }
for _, application := range data.Applications { for _, application := range data.Applications {
if application.Providers == nil { if application.Providers == nil {
@ -258,11 +225,6 @@ func readInitDataFromFile(filePath string) (*InitData, error) {
pricing.Plans = []string{} pricing.Plans = []string{}
} }
} }
for _, session := range data.Sessions {
if session.SessionId == nil {
session.SessionId = []string{}
}
}
return data, nil return data, nil
} }
@ -273,21 +235,10 @@ func initDefinedOrganization(organization *Organization) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := deleteOrganization(organization)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete organization")
}
} }
organization.CreatedTime = util.GetCurrentTime() organization.CreatedTime = util.GetCurrentTime()
if len(organization.AccountItems) == 0 { organization.AccountItems = getBuiltInAccountItems()
organization.AccountItems = getBuiltInAccountItems()
}
_, err = AddOrganization(organization) _, err = AddOrganization(organization)
if err != nil { if err != nil {
@ -302,16 +253,7 @@ func initDefinedApplication(application *Application) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := deleteApplication(application)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete application")
}
} }
application.CreatedTime = util.GetCurrentTime() application.CreatedTime = util.GetCurrentTime()
_, err = AddApplication(application) _, err = AddApplication(application)
@ -326,22 +268,11 @@ func initDefinedUser(user *User) {
panic(err) panic(err)
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := deleteUser(user)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete user")
}
} }
user.CreatedTime = util.GetCurrentTime() user.CreatedTime = util.GetCurrentTime()
user.Id = util.GenerateId() user.Id = util.GenerateId()
if user.Properties == nil { user.Properties = make(map[string]string)
user.Properties = make(map[string]string)
}
_, err = AddUser(user) _, err = AddUser(user)
if err != nil { if err != nil {
panic(err) panic(err)
@ -355,16 +286,7 @@ func initDefinedCert(cert *Cert) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeleteCert(cert)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete cert")
}
} }
cert.CreatedTime = util.GetCurrentTime() cert.CreatedTime = util.GetCurrentTime()
_, err = AddCert(cert) _, err = AddCert(cert)
@ -380,16 +302,7 @@ func initDefinedLdap(ldap *Ldap) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeleteLdap(ldap)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete ldap")
}
} }
_, err = AddLdap(ldap) _, err = AddLdap(ldap)
if err != nil { if err != nil {
@ -404,16 +317,7 @@ func initDefinedProvider(provider *Provider) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeleteProvider(provider)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete provider")
}
} }
_, err = AddProvider(provider) _, err = AddProvider(provider)
if err != nil { if err != nil {
@ -428,16 +332,7 @@ func initDefinedModel(model *Model) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeleteModel(model)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete provider")
}
} }
model.CreatedTime = util.GetCurrentTime() model.CreatedTime = util.GetCurrentTime()
_, err = AddModel(model) _, err = AddModel(model)
@ -453,16 +348,7 @@ func initDefinedPermission(permission *Permission) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := deletePermission(permission)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete permission")
}
} }
permission.CreatedTime = util.GetCurrentTime() permission.CreatedTime = util.GetCurrentTime()
_, err = AddPermission(permission) _, err = AddPermission(permission)
@ -478,16 +364,7 @@ func initDefinedPayment(payment *Payment) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeletePayment(payment)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete payment")
}
} }
payment.CreatedTime = util.GetCurrentTime() payment.CreatedTime = util.GetCurrentTime()
_, err = AddPayment(payment) _, err = AddPayment(payment)
@ -503,16 +380,7 @@ func initDefinedProduct(product *Product) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeleteProduct(product)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete product")
}
} }
product.CreatedTime = util.GetCurrentTime() product.CreatedTime = util.GetCurrentTime()
_, err = AddProduct(product) _, err = AddProduct(product)
@ -528,16 +396,7 @@ func initDefinedResource(resource *Resource) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeleteResource(resource)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete resource")
}
} }
resource.CreatedTime = util.GetCurrentTime() resource.CreatedTime = util.GetCurrentTime()
_, err = AddResource(resource) _, err = AddResource(resource)
@ -553,16 +412,7 @@ func initDefinedRole(role *Role) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := deleteRole(role)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete role")
}
} }
role.CreatedTime = util.GetCurrentTime() role.CreatedTime = util.GetCurrentTime()
_, err = AddRole(role) _, err = AddRole(role)
@ -578,16 +428,7 @@ func initDefinedSyncer(syncer *Syncer) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeleteSyncer(syncer)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete role")
}
} }
syncer.CreatedTime = util.GetCurrentTime() syncer.CreatedTime = util.GetCurrentTime()
_, err = AddSyncer(syncer) _, err = AddSyncer(syncer)
@ -603,16 +444,7 @@ func initDefinedToken(token *Token) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeleteToken(token)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete token")
}
} }
token.CreatedTime = util.GetCurrentTime() token.CreatedTime = util.GetCurrentTime()
_, err = AddToken(token) _, err = AddToken(token)
@ -628,16 +460,7 @@ func initDefinedWebhook(webhook *Webhook) {
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeleteWebhook(webhook)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete webhook")
}
} }
webhook.CreatedTime = util.GetCurrentTime() webhook.CreatedTime = util.GetCurrentTime()
_, err = AddWebhook(webhook) _, err = AddWebhook(webhook)
@ -652,16 +475,7 @@ func initDefinedGroup(group *Group) {
panic(err) panic(err)
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := deleteGroup(group)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete group")
}
} }
group.CreatedTime = util.GetCurrentTime() group.CreatedTime = util.GetCurrentTime()
_, err = AddGroup(group) _, err = AddGroup(group)
@ -676,16 +490,7 @@ func initDefinedAdapter(adapter *Adapter) {
panic(err) panic(err)
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeleteAdapter(adapter)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete adapter")
}
} }
adapter.CreatedTime = util.GetCurrentTime() adapter.CreatedTime = util.GetCurrentTime()
_, err = AddAdapter(adapter) _, err = AddAdapter(adapter)
@ -700,16 +505,7 @@ func initDefinedEnforcer(enforcer *Enforcer) {
panic(err) panic(err)
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeleteEnforcer(enforcer)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete enforcer")
}
} }
enforcer.CreatedTime = util.GetCurrentTime() enforcer.CreatedTime = util.GetCurrentTime()
_, err = AddEnforcer(enforcer) _, err = AddEnforcer(enforcer)
@ -724,16 +520,7 @@ func initDefinedPlan(plan *Plan) {
panic(err) panic(err)
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeletePlan(plan)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete plan")
}
} }
plan.CreatedTime = util.GetCurrentTime() plan.CreatedTime = util.GetCurrentTime()
_, err = AddPlan(plan) _, err = AddPlan(plan)
@ -743,21 +530,12 @@ func initDefinedPlan(plan *Plan) {
} }
func initDefinedPricing(pricing *Pricing) { func initDefinedPricing(pricing *Pricing) {
existed, err := getPricing(pricing.Owner, pricing.Name) existed, err := getPlan(pricing.Owner, pricing.Name)
if err != nil { if err != nil {
panic(err) panic(err)
} }
if existed != nil { if existed != nil {
if initDataNewOnly { return
return
}
affected, err := DeletePricing(pricing)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete pricing")
}
} }
pricing.CreatedTime = util.GetCurrentTime() pricing.CreatedTime = util.GetCurrentTime()
_, err = AddPricing(pricing) _, err = AddPricing(pricing)
@ -765,89 +543,3 @@ func initDefinedPricing(pricing *Pricing) {
panic(err) panic(err)
} }
} }
func initDefinedInvitation(invitation *Invitation) {
existed, err := getInvitation(invitation.Owner, invitation.Name)
if err != nil {
panic(err)
}
if existed != nil {
if initDataNewOnly {
return
}
affected, err := DeleteInvitation(invitation)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete invitation")
}
}
invitation.CreatedTime = util.GetCurrentTime()
_, err = AddInvitation(invitation, "en")
if err != nil {
panic(err)
}
}
func initDefinedRecord(record *casvisorsdk.Record) {
record.Id = 0
record.CreatedTime = util.GetCurrentTime()
_ = AddRecord(record)
}
func initDefinedSession(session *Session) {
session.CreatedTime = util.GetCurrentTime()
_, err := AddSession(session)
if err != nil {
panic(err)
}
}
func initDefinedSubscription(subscription *Subscription) {
existed, err := getSubscription(subscription.Owner, subscription.Name)
if err != nil {
panic(err)
}
if existed != nil {
if initDataNewOnly {
return
}
affected, err := DeleteSubscription(subscription)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete subscription")
}
}
subscription.CreatedTime = util.GetCurrentTime()
_, err = AddSubscription(subscription)
if err != nil {
panic(err)
}
}
func initDefinedTransaction(transaction *Transaction) {
existed, err := getTransaction(transaction.Owner, transaction.Name)
if err != nil {
panic(err)
}
if existed != nil {
if initDataNewOnly {
return
}
affected, err := DeleteTransaction(transaction)
if err != nil {
panic(err)
}
if !affected {
panic("Fail to delete transaction")
}
}
transaction.CreatedTime = util.GetCurrentTime()
_, err = AddTransaction(transaction)
if err != nil {
panic(err)
}
}

View File

@ -121,31 +121,6 @@ func writeInitDataToFile(filePath string) error {
return err return err
} }
invitations, err := GetInvitations("")
if err != nil {
return err
}
records, err := GetRecords()
if err != nil {
return err
}
sessions, err := GetSessions("")
if err != nil {
return err
}
subscriptions, err := GetSubscriptions("")
if err != nil {
return err
}
transactions, err := GetTransactions("")
if err != nil {
return err
}
data := &InitData{ data := &InitData{
Organizations: organizations, Organizations: organizations,
Applications: applications, Applications: applications,
@ -167,11 +142,6 @@ func writeInitDataToFile(filePath string) error {
Enforcers: enforcers, Enforcers: enforcers,
Plans: plans, Plans: plans,
Pricings: pricings, Pricings: pricings,
Invitations: invitations,
Records: records,
Sessions: sessions,
Subscriptions: subscriptions,
Transactions: transactions,
} }
text := util.StructToJsonFormatted(data) text := util.StructToJsonFormatted(data)

View File

@ -32,8 +32,6 @@ type Ldap struct {
BaseDn string `xorm:"varchar(100)" json:"baseDn"` BaseDn string `xorm:"varchar(100)" json:"baseDn"`
Filter string `xorm:"varchar(200)" json:"filter"` Filter string `xorm:"varchar(200)" json:"filter"`
FilterFields []string `xorm:"varchar(100)" json:"filterFields"` FilterFields []string `xorm:"varchar(100)" json:"filterFields"`
DefaultGroup string `xorm:"varchar(100)" json:"defaultGroup"`
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
AutoSync int `json:"autoSync"` AutoSync int `json:"autoSync"`
LastSync string `xorm:"varchar(100)" json:"lastSync"` LastSync string `xorm:"varchar(100)" json:"lastSync"`
@ -150,7 +148,7 @@ func UpdateLdap(ldap *Ldap) (bool, error) {
} }
affected, err := ormer.Engine.ID(ldap.Id).Cols("owner", "server_name", "host", 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").Update(ldap) "port", "enable_ssl", "username", "password", "base_dn", "filter", "filter_fields", "auto_sync").Update(ldap)
if err != nil { if err != nil {
return false, nil return false, nil
} }

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